highstock.src.js 2.5 MB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469274702747127472274732747427475274762747727478274792748027481274822748327484274852748627487274882748927490274912749227493274942749527496274972749827499275002750127502275032750427505275062750727508275092751027511275122751327514275152751627517275182751927520275212752227523275242752527526275272752827529275302753127532275332753427535275362753727538275392754027541275422754327544275452754627547275482754927550275512755227553275542755527556275572755827559275602756127562275632756427565275662756727568275692757027571275722757327574275752757627577275782757927580275812758227583275842758527586275872758827589275902759127592275932759427595275962759727598275992760027601276022760327604276052760627607276082760927610276112761227613276142761527616276172761827619276202762127622276232762427625276262762727628276292763027631276322763327634276352763627637276382763927640276412764227643276442764527646276472764827649276502765127652276532765427655276562765727658276592766027661276622766327664276652766627667276682766927670276712767227673276742767527676276772767827679276802768127682276832768427685276862768727688276892769027691276922769327694276952769627697276982769927700277012770227703277042770527706277072770827709277102771127712277132771427715277162771727718277192772027721277222772327724277252772627727277282772927730277312773227733277342773527736277372773827739277402774127742277432774427745277462774727748277492775027751277522775327754277552775627757277582775927760277612776227763277642776527766277672776827769277702777127772277732777427775277762777727778277792778027781277822778327784277852778627787277882778927790277912779227793277942779527796277972779827799278002780127802278032780427805278062780727808278092781027811278122781327814278152781627817278182781927820278212782227823278242782527826278272782827829278302783127832278332783427835278362783727838278392784027841278422784327844278452784627847278482784927850278512785227853278542785527856278572785827859278602786127862278632786427865278662786727868278692787027871278722787327874278752787627877278782787927880278812788227883278842788527886278872788827889278902789127892278932789427895278962789727898278992790027901279022790327904279052790627907279082790927910279112791227913279142791527916279172791827919279202792127922279232792427925279262792727928279292793027931279322793327934279352793627937279382793927940279412794227943279442794527946279472794827949279502795127952279532795427955279562795727958279592796027961279622796327964279652796627967279682796927970279712797227973279742797527976279772797827979279802798127982279832798427985279862798727988279892799027991279922799327994279952799627997279982799928000280012800228003280042800528006280072800828009280102801128012280132801428015280162801728018280192802028021280222802328024280252802628027280282802928030280312803228033280342803528036280372803828039280402804128042280432804428045280462804728048280492805028051280522805328054280552805628057280582805928060280612806228063280642806528066280672806828069280702807128072280732807428075280762807728078280792808028081280822808328084280852808628087280882808928090280912809228093280942809528096280972809828099281002810128102281032810428105281062810728108281092811028111281122811328114281152811628117281182811928120281212812228123281242812528126281272812828129281302813128132281332813428135281362813728138281392814028141281422814328144281452814628147281482814928150281512815228153281542815528156281572815828159281602816128162281632816428165281662816728168281692817028171281722817328174281752817628177281782817928180281812818228183281842818528186281872818828189281902819128192281932819428195281962819728198281992820028201282022820328204282052820628207282082820928210282112821228213282142821528216282172821828219282202822128222282232822428225282262822728228282292823028231282322823328234282352823628237282382823928240282412824228243282442824528246282472824828249282502825128252282532825428255282562825728258282592826028261282622826328264282652826628267282682826928270282712827228273282742827528276282772827828279282802828128282282832828428285282862828728288282892829028291282922829328294282952829628297282982829928300283012830228303283042830528306283072830828309283102831128312283132831428315283162831728318283192832028321283222832328324283252832628327283282832928330283312833228333283342833528336283372833828339283402834128342283432834428345283462834728348283492835028351283522835328354283552835628357283582835928360283612836228363283642836528366283672836828369283702837128372283732837428375283762837728378283792838028381283822838328384283852838628387283882838928390283912839228393283942839528396283972839828399284002840128402284032840428405284062840728408284092841028411284122841328414284152841628417284182841928420284212842228423284242842528426284272842828429284302843128432284332843428435284362843728438284392844028441284422844328444284452844628447284482844928450284512845228453284542845528456284572845828459284602846128462284632846428465284662846728468284692847028471284722847328474284752847628477284782847928480284812848228483284842848528486284872848828489284902849128492284932849428495284962849728498284992850028501285022850328504285052850628507285082850928510285112851228513285142851528516285172851828519285202852128522285232852428525285262852728528285292853028531285322853328534285352853628537285382853928540285412854228543285442854528546285472854828549285502855128552285532855428555285562855728558285592856028561285622856328564285652856628567285682856928570285712857228573285742857528576285772857828579285802858128582285832858428585285862858728588285892859028591285922859328594285952859628597285982859928600286012860228603286042860528606286072860828609286102861128612286132861428615286162861728618286192862028621286222862328624286252862628627286282862928630286312863228633286342863528636286372863828639286402864128642286432864428645286462864728648286492865028651286522865328654286552865628657286582865928660286612866228663286642866528666286672866828669286702867128672286732867428675286762867728678286792868028681286822868328684286852868628687286882868928690286912869228693286942869528696286972869828699287002870128702287032870428705287062870728708287092871028711287122871328714287152871628717287182871928720287212872228723287242872528726287272872828729287302873128732287332873428735287362873728738287392874028741287422874328744287452874628747287482874928750287512875228753287542875528756287572875828759287602876128762287632876428765287662876728768287692877028771287722877328774287752877628777287782877928780287812878228783287842878528786287872878828789287902879128792287932879428795287962879728798287992880028801288022880328804288052880628807288082880928810288112881228813288142881528816288172881828819288202882128822288232882428825288262882728828288292883028831288322883328834288352883628837288382883928840288412884228843288442884528846288472884828849288502885128852288532885428855288562885728858288592886028861288622886328864288652886628867288682886928870288712887228873288742887528876288772887828879288802888128882288832888428885288862888728888288892889028891288922889328894288952889628897288982889928900289012890228903289042890528906289072890828909289102891128912289132891428915289162891728918289192892028921289222892328924289252892628927289282892928930289312893228933289342893528936289372893828939289402894128942289432894428945289462894728948289492895028951289522895328954289552895628957289582895928960289612896228963289642896528966289672896828969289702897128972289732897428975289762897728978289792898028981289822898328984289852898628987289882898928990289912899228993289942899528996289972899828999290002900129002290032900429005290062900729008290092901029011290122901329014290152901629017290182901929020290212902229023290242902529026290272902829029290302903129032290332903429035290362903729038290392904029041290422904329044290452904629047290482904929050290512905229053290542905529056290572905829059290602906129062290632906429065290662906729068290692907029071290722907329074290752907629077290782907929080290812908229083290842908529086290872908829089290902909129092290932909429095290962909729098290992910029101291022910329104291052910629107291082910929110291112911229113291142911529116291172911829119291202912129122291232912429125291262912729128291292913029131291322913329134291352913629137291382913929140291412914229143291442914529146291472914829149291502915129152291532915429155291562915729158291592916029161291622916329164291652916629167291682916929170291712917229173291742917529176291772917829179291802918129182291832918429185291862918729188291892919029191291922919329194291952919629197291982919929200292012920229203292042920529206292072920829209292102921129212292132921429215292162921729218292192922029221292222922329224292252922629227292282922929230292312923229233292342923529236292372923829239292402924129242292432924429245292462924729248292492925029251292522925329254292552925629257292582925929260292612926229263292642926529266292672926829269292702927129272292732927429275292762927729278292792928029281292822928329284292852928629287292882928929290292912929229293292942929529296292972929829299293002930129302293032930429305293062930729308293092931029311293122931329314293152931629317293182931929320293212932229323293242932529326293272932829329293302933129332293332933429335293362933729338293392934029341293422934329344293452934629347293482934929350293512935229353293542935529356293572935829359293602936129362293632936429365293662936729368293692937029371293722937329374293752937629377293782937929380293812938229383293842938529386293872938829389293902939129392293932939429395293962939729398293992940029401294022940329404294052940629407294082940929410294112941229413294142941529416294172941829419294202942129422294232942429425294262942729428294292943029431294322943329434294352943629437294382943929440294412944229443294442944529446294472944829449294502945129452294532945429455294562945729458294592946029461294622946329464294652946629467294682946929470294712947229473294742947529476294772947829479294802948129482294832948429485294862948729488294892949029491294922949329494294952949629497294982949929500295012950229503295042950529506295072950829509295102951129512295132951429515295162951729518295192952029521295222952329524295252952629527295282952929530295312953229533295342953529536295372953829539295402954129542295432954429545295462954729548295492955029551295522955329554295552955629557295582955929560295612956229563295642956529566295672956829569295702957129572295732957429575295762957729578295792958029581295822958329584295852958629587295882958929590295912959229593295942959529596295972959829599296002960129602296032960429605296062960729608296092961029611296122961329614296152961629617296182961929620296212962229623296242962529626296272962829629296302963129632296332963429635296362963729638296392964029641296422964329644296452964629647296482964929650296512965229653296542965529656296572965829659296602966129662296632966429665296662966729668296692967029671296722967329674296752967629677296782967929680296812968229683296842968529686296872968829689296902969129692296932969429695296962969729698296992970029701297022970329704297052970629707297082970929710297112971229713297142971529716297172971829719297202972129722297232972429725297262972729728297292973029731297322973329734297352973629737297382973929740297412974229743297442974529746297472974829749297502975129752297532975429755297562975729758297592976029761297622976329764297652976629767297682976929770297712977229773297742977529776297772977829779297802978129782297832978429785297862978729788297892979029791297922979329794297952979629797297982979929800298012980229803298042980529806298072980829809298102981129812298132981429815298162981729818298192982029821298222982329824298252982629827298282982929830298312983229833298342983529836298372983829839298402984129842298432984429845298462984729848298492985029851298522985329854298552985629857298582985929860298612986229863298642986529866298672986829869298702987129872298732987429875298762987729878298792988029881298822988329884298852988629887298882988929890298912989229893298942989529896298972989829899299002990129902299032990429905299062990729908299092991029911299122991329914299152991629917299182991929920299212992229923299242992529926299272992829929299302993129932299332993429935299362993729938299392994029941299422994329944299452994629947299482994929950299512995229953299542995529956299572995829959299602996129962299632996429965299662996729968299692997029971299722997329974299752997629977299782997929980299812998229983299842998529986299872998829989299902999129992299932999429995299962999729998299993000030001300023000330004300053000630007300083000930010300113001230013300143001530016300173001830019300203002130022300233002430025300263002730028300293003030031300323003330034300353003630037300383003930040300413004230043300443004530046300473004830049300503005130052300533005430055300563005730058300593006030061300623006330064300653006630067300683006930070300713007230073300743007530076300773007830079300803008130082300833008430085300863008730088300893009030091300923009330094300953009630097300983009930100301013010230103301043010530106301073010830109301103011130112301133011430115301163011730118301193012030121301223012330124301253012630127301283012930130301313013230133301343013530136301373013830139301403014130142301433014430145301463014730148301493015030151301523015330154301553015630157301583015930160301613016230163301643016530166301673016830169301703017130172301733017430175301763017730178301793018030181301823018330184301853018630187301883018930190301913019230193301943019530196301973019830199302003020130202302033020430205302063020730208302093021030211302123021330214302153021630217302183021930220302213022230223302243022530226302273022830229302303023130232302333023430235302363023730238302393024030241302423024330244302453024630247302483024930250302513025230253302543025530256302573025830259302603026130262302633026430265302663026730268302693027030271302723027330274302753027630277302783027930280302813028230283302843028530286302873028830289302903029130292302933029430295302963029730298302993030030301303023030330304303053030630307303083030930310303113031230313303143031530316303173031830319303203032130322303233032430325303263032730328303293033030331303323033330334303353033630337303383033930340303413034230343303443034530346303473034830349303503035130352303533035430355303563035730358303593036030361303623036330364303653036630367303683036930370303713037230373303743037530376303773037830379303803038130382303833038430385303863038730388303893039030391303923039330394303953039630397303983039930400304013040230403304043040530406304073040830409304103041130412304133041430415304163041730418304193042030421304223042330424304253042630427304283042930430304313043230433304343043530436304373043830439304403044130442304433044430445304463044730448304493045030451304523045330454304553045630457304583045930460304613046230463304643046530466304673046830469304703047130472304733047430475304763047730478304793048030481304823048330484304853048630487304883048930490304913049230493304943049530496304973049830499305003050130502305033050430505305063050730508305093051030511305123051330514305153051630517305183051930520305213052230523305243052530526305273052830529305303053130532305333053430535305363053730538305393054030541305423054330544305453054630547305483054930550305513055230553305543055530556305573055830559305603056130562305633056430565305663056730568305693057030571305723057330574305753057630577305783057930580305813058230583305843058530586305873058830589305903059130592305933059430595305963059730598305993060030601306023060330604306053060630607306083060930610306113061230613306143061530616306173061830619306203062130622306233062430625306263062730628306293063030631306323063330634306353063630637306383063930640306413064230643306443064530646306473064830649306503065130652306533065430655306563065730658306593066030661306623066330664306653066630667306683066930670306713067230673306743067530676306773067830679306803068130682306833068430685306863068730688306893069030691306923069330694306953069630697306983069930700307013070230703307043070530706307073070830709307103071130712307133071430715307163071730718307193072030721307223072330724307253072630727307283072930730307313073230733307343073530736307373073830739307403074130742307433074430745307463074730748307493075030751307523075330754307553075630757307583075930760307613076230763307643076530766307673076830769307703077130772307733077430775307763077730778307793078030781307823078330784307853078630787307883078930790307913079230793307943079530796307973079830799308003080130802308033080430805308063080730808308093081030811308123081330814308153081630817308183081930820308213082230823308243082530826308273082830829308303083130832308333083430835308363083730838308393084030841308423084330844308453084630847308483084930850308513085230853308543085530856308573085830859308603086130862308633086430865308663086730868308693087030871308723087330874308753087630877308783087930880308813088230883308843088530886308873088830889308903089130892308933089430895308963089730898308993090030901309023090330904309053090630907309083090930910309113091230913309143091530916309173091830919309203092130922309233092430925309263092730928309293093030931309323093330934309353093630937309383093930940309413094230943309443094530946309473094830949309503095130952309533095430955309563095730958309593096030961309623096330964309653096630967309683096930970309713097230973309743097530976309773097830979309803098130982309833098430985309863098730988309893099030991309923099330994309953099630997309983099931000310013100231003310043100531006310073100831009310103101131012310133101431015310163101731018310193102031021310223102331024310253102631027310283102931030310313103231033310343103531036310373103831039310403104131042310433104431045310463104731048310493105031051310523105331054310553105631057310583105931060310613106231063310643106531066310673106831069310703107131072310733107431075310763107731078310793108031081310823108331084310853108631087310883108931090310913109231093310943109531096310973109831099311003110131102311033110431105311063110731108311093111031111311123111331114311153111631117311183111931120311213112231123311243112531126311273112831129311303113131132311333113431135311363113731138311393114031141311423114331144311453114631147311483114931150311513115231153311543115531156311573115831159311603116131162311633116431165311663116731168311693117031171311723117331174311753117631177311783117931180311813118231183311843118531186311873118831189311903119131192311933119431195311963119731198311993120031201312023120331204312053120631207312083120931210312113121231213312143121531216312173121831219312203122131222312233122431225312263122731228312293123031231312323123331234312353123631237312383123931240312413124231243312443124531246312473124831249312503125131252312533125431255312563125731258312593126031261312623126331264312653126631267312683126931270312713127231273312743127531276312773127831279312803128131282312833128431285312863128731288312893129031291312923129331294312953129631297312983129931300313013130231303313043130531306313073130831309313103131131312313133131431315313163131731318313193132031321313223132331324313253132631327313283132931330313313133231333313343133531336313373133831339313403134131342313433134431345313463134731348313493135031351313523135331354313553135631357313583135931360313613136231363313643136531366313673136831369313703137131372313733137431375313763137731378313793138031381313823138331384313853138631387313883138931390313913139231393313943139531396313973139831399314003140131402314033140431405314063140731408314093141031411314123141331414314153141631417314183141931420314213142231423314243142531426314273142831429314303143131432314333143431435314363143731438314393144031441314423144331444314453144631447314483144931450314513145231453314543145531456314573145831459314603146131462314633146431465314663146731468314693147031471314723147331474314753147631477314783147931480314813148231483314843148531486314873148831489314903149131492314933149431495314963149731498314993150031501315023150331504315053150631507315083150931510315113151231513315143151531516315173151831519315203152131522315233152431525315263152731528315293153031531315323153331534315353153631537315383153931540315413154231543315443154531546315473154831549315503155131552315533155431555315563155731558315593156031561315623156331564315653156631567315683156931570315713157231573315743157531576315773157831579315803158131582315833158431585315863158731588315893159031591315923159331594315953159631597315983159931600316013160231603316043160531606316073160831609316103161131612316133161431615316163161731618316193162031621316223162331624316253162631627316283162931630316313163231633316343163531636316373163831639316403164131642316433164431645316463164731648316493165031651316523165331654316553165631657316583165931660316613166231663316643166531666316673166831669316703167131672316733167431675316763167731678316793168031681316823168331684316853168631687316883168931690316913169231693316943169531696316973169831699317003170131702317033170431705317063170731708317093171031711317123171331714317153171631717317183171931720317213172231723317243172531726317273172831729317303173131732317333173431735317363173731738317393174031741317423174331744317453174631747317483174931750317513175231753317543175531756317573175831759317603176131762317633176431765317663176731768317693177031771317723177331774317753177631777317783177931780317813178231783317843178531786317873178831789317903179131792317933179431795317963179731798317993180031801318023180331804318053180631807318083180931810318113181231813318143181531816318173181831819318203182131822318233182431825318263182731828318293183031831318323183331834318353183631837318383183931840318413184231843318443184531846318473184831849318503185131852318533185431855318563185731858318593186031861318623186331864318653186631867318683186931870318713187231873318743187531876318773187831879318803188131882318833188431885318863188731888318893189031891318923189331894318953189631897318983189931900319013190231903319043190531906319073190831909319103191131912319133191431915319163191731918319193192031921319223192331924319253192631927319283192931930319313193231933319343193531936319373193831939319403194131942319433194431945319463194731948319493195031951319523195331954319553195631957319583195931960319613196231963319643196531966319673196831969319703197131972319733197431975319763197731978319793198031981319823198331984319853198631987319883198931990319913199231993319943199531996319973199831999320003200132002320033200432005320063200732008320093201032011320123201332014320153201632017320183201932020320213202232023320243202532026320273202832029320303203132032320333203432035320363203732038320393204032041320423204332044320453204632047320483204932050320513205232053320543205532056320573205832059320603206132062320633206432065320663206732068320693207032071320723207332074320753207632077320783207932080320813208232083320843208532086320873208832089320903209132092320933209432095320963209732098320993210032101321023210332104321053210632107321083210932110321113211232113321143211532116321173211832119321203212132122321233212432125321263212732128321293213032131321323213332134321353213632137321383213932140321413214232143321443214532146321473214832149321503215132152321533215432155321563215732158321593216032161321623216332164321653216632167321683216932170321713217232173321743217532176321773217832179321803218132182321833218432185321863218732188321893219032191321923219332194321953219632197321983219932200322013220232203322043220532206322073220832209322103221132212322133221432215322163221732218322193222032221322223222332224322253222632227322283222932230322313223232233322343223532236322373223832239322403224132242322433224432245322463224732248322493225032251322523225332254322553225632257322583225932260322613226232263322643226532266322673226832269322703227132272322733227432275322763227732278322793228032281322823228332284322853228632287322883228932290322913229232293322943229532296322973229832299323003230132302323033230432305323063230732308323093231032311323123231332314323153231632317323183231932320323213232232323323243232532326323273232832329323303233132332323333233432335323363233732338323393234032341323423234332344323453234632347323483234932350323513235232353323543235532356323573235832359323603236132362323633236432365323663236732368323693237032371323723237332374323753237632377323783237932380323813238232383323843238532386323873238832389323903239132392323933239432395323963239732398323993240032401324023240332404324053240632407324083240932410324113241232413324143241532416324173241832419324203242132422324233242432425324263242732428324293243032431324323243332434324353243632437324383243932440324413244232443324443244532446324473244832449324503245132452324533245432455324563245732458324593246032461324623246332464324653246632467324683246932470324713247232473324743247532476324773247832479324803248132482324833248432485324863248732488324893249032491324923249332494324953249632497324983249932500325013250232503325043250532506325073250832509325103251132512325133251432515325163251732518325193252032521325223252332524325253252632527325283252932530325313253232533325343253532536325373253832539325403254132542325433254432545325463254732548325493255032551325523255332554325553255632557325583255932560325613256232563325643256532566325673256832569325703257132572325733257432575325763257732578325793258032581325823258332584325853258632587325883258932590325913259232593325943259532596325973259832599326003260132602326033260432605326063260732608326093261032611326123261332614326153261632617326183261932620326213262232623326243262532626326273262832629326303263132632326333263432635326363263732638326393264032641326423264332644326453264632647326483264932650326513265232653326543265532656326573265832659326603266132662326633266432665326663266732668326693267032671326723267332674326753267632677326783267932680326813268232683326843268532686326873268832689326903269132692326933269432695326963269732698326993270032701327023270332704327053270632707327083270932710327113271232713327143271532716327173271832719327203272132722327233272432725327263272732728327293273032731327323273332734327353273632737327383273932740327413274232743327443274532746327473274832749327503275132752327533275432755327563275732758327593276032761327623276332764327653276632767327683276932770327713277232773327743277532776327773277832779327803278132782327833278432785327863278732788327893279032791327923279332794327953279632797327983279932800328013280232803328043280532806328073280832809328103281132812328133281432815328163281732818328193282032821328223282332824328253282632827328283282932830328313283232833328343283532836328373283832839328403284132842328433284432845328463284732848328493285032851328523285332854328553285632857328583285932860328613286232863328643286532866328673286832869328703287132872328733287432875328763287732878328793288032881328823288332884328853288632887328883288932890328913289232893328943289532896328973289832899329003290132902329033290432905329063290732908329093291032911329123291332914329153291632917329183291932920329213292232923329243292532926329273292832929329303293132932329333293432935329363293732938329393294032941329423294332944329453294632947329483294932950329513295232953329543295532956329573295832959329603296132962329633296432965329663296732968329693297032971329723297332974329753297632977329783297932980329813298232983329843298532986329873298832989329903299132992329933299432995329963299732998329993300033001330023300333004330053300633007330083300933010330113301233013330143301533016330173301833019330203302133022330233302433025330263302733028330293303033031330323303333034330353303633037330383303933040330413304233043330443304533046330473304833049330503305133052330533305433055330563305733058330593306033061330623306333064330653306633067330683306933070330713307233073330743307533076330773307833079330803308133082330833308433085330863308733088330893309033091330923309333094330953309633097330983309933100331013310233103331043310533106331073310833109331103311133112331133311433115331163311733118331193312033121331223312333124331253312633127331283312933130331313313233133331343313533136331373313833139331403314133142331433314433145331463314733148331493315033151331523315333154331553315633157331583315933160331613316233163331643316533166331673316833169331703317133172331733317433175331763317733178331793318033181331823318333184331853318633187331883318933190331913319233193331943319533196331973319833199332003320133202332033320433205332063320733208332093321033211332123321333214332153321633217332183321933220332213322233223332243322533226332273322833229332303323133232332333323433235332363323733238332393324033241332423324333244332453324633247332483324933250332513325233253332543325533256332573325833259332603326133262332633326433265332663326733268332693327033271332723327333274332753327633277332783327933280332813328233283332843328533286332873328833289332903329133292332933329433295332963329733298332993330033301333023330333304333053330633307333083330933310333113331233313333143331533316333173331833319333203332133322333233332433325333263332733328333293333033331333323333333334333353333633337333383333933340333413334233343333443334533346333473334833349333503335133352333533335433355333563335733358333593336033361333623336333364333653336633367333683336933370333713337233373333743337533376333773337833379333803338133382333833338433385333863338733388333893339033391333923339333394333953339633397333983339933400334013340233403334043340533406334073340833409334103341133412334133341433415334163341733418334193342033421334223342333424334253342633427334283342933430334313343233433334343343533436334373343833439334403344133442334433344433445334463344733448334493345033451334523345333454334553345633457334583345933460334613346233463334643346533466334673346833469334703347133472334733347433475334763347733478334793348033481334823348333484334853348633487334883348933490334913349233493334943349533496334973349833499335003350133502335033350433505335063350733508335093351033511335123351333514335153351633517335183351933520335213352233523335243352533526335273352833529335303353133532335333353433535335363353733538335393354033541335423354333544335453354633547335483354933550335513355233553335543355533556335573355833559335603356133562335633356433565335663356733568335693357033571335723357333574335753357633577335783357933580335813358233583335843358533586335873358833589335903359133592335933359433595335963359733598335993360033601336023360333604336053360633607336083360933610336113361233613336143361533616336173361833619336203362133622336233362433625336263362733628336293363033631336323363333634336353363633637336383363933640336413364233643336443364533646336473364833649336503365133652336533365433655336563365733658336593366033661336623366333664336653366633667336683366933670336713367233673336743367533676336773367833679336803368133682336833368433685336863368733688336893369033691336923369333694336953369633697336983369933700337013370233703337043370533706337073370833709337103371133712337133371433715337163371733718337193372033721337223372333724337253372633727337283372933730337313373233733337343373533736337373373833739337403374133742337433374433745337463374733748337493375033751337523375333754337553375633757337583375933760337613376233763337643376533766337673376833769337703377133772337733377433775337763377733778337793378033781337823378333784337853378633787337883378933790337913379233793337943379533796337973379833799338003380133802338033380433805338063380733808338093381033811338123381333814338153381633817338183381933820338213382233823338243382533826338273382833829338303383133832338333383433835338363383733838338393384033841338423384333844338453384633847338483384933850338513385233853338543385533856338573385833859338603386133862338633386433865338663386733868338693387033871338723387333874338753387633877338783387933880338813388233883338843388533886338873388833889338903389133892338933389433895338963389733898338993390033901339023390333904339053390633907339083390933910339113391233913339143391533916339173391833919339203392133922339233392433925339263392733928339293393033931339323393333934339353393633937339383393933940339413394233943339443394533946339473394833949339503395133952339533395433955339563395733958339593396033961339623396333964339653396633967339683396933970339713397233973339743397533976339773397833979339803398133982339833398433985339863398733988339893399033991339923399333994339953399633997339983399934000340013400234003340043400534006340073400834009340103401134012340133401434015340163401734018340193402034021340223402334024340253402634027340283402934030340313403234033340343403534036340373403834039340403404134042340433404434045340463404734048340493405034051340523405334054340553405634057340583405934060340613406234063340643406534066340673406834069340703407134072340733407434075340763407734078340793408034081340823408334084340853408634087340883408934090340913409234093340943409534096340973409834099341003410134102341033410434105341063410734108341093411034111341123411334114341153411634117341183411934120341213412234123341243412534126341273412834129341303413134132341333413434135341363413734138341393414034141341423414334144341453414634147341483414934150341513415234153341543415534156341573415834159341603416134162341633416434165341663416734168341693417034171341723417334174341753417634177341783417934180341813418234183341843418534186341873418834189341903419134192341933419434195341963419734198341993420034201342023420334204342053420634207342083420934210342113421234213342143421534216342173421834219342203422134222342233422434225342263422734228342293423034231342323423334234342353423634237342383423934240342413424234243342443424534246342473424834249342503425134252342533425434255342563425734258342593426034261342623426334264342653426634267342683426934270342713427234273342743427534276342773427834279342803428134282342833428434285342863428734288342893429034291342923429334294342953429634297342983429934300343013430234303343043430534306343073430834309343103431134312343133431434315343163431734318343193432034321343223432334324343253432634327343283432934330343313433234333343343433534336343373433834339343403434134342343433434434345343463434734348343493435034351343523435334354343553435634357343583435934360343613436234363343643436534366343673436834369343703437134372343733437434375343763437734378343793438034381343823438334384343853438634387343883438934390343913439234393343943439534396343973439834399344003440134402344033440434405344063440734408344093441034411344123441334414344153441634417344183441934420344213442234423344243442534426344273442834429344303443134432344333443434435344363443734438344393444034441344423444334444344453444634447344483444934450344513445234453344543445534456344573445834459344603446134462344633446434465344663446734468344693447034471344723447334474344753447634477344783447934480344813448234483344843448534486344873448834489344903449134492344933449434495344963449734498344993450034501345023450334504345053450634507345083450934510345113451234513345143451534516345173451834519345203452134522345233452434525345263452734528345293453034531345323453334534345353453634537345383453934540345413454234543345443454534546345473454834549345503455134552345533455434555345563455734558345593456034561345623456334564345653456634567345683456934570345713457234573345743457534576345773457834579345803458134582345833458434585345863458734588345893459034591345923459334594345953459634597345983459934600346013460234603346043460534606346073460834609346103461134612346133461434615346163461734618346193462034621346223462334624346253462634627346283462934630346313463234633346343463534636346373463834639346403464134642346433464434645346463464734648346493465034651346523465334654346553465634657346583465934660346613466234663346643466534666346673466834669346703467134672346733467434675346763467734678346793468034681346823468334684346853468634687346883468934690346913469234693346943469534696346973469834699347003470134702347033470434705347063470734708347093471034711347123471334714347153471634717347183471934720347213472234723347243472534726347273472834729347303473134732347333473434735347363473734738347393474034741347423474334744347453474634747347483474934750347513475234753347543475534756347573475834759347603476134762347633476434765347663476734768347693477034771347723477334774347753477634777347783477934780347813478234783347843478534786347873478834789347903479134792347933479434795347963479734798347993480034801348023480334804348053480634807348083480934810348113481234813348143481534816348173481834819348203482134822348233482434825348263482734828348293483034831348323483334834348353483634837348383483934840348413484234843348443484534846348473484834849348503485134852348533485434855348563485734858348593486034861348623486334864348653486634867348683486934870348713487234873348743487534876348773487834879348803488134882348833488434885348863488734888348893489034891348923489334894348953489634897348983489934900349013490234903349043490534906349073490834909349103491134912349133491434915349163491734918349193492034921349223492334924349253492634927349283492934930349313493234933349343493534936349373493834939349403494134942349433494434945349463494734948349493495034951349523495334954349553495634957349583495934960349613496234963349643496534966349673496834969349703497134972349733497434975349763497734978349793498034981349823498334984349853498634987349883498934990349913499234993349943499534996349973499834999350003500135002350033500435005350063500735008350093501035011350123501335014350153501635017350183501935020350213502235023350243502535026350273502835029350303503135032350333503435035350363503735038350393504035041350423504335044350453504635047350483504935050350513505235053350543505535056350573505835059350603506135062350633506435065350663506735068350693507035071350723507335074350753507635077350783507935080350813508235083350843508535086350873508835089350903509135092350933509435095350963509735098350993510035101351023510335104351053510635107351083510935110351113511235113351143511535116351173511835119351203512135122351233512435125351263512735128351293513035131351323513335134351353513635137351383513935140351413514235143351443514535146351473514835149351503515135152351533515435155351563515735158351593516035161351623516335164351653516635167351683516935170351713517235173351743517535176351773517835179351803518135182351833518435185351863518735188351893519035191351923519335194351953519635197351983519935200352013520235203352043520535206352073520835209352103521135212352133521435215352163521735218352193522035221352223522335224352253522635227352283522935230352313523235233352343523535236352373523835239352403524135242352433524435245352463524735248352493525035251352523525335254352553525635257352583525935260352613526235263352643526535266352673526835269352703527135272352733527435275352763527735278352793528035281352823528335284352853528635287352883528935290352913529235293352943529535296352973529835299353003530135302353033530435305353063530735308353093531035311353123531335314353153531635317353183531935320353213532235323353243532535326353273532835329353303533135332353333533435335353363533735338353393534035341353423534335344353453534635347353483534935350353513535235353353543535535356353573535835359353603536135362353633536435365353663536735368353693537035371353723537335374353753537635377353783537935380353813538235383353843538535386353873538835389353903539135392353933539435395353963539735398353993540035401354023540335404354053540635407354083540935410354113541235413354143541535416354173541835419354203542135422354233542435425354263542735428354293543035431354323543335434354353543635437354383543935440354413544235443354443544535446354473544835449354503545135452354533545435455354563545735458354593546035461354623546335464354653546635467354683546935470354713547235473354743547535476354773547835479354803548135482354833548435485354863548735488354893549035491354923549335494354953549635497354983549935500355013550235503355043550535506355073550835509355103551135512355133551435515355163551735518355193552035521355223552335524355253552635527355283552935530355313553235533355343553535536355373553835539355403554135542355433554435545355463554735548355493555035551355523555335554355553555635557355583555935560355613556235563355643556535566355673556835569355703557135572355733557435575355763557735578355793558035581355823558335584355853558635587355883558935590355913559235593355943559535596355973559835599356003560135602356033560435605356063560735608356093561035611356123561335614356153561635617356183561935620356213562235623356243562535626356273562835629356303563135632356333563435635356363563735638356393564035641356423564335644356453564635647356483564935650356513565235653356543565535656356573565835659356603566135662356633566435665356663566735668356693567035671356723567335674356753567635677356783567935680356813568235683356843568535686356873568835689356903569135692356933569435695356963569735698356993570035701357023570335704357053570635707357083570935710357113571235713357143571535716357173571835719357203572135722357233572435725357263572735728357293573035731357323573335734357353573635737357383573935740357413574235743357443574535746357473574835749357503575135752357533575435755357563575735758357593576035761357623576335764357653576635767357683576935770357713577235773357743577535776357773577835779357803578135782357833578435785357863578735788357893579035791357923579335794357953579635797357983579935800358013580235803358043580535806358073580835809358103581135812358133581435815358163581735818358193582035821358223582335824358253582635827358283582935830358313583235833358343583535836358373583835839358403584135842358433584435845358463584735848358493585035851358523585335854358553585635857358583585935860358613586235863358643586535866358673586835869358703587135872358733587435875358763587735878358793588035881358823588335884358853588635887358883588935890358913589235893358943589535896358973589835899359003590135902359033590435905359063590735908359093591035911359123591335914359153591635917359183591935920359213592235923359243592535926359273592835929359303593135932359333593435935359363593735938359393594035941359423594335944359453594635947359483594935950359513595235953359543595535956359573595835959359603596135962359633596435965359663596735968359693597035971359723597335974359753597635977359783597935980359813598235983359843598535986359873598835989359903599135992359933599435995359963599735998359993600036001360023600336004360053600636007360083600936010360113601236013360143601536016360173601836019360203602136022360233602436025360263602736028360293603036031360323603336034360353603636037360383603936040360413604236043360443604536046360473604836049360503605136052360533605436055360563605736058360593606036061360623606336064360653606636067360683606936070360713607236073360743607536076360773607836079360803608136082360833608436085360863608736088360893609036091360923609336094360953609636097360983609936100361013610236103361043610536106361073610836109361103611136112361133611436115361163611736118361193612036121361223612336124361253612636127361283612936130361313613236133361343613536136361373613836139361403614136142361433614436145361463614736148361493615036151361523615336154361553615636157361583615936160361613616236163361643616536166361673616836169361703617136172361733617436175361763617736178361793618036181361823618336184361853618636187361883618936190361913619236193361943619536196361973619836199362003620136202362033620436205362063620736208362093621036211362123621336214362153621636217362183621936220362213622236223362243622536226362273622836229362303623136232362333623436235362363623736238362393624036241362423624336244362453624636247362483624936250362513625236253362543625536256362573625836259362603626136262362633626436265362663626736268362693627036271362723627336274362753627636277362783627936280362813628236283362843628536286362873628836289362903629136292362933629436295362963629736298362993630036301363023630336304363053630636307363083630936310363113631236313363143631536316363173631836319363203632136322363233632436325363263632736328363293633036331363323633336334363353633636337363383633936340363413634236343363443634536346363473634836349363503635136352363533635436355363563635736358363593636036361363623636336364363653636636367363683636936370363713637236373363743637536376363773637836379363803638136382363833638436385363863638736388363893639036391363923639336394363953639636397363983639936400364013640236403364043640536406364073640836409364103641136412364133641436415364163641736418364193642036421364223642336424364253642636427364283642936430364313643236433364343643536436364373643836439364403644136442364433644436445364463644736448364493645036451364523645336454364553645636457364583645936460364613646236463364643646536466364673646836469364703647136472364733647436475364763647736478364793648036481364823648336484364853648636487364883648936490364913649236493364943649536496364973649836499365003650136502365033650436505365063650736508365093651036511365123651336514365153651636517365183651936520365213652236523365243652536526365273652836529365303653136532365333653436535365363653736538365393654036541365423654336544365453654636547365483654936550365513655236553365543655536556365573655836559365603656136562365633656436565365663656736568365693657036571365723657336574365753657636577365783657936580365813658236583365843658536586365873658836589365903659136592365933659436595365963659736598365993660036601366023660336604366053660636607366083660936610366113661236613366143661536616366173661836619366203662136622366233662436625366263662736628366293663036631366323663336634366353663636637366383663936640366413664236643366443664536646366473664836649366503665136652366533665436655366563665736658366593666036661366623666336664366653666636667366683666936670366713667236673366743667536676366773667836679366803668136682366833668436685366863668736688366893669036691366923669336694366953669636697366983669936700367013670236703367043670536706367073670836709367103671136712367133671436715367163671736718367193672036721367223672336724367253672636727367283672936730367313673236733367343673536736367373673836739367403674136742367433674436745367463674736748367493675036751367523675336754367553675636757367583675936760367613676236763367643676536766367673676836769367703677136772367733677436775367763677736778367793678036781367823678336784367853678636787367883678936790367913679236793367943679536796367973679836799368003680136802368033680436805368063680736808368093681036811368123681336814368153681636817368183681936820368213682236823368243682536826368273682836829368303683136832368333683436835368363683736838368393684036841368423684336844368453684636847368483684936850368513685236853368543685536856368573685836859368603686136862368633686436865368663686736868368693687036871368723687336874368753687636877368783687936880368813688236883368843688536886368873688836889368903689136892368933689436895368963689736898368993690036901369023690336904369053690636907369083690936910369113691236913369143691536916369173691836919369203692136922369233692436925369263692736928369293693036931369323693336934369353693636937369383693936940369413694236943369443694536946369473694836949369503695136952369533695436955369563695736958369593696036961369623696336964369653696636967369683696936970369713697236973369743697536976369773697836979369803698136982369833698436985369863698736988369893699036991369923699336994369953699636997369983699937000370013700237003370043700537006370073700837009370103701137012370133701437015370163701737018370193702037021370223702337024370253702637027370283702937030370313703237033370343703537036370373703837039370403704137042370433704437045370463704737048370493705037051370523705337054370553705637057370583705937060370613706237063370643706537066370673706837069370703707137072370733707437075370763707737078370793708037081370823708337084370853708637087370883708937090370913709237093370943709537096370973709837099371003710137102371033710437105371063710737108371093711037111371123711337114371153711637117371183711937120371213712237123371243712537126371273712837129371303713137132371333713437135371363713737138371393714037141371423714337144371453714637147371483714937150371513715237153371543715537156371573715837159371603716137162371633716437165371663716737168371693717037171371723717337174371753717637177371783717937180371813718237183371843718537186371873718837189371903719137192371933719437195371963719737198371993720037201372023720337204372053720637207372083720937210372113721237213372143721537216372173721837219372203722137222372233722437225372263722737228372293723037231372323723337234372353723637237372383723937240372413724237243372443724537246372473724837249372503725137252372533725437255372563725737258372593726037261372623726337264372653726637267372683726937270372713727237273372743727537276372773727837279372803728137282372833728437285372863728737288372893729037291372923729337294372953729637297372983729937300373013730237303373043730537306373073730837309373103731137312373133731437315373163731737318373193732037321373223732337324373253732637327373283732937330373313733237333373343733537336373373733837339373403734137342373433734437345373463734737348373493735037351373523735337354373553735637357373583735937360373613736237363373643736537366373673736837369373703737137372373733737437375373763737737378373793738037381373823738337384373853738637387373883738937390373913739237393373943739537396373973739837399374003740137402374033740437405374063740737408374093741037411374123741337414374153741637417374183741937420374213742237423374243742537426374273742837429374303743137432374333743437435374363743737438374393744037441374423744337444374453744637447374483744937450374513745237453374543745537456374573745837459374603746137462374633746437465374663746737468374693747037471374723747337474374753747637477374783747937480374813748237483374843748537486374873748837489374903749137492374933749437495374963749737498374993750037501375023750337504375053750637507375083750937510375113751237513375143751537516375173751837519375203752137522375233752437525375263752737528375293753037531375323753337534375353753637537375383753937540375413754237543375443754537546375473754837549375503755137552375533755437555375563755737558375593756037561375623756337564375653756637567375683756937570375713757237573375743757537576375773757837579375803758137582375833758437585375863758737588375893759037591375923759337594375953759637597375983759937600376013760237603376043760537606376073760837609376103761137612376133761437615376163761737618376193762037621376223762337624376253762637627376283762937630376313763237633376343763537636376373763837639376403764137642376433764437645376463764737648376493765037651376523765337654376553765637657376583765937660376613766237663376643766537666376673766837669376703767137672376733767437675376763767737678376793768037681376823768337684376853768637687376883768937690376913769237693376943769537696376973769837699377003770137702377033770437705377063770737708377093771037711377123771337714377153771637717377183771937720377213772237723377243772537726377273772837729377303773137732377333773437735377363773737738377393774037741377423774337744377453774637747377483774937750377513775237753377543775537756377573775837759377603776137762377633776437765377663776737768377693777037771377723777337774377753777637777377783777937780377813778237783377843778537786377873778837789377903779137792377933779437795377963779737798377993780037801378023780337804378053780637807378083780937810378113781237813378143781537816378173781837819378203782137822378233782437825378263782737828378293783037831378323783337834378353783637837378383783937840378413784237843378443784537846378473784837849378503785137852378533785437855378563785737858378593786037861378623786337864378653786637867378683786937870378713787237873378743787537876378773787837879378803788137882378833788437885378863788737888378893789037891378923789337894378953789637897378983789937900379013790237903379043790537906379073790837909379103791137912379133791437915379163791737918379193792037921379223792337924379253792637927379283792937930379313793237933379343793537936379373793837939379403794137942379433794437945379463794737948379493795037951379523795337954379553795637957379583795937960379613796237963379643796537966379673796837969379703797137972379733797437975379763797737978379793798037981379823798337984379853798637987379883798937990379913799237993379943799537996379973799837999380003800138002380033800438005380063800738008380093801038011380123801338014380153801638017380183801938020380213802238023380243802538026380273802838029380303803138032380333803438035380363803738038380393804038041380423804338044380453804638047380483804938050380513805238053380543805538056380573805838059380603806138062380633806438065380663806738068380693807038071380723807338074380753807638077380783807938080380813808238083380843808538086380873808838089380903809138092380933809438095380963809738098380993810038101381023810338104381053810638107381083810938110381113811238113381143811538116381173811838119381203812138122381233812438125381263812738128381293813038131381323813338134381353813638137381383813938140381413814238143381443814538146381473814838149381503815138152381533815438155381563815738158381593816038161381623816338164381653816638167381683816938170381713817238173381743817538176381773817838179381803818138182381833818438185381863818738188381893819038191381923819338194381953819638197381983819938200382013820238203382043820538206382073820838209382103821138212382133821438215382163821738218382193822038221382223822338224382253822638227382283822938230382313823238233382343823538236382373823838239382403824138242382433824438245382463824738248382493825038251382523825338254382553825638257382583825938260382613826238263382643826538266382673826838269382703827138272382733827438275382763827738278382793828038281382823828338284382853828638287382883828938290382913829238293382943829538296382973829838299383003830138302383033830438305383063830738308383093831038311383123831338314383153831638317383183831938320383213832238323383243832538326383273832838329383303833138332383333833438335383363833738338383393834038341383423834338344383453834638347383483834938350383513835238353383543835538356383573835838359383603836138362383633836438365383663836738368383693837038371383723837338374383753837638377383783837938380383813838238383383843838538386383873838838389383903839138392383933839438395383963839738398383993840038401384023840338404384053840638407384083840938410384113841238413384143841538416384173841838419384203842138422384233842438425384263842738428384293843038431384323843338434384353843638437384383843938440384413844238443384443844538446384473844838449384503845138452384533845438455384563845738458384593846038461384623846338464384653846638467384683846938470384713847238473384743847538476384773847838479384803848138482384833848438485384863848738488384893849038491384923849338494384953849638497384983849938500385013850238503385043850538506385073850838509385103851138512385133851438515385163851738518385193852038521385223852338524385253852638527385283852938530385313853238533385343853538536385373853838539385403854138542385433854438545385463854738548385493855038551385523855338554385553855638557385583855938560385613856238563385643856538566385673856838569385703857138572385733857438575385763857738578385793858038581385823858338584385853858638587385883858938590385913859238593385943859538596385973859838599386003860138602386033860438605386063860738608386093861038611386123861338614386153861638617386183861938620386213862238623386243862538626386273862838629386303863138632386333863438635386363863738638386393864038641386423864338644386453864638647386483864938650386513865238653386543865538656386573865838659386603866138662386633866438665386663866738668386693867038671386723867338674386753867638677386783867938680386813868238683386843868538686386873868838689386903869138692386933869438695386963869738698386993870038701387023870338704387053870638707387083870938710387113871238713387143871538716387173871838719387203872138722387233872438725387263872738728387293873038731387323873338734387353873638737387383873938740387413874238743387443874538746387473874838749387503875138752387533875438755387563875738758387593876038761387623876338764387653876638767387683876938770387713877238773387743877538776387773877838779387803878138782387833878438785387863878738788387893879038791387923879338794387953879638797387983879938800388013880238803388043880538806388073880838809388103881138812388133881438815388163881738818388193882038821388223882338824388253882638827388283882938830388313883238833388343883538836388373883838839388403884138842388433884438845388463884738848388493885038851388523885338854388553885638857388583885938860388613886238863388643886538866388673886838869388703887138872388733887438875388763887738878388793888038881388823888338884388853888638887388883888938890388913889238893388943889538896388973889838899389003890138902389033890438905389063890738908389093891038911389123891338914389153891638917389183891938920389213892238923389243892538926389273892838929389303893138932389333893438935389363893738938389393894038941389423894338944389453894638947389483894938950389513895238953389543895538956389573895838959389603896138962389633896438965389663896738968389693897038971389723897338974389753897638977389783897938980389813898238983389843898538986389873898838989389903899138992389933899438995389963899738998389993900039001390023900339004390053900639007390083900939010390113901239013390143901539016390173901839019390203902139022390233902439025390263902739028390293903039031390323903339034390353903639037390383903939040390413904239043390443904539046390473904839049390503905139052390533905439055390563905739058390593906039061390623906339064390653906639067390683906939070390713907239073390743907539076390773907839079390803908139082390833908439085390863908739088390893909039091390923909339094390953909639097390983909939100391013910239103391043910539106391073910839109391103911139112391133911439115391163911739118391193912039121391223912339124391253912639127391283912939130391313913239133391343913539136391373913839139391403914139142391433914439145391463914739148391493915039151391523915339154391553915639157391583915939160391613916239163391643916539166391673916839169391703917139172391733917439175391763917739178391793918039181391823918339184391853918639187391883918939190391913919239193391943919539196391973919839199392003920139202392033920439205392063920739208392093921039211392123921339214392153921639217392183921939220392213922239223392243922539226392273922839229392303923139232392333923439235392363923739238392393924039241392423924339244392453924639247392483924939250392513925239253392543925539256392573925839259392603926139262392633926439265392663926739268392693927039271392723927339274392753927639277392783927939280392813928239283392843928539286392873928839289392903929139292392933929439295392963929739298392993930039301393023930339304393053930639307393083930939310393113931239313393143931539316393173931839319393203932139322393233932439325393263932739328393293933039331393323933339334393353933639337393383933939340393413934239343393443934539346393473934839349393503935139352393533935439355393563935739358393593936039361393623936339364393653936639367393683936939370393713937239373393743937539376393773937839379393803938139382393833938439385393863938739388393893939039391393923939339394393953939639397393983939939400394013940239403394043940539406394073940839409394103941139412394133941439415394163941739418394193942039421394223942339424394253942639427394283942939430394313943239433394343943539436394373943839439394403944139442394433944439445394463944739448394493945039451394523945339454394553945639457394583945939460394613946239463394643946539466394673946839469394703947139472394733947439475394763947739478394793948039481394823948339484394853948639487394883948939490394913949239493394943949539496394973949839499395003950139502395033950439505395063950739508395093951039511395123951339514395153951639517395183951939520395213952239523395243952539526395273952839529395303953139532395333953439535395363953739538395393954039541395423954339544395453954639547395483954939550395513955239553395543955539556395573955839559395603956139562395633956439565395663956739568395693957039571395723957339574395753957639577395783957939580395813958239583395843958539586395873958839589395903959139592395933959439595395963959739598395993960039601396023960339604396053960639607396083960939610396113961239613396143961539616396173961839619396203962139622396233962439625396263962739628396293963039631396323963339634396353963639637396383963939640396413964239643396443964539646396473964839649396503965139652396533965439655396563965739658396593966039661396623966339664396653966639667396683966939670396713967239673396743967539676396773967839679396803968139682396833968439685396863968739688396893969039691396923969339694396953969639697396983969939700397013970239703397043970539706397073970839709397103971139712397133971439715397163971739718397193972039721397223972339724397253972639727397283972939730397313973239733397343973539736397373973839739397403974139742397433974439745397463974739748397493975039751397523975339754397553975639757397583975939760397613976239763397643976539766397673976839769397703977139772397733977439775397763977739778397793978039781397823978339784397853978639787397883978939790397913979239793397943979539796397973979839799398003980139802398033980439805398063980739808398093981039811398123981339814398153981639817398183981939820398213982239823398243982539826398273982839829398303983139832398333983439835398363983739838398393984039841398423984339844398453984639847398483984939850398513985239853398543985539856398573985839859398603986139862398633986439865398663986739868398693987039871398723987339874398753987639877398783987939880398813988239883398843988539886398873988839889398903989139892398933989439895398963989739898398993990039901399023990339904399053990639907399083990939910399113991239913399143991539916399173991839919399203992139922399233992439925399263992739928399293993039931399323993339934399353993639937399383993939940399413994239943399443994539946399473994839949399503995139952399533995439955399563995739958399593996039961399623996339964399653996639967399683996939970399713997239973399743997539976399773997839979399803998139982399833998439985399863998739988399893999039991399923999339994399953999639997399983999940000400014000240003400044000540006400074000840009400104001140012400134001440015400164001740018400194002040021400224002340024400254002640027400284002940030400314003240033400344003540036400374003840039400404004140042400434004440045400464004740048400494005040051400524005340054400554005640057400584005940060400614006240063400644006540066400674006840069400704007140072400734007440075400764007740078400794008040081400824008340084400854008640087400884008940090400914009240093400944009540096400974009840099401004010140102401034010440105401064010740108401094011040111401124011340114401154011640117401184011940120401214012240123401244012540126401274012840129401304013140132401334013440135401364013740138401394014040141401424014340144401454014640147401484014940150401514015240153401544015540156401574015840159401604016140162401634016440165401664016740168401694017040171401724017340174401754017640177401784017940180401814018240183401844018540186401874018840189401904019140192401934019440195401964019740198401994020040201402024020340204402054020640207402084020940210402114021240213402144021540216402174021840219402204022140222402234022440225402264022740228402294023040231402324023340234402354023640237402384023940240402414024240243402444024540246402474024840249402504025140252402534025440255402564025740258402594026040261402624026340264402654026640267402684026940270402714027240273402744027540276402774027840279402804028140282402834028440285402864028740288402894029040291402924029340294402954029640297402984029940300403014030240303403044030540306403074030840309403104031140312403134031440315403164031740318403194032040321403224032340324403254032640327403284032940330403314033240333403344033540336403374033840339403404034140342403434034440345403464034740348403494035040351403524035340354403554035640357403584035940360403614036240363403644036540366403674036840369403704037140372403734037440375403764037740378403794038040381403824038340384403854038640387403884038940390403914039240393403944039540396403974039840399404004040140402404034040440405404064040740408404094041040411404124041340414404154041640417404184041940420404214042240423404244042540426404274042840429404304043140432404334043440435404364043740438404394044040441404424044340444404454044640447404484044940450404514045240453404544045540456404574045840459404604046140462404634046440465404664046740468404694047040471404724047340474404754047640477404784047940480404814048240483404844048540486404874048840489404904049140492404934049440495404964049740498404994050040501405024050340504405054050640507405084050940510405114051240513405144051540516405174051840519405204052140522405234052440525405264052740528405294053040531405324053340534405354053640537405384053940540405414054240543405444054540546405474054840549405504055140552405534055440555405564055740558405594056040561405624056340564405654056640567405684056940570405714057240573405744057540576405774057840579405804058140582405834058440585405864058740588405894059040591405924059340594405954059640597405984059940600406014060240603406044060540606406074060840609406104061140612406134061440615406164061740618406194062040621406224062340624406254062640627406284062940630406314063240633406344063540636406374063840639406404064140642406434064440645406464064740648406494065040651406524065340654406554065640657406584065940660406614066240663406644066540666406674066840669406704067140672406734067440675406764067740678406794068040681406824068340684406854068640687406884068940690406914069240693406944069540696406974069840699407004070140702407034070440705407064070740708407094071040711407124071340714407154071640717407184071940720407214072240723407244072540726407274072840729407304073140732407334073440735407364073740738407394074040741407424074340744407454074640747407484074940750407514075240753407544075540756407574075840759407604076140762407634076440765407664076740768407694077040771407724077340774407754077640777407784077940780407814078240783407844078540786407874078840789407904079140792407934079440795407964079740798407994080040801408024080340804408054080640807408084080940810408114081240813408144081540816408174081840819408204082140822408234082440825408264082740828408294083040831408324083340834408354083640837408384083940840408414084240843408444084540846408474084840849408504085140852408534085440855408564085740858408594086040861408624086340864408654086640867408684086940870408714087240873408744087540876408774087840879408804088140882408834088440885408864088740888408894089040891408924089340894408954089640897408984089940900409014090240903409044090540906409074090840909409104091140912409134091440915409164091740918409194092040921409224092340924409254092640927409284092940930409314093240933409344093540936409374093840939409404094140942409434094440945409464094740948409494095040951409524095340954409554095640957409584095940960409614096240963409644096540966409674096840969409704097140972409734097440975409764097740978409794098040981409824098340984409854098640987409884098940990409914099240993409944099540996409974099840999410004100141002410034100441005410064100741008410094101041011410124101341014410154101641017410184101941020410214102241023410244102541026410274102841029410304103141032410334103441035410364103741038410394104041041410424104341044410454104641047410484104941050410514105241053410544105541056410574105841059410604106141062410634106441065410664106741068410694107041071410724107341074410754107641077410784107941080410814108241083410844108541086410874108841089410904109141092410934109441095410964109741098410994110041101411024110341104411054110641107411084110941110411114111241113411144111541116411174111841119411204112141122411234112441125411264112741128411294113041131411324113341134411354113641137411384113941140411414114241143411444114541146411474114841149411504115141152411534115441155411564115741158411594116041161411624116341164411654116641167411684116941170411714117241173411744117541176411774117841179411804118141182411834118441185411864118741188411894119041191411924119341194411954119641197411984119941200412014120241203412044120541206412074120841209412104121141212412134121441215412164121741218412194122041221412224122341224412254122641227412284122941230412314123241233412344123541236412374123841239412404124141242412434124441245412464124741248412494125041251412524125341254412554125641257412584125941260412614126241263412644126541266412674126841269412704127141272412734127441275412764127741278412794128041281412824128341284412854128641287412884128941290412914129241293412944129541296412974129841299413004130141302413034130441305413064130741308413094131041311413124131341314413154131641317413184131941320413214132241323413244132541326413274132841329413304133141332413334133441335413364133741338413394134041341413424134341344413454134641347413484134941350413514135241353413544135541356413574135841359413604136141362413634136441365413664136741368413694137041371413724137341374413754137641377413784137941380413814138241383413844138541386413874138841389413904139141392413934139441395413964139741398413994140041401414024140341404414054140641407414084140941410414114141241413414144141541416414174141841419414204142141422414234142441425414264142741428414294143041431414324143341434414354143641437414384143941440414414144241443414444144541446414474144841449414504145141452414534145441455414564145741458414594146041461414624146341464414654146641467414684146941470414714147241473414744147541476414774147841479414804148141482414834148441485414864148741488414894149041491414924149341494414954149641497414984149941500415014150241503415044150541506415074150841509415104151141512415134151441515415164151741518415194152041521415224152341524415254152641527415284152941530415314153241533415344153541536415374153841539415404154141542415434154441545415464154741548415494155041551415524155341554415554155641557415584155941560415614156241563415644156541566415674156841569415704157141572415734157441575415764157741578415794158041581415824158341584415854158641587415884158941590415914159241593415944159541596415974159841599416004160141602416034160441605416064160741608416094161041611416124161341614416154161641617416184161941620416214162241623416244162541626416274162841629416304163141632416334163441635416364163741638416394164041641416424164341644416454164641647416484164941650416514165241653416544165541656416574165841659416604166141662416634166441665416664166741668416694167041671416724167341674416754167641677416784167941680416814168241683416844168541686416874168841689416904169141692416934169441695416964169741698416994170041701417024170341704417054170641707417084170941710417114171241713417144171541716417174171841719417204172141722417234172441725417264172741728417294173041731417324173341734417354173641737417384173941740417414174241743417444174541746417474174841749417504175141752417534175441755417564175741758417594176041761417624176341764417654176641767417684176941770417714177241773417744177541776417774177841779417804178141782417834178441785417864178741788417894179041791417924179341794417954179641797417984179941800418014180241803418044180541806418074180841809418104181141812418134181441815418164181741818418194182041821418224182341824418254182641827418284182941830418314183241833418344183541836418374183841839418404184141842418434184441845418464184741848418494185041851418524185341854418554185641857418584185941860418614186241863418644186541866418674186841869418704187141872418734187441875418764187741878418794188041881418824188341884418854188641887418884188941890418914189241893418944189541896418974189841899419004190141902419034190441905419064190741908419094191041911419124191341914419154191641917419184191941920419214192241923419244192541926419274192841929419304193141932419334193441935419364193741938419394194041941419424194341944419454194641947419484194941950419514195241953419544195541956419574195841959419604196141962419634196441965419664196741968419694197041971419724197341974419754197641977419784197941980419814198241983419844198541986419874198841989419904199141992419934199441995419964199741998419994200042001420024200342004420054200642007420084200942010420114201242013420144201542016420174201842019420204202142022420234202442025420264202742028420294203042031420324203342034420354203642037420384203942040420414204242043420444204542046420474204842049420504205142052420534205442055420564205742058420594206042061420624206342064420654206642067420684206942070420714207242073420744207542076420774207842079420804208142082420834208442085420864208742088420894209042091420924209342094420954209642097420984209942100421014210242103421044210542106421074210842109421104211142112421134211442115421164211742118421194212042121421224212342124421254212642127421284212942130421314213242133421344213542136421374213842139421404214142142421434214442145421464214742148421494215042151421524215342154421554215642157421584215942160421614216242163421644216542166421674216842169421704217142172421734217442175421764217742178421794218042181421824218342184421854218642187421884218942190421914219242193421944219542196421974219842199422004220142202422034220442205422064220742208422094221042211422124221342214422154221642217422184221942220422214222242223422244222542226422274222842229422304223142232422334223442235422364223742238422394224042241422424224342244422454224642247422484224942250422514225242253422544225542256422574225842259422604226142262422634226442265422664226742268422694227042271422724227342274422754227642277422784227942280422814228242283422844228542286422874228842289422904229142292422934229442295422964229742298422994230042301423024230342304423054230642307423084230942310423114231242313423144231542316423174231842319423204232142322423234232442325423264232742328423294233042331423324233342334423354233642337423384233942340423414234242343423444234542346423474234842349423504235142352423534235442355423564235742358423594236042361423624236342364423654236642367423684236942370423714237242373423744237542376423774237842379423804238142382423834238442385423864238742388423894239042391423924239342394423954239642397423984239942400424014240242403424044240542406424074240842409424104241142412424134241442415424164241742418424194242042421424224242342424424254242642427424284242942430424314243242433424344243542436424374243842439424404244142442424434244442445424464244742448424494245042451424524245342454424554245642457424584245942460424614246242463424644246542466424674246842469424704247142472424734247442475424764247742478424794248042481424824248342484424854248642487424884248942490424914249242493424944249542496424974249842499425004250142502425034250442505425064250742508425094251042511425124251342514425154251642517425184251942520425214252242523425244252542526425274252842529425304253142532425334253442535425364253742538425394254042541425424254342544425454254642547425484254942550425514255242553425544255542556425574255842559425604256142562425634256442565425664256742568425694257042571425724257342574425754257642577425784257942580425814258242583425844258542586425874258842589425904259142592425934259442595425964259742598425994260042601426024260342604426054260642607426084260942610426114261242613426144261542616426174261842619426204262142622426234262442625426264262742628426294263042631426324263342634426354263642637426384263942640426414264242643426444264542646426474264842649426504265142652426534265442655426564265742658426594266042661426624266342664426654266642667426684266942670426714267242673426744267542676426774267842679426804268142682426834268442685426864268742688426894269042691426924269342694426954269642697426984269942700427014270242703427044270542706427074270842709427104271142712427134271442715427164271742718427194272042721427224272342724427254272642727427284272942730427314273242733427344273542736427374273842739427404274142742427434274442745427464274742748427494275042751427524275342754427554275642757427584275942760427614276242763427644276542766427674276842769427704277142772427734277442775427764277742778427794278042781427824278342784427854278642787427884278942790427914279242793427944279542796427974279842799428004280142802428034280442805428064280742808428094281042811428124281342814428154281642817428184281942820428214282242823428244282542826428274282842829428304283142832428334283442835428364283742838428394284042841428424284342844428454284642847428484284942850428514285242853428544285542856428574285842859428604286142862428634286442865428664286742868428694287042871428724287342874428754287642877428784287942880428814288242883428844288542886428874288842889428904289142892428934289442895428964289742898428994290042901429024290342904429054290642907429084290942910429114291242913429144291542916429174291842919429204292142922429234292442925429264292742928429294293042931429324293342934429354293642937429384293942940429414294242943429444294542946429474294842949429504295142952429534295442955429564295742958429594296042961429624296342964429654296642967429684296942970429714297242973429744297542976429774297842979429804298142982429834298442985429864298742988429894299042991429924299342994429954299642997429984299943000430014300243003430044300543006430074300843009430104301143012430134301443015430164301743018430194302043021430224302343024430254302643027430284302943030430314303243033430344303543036430374303843039430404304143042430434304443045430464304743048430494305043051430524305343054430554305643057430584305943060430614306243063430644306543066430674306843069430704307143072430734307443075430764307743078430794308043081430824308343084430854308643087430884308943090430914309243093430944309543096430974309843099431004310143102431034310443105431064310743108431094311043111431124311343114431154311643117431184311943120431214312243123431244312543126431274312843129431304313143132431334313443135431364313743138431394314043141431424314343144431454314643147431484314943150431514315243153431544315543156431574315843159431604316143162431634316443165431664316743168431694317043171431724317343174431754317643177431784317943180431814318243183431844318543186431874318843189431904319143192431934319443195431964319743198431994320043201432024320343204432054320643207432084320943210432114321243213432144321543216432174321843219432204322143222432234322443225432264322743228432294323043231432324323343234432354323643237432384323943240432414324243243432444324543246432474324843249432504325143252432534325443255432564325743258432594326043261432624326343264432654326643267432684326943270432714327243273432744327543276432774327843279432804328143282432834328443285432864328743288432894329043291432924329343294432954329643297432984329943300433014330243303433044330543306433074330843309433104331143312433134331443315433164331743318433194332043321433224332343324433254332643327433284332943330433314333243333433344333543336433374333843339433404334143342433434334443345433464334743348433494335043351433524335343354433554335643357433584335943360433614336243363433644336543366433674336843369433704337143372433734337443375433764337743378433794338043381433824338343384433854338643387433884338943390433914339243393433944339543396433974339843399434004340143402434034340443405434064340743408434094341043411434124341343414434154341643417434184341943420434214342243423434244342543426434274342843429434304343143432434334343443435434364343743438434394344043441434424344343444434454344643447434484344943450434514345243453434544345543456434574345843459434604346143462434634346443465434664346743468434694347043471434724347343474434754347643477434784347943480434814348243483434844348543486434874348843489434904349143492434934349443495434964349743498434994350043501435024350343504435054350643507435084350943510435114351243513435144351543516435174351843519435204352143522435234352443525435264352743528435294353043531435324353343534435354353643537435384353943540435414354243543435444354543546435474354843549435504355143552435534355443555435564355743558435594356043561435624356343564435654356643567435684356943570435714357243573435744357543576435774357843579435804358143582435834358443585435864358743588435894359043591435924359343594435954359643597435984359943600436014360243603436044360543606436074360843609436104361143612436134361443615436164361743618436194362043621436224362343624436254362643627436284362943630436314363243633436344363543636436374363843639436404364143642436434364443645436464364743648436494365043651436524365343654436554365643657436584365943660436614366243663436644366543666436674366843669436704367143672436734367443675436764367743678436794368043681436824368343684436854368643687436884368943690436914369243693436944369543696436974369843699437004370143702437034370443705437064370743708437094371043711437124371343714437154371643717437184371943720437214372243723437244372543726437274372843729437304373143732437334373443735437364373743738437394374043741437424374343744437454374643747437484374943750437514375243753437544375543756437574375843759437604376143762437634376443765437664376743768437694377043771437724377343774437754377643777437784377943780437814378243783437844378543786437874378843789437904379143792437934379443795437964379743798437994380043801438024380343804438054380643807438084380943810438114381243813438144381543816438174381843819438204382143822438234382443825438264382743828438294383043831438324383343834438354383643837438384383943840438414384243843438444384543846438474384843849438504385143852438534385443855438564385743858438594386043861438624386343864438654386643867438684386943870438714387243873438744387543876438774387843879438804388143882438834388443885438864388743888438894389043891438924389343894438954389643897438984389943900439014390243903439044390543906439074390843909439104391143912439134391443915439164391743918439194392043921439224392343924439254392643927439284392943930439314393243933439344393543936439374393843939439404394143942439434394443945439464394743948439494395043951439524395343954439554395643957439584395943960439614396243963439644396543966439674396843969439704397143972439734397443975439764397743978439794398043981439824398343984439854398643987439884398943990439914399243993439944399543996439974399843999440004400144002440034400444005440064400744008440094401044011440124401344014440154401644017440184401944020440214402244023440244402544026440274402844029440304403144032440334403444035440364403744038440394404044041440424404344044440454404644047440484404944050440514405244053440544405544056440574405844059440604406144062440634406444065440664406744068440694407044071440724407344074440754407644077440784407944080440814408244083440844408544086440874408844089440904409144092440934409444095440964409744098440994410044101441024410344104441054410644107441084410944110441114411244113441144411544116441174411844119441204412144122441234412444125441264412744128441294413044131441324413344134441354413644137441384413944140441414414244143441444414544146441474414844149441504415144152441534415444155441564415744158441594416044161441624416344164441654416644167441684416944170441714417244173441744417544176441774417844179441804418144182441834418444185441864418744188441894419044191441924419344194441954419644197441984419944200442014420244203442044420544206442074420844209442104421144212442134421444215442164421744218442194422044221442224422344224442254422644227442284422944230442314423244233442344423544236442374423844239442404424144242442434424444245442464424744248442494425044251442524425344254442554425644257442584425944260442614426244263442644426544266442674426844269442704427144272442734427444275442764427744278442794428044281442824428344284442854428644287442884428944290442914429244293442944429544296442974429844299443004430144302443034430444305443064430744308443094431044311443124431344314443154431644317443184431944320443214432244323443244432544326443274432844329443304433144332443334433444335443364433744338443394434044341443424434344344443454434644347443484434944350443514435244353443544435544356443574435844359443604436144362443634436444365443664436744368443694437044371443724437344374443754437644377443784437944380443814438244383443844438544386443874438844389443904439144392443934439444395443964439744398443994440044401444024440344404444054440644407444084440944410444114441244413444144441544416444174441844419444204442144422444234442444425444264442744428444294443044431444324443344434444354443644437444384443944440444414444244443444444444544446444474444844449444504445144452444534445444455444564445744458444594446044461444624446344464444654446644467444684446944470444714447244473444744447544476444774447844479444804448144482444834448444485444864448744488444894449044491444924449344494444954449644497444984449944500445014450244503445044450544506445074450844509445104451144512445134451444515445164451744518445194452044521445224452344524445254452644527445284452944530445314453244533445344453544536445374453844539445404454144542445434454444545445464454744548445494455044551445524455344554445554455644557445584455944560445614456244563445644456544566445674456844569445704457144572445734457444575445764457744578445794458044581445824458344584445854458644587445884458944590445914459244593445944459544596445974459844599446004460144602446034460444605446064460744608446094461044611446124461344614446154461644617446184461944620446214462244623446244462544626446274462844629446304463144632446334463444635446364463744638446394464044641446424464344644446454464644647446484464944650446514465244653446544465544656446574465844659446604466144662446634466444665446664466744668446694467044671446724467344674446754467644677446784467944680446814468244683446844468544686446874468844689446904469144692446934469444695446964469744698446994470044701447024470344704447054470644707447084470944710447114471244713447144471544716447174471844719447204472144722447234472444725447264472744728447294473044731447324473344734447354473644737447384473944740447414474244743447444474544746447474474844749447504475144752447534475444755447564475744758447594476044761447624476344764447654476644767447684476944770447714477244773447744477544776447774477844779447804478144782447834478444785447864478744788447894479044791447924479344794447954479644797447984479944800448014480244803448044480544806448074480844809448104481144812448134481444815448164481744818448194482044821448224482344824448254482644827448284482944830448314483244833448344483544836448374483844839448404484144842448434484444845448464484744848448494485044851448524485344854448554485644857448584485944860448614486244863448644486544866448674486844869448704487144872448734487444875448764487744878448794488044881448824488344884448854488644887448884488944890448914489244893448944489544896448974489844899449004490144902449034490444905449064490744908449094491044911449124491344914449154491644917449184491944920449214492244923449244492544926449274492844929449304493144932449334493444935449364493744938449394494044941449424494344944449454494644947449484494944950449514495244953449544495544956449574495844959449604496144962449634496444965449664496744968449694497044971449724497344974449754497644977449784497944980449814498244983449844498544986449874498844989449904499144992449934499444995449964499744998449994500045001450024500345004450054500645007450084500945010450114501245013450144501545016450174501845019450204502145022450234502445025450264502745028450294503045031450324503345034450354503645037450384503945040450414504245043450444504545046450474504845049450504505145052450534505445055450564505745058450594506045061450624506345064450654506645067450684506945070450714507245073450744507545076450774507845079450804508145082450834508445085450864508745088450894509045091450924509345094450954509645097450984509945100451014510245103451044510545106451074510845109451104511145112451134511445115451164511745118451194512045121451224512345124451254512645127451284512945130451314513245133451344513545136451374513845139451404514145142451434514445145451464514745148451494515045151451524515345154451554515645157451584515945160451614516245163451644516545166451674516845169451704517145172451734517445175451764517745178451794518045181451824518345184451854518645187451884518945190451914519245193451944519545196451974519845199452004520145202452034520445205452064520745208452094521045211452124521345214452154521645217452184521945220452214522245223452244522545226452274522845229452304523145232452334523445235452364523745238452394524045241452424524345244452454524645247452484524945250452514525245253452544525545256452574525845259452604526145262452634526445265452664526745268452694527045271452724527345274452754527645277452784527945280452814528245283452844528545286452874528845289452904529145292452934529445295452964529745298452994530045301453024530345304453054530645307453084530945310453114531245313453144531545316453174531845319453204532145322453234532445325453264532745328453294533045331453324533345334453354533645337453384533945340453414534245343453444534545346453474534845349453504535145352453534535445355453564535745358453594536045361453624536345364453654536645367453684536945370453714537245373453744537545376453774537845379453804538145382453834538445385453864538745388453894539045391453924539345394453954539645397453984539945400454014540245403454044540545406454074540845409454104541145412454134541445415454164541745418454194542045421454224542345424454254542645427454284542945430454314543245433454344543545436454374543845439454404544145442454434544445445454464544745448454494545045451454524545345454454554545645457454584545945460454614546245463454644546545466454674546845469454704547145472454734547445475454764547745478454794548045481454824548345484454854548645487454884548945490454914549245493454944549545496454974549845499455004550145502455034550445505455064550745508455094551045511455124551345514455154551645517455184551945520455214552245523455244552545526455274552845529455304553145532455334553445535455364553745538455394554045541455424554345544455454554645547455484554945550455514555245553455544555545556455574555845559455604556145562455634556445565455664556745568455694557045571455724557345574455754557645577455784557945580455814558245583455844558545586455874558845589455904559145592455934559445595455964559745598455994560045601456024560345604456054560645607456084560945610456114561245613456144561545616456174561845619456204562145622456234562445625456264562745628456294563045631456324563345634456354563645637456384563945640456414564245643456444564545646456474564845649456504565145652456534565445655456564565745658456594566045661456624566345664456654566645667456684566945670456714567245673456744567545676456774567845679456804568145682456834568445685456864568745688456894569045691456924569345694456954569645697456984569945700457014570245703457044570545706457074570845709457104571145712457134571445715457164571745718457194572045721457224572345724457254572645727457284572945730457314573245733457344573545736457374573845739457404574145742457434574445745457464574745748457494575045751457524575345754457554575645757457584575945760457614576245763457644576545766457674576845769457704577145772457734577445775457764577745778457794578045781457824578345784457854578645787457884578945790457914579245793457944579545796457974579845799458004580145802458034580445805458064580745808458094581045811458124581345814458154581645817458184581945820458214582245823458244582545826458274582845829458304583145832458334583445835458364583745838458394584045841458424584345844458454584645847458484584945850458514585245853458544585545856458574585845859458604586145862458634586445865458664586745868458694587045871458724587345874458754587645877458784587945880458814588245883458844588545886458874588845889458904589145892458934589445895458964589745898458994590045901459024590345904459054590645907459084590945910459114591245913459144591545916459174591845919459204592145922459234592445925459264592745928459294593045931459324593345934459354593645937459384593945940459414594245943459444594545946459474594845949459504595145952459534595445955459564595745958459594596045961459624596345964459654596645967459684596945970459714597245973459744597545976459774597845979459804598145982459834598445985459864598745988459894599045991459924599345994459954599645997459984599946000460014600246003460044600546006460074600846009460104601146012460134601446015460164601746018460194602046021460224602346024460254602646027460284602946030460314603246033460344603546036460374603846039460404604146042460434604446045460464604746048460494605046051460524605346054460554605646057460584605946060460614606246063460644606546066460674606846069460704607146072460734607446075460764607746078460794608046081460824608346084460854608646087460884608946090460914609246093460944609546096460974609846099461004610146102461034610446105461064610746108461094611046111461124611346114461154611646117461184611946120461214612246123461244612546126461274612846129461304613146132461334613446135461364613746138461394614046141461424614346144461454614646147461484614946150461514615246153461544615546156461574615846159461604616146162461634616446165461664616746168461694617046171461724617346174461754617646177461784617946180461814618246183461844618546186461874618846189461904619146192461934619446195461964619746198461994620046201462024620346204462054620646207462084620946210462114621246213462144621546216462174621846219462204622146222462234622446225462264622746228462294623046231462324623346234462354623646237462384623946240462414624246243462444624546246462474624846249462504625146252462534625446255462564625746258462594626046261462624626346264462654626646267462684626946270462714627246273462744627546276462774627846279462804628146282462834628446285462864628746288462894629046291462924629346294462954629646297462984629946300463014630246303463044630546306463074630846309463104631146312463134631446315463164631746318463194632046321463224632346324463254632646327463284632946330463314633246333463344633546336463374633846339463404634146342463434634446345463464634746348463494635046351463524635346354463554635646357463584635946360463614636246363463644636546366463674636846369463704637146372463734637446375463764637746378463794638046381463824638346384463854638646387463884638946390463914639246393463944639546396463974639846399464004640146402464034640446405464064640746408464094641046411464124641346414464154641646417464184641946420464214642246423464244642546426464274642846429464304643146432464334643446435464364643746438464394644046441464424644346444464454644646447464484644946450464514645246453464544645546456464574645846459464604646146462464634646446465464664646746468464694647046471464724647346474464754647646477464784647946480464814648246483464844648546486464874648846489464904649146492464934649446495464964649746498464994650046501465024650346504465054650646507465084650946510465114651246513465144651546516465174651846519465204652146522465234652446525465264652746528465294653046531465324653346534465354653646537465384653946540465414654246543465444654546546465474654846549465504655146552465534655446555465564655746558465594656046561465624656346564465654656646567465684656946570465714657246573465744657546576465774657846579465804658146582465834658446585465864658746588465894659046591465924659346594465954659646597465984659946600466014660246603466044660546606466074660846609466104661146612466134661446615466164661746618466194662046621466224662346624466254662646627466284662946630466314663246633466344663546636466374663846639466404664146642466434664446645466464664746648466494665046651466524665346654466554665646657466584665946660466614666246663466644666546666466674666846669466704667146672466734667446675466764667746678466794668046681466824668346684466854668646687466884668946690466914669246693466944669546696466974669846699467004670146702467034670446705467064670746708467094671046711467124671346714467154671646717467184671946720467214672246723467244672546726467274672846729467304673146732467334673446735467364673746738467394674046741467424674346744467454674646747467484674946750467514675246753467544675546756467574675846759467604676146762467634676446765467664676746768467694677046771467724677346774467754677646777467784677946780467814678246783467844678546786467874678846789467904679146792467934679446795467964679746798467994680046801468024680346804468054680646807468084680946810468114681246813468144681546816468174681846819468204682146822468234682446825468264682746828468294683046831468324683346834468354683646837468384683946840468414684246843468444684546846468474684846849468504685146852468534685446855468564685746858468594686046861468624686346864468654686646867468684686946870468714687246873468744687546876468774687846879468804688146882468834688446885468864688746888468894689046891468924689346894468954689646897468984689946900469014690246903469044690546906469074690846909469104691146912469134691446915469164691746918469194692046921469224692346924469254692646927469284692946930469314693246933469344693546936469374693846939469404694146942469434694446945469464694746948469494695046951469524695346954469554695646957469584695946960469614696246963469644696546966469674696846969469704697146972469734697446975469764697746978469794698046981469824698346984469854698646987469884698946990469914699246993469944699546996469974699846999470004700147002470034700447005470064700747008470094701047011470124701347014470154701647017470184701947020470214702247023470244702547026470274702847029470304703147032470334703447035470364703747038470394704047041470424704347044470454704647047470484704947050470514705247053470544705547056470574705847059470604706147062470634706447065470664706747068470694707047071470724707347074470754707647077470784707947080470814708247083470844708547086470874708847089470904709147092470934709447095470964709747098470994710047101471024710347104471054710647107471084710947110471114711247113471144711547116471174711847119471204712147122471234712447125471264712747128471294713047131471324713347134471354713647137471384713947140471414714247143471444714547146471474714847149471504715147152471534715447155471564715747158471594716047161471624716347164471654716647167471684716947170471714717247173471744717547176471774717847179471804718147182471834718447185471864718747188471894719047191471924719347194471954719647197471984719947200472014720247203472044720547206472074720847209472104721147212472134721447215472164721747218472194722047221472224722347224472254722647227472284722947230472314723247233472344723547236472374723847239472404724147242472434724447245472464724747248472494725047251472524725347254472554725647257472584725947260472614726247263472644726547266472674726847269472704727147272472734727447275472764727747278472794728047281472824728347284472854728647287472884728947290472914729247293472944729547296472974729847299473004730147302473034730447305473064730747308473094731047311473124731347314473154731647317473184731947320473214732247323473244732547326473274732847329473304733147332473334733447335473364733747338473394734047341473424734347344473454734647347473484734947350473514735247353473544735547356473574735847359473604736147362473634736447365473664736747368473694737047371473724737347374473754737647377473784737947380473814738247383473844738547386473874738847389473904739147392473934739447395473964739747398473994740047401474024740347404474054740647407474084740947410474114741247413474144741547416474174741847419474204742147422474234742447425474264742747428474294743047431474324743347434474354743647437474384743947440474414744247443474444744547446474474744847449474504745147452474534745447455474564745747458474594746047461474624746347464474654746647467474684746947470474714747247473474744747547476474774747847479474804748147482474834748447485474864748747488474894749047491474924749347494474954749647497474984749947500475014750247503475044750547506475074750847509475104751147512475134751447515475164751747518475194752047521475224752347524475254752647527475284752947530475314753247533475344753547536475374753847539475404754147542475434754447545475464754747548475494755047551475524755347554475554755647557475584755947560475614756247563475644756547566475674756847569475704757147572475734757447575475764757747578475794758047581475824758347584475854758647587475884758947590475914759247593475944759547596475974759847599476004760147602476034760447605476064760747608476094761047611476124761347614476154761647617476184761947620476214762247623476244762547626476274762847629476304763147632476334763447635476364763747638476394764047641476424764347644476454764647647476484764947650476514765247653476544765547656476574765847659476604766147662476634766447665476664766747668476694767047671476724767347674476754767647677476784767947680476814768247683476844768547686476874768847689476904769147692476934769447695476964769747698476994770047701477024770347704477054770647707477084770947710477114771247713477144771547716477174771847719477204772147722477234772447725477264772747728477294773047731477324773347734477354773647737477384773947740477414774247743477444774547746477474774847749477504775147752477534775447755477564775747758477594776047761477624776347764477654776647767477684776947770477714777247773477744777547776477774777847779477804778147782477834778447785477864778747788477894779047791477924779347794477954779647797477984779947800478014780247803478044780547806478074780847809478104781147812478134781447815478164781747818478194782047821478224782347824478254782647827478284782947830478314783247833478344783547836478374783847839478404784147842478434784447845478464784747848478494785047851478524785347854478554785647857478584785947860478614786247863478644786547866478674786847869478704787147872478734787447875478764787747878478794788047881478824788347884478854788647887478884788947890478914789247893478944789547896478974789847899479004790147902479034790447905479064790747908479094791047911479124791347914479154791647917479184791947920479214792247923479244792547926479274792847929479304793147932479334793447935479364793747938479394794047941479424794347944479454794647947479484794947950479514795247953479544795547956479574795847959479604796147962479634796447965479664796747968479694797047971479724797347974479754797647977479784797947980479814798247983479844798547986479874798847989479904799147992479934799447995479964799747998479994800048001480024800348004480054800648007480084800948010480114801248013480144801548016480174801848019480204802148022480234802448025480264802748028480294803048031480324803348034480354803648037480384803948040480414804248043480444804548046480474804848049480504805148052480534805448055480564805748058480594806048061480624806348064480654806648067480684806948070480714807248073480744807548076480774807848079480804808148082480834808448085480864808748088480894809048091480924809348094480954809648097480984809948100481014810248103481044810548106481074810848109481104811148112481134811448115481164811748118481194812048121481224812348124481254812648127481284812948130481314813248133481344813548136481374813848139481404814148142481434814448145481464814748148481494815048151481524815348154481554815648157481584815948160481614816248163481644816548166481674816848169481704817148172481734817448175481764817748178481794818048181481824818348184481854818648187481884818948190481914819248193481944819548196481974819848199482004820148202482034820448205482064820748208482094821048211482124821348214482154821648217482184821948220482214822248223482244822548226482274822848229482304823148232482334823448235482364823748238482394824048241482424824348244482454824648247482484824948250482514825248253482544825548256482574825848259482604826148262482634826448265482664826748268482694827048271482724827348274482754827648277482784827948280482814828248283482844828548286482874828848289482904829148292482934829448295482964829748298482994830048301483024830348304483054830648307483084830948310483114831248313483144831548316483174831848319483204832148322483234832448325483264832748328483294833048331483324833348334483354833648337483384833948340483414834248343483444834548346483474834848349483504835148352483534835448355483564835748358483594836048361483624836348364483654836648367483684836948370483714837248373483744837548376483774837848379483804838148382483834838448385483864838748388483894839048391483924839348394483954839648397483984839948400484014840248403484044840548406484074840848409484104841148412484134841448415484164841748418484194842048421484224842348424484254842648427484284842948430484314843248433484344843548436484374843848439484404844148442484434844448445484464844748448484494845048451484524845348454484554845648457484584845948460484614846248463484644846548466484674846848469484704847148472484734847448475484764847748478484794848048481484824848348484484854848648487484884848948490484914849248493484944849548496484974849848499485004850148502485034850448505485064850748508485094851048511485124851348514485154851648517485184851948520485214852248523485244852548526485274852848529485304853148532485334853448535485364853748538485394854048541485424854348544485454854648547485484854948550485514855248553485544855548556485574855848559485604856148562485634856448565485664856748568485694857048571485724857348574485754857648577485784857948580485814858248583485844858548586485874858848589485904859148592485934859448595485964859748598485994860048601486024860348604486054860648607486084860948610486114861248613486144861548616486174861848619486204862148622486234862448625486264862748628486294863048631486324863348634486354863648637486384863948640486414864248643486444864548646486474864848649486504865148652486534865448655486564865748658486594866048661486624866348664486654866648667486684866948670486714867248673486744867548676486774867848679486804868148682486834868448685486864868748688486894869048691486924869348694486954869648697486984869948700487014870248703487044870548706487074870848709487104871148712487134871448715487164871748718487194872048721487224872348724487254872648727487284872948730487314873248733487344873548736487374873848739487404874148742487434874448745487464874748748487494875048751487524875348754487554875648757487584875948760487614876248763487644876548766487674876848769487704877148772487734877448775487764877748778487794878048781487824878348784487854878648787487884878948790487914879248793487944879548796487974879848799488004880148802488034880448805488064880748808488094881048811488124881348814488154881648817488184881948820488214882248823488244882548826488274882848829488304883148832488334883448835488364883748838488394884048841488424884348844488454884648847488484884948850488514885248853488544885548856488574885848859488604886148862488634886448865488664886748868488694887048871488724887348874488754887648877488784887948880488814888248883488844888548886488874888848889488904889148892488934889448895488964889748898488994890048901489024890348904489054890648907489084890948910489114891248913489144891548916489174891848919489204892148922489234892448925489264892748928489294893048931489324893348934489354893648937489384893948940489414894248943489444894548946489474894848949489504895148952489534895448955489564895748958489594896048961489624896348964489654896648967489684896948970489714897248973489744897548976489774897848979489804898148982489834898448985489864898748988489894899048991489924899348994489954899648997489984899949000490014900249003490044900549006490074900849009490104901149012490134901449015490164901749018490194902049021490224902349024490254902649027490284902949030490314903249033490344903549036490374903849039490404904149042490434904449045490464904749048490494905049051490524905349054490554905649057490584905949060490614906249063490644906549066490674906849069490704907149072490734907449075490764907749078490794908049081490824908349084490854908649087490884908949090490914909249093490944909549096490974909849099491004910149102491034910449105491064910749108491094911049111491124911349114491154911649117491184911949120491214912249123491244912549126491274912849129491304913149132491334913449135491364913749138491394914049141491424914349144491454914649147491484914949150491514915249153491544915549156491574915849159491604916149162491634916449165491664916749168491694917049171491724917349174491754917649177491784917949180491814918249183491844918549186491874918849189491904919149192491934919449195491964919749198491994920049201492024920349204492054920649207492084920949210492114921249213492144921549216492174921849219492204922149222492234922449225492264922749228492294923049231492324923349234492354923649237492384923949240492414924249243492444924549246492474924849249492504925149252492534925449255492564925749258492594926049261492624926349264492654926649267492684926949270492714927249273492744927549276492774927849279492804928149282492834928449285492864928749288492894929049291492924929349294492954929649297492984929949300493014930249303493044930549306493074930849309493104931149312493134931449315493164931749318493194932049321493224932349324493254932649327493284932949330493314933249333493344933549336493374933849339493404934149342493434934449345493464934749348493494935049351493524935349354493554935649357493584935949360493614936249363493644936549366493674936849369493704937149372493734937449375493764937749378493794938049381493824938349384493854938649387493884938949390493914939249393493944939549396493974939849399494004940149402494034940449405494064940749408494094941049411494124941349414494154941649417494184941949420494214942249423494244942549426494274942849429494304943149432494334943449435494364943749438494394944049441494424944349444494454944649447494484944949450494514945249453494544945549456494574945849459494604946149462494634946449465494664946749468494694947049471494724947349474494754947649477494784947949480494814948249483494844948549486494874948849489494904949149492494934949449495494964949749498494994950049501495024950349504495054950649507495084950949510495114951249513495144951549516495174951849519495204952149522495234952449525495264952749528495294953049531495324953349534495354953649537495384953949540495414954249543495444954549546495474954849549495504955149552495534955449555495564955749558495594956049561495624956349564495654956649567495684956949570495714957249573495744957549576495774957849579495804958149582495834958449585495864958749588495894959049591495924959349594495954959649597495984959949600496014960249603496044960549606496074960849609496104961149612496134961449615496164961749618496194962049621496224962349624496254962649627496284962949630496314963249633496344963549636496374963849639496404964149642496434964449645496464964749648496494965049651496524965349654496554965649657496584965949660496614966249663496644966549666496674966849669496704967149672496734967449675496764967749678496794968049681496824968349684496854968649687496884968949690496914969249693496944969549696496974969849699497004970149702497034970449705497064970749708497094971049711497124971349714497154971649717497184971949720497214972249723497244972549726497274972849729497304973149732497334973449735497364973749738497394974049741497424974349744497454974649747497484974949750497514975249753497544975549756497574975849759497604976149762497634976449765497664976749768497694977049771497724977349774497754977649777497784977949780497814978249783497844978549786497874978849789497904979149792497934979449795497964979749798497994980049801498024980349804498054980649807498084980949810498114981249813498144981549816498174981849819498204982149822498234982449825498264982749828498294983049831498324983349834498354983649837498384983949840498414984249843498444984549846498474984849849498504985149852498534985449855498564985749858498594986049861498624986349864498654986649867498684986949870498714987249873498744987549876498774987849879498804988149882498834988449885498864988749888498894989049891498924989349894498954989649897498984989949900499014990249903499044990549906499074990849909499104991149912499134991449915499164991749918499194992049921499224992349924499254992649927499284992949930499314993249933499344993549936499374993849939499404994149942499434994449945499464994749948499494995049951499524995349954499554995649957499584995949960499614996249963499644996549966499674996849969499704997149972499734997449975499764997749978499794998049981499824998349984499854998649987499884998949990499914999249993499944999549996499974999849999500005000150002500035000450005500065000750008500095001050011500125001350014500155001650017500185001950020500215002250023500245002550026500275002850029500305003150032500335003450035500365003750038500395004050041500425004350044500455004650047500485004950050500515005250053500545005550056500575005850059500605006150062500635006450065500665006750068500695007050071500725007350074500755007650077500785007950080500815008250083500845008550086500875008850089500905009150092500935009450095500965009750098500995010050101501025010350104501055010650107501085010950110501115011250113501145011550116501175011850119501205012150122501235012450125501265012750128501295013050131501325013350134501355013650137501385013950140501415014250143501445014550146501475014850149501505015150152501535015450155501565015750158501595016050161501625016350164501655016650167501685016950170501715017250173501745017550176501775017850179501805018150182501835018450185501865018750188501895019050191501925019350194501955019650197501985019950200502015020250203502045020550206502075020850209502105021150212502135021450215502165021750218502195022050221502225022350224502255022650227502285022950230502315023250233502345023550236502375023850239502405024150242502435024450245502465024750248502495025050251502525025350254502555025650257502585025950260502615026250263502645026550266502675026850269502705027150272502735027450275502765027750278502795028050281502825028350284502855028650287502885028950290502915029250293502945029550296502975029850299503005030150302503035030450305503065030750308503095031050311503125031350314503155031650317503185031950320503215032250323503245032550326503275032850329503305033150332503335033450335503365033750338503395034050341503425034350344503455034650347503485034950350503515035250353503545035550356503575035850359503605036150362503635036450365503665036750368503695037050371503725037350374503755037650377503785037950380503815038250383503845038550386503875038850389503905039150392503935039450395503965039750398503995040050401504025040350404504055040650407504085040950410504115041250413504145041550416504175041850419504205042150422504235042450425504265042750428504295043050431504325043350434504355043650437504385043950440504415044250443504445044550446504475044850449504505045150452504535045450455504565045750458504595046050461504625046350464504655046650467504685046950470504715047250473504745047550476504775047850479504805048150482504835048450485504865048750488504895049050491504925049350494504955049650497504985049950500505015050250503505045050550506505075050850509505105051150512505135051450515505165051750518505195052050521505225052350524505255052650527505285052950530505315053250533505345053550536505375053850539505405054150542505435054450545505465054750548505495055050551505525055350554505555055650557505585055950560505615056250563505645056550566505675056850569505705057150572505735057450575505765057750578505795058050581505825058350584505855058650587505885058950590505915059250593505945059550596505975059850599506005060150602506035060450605506065060750608506095061050611506125061350614506155061650617506185061950620506215062250623506245062550626506275062850629506305063150632506335063450635506365063750638506395064050641506425064350644506455064650647506485064950650506515065250653506545065550656506575065850659506605066150662506635066450665506665066750668506695067050671506725067350674506755067650677506785067950680506815068250683506845068550686506875068850689506905069150692506935069450695506965069750698506995070050701507025070350704507055070650707507085070950710507115071250713507145071550716507175071850719507205072150722507235072450725507265072750728507295073050731507325073350734507355073650737507385073950740507415074250743507445074550746507475074850749507505075150752507535075450755507565075750758507595076050761507625076350764507655076650767507685076950770507715077250773507745077550776507775077850779507805078150782507835078450785507865078750788507895079050791507925079350794507955079650797507985079950800508015080250803508045080550806508075080850809508105081150812508135081450815508165081750818508195082050821508225082350824508255082650827508285082950830508315083250833508345083550836508375083850839508405084150842508435084450845508465084750848508495085050851508525085350854508555085650857508585085950860508615086250863508645086550866508675086850869508705087150872508735087450875508765087750878508795088050881508825088350884508855088650887508885088950890508915089250893508945089550896508975089850899509005090150902509035090450905509065090750908509095091050911509125091350914509155091650917509185091950920509215092250923509245092550926509275092850929509305093150932509335093450935509365093750938509395094050941509425094350944509455094650947509485094950950509515095250953509545095550956509575095850959509605096150962509635096450965509665096750968509695097050971509725097350974509755097650977509785097950980509815098250983509845098550986509875098850989509905099150992509935099450995509965099750998509995100051001510025100351004510055100651007510085100951010510115101251013510145101551016510175101851019510205102151022510235102451025510265102751028510295103051031510325103351034510355103651037510385103951040510415104251043510445104551046510475104851049510505105151052510535105451055510565105751058510595106051061510625106351064510655106651067510685106951070510715107251073510745107551076510775107851079510805108151082510835108451085510865108751088510895109051091510925109351094510955109651097510985109951100511015110251103511045110551106511075110851109511105111151112511135111451115511165111751118511195112051121511225112351124511255112651127511285112951130511315113251133511345113551136511375113851139511405114151142511435114451145511465114751148511495115051151511525115351154511555115651157511585115951160511615116251163511645116551166511675116851169511705117151172511735117451175511765117751178511795118051181511825118351184511855118651187511885118951190511915119251193511945119551196511975119851199512005120151202512035120451205512065120751208512095121051211512125121351214512155121651217512185121951220512215122251223512245122551226512275122851229512305123151232512335123451235512365123751238512395124051241512425124351244512455124651247512485124951250512515125251253512545125551256512575125851259512605126151262512635126451265512665126751268512695127051271512725127351274512755127651277512785127951280512815128251283512845128551286512875128851289512905129151292512935129451295512965129751298512995130051301513025130351304513055130651307513085130951310513115131251313513145131551316513175131851319513205132151322513235132451325513265132751328513295133051331513325133351334513355133651337513385133951340513415134251343513445134551346513475134851349513505135151352513535135451355513565135751358513595136051361513625136351364513655136651367513685136951370513715137251373513745137551376513775137851379513805138151382513835138451385513865138751388513895139051391513925139351394513955139651397513985139951400514015140251403514045140551406514075140851409514105141151412514135141451415514165141751418514195142051421514225142351424514255142651427514285142951430514315143251433514345143551436514375143851439514405144151442514435144451445514465144751448514495145051451514525145351454514555145651457514585145951460514615146251463514645146551466514675146851469514705147151472514735147451475514765147751478514795148051481514825148351484514855148651487514885148951490514915149251493514945149551496514975149851499515005150151502515035150451505515065150751508515095151051511515125151351514515155151651517515185151951520515215152251523515245152551526515275152851529515305153151532515335153451535515365153751538515395154051541515425154351544515455154651547515485154951550515515155251553515545155551556515575155851559515605156151562515635156451565515665156751568515695157051571515725157351574515755157651577515785157951580515815158251583515845158551586515875158851589515905159151592515935159451595515965159751598515995160051601516025160351604516055160651607516085160951610516115161251613516145161551616516175161851619516205162151622516235162451625516265162751628516295163051631516325163351634516355163651637516385163951640516415164251643516445164551646516475164851649516505165151652516535165451655516565165751658516595166051661516625166351664516655166651667516685166951670516715167251673516745167551676516775167851679516805168151682516835168451685516865168751688516895169051691516925169351694516955169651697516985169951700517015170251703517045170551706517075170851709517105171151712517135171451715517165171751718517195172051721517225172351724517255172651727517285172951730517315173251733517345173551736517375173851739517405174151742517435174451745517465174751748517495175051751517525175351754517555175651757517585175951760517615176251763517645176551766517675176851769517705177151772517735177451775517765177751778517795178051781517825178351784517855178651787517885178951790517915179251793517945179551796517975179851799518005180151802518035180451805518065180751808518095181051811518125181351814518155181651817518185181951820518215182251823518245182551826518275182851829518305183151832518335183451835518365183751838518395184051841518425184351844518455184651847518485184951850518515185251853518545185551856518575185851859518605186151862518635186451865518665186751868518695187051871518725187351874518755187651877518785187951880518815188251883518845188551886518875188851889518905189151892518935189451895518965189751898518995190051901519025190351904519055190651907519085190951910519115191251913519145191551916519175191851919519205192151922519235192451925519265192751928519295193051931519325193351934519355193651937519385193951940519415194251943519445194551946519475194851949519505195151952519535195451955519565195751958519595196051961519625196351964519655196651967519685196951970519715197251973519745197551976519775197851979519805198151982519835198451985519865198751988519895199051991519925199351994519955199651997519985199952000520015200252003520045200552006520075200852009520105201152012520135201452015520165201752018520195202052021520225202352024520255202652027520285202952030520315203252033520345203552036520375203852039520405204152042520435204452045520465204752048520495205052051520525205352054520555205652057520585205952060520615206252063520645206552066520675206852069520705207152072520735207452075520765207752078520795208052081520825208352084520855208652087520885208952090520915209252093520945209552096520975209852099521005210152102521035210452105521065210752108521095211052111521125211352114521155211652117521185211952120521215212252123521245212552126521275212852129521305213152132521335213452135521365213752138521395214052141521425214352144521455214652147521485214952150521515215252153521545215552156521575215852159521605216152162521635216452165521665216752168521695217052171521725217352174521755217652177521785217952180521815218252183521845218552186521875218852189521905219152192521935219452195521965219752198521995220052201522025220352204522055220652207522085220952210522115221252213522145221552216522175221852219522205222152222522235222452225522265222752228522295223052231522325223352234522355223652237522385223952240522415224252243522445224552246522475224852249522505225152252522535225452255522565225752258522595226052261522625226352264522655226652267522685226952270522715227252273522745227552276522775227852279522805228152282522835228452285522865228752288522895229052291522925229352294522955229652297522985229952300523015230252303523045230552306523075230852309523105231152312523135231452315523165231752318523195232052321523225232352324523255232652327523285232952330523315233252333523345233552336523375233852339523405234152342523435234452345523465234752348523495235052351523525235352354523555235652357523585235952360523615236252363523645236552366523675236852369523705237152372523735237452375523765237752378523795238052381523825238352384523855238652387523885238952390523915239252393523945239552396523975239852399524005240152402524035240452405524065240752408524095241052411524125241352414524155241652417524185241952420524215242252423524245242552426524275242852429524305243152432524335243452435524365243752438524395244052441524425244352444524455244652447524485244952450524515245252453524545245552456524575245852459524605246152462524635246452465524665246752468524695247052471524725247352474524755247652477524785247952480524815248252483524845248552486524875248852489524905249152492524935249452495524965249752498524995250052501525025250352504525055250652507525085250952510525115251252513525145251552516525175251852519525205252152522525235252452525525265252752528525295253052531525325253352534525355253652537525385253952540525415254252543525445254552546525475254852549525505255152552525535255452555525565255752558525595256052561525625256352564525655256652567525685256952570525715257252573525745257552576525775257852579525805258152582525835258452585525865258752588525895259052591525925259352594525955259652597525985259952600526015260252603526045260552606526075260852609526105261152612526135261452615526165261752618526195262052621526225262352624526255262652627526285262952630526315263252633526345263552636526375263852639526405264152642526435264452645526465264752648526495265052651526525265352654526555265652657526585265952660526615266252663526645266552666526675266852669526705267152672526735267452675526765267752678526795268052681526825268352684526855268652687526885268952690526915269252693526945269552696526975269852699527005270152702527035270452705527065270752708527095271052711527125271352714527155271652717527185271952720527215272252723527245272552726527275272852729527305273152732527335273452735527365273752738527395274052741527425274352744527455274652747527485274952750527515275252753527545275552756527575275852759527605276152762527635276452765527665276752768527695277052771527725277352774527755277652777527785277952780527815278252783527845278552786527875278852789527905279152792527935279452795527965279752798527995280052801528025280352804528055280652807528085280952810528115281252813528145281552816528175281852819528205282152822528235282452825528265282752828528295283052831528325283352834528355283652837528385283952840528415284252843528445284552846528475284852849528505285152852528535285452855528565285752858528595286052861528625286352864528655286652867528685286952870528715287252873528745287552876528775287852879528805288152882528835288452885528865288752888528895289052891528925289352894528955289652897528985289952900529015290252903529045290552906529075290852909529105291152912529135291452915529165291752918529195292052921529225292352924529255292652927529285292952930529315293252933529345293552936529375293852939529405294152942529435294452945529465294752948529495295052951529525295352954529555295652957529585295952960529615296252963529645296552966529675296852969529705297152972529735297452975529765297752978529795298052981529825298352984529855298652987529885298952990529915299252993529945299552996529975299852999530005300153002530035300453005530065300753008530095301053011530125301353014530155301653017530185301953020530215302253023530245302553026530275302853029530305303153032530335303453035530365303753038530395304053041530425304353044530455304653047530485304953050530515305253053530545305553056530575305853059530605306153062530635306453065530665306753068530695307053071530725307353074530755307653077530785307953080530815308253083530845308553086530875308853089530905309153092530935309453095530965309753098530995310053101531025310353104531055310653107531085310953110531115311253113531145311553116531175311853119531205312153122531235312453125531265312753128531295313053131531325313353134531355313653137531385313953140531415314253143531445314553146531475314853149531505315153152531535315453155531565315753158531595316053161531625316353164531655316653167531685316953170531715317253173531745317553176531775317853179531805318153182531835318453185531865318753188531895319053191531925319353194531955319653197531985319953200532015320253203532045320553206532075320853209532105321153212532135321453215532165321753218532195322053221532225322353224532255322653227532285322953230532315323253233532345323553236532375323853239532405324153242532435324453245532465324753248532495325053251532525325353254532555325653257532585325953260532615326253263532645326553266532675326853269532705327153272532735327453275532765327753278532795328053281532825328353284532855328653287532885328953290532915329253293532945329553296532975329853299533005330153302533035330453305533065330753308533095331053311533125331353314533155331653317533185331953320533215332253323533245332553326533275332853329533305333153332533335333453335533365333753338533395334053341533425334353344533455334653347533485334953350533515335253353533545335553356533575335853359533605336153362533635336453365533665336753368533695337053371533725337353374533755337653377533785337953380533815338253383533845338553386533875338853389533905339153392533935339453395533965339753398533995340053401534025340353404534055340653407534085340953410534115341253413534145341553416534175341853419534205342153422534235342453425534265342753428534295343053431534325343353434534355343653437534385343953440534415344253443534445344553446534475344853449534505345153452534535345453455534565345753458534595346053461534625346353464534655346653467534685346953470534715347253473534745347553476534775347853479534805348153482534835348453485534865348753488534895349053491534925349353494534955349653497534985349953500535015350253503535045350553506535075350853509535105351153512535135351453515535165351753518535195352053521535225352353524535255352653527535285352953530535315353253533535345353553536535375353853539535405354153542535435354453545535465354753548535495355053551535525355353554535555355653557535585355953560535615356253563535645356553566535675356853569535705357153572535735357453575535765357753578535795358053581535825358353584535855358653587535885358953590535915359253593535945359553596535975359853599536005360153602536035360453605536065360753608536095361053611536125361353614536155361653617536185361953620536215362253623536245362553626536275362853629536305363153632536335363453635536365363753638536395364053641536425364353644536455364653647536485364953650536515365253653536545365553656536575365853659536605366153662536635366453665536665366753668536695367053671536725367353674536755367653677536785367953680536815368253683536845368553686536875368853689536905369153692536935369453695536965369753698536995370053701537025370353704537055370653707537085370953710537115371253713537145371553716537175371853719537205372153722537235372453725537265372753728537295373053731537325373353734537355373653737537385373953740537415374253743537445374553746537475374853749537505375153752537535375453755537565375753758537595376053761537625376353764537655376653767537685376953770537715377253773537745377553776537775377853779537805378153782537835378453785537865378753788537895379053791537925379353794537955379653797537985379953800538015380253803538045380553806538075380853809538105381153812538135381453815538165381753818538195382053821538225382353824538255382653827538285382953830538315383253833538345383553836538375383853839538405384153842538435384453845538465384753848538495385053851538525385353854538555385653857538585385953860538615386253863538645386553866538675386853869538705387153872538735387453875538765387753878538795388053881538825388353884538855388653887538885388953890538915389253893538945389553896538975389853899539005390153902539035390453905539065390753908539095391053911539125391353914539155391653917539185391953920539215392253923539245392553926539275392853929539305393153932539335393453935539365393753938539395394053941539425394353944539455394653947539485394953950539515395253953539545395553956539575395853959539605396153962539635396453965539665396753968539695397053971539725397353974539755397653977539785397953980539815398253983539845398553986539875398853989539905399153992539935399453995539965399753998539995400054001540025400354004540055400654007540085400954010540115401254013540145401554016540175401854019540205402154022540235402454025540265402754028540295403054031540325403354034540355403654037540385403954040540415404254043540445404554046540475404854049540505405154052540535405454055540565405754058540595406054061540625406354064540655406654067540685406954070540715407254073540745407554076540775407854079540805408154082540835408454085540865408754088540895409054091540925409354094540955409654097540985409954100541015410254103541045410554106541075410854109541105411154112541135411454115541165411754118541195412054121541225412354124541255412654127541285412954130541315413254133541345413554136541375413854139541405414154142541435414454145541465414754148541495415054151541525415354154541555415654157541585415954160541615416254163541645416554166541675416854169541705417154172541735417454175541765417754178541795418054181541825418354184541855418654187541885418954190541915419254193541945419554196541975419854199542005420154202542035420454205542065420754208542095421054211542125421354214542155421654217542185421954220542215422254223542245422554226542275422854229542305423154232542335423454235542365423754238542395424054241542425424354244542455424654247542485424954250542515425254253542545425554256542575425854259542605426154262542635426454265542665426754268542695427054271542725427354274542755427654277542785427954280542815428254283542845428554286542875428854289542905429154292542935429454295542965429754298542995430054301543025430354304543055430654307543085430954310543115431254313543145431554316543175431854319543205432154322543235432454325543265432754328543295433054331543325433354334543355433654337543385433954340543415434254343543445434554346543475434854349543505435154352543535435454355543565435754358543595436054361543625436354364543655436654367543685436954370543715437254373543745437554376543775437854379543805438154382543835438454385543865438754388543895439054391543925439354394543955439654397543985439954400544015440254403544045440554406544075440854409544105441154412544135441454415544165441754418544195442054421544225442354424544255442654427544285442954430544315443254433544345443554436544375443854439544405444154442544435444454445544465444754448544495445054451544525445354454544555445654457544585445954460544615446254463544645446554466544675446854469544705447154472544735447454475544765447754478544795448054481544825448354484544855448654487544885448954490544915449254493544945449554496544975449854499545005450154502545035450454505545065450754508545095451054511545125451354514545155451654517545185451954520545215452254523545245452554526545275452854529545305453154532545335453454535545365453754538545395454054541545425454354544545455454654547545485454954550545515455254553545545455554556545575455854559545605456154562545635456454565545665456754568545695457054571545725457354574545755457654577545785457954580545815458254583545845458554586545875458854589545905459154592545935459454595545965459754598545995460054601546025460354604546055460654607546085460954610546115461254613546145461554616546175461854619546205462154622546235462454625546265462754628546295463054631546325463354634546355463654637546385463954640546415464254643546445464554646546475464854649546505465154652546535465454655546565465754658546595466054661546625466354664546655466654667546685466954670546715467254673546745467554676546775467854679546805468154682546835468454685546865468754688546895469054691546925469354694546955469654697546985469954700547015470254703547045470554706547075470854709547105471154712547135471454715547165471754718547195472054721547225472354724547255472654727547285472954730547315473254733547345473554736547375473854739547405474154742547435474454745547465474754748547495475054751547525475354754547555475654757547585475954760547615476254763547645476554766547675476854769547705477154772547735477454775547765477754778547795478054781547825478354784547855478654787547885478954790547915479254793547945479554796547975479854799548005480154802548035480454805548065480754808548095481054811548125481354814548155481654817548185481954820548215482254823548245482554826548275482854829548305483154832548335483454835548365483754838548395484054841548425484354844548455484654847548485484954850548515485254853548545485554856548575485854859548605486154862548635486454865548665486754868548695487054871548725487354874548755487654877548785487954880548815488254883548845488554886548875488854889548905489154892548935489454895548965489754898548995490054901549025490354904549055490654907549085490954910549115491254913549145491554916549175491854919549205492154922549235492454925549265492754928549295493054931549325493354934549355493654937549385493954940549415494254943549445494554946549475494854949549505495154952549535495454955549565495754958549595496054961549625496354964549655496654967549685496954970549715497254973549745497554976549775497854979549805498154982549835498454985549865498754988549895499054991549925499354994549955499654997549985499955000550015500255003550045500555006550075500855009550105501155012550135501455015550165501755018550195502055021550225502355024550255502655027550285502955030550315503255033550345503555036550375503855039550405504155042550435504455045550465504755048550495505055051550525505355054550555505655057550585505955060550615506255063550645506555066550675506855069550705507155072550735507455075550765507755078550795508055081550825508355084550855508655087550885508955090550915509255093550945509555096550975509855099551005510155102551035510455105551065510755108551095511055111551125511355114551155511655117551185511955120551215512255123551245512555126551275512855129551305513155132551335513455135551365513755138551395514055141551425514355144551455514655147551485514955150551515515255153551545515555156551575515855159551605516155162551635516455165551665516755168551695517055171551725517355174551755517655177551785517955180551815518255183551845518555186551875518855189551905519155192551935519455195551965519755198551995520055201552025520355204552055520655207552085520955210552115521255213552145521555216552175521855219552205522155222552235522455225552265522755228552295523055231552325523355234552355523655237552385523955240552415524255243552445524555246552475524855249552505525155252552535525455255552565525755258552595526055261552625526355264552655526655267552685526955270552715527255273552745527555276552775527855279552805528155282552835528455285552865528755288552895529055291552925529355294552955529655297552985529955300553015530255303553045530555306553075530855309553105531155312553135531455315553165531755318553195532055321553225532355324553255532655327553285532955330553315533255333553345533555336553375533855339553405534155342553435534455345553465534755348553495535055351553525535355354553555535655357553585535955360553615536255363553645536555366553675536855369553705537155372553735537455375553765537755378553795538055381553825538355384553855538655387553885538955390553915539255393553945539555396553975539855399554005540155402554035540455405554065540755408554095541055411554125541355414554155541655417554185541955420554215542255423554245542555426554275542855429554305543155432554335543455435554365543755438554395544055441554425544355444554455544655447554485544955450554515545255453554545545555456554575545855459554605546155462554635546455465554665546755468554695547055471554725547355474554755547655477554785547955480554815548255483554845548555486554875548855489554905549155492554935549455495554965549755498554995550055501555025550355504555055550655507555085550955510555115551255513555145551555516555175551855519555205552155522555235552455525555265552755528555295553055531555325553355534555355553655537555385553955540555415554255543555445554555546555475554855549555505555155552555535555455555555565555755558555595556055561555625556355564555655556655567555685556955570555715557255573555745557555576555775557855579555805558155582555835558455585555865558755588555895559055591555925559355594555955559655597555985559955600556015560255603556045560555606556075560855609556105561155612556135561455615556165561755618556195562055621556225562355624556255562655627556285562955630556315563255633556345563555636556375563855639556405564155642556435564455645556465564755648556495565055651556525565355654556555565655657556585565955660556615566255663556645566555666556675566855669556705567155672556735567455675556765567755678556795568055681556825568355684556855568655687556885568955690556915569255693556945569555696556975569855699557005570155702557035570455705557065570755708557095571055711557125571355714557155571655717557185571955720557215572255723557245572555726557275572855729557305573155732557335573455735557365573755738557395574055741557425574355744557455574655747557485574955750557515575255753557545575555756557575575855759557605576155762557635576455765557665576755768557695577055771557725577355774557755577655777557785577955780557815578255783557845578555786557875578855789557905579155792557935579455795557965579755798557995580055801558025580355804558055580655807558085580955810558115581255813558145581555816558175581855819558205582155822558235582455825558265582755828558295583055831558325583355834558355583655837558385583955840558415584255843558445584555846558475584855849558505585155852558535585455855558565585755858558595586055861558625586355864558655586655867558685586955870558715587255873558745587555876558775587855879558805588155882558835588455885558865588755888558895589055891558925589355894558955589655897558985589955900559015590255903559045590555906559075590855909559105591155912559135591455915559165591755918559195592055921559225592355924559255592655927559285592955930559315593255933559345593555936559375593855939559405594155942559435594455945559465594755948559495595055951559525595355954559555595655957559585595955960559615596255963559645596555966559675596855969559705597155972559735597455975559765597755978559795598055981559825598355984559855598655987559885598955990559915599255993559945599555996559975599855999560005600156002560035600456005560065600756008560095601056011560125601356014560155601656017560185601956020560215602256023560245602556026560275602856029560305603156032560335603456035560365603756038560395604056041560425604356044560455604656047560485604956050560515605256053560545605556056560575605856059560605606156062560635606456065560665606756068560695607056071560725607356074560755607656077560785607956080560815608256083560845608556086560875608856089560905609156092560935609456095560965609756098560995610056101561025610356104561055610656107561085610956110561115611256113561145611556116561175611856119561205612156122561235612456125561265612756128561295613056131561325613356134561355613656137561385613956140561415614256143561445614556146561475614856149561505615156152561535615456155561565615756158561595616056161561625616356164561655616656167561685616956170561715617256173561745617556176561775617856179561805618156182561835618456185561865618756188561895619056191561925619356194561955619656197561985619956200562015620256203562045620556206562075620856209562105621156212562135621456215562165621756218562195622056221562225622356224562255622656227562285622956230562315623256233562345623556236562375623856239562405624156242562435624456245562465624756248562495625056251562525625356254562555625656257562585625956260562615626256263562645626556266562675626856269562705627156272562735627456275562765627756278562795628056281562825628356284562855628656287562885628956290562915629256293562945629556296562975629856299563005630156302563035630456305563065630756308563095631056311563125631356314563155631656317563185631956320563215632256323563245632556326563275632856329563305633156332563335633456335563365633756338563395634056341563425634356344563455634656347563485634956350563515635256353563545635556356563575635856359563605636156362563635636456365563665636756368563695637056371563725637356374563755637656377563785637956380563815638256383563845638556386563875638856389563905639156392563935639456395563965639756398563995640056401564025640356404564055640656407564085640956410564115641256413564145641556416564175641856419564205642156422564235642456425564265642756428564295643056431564325643356434564355643656437564385643956440564415644256443564445644556446564475644856449564505645156452564535645456455564565645756458564595646056461564625646356464564655646656467564685646956470564715647256473564745647556476564775647856479564805648156482564835648456485564865648756488564895649056491564925649356494564955649656497564985649956500565015650256503565045650556506565075650856509565105651156512565135651456515565165651756518565195652056521565225652356524565255652656527565285652956530565315653256533565345653556536565375653856539565405654156542565435654456545565465654756548565495655056551565525655356554565555655656557565585655956560565615656256563565645656556566565675656856569565705657156572565735657456575565765657756578565795658056581565825658356584565855658656587565885658956590565915659256593565945659556596565975659856599566005660156602566035660456605566065660756608566095661056611566125661356614566155661656617566185661956620566215662256623566245662556626566275662856629566305663156632566335663456635566365663756638566395664056641566425664356644566455664656647566485664956650566515665256653566545665556656566575665856659566605666156662566635666456665566665666756668566695667056671566725667356674566755667656677566785667956680566815668256683566845668556686566875668856689566905669156692566935669456695566965669756698566995670056701567025670356704567055670656707567085670956710567115671256713567145671556716567175671856719567205672156722567235672456725567265672756728567295673056731567325673356734567355673656737567385673956740567415674256743567445674556746567475674856749567505675156752567535675456755567565675756758567595676056761567625676356764567655676656767567685676956770567715677256773567745677556776567775677856779567805678156782567835678456785567865678756788567895679056791567925679356794567955679656797567985679956800568015680256803568045680556806568075680856809568105681156812568135681456815568165681756818568195682056821568225682356824568255682656827568285682956830568315683256833568345683556836568375683856839568405684156842568435684456845568465684756848568495685056851568525685356854568555685656857568585685956860568615686256863568645686556866568675686856869568705687156872568735687456875568765687756878568795688056881568825688356884568855688656887568885688956890568915689256893568945689556896568975689856899569005690156902569035690456905569065690756908569095691056911569125691356914569155691656917569185691956920569215692256923569245692556926569275692856929569305693156932569335693456935569365693756938569395694056941569425694356944569455694656947569485694956950569515695256953569545695556956569575695856959569605696156962569635696456965569665696756968569695697056971569725697356974569755697656977569785697956980569815698256983569845698556986569875698856989569905699156992569935699456995569965699756998569995700057001570025700357004570055700657007570085700957010570115701257013570145701557016570175701857019570205702157022570235702457025570265702757028570295703057031570325703357034570355703657037570385703957040570415704257043570445704557046570475704857049
  1. /**
  2. * @license Highstock JS v9.0.1 (2021-02-16)
  3. *
  4. * (c) 2009-2021 Torstein Honsi
  5. *
  6. * License: www.highcharts.com/license
  7. */
  8. 'use strict';
  9. (function (root, factory) {
  10. if (typeof module === 'object' && module.exports) {
  11. factory['default'] = factory;
  12. module.exports = root.document ?
  13. factory(root) :
  14. factory;
  15. } else if (typeof define === 'function' && define.amd) {
  16. define('highcharts/highstock', function () {
  17. return factory(root);
  18. });
  19. } else {
  20. if (root.Highcharts) {
  21. root.Highcharts.error(16, true);
  22. }
  23. root.Highcharts = factory(root);
  24. }
  25. }(typeof window !== 'undefined' ? window : this, function (win) {
  26. var _modules = {};
  27. function _registerModule(obj, path, args, fn) {
  28. if (!obj.hasOwnProperty(path)) {
  29. obj[path] = fn.apply(null, args);
  30. }
  31. }
  32. _registerModule(_modules, 'Core/Globals.js', [], function () {
  33. /* *
  34. *
  35. * (c) 2010-2021 Torstein Honsi
  36. *
  37. * License: www.highcharts.com/license
  38. *
  39. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  40. *
  41. * */
  42. /* globals Image, window */
  43. /**
  44. * Reference to the global SVGElement class as a workaround for a name conflict
  45. * in the Highcharts namespace.
  46. *
  47. * @global
  48. * @typedef {global.SVGElement} GlobalSVGElement
  49. *
  50. * @see https://developer.mozilla.org/en-US/docs/Web/API/SVGElement
  51. */
  52. // glob is a temporary fix to allow our es-modules to work.
  53. var glob = ( // @todo UMD variable named `window`, and glob named `win`
  54. typeof win !== 'undefined' ?
  55. win :
  56. typeof window !== 'undefined' ?
  57. window :
  58. {}), doc = glob.document, SVG_NS = 'http://www.w3.org/2000/svg', userAgent = (glob.navigator && glob.navigator.userAgent) || '', svg = (doc &&
  59. doc.createElementNS &&
  60. !!doc.createElementNS(SVG_NS, 'svg').createSVGRect), isMS = /(edge|msie|trident)/i.test(userAgent) && !glob.opera, isFirefox = userAgent.indexOf('Firefox') !== -1, isChrome = userAgent.indexOf('Chrome') !== -1, hasBidiBug = (isFirefox &&
  61. parseInt(userAgent.split('Firefox/')[1], 10) < 4 // issue #38
  62. ), noop = function () { },
  63. // Checks whether the browser supports passive events, (#11353).
  64. checkPassiveEvents = function () {
  65. var supportsPassive = false;
  66. // Object.defineProperty doesn't work on IE as well as passive events -
  67. // instead of using polyfill, we can exclude IE totally.
  68. if (!isMS) {
  69. var opts = Object.defineProperty({}, 'passive', {
  70. get: function () {
  71. supportsPassive = true;
  72. }
  73. });
  74. if (glob.addEventListener && glob.removeEventListener) {
  75. glob.addEventListener('testPassive', noop, opts);
  76. glob.removeEventListener('testPassive', noop, opts);
  77. }
  78. }
  79. return supportsPassive;
  80. };
  81. var H = {
  82. product: 'Highcharts',
  83. version: '9.0.1',
  84. deg2rad: Math.PI * 2 / 360,
  85. doc: doc,
  86. hasBidiBug: hasBidiBug,
  87. hasTouch: !!glob.TouchEvent,
  88. isMS: isMS,
  89. isWebKit: userAgent.indexOf('AppleWebKit') !== -1,
  90. isFirefox: isFirefox,
  91. isChrome: isChrome,
  92. isSafari: !isChrome && userAgent.indexOf('Safari') !== -1,
  93. isTouchDevice: /(Mobile|Android|Windows Phone)/.test(userAgent),
  94. SVG_NS: SVG_NS,
  95. chartCount: 0,
  96. seriesTypes: {},
  97. supportsPassiveEvents: checkPassiveEvents(),
  98. symbolSizes: {},
  99. svg: svg,
  100. win: glob,
  101. marginNames: ['plotTop', 'marginRight', 'marginBottom', 'plotLeft'],
  102. noop: noop,
  103. /**
  104. * Theme options that should get applied to the chart. In module mode it
  105. * might not be possible to change this property because of read-only
  106. * restrictions, instead use {@link Highcharts.setOptions}.
  107. *
  108. * @name Highcharts.theme
  109. * @type {Highcharts.Options}
  110. */
  111. /**
  112. * An array containing the current chart objects in the page. A chart's
  113. * position in the array is preserved throughout the page's lifetime. When
  114. * a chart is destroyed, the array item becomes `undefined`.
  115. *
  116. * @name Highcharts.charts
  117. * @type {Array<Highcharts.Chart|undefined>}
  118. */
  119. charts: [],
  120. /**
  121. * A hook for defining additional date format specifiers. New
  122. * specifiers are defined as key-value pairs by using the
  123. * specifier as key, and a function which takes the timestamp as
  124. * value. This function returns the formatted portion of the
  125. * date.
  126. *
  127. * @sample highcharts/global/dateformats/
  128. * Adding support for week number
  129. *
  130. * @name Highcharts.dateFormats
  131. * @type {Highcharts.Dictionary<Highcharts.TimeFormatCallbackFunction>}
  132. */
  133. dateFormats: {}
  134. };
  135. return H;
  136. });
  137. _registerModule(_modules, 'Core/Utilities.js', [_modules['Core/Globals.js']], function (H) {
  138. /* *
  139. *
  140. * (c) 2010-2021 Torstein Honsi
  141. *
  142. * License: www.highcharts.com/license
  143. *
  144. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  145. *
  146. * */
  147. var charts = H.charts,
  148. doc = H.doc,
  149. win = H.win;
  150. /**
  151. * An animation configuration. Animation configurations can also be defined as
  152. * booleans, where `false` turns off animation and `true` defaults to a duration
  153. * of 500ms and defer of 0ms.
  154. *
  155. * @interface Highcharts.AnimationOptionsObject
  156. */ /**
  157. * A callback function to exectute when the animation finishes.
  158. * @name Highcharts.AnimationOptionsObject#complete
  159. * @type {Function|undefined}
  160. */ /**
  161. * The animation defer in milliseconds.
  162. * @name Highcharts.AnimationOptionsObject#defer
  163. * @type {number|undefined}
  164. */ /**
  165. * The animation duration in milliseconds.
  166. * @name Highcharts.AnimationOptionsObject#duration
  167. * @type {number|undefined}
  168. */ /**
  169. * The name of an easing function as defined on the `Math` object.
  170. * @name Highcharts.AnimationOptionsObject#easing
  171. * @type {string|Function|undefined}
  172. */ /**
  173. * A callback function to execute on each step of each attribute or CSS property
  174. * that's being animated. The first argument contains information about the
  175. * animation and progress.
  176. * @name Highcharts.AnimationOptionsObject#step
  177. * @type {Function|undefined}
  178. */
  179. /**
  180. * Creates a frame for the animated SVG element.
  181. *
  182. * @callback Highcharts.AnimationStepCallbackFunction
  183. *
  184. * @param {Highcharts.SVGElement} this
  185. * The SVG element to animate.
  186. *
  187. * @return {void}
  188. */
  189. /**
  190. * Interface description for a class.
  191. *
  192. * @interface Highcharts.Class<T>
  193. * @extends Function
  194. */ /**
  195. * Class costructor.
  196. * @function Highcharts.Class<T>#new
  197. * @param {...Array<*>} args
  198. * Constructor arguments.
  199. * @return {T}
  200. * Class instance.
  201. */
  202. /**
  203. * A style object with camel case property names to define visual appearance of
  204. * a SVG element or HTML element. The properties can be whatever styles are
  205. * supported on the given SVG or HTML element.
  206. *
  207. * @example
  208. * {
  209. * fontFamily: 'monospace',
  210. * fontSize: '1.2em'
  211. * }
  212. *
  213. * @interface Highcharts.CSSObject
  214. */ /**
  215. * @name Highcharts.CSSObject#[key:string]
  216. * @type {boolean|number|string|undefined}
  217. */ /**
  218. * Background style for the element.
  219. * @name Highcharts.CSSObject#background
  220. * @type {string|undefined}
  221. */ /**
  222. * Background color of the element.
  223. * @name Highcharts.CSSObject#backgroundColor
  224. * @type {Highcharts.ColorString|undefined}
  225. */ /**
  226. * Border style for the element.
  227. * @name Highcharts.CSSObject#border
  228. * @type {string|undefined}
  229. */ /**
  230. * Radius of the element border.
  231. * @name Highcharts.CSSObject#borderRadius
  232. * @type {number|undefined}
  233. */ /**
  234. * Color used in the element. The 'contrast' option is a Highcharts custom
  235. * property that results in black or white, depending on the background of the
  236. * element.
  237. * @name Highcharts.CSSObject#color
  238. * @type {'contrast'|Highcharts.ColorString|undefined}
  239. */ /**
  240. * Style of the mouse cursor when resting over the element.
  241. * @name Highcharts.CSSObject#cursor
  242. * @type {Highcharts.CursorValue|undefined}
  243. */ /**
  244. * Font family of the element text. Multiple values have to be in decreasing
  245. * preference order and separated by comma.
  246. * @name Highcharts.CSSObject#fontFamily
  247. * @type {string|undefined}
  248. */ /**
  249. * Font size of the element text.
  250. * @name Highcharts.CSSObject#fontSize
  251. * @type {string|undefined}
  252. */ /**
  253. * Font weight of the element text.
  254. * @name Highcharts.CSSObject#fontWeight
  255. * @type {string|undefined}
  256. */ /**
  257. * Height of the element.
  258. * @name Highcharts.CSSObject#height
  259. * @type {number|undefined}
  260. */ /**
  261. * Width of the element border.
  262. * @name Highcharts.CSSObject#lineWidth
  263. * @type {number|undefined}
  264. */ /**
  265. * Opacity of the element.
  266. * @name Highcharts.CSSObject#opacity
  267. * @type {number|undefined}
  268. */ /**
  269. * Space around the element content.
  270. * @name Highcharts.CSSObject#padding
  271. * @type {string|undefined}
  272. */ /**
  273. * Behaviour of the element when the mouse cursor rests over it.
  274. * @name Highcharts.CSSObject#pointerEvents
  275. * @type {string|undefined}
  276. */ /**
  277. * Positioning of the element.
  278. * @name Highcharts.CSSObject#position
  279. * @type {string|undefined}
  280. */ /**
  281. * Alignment of the element text.
  282. * @name Highcharts.CSSObject#textAlign
  283. * @type {string|undefined}
  284. */ /**
  285. * Additional decoration of the element text.
  286. * @name Highcharts.CSSObject#textDecoration
  287. * @type {string|undefined}
  288. */ /**
  289. * Outline style of the element text.
  290. * @name Highcharts.CSSObject#textOutline
  291. * @type {string|undefined}
  292. */ /**
  293. * Line break style of the element text. Highcharts SVG elements support
  294. * `ellipsis` when a `width` is set.
  295. * @name Highcharts.CSSObject#textOverflow
  296. * @type {string|undefined}
  297. */ /**
  298. * Top spacing of the element relative to the parent element.
  299. * @name Highcharts.CSSObject#top
  300. * @type {string|undefined}
  301. */ /**
  302. * Animated transition of selected element properties.
  303. * @name Highcharts.CSSObject#transition
  304. * @type {string|undefined}
  305. */ /**
  306. * Line break style of the element text.
  307. * @name Highcharts.CSSObject#whiteSpace
  308. * @type {string|undefined}
  309. */ /**
  310. * Width of the element.
  311. * @name Highcharts.CSSObject#width
  312. * @type {number|undefined}
  313. */
  314. /**
  315. * All possible cursor styles.
  316. *
  317. * @typedef {'alias'|'all-scroll'|'auto'|'cell'|'col-resize'|'context-menu'|'copy'|'crosshair'|'default'|'e-resize'|'ew-resize'|'grab'|'grabbing'|'help'|'move'|'n-resize'|'ne-resize'|'nesw-resize'|'no-drop'|'none'|'not-allowed'|'ns-resize'|'nw-resize'|'nwse-resize'|'pointer'|'progress'|'row-resize'|'s-resize'|'se-resize'|'sw-resize'|'text'|'vertical-text'|'w-resize'|'wait'|'zoom-in'|'zoom-out'} Highcharts.CursorValue
  318. */
  319. /**
  320. * All possible dash styles.
  321. *
  322. * @typedef {'Dash'|'DashDot'|'Dot'|'LongDash'|'LongDashDot'|'LongDashDotDot'|'ShortDash'|'ShortDashDot'|'ShortDashDotDot'|'ShortDot'|'Solid'} Highcharts.DashStyleValue
  323. */
  324. /**
  325. * Generic dictionary in TypeScript notation.
  326. * Use the native `Record<string, any>` instead.
  327. *
  328. * @deprecated
  329. * @interface Highcharts.Dictionary<T>
  330. */ /**
  331. * @name Highcharts.Dictionary<T>#[key:string]
  332. * @type {T}
  333. */
  334. /**
  335. * The function callback to execute when the event is fired. The `this` context
  336. * contains the instance, that fired the event.
  337. *
  338. * @callback Highcharts.EventCallbackFunction<T>
  339. *
  340. * @param {T} this
  341. *
  342. * @param {Highcharts.Dictionary<*>|Event} [eventArguments]
  343. * Event arguments.
  344. *
  345. * @return {boolean|void}
  346. */
  347. /**
  348. * The event options for adding function callback.
  349. *
  350. * @interface Highcharts.EventOptionsObject
  351. */ /**
  352. * The order the event handler should be called. This opens for having one
  353. * handler be called before another, independent of in which order they were
  354. * added.
  355. * @name Highcharts.EventOptionsObject#order
  356. * @type {number}
  357. */ /**
  358. * Whether an event should be passive or not.
  359. * When set to `true`, the function specified by listener will never call
  360. * `preventDefault()`.
  361. * @name Highcharts.EventOptionsObject#passive
  362. * @type boolean
  363. */
  364. /**
  365. * Formats data as a string. Usually the data is accessible throught the `this`
  366. * keyword.
  367. *
  368. * @callback Highcharts.FormatterCallbackFunction<T>
  369. *
  370. * @param {T} this
  371. * Context to format
  372. *
  373. * @return {string}
  374. * Formatted text
  375. */
  376. /**
  377. * An object of key-value pairs for HTML attributes.
  378. *
  379. * @typedef {Highcharts.Dictionary<boolean|number|string|Function>} Highcharts.HTMLAttributes
  380. */
  381. /**
  382. * An HTML DOM element. The type is a reference to the regular HTMLElement in
  383. * the global scope.
  384. *
  385. * @typedef {global.HTMLElement} Highcharts.HTMLDOMElement
  386. *
  387. * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
  388. */
  389. /**
  390. * The iterator callback.
  391. *
  392. * @callback Highcharts.ObjectEachCallbackFunction<T>
  393. *
  394. * @param {T} this
  395. * The context.
  396. *
  397. * @param {*} value
  398. * The property value.
  399. *
  400. * @param {string} key
  401. * The property key.
  402. *
  403. * @param {*} obj
  404. * The object that objectEach is being applied to.
  405. */
  406. /**
  407. * An object containing `left` and `top` properties for the position in the
  408. * page.
  409. *
  410. * @interface Highcharts.OffsetObject
  411. */ /**
  412. * Left distance to the page border.
  413. * @name Highcharts.OffsetObject#left
  414. * @type {number}
  415. */ /**
  416. * Top distance to the page border.
  417. * @name Highcharts.OffsetObject#top
  418. * @type {number}
  419. */
  420. /**
  421. * Describes a range.
  422. *
  423. * @interface Highcharts.RangeObject
  424. */ /**
  425. * Maximum number of the range.
  426. * @name Highcharts.RangeObject#max
  427. * @type {number}
  428. */ /**
  429. * Minimum number of the range.
  430. * @name Highcharts.RangeObject#min
  431. * @type {number}
  432. */
  433. /**
  434. * If a number is given, it defines the pixel length. If a percentage string is
  435. * given, like for example `'50%'`, the setting defines a length relative to a
  436. * base size, for example the size of a container.
  437. *
  438. * @typedef {number|string} Highcharts.RelativeSize
  439. */
  440. /**
  441. * Proceed function to call original (wrapped) function.
  442. *
  443. * @callback Highcharts.WrapProceedFunction
  444. *
  445. * @param {*} [arg1]
  446. * Optional argument. Without any arguments defaults to first argument of
  447. * the wrapping function.
  448. *
  449. * @param {*} [arg2]
  450. * Optional argument. Without any arguments defaults to second argument
  451. * of the wrapping function.
  452. *
  453. * @param {*} [arg3]
  454. * Optional argument. Without any arguments defaults to third argument of
  455. * the wrapping function.
  456. *
  457. * @return {*}
  458. * Return value of the original function.
  459. */
  460. /**
  461. * The Highcharts object is the placeholder for all other members, and various
  462. * utility functions. The most important member of the namespace would be the
  463. * chart constructor.
  464. *
  465. * @example
  466. * var chart = Highcharts.chart('container', { ... });
  467. *
  468. * @namespace Highcharts
  469. */
  470. ''; // detach doclets above
  471. /**
  472. * Provide error messages for debugging, with links to online explanation. This
  473. * function can be overridden to provide custom error handling.
  474. *
  475. * @sample highcharts/chart/highcharts-error/
  476. * Custom error handler
  477. *
  478. * @function Highcharts.error
  479. *
  480. * @param {number|string} code
  481. * The error code. See
  482. * [errors.xml](https://github.com/highcharts/highcharts/blob/master/errors/errors.xml)
  483. * for available codes. If it is a string, the error message is printed
  484. * directly in the console.
  485. *
  486. * @param {boolean} [stop=false]
  487. * Whether to throw an error or just log a warning in the console.
  488. *
  489. * @param {Highcharts.Chart} [chart]
  490. * Reference to the chart that causes the error. Used in 'debugger'
  491. * module to display errors directly on the chart.
  492. * Important note: This argument is undefined for errors that lack
  493. * access to the Chart instance.
  494. *
  495. * @param {Highcharts.Dictionary<string>} [params]
  496. * Additional parameters for the generated message.
  497. *
  498. * @return {void}
  499. */
  500. function error(code, stop, chart, params) {
  501. var severity = stop ? 'Highcharts error' : 'Highcharts warning';
  502. if (code === 32) {
  503. code = severity + ": Deprecated member";
  504. }
  505. var isCode = isNumber(code),
  506. message = isCode ?
  507. severity + " #" + code + ": www.highcharts.com/errors/" + code + "/" :
  508. code.toString(),
  509. defaultHandler = function () {
  510. if (stop) {
  511. throw new Error(message);
  512. }
  513. // else ...
  514. if (win.console &&
  515. error.messages.indexOf(message) === -1 // prevent console flooting
  516. ) {
  517. console.warn(message); // eslint-disable-line no-console
  518. }
  519. };
  520. if (typeof params !== 'undefined') {
  521. var additionalMessages_1 = '';
  522. if (isCode) {
  523. message += '?';
  524. }
  525. objectEach(params, function (value, key) {
  526. additionalMessages_1 += "\n - " + key + ": " + value;
  527. if (isCode) {
  528. message += encodeURI(key) + '=' + encodeURI(value);
  529. }
  530. });
  531. message += additionalMessages_1;
  532. }
  533. if (chart) {
  534. fireEvent(chart, 'displayError', { code: code, message: message, params: params }, defaultHandler);
  535. }
  536. else {
  537. defaultHandler();
  538. }
  539. error.messages.push(message);
  540. }
  541. (function (error) {
  542. error.messages = [];
  543. })(error || (error = {}));
  544. /* eslint-disable valid-jsdoc */
  545. /**
  546. * Utility function to deep merge two or more objects and return a third object.
  547. * If the first argument is true, the contents of the second object is copied
  548. * into the first object. The merge function can also be used with a single
  549. * object argument to create a deep copy of an object.
  550. *
  551. * @function Highcharts.merge<T>
  552. *
  553. * @param {boolean} extend
  554. * Whether to extend the left-side object (a) or return a whole new
  555. * object.
  556. *
  557. * @param {T|undefined} a
  558. * The first object to extend. When only this is given, the function
  559. * returns a deep copy.
  560. *
  561. * @param {...Array<object|undefined>} [n]
  562. * An object to merge into the previous one.
  563. *
  564. * @return {T}
  565. * The merged object. If the first argument is true, the return is the
  566. * same as the second argument.
  567. */ /**
  568. * Utility function to deep merge two or more objects and return a third object.
  569. * The merge function can also be used with a single object argument to create a
  570. * deep copy of an object.
  571. *
  572. * @function Highcharts.merge<T>
  573. *
  574. * @param {T|undefined} a
  575. * The first object to extend. When only this is given, the function
  576. * returns a deep copy.
  577. *
  578. * @param {...Array<object|undefined>} [n]
  579. * An object to merge into the previous one.
  580. *
  581. * @return {T}
  582. * The merged object. If the first argument is true, the return is the
  583. * same as the second argument.
  584. */
  585. function merge() {
  586. /* eslint-enable valid-jsdoc */
  587. var i,
  588. args = arguments,
  589. len,
  590. ret = {},
  591. doCopy = function (copy,
  592. original) {
  593. // An object is replacing a primitive
  594. if (typeof copy !== 'object') {
  595. copy = {};
  596. }
  597. objectEach(original, function (value, key) {
  598. // Prototype pollution (#14883)
  599. if (key === '__proto__' || key === 'constructor') {
  600. return;
  601. }
  602. // Copy the contents of objects, but not arrays or DOM nodes
  603. if (isObject(value, true) &&
  604. !isClass(value) &&
  605. !isDOMElement(value)) {
  606. copy[key] = doCopy(copy[key] || {}, value);
  607. // Primitives and arrays are copied over directly
  608. }
  609. else {
  610. copy[key] = original[key];
  611. }
  612. });
  613. return copy;
  614. };
  615. // If first argument is true, copy into the existing object. Used in
  616. // setOptions.
  617. if (args[0] === true) {
  618. ret = args[1];
  619. args = Array.prototype.slice.call(args, 2);
  620. }
  621. // For each argument, extend the return
  622. len = args.length;
  623. for (i = 0; i < len; i++) {
  624. ret = doCopy(ret, args[i]);
  625. }
  626. return ret;
  627. }
  628. /**
  629. * Constrain a value to within a lower and upper threshold.
  630. *
  631. * @private
  632. * @param {number} value The initial value
  633. * @param {number} min The lower threshold
  634. * @param {number} max The upper threshold
  635. * @return {number} Returns a number value within min and max.
  636. */
  637. function clamp(value, min, max) {
  638. return value > min ? value < max ? value : max : min;
  639. }
  640. // eslint-disable-next-line valid-jsdoc
  641. /**
  642. * Remove settings that have not changed, to avoid unnecessary rendering or
  643. * computing (#9197).
  644. * @private
  645. */
  646. function cleanRecursively(newer, older) {
  647. var result = {};
  648. objectEach(newer, function (_val, key) {
  649. var ob;
  650. // Dive into objects (except DOM nodes)
  651. if (isObject(newer[key], true) &&
  652. !newer.nodeType && // #10044
  653. older[key]) {
  654. ob = cleanRecursively(newer[key], older[key]);
  655. if (Object.keys(ob).length) {
  656. result[key] = ob;
  657. }
  658. // Arrays, primitives and DOM nodes are copied directly
  659. }
  660. else if (isObject(newer[key]) ||
  661. newer[key] !== older[key]) {
  662. result[key] = newer[key];
  663. }
  664. });
  665. return result;
  666. }
  667. /**
  668. * Shortcut for parseInt
  669. *
  670. * @private
  671. * @function Highcharts.pInt
  672. *
  673. * @param {*} s
  674. * any
  675. *
  676. * @param {number} [mag]
  677. * Magnitude
  678. *
  679. * @return {number}
  680. * number
  681. */
  682. function pInt(s, mag) {
  683. return parseInt(s, mag || 10);
  684. }
  685. /**
  686. * Utility function to check for string type.
  687. *
  688. * @function Highcharts.isString
  689. *
  690. * @param {*} s
  691. * The item to check.
  692. *
  693. * @return {boolean}
  694. * True if the argument is a string.
  695. */
  696. function isString(s) {
  697. return typeof s === 'string';
  698. }
  699. /**
  700. * Utility function to check if an item is an array.
  701. *
  702. * @function Highcharts.isArray
  703. *
  704. * @param {*} obj
  705. * The item to check.
  706. *
  707. * @return {boolean}
  708. * True if the argument is an array.
  709. */
  710. function isArray(obj) {
  711. var str = Object.prototype.toString.call(obj);
  712. return str === '[object Array]' || str === '[object Array Iterator]';
  713. }
  714. /**
  715. * Utility function to check if an item is of type object.
  716. *
  717. * @function Highcharts.isObject
  718. *
  719. * @param {*} obj
  720. * The item to check.
  721. *
  722. * @param {boolean} [strict=false]
  723. * Also checks that the object is not an array.
  724. *
  725. * @return {boolean}
  726. * True if the argument is an object.
  727. */
  728. function isObject(obj, strict) {
  729. return (!!obj &&
  730. typeof obj === 'object' &&
  731. (!strict || !isArray(obj))); // eslint-disable-line @typescript-eslint/no-explicit-any
  732. }
  733. /**
  734. * Utility function to check if an Object is a HTML Element.
  735. *
  736. * @function Highcharts.isDOMElement
  737. *
  738. * @param {*} obj
  739. * The item to check.
  740. *
  741. * @return {boolean}
  742. * True if the argument is a HTML Element.
  743. */
  744. function isDOMElement(obj) {
  745. return isObject(obj) && typeof obj.nodeType === 'number';
  746. }
  747. /**
  748. * Utility function to check if an Object is a class.
  749. *
  750. * @function Highcharts.isClass
  751. *
  752. * @param {object|undefined} obj
  753. * The item to check.
  754. *
  755. * @return {boolean}
  756. * True if the argument is a class.
  757. */
  758. function isClass(obj) {
  759. var c = obj && obj.constructor;
  760. return !!(isObject(obj, true) &&
  761. !isDOMElement(obj) &&
  762. (c && c.name && c.name !== 'Object'));
  763. }
  764. /**
  765. * Utility function to check if an item is a number and it is finite (not NaN,
  766. * Infinity or -Infinity).
  767. *
  768. * @function Highcharts.isNumber
  769. *
  770. * @param {*} n
  771. * The item to check.
  772. *
  773. * @return {boolean}
  774. * True if the item is a finite number
  775. */
  776. function isNumber(n) {
  777. return typeof n === 'number' && !isNaN(n) && n < Infinity && n > -Infinity;
  778. }
  779. /**
  780. * Remove the last occurence of an item from an array.
  781. *
  782. * @function Highcharts.erase
  783. *
  784. * @param {Array<*>} arr
  785. * The array.
  786. *
  787. * @param {*} item
  788. * The item to remove.
  789. *
  790. * @return {void}
  791. */
  792. function erase(arr, item) {
  793. var i = arr.length;
  794. while (i--) {
  795. if (arr[i] === item) {
  796. arr.splice(i, 1);
  797. break;
  798. }
  799. }
  800. }
  801. /**
  802. * Check if an object is null or undefined.
  803. *
  804. * @function Highcharts.defined
  805. *
  806. * @param {*} obj
  807. * The object to check.
  808. *
  809. * @return {boolean}
  810. * False if the object is null or undefined, otherwise true.
  811. */
  812. function defined(obj) {
  813. return typeof obj !== 'undefined' && obj !== null;
  814. }
  815. /**
  816. * Set or get an attribute or an object of attributes. To use as a setter, pass
  817. * a key and a value, or let the second argument be a collection of keys and
  818. * values. To use as a getter, pass only a string as the second argument.
  819. *
  820. * @function Highcharts.attr
  821. *
  822. * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} elem
  823. * The DOM element to receive the attribute(s).
  824. *
  825. * @param {string|Highcharts.HTMLAttributes|Highcharts.SVGAttributes} [prop]
  826. * The property or an object of key-value pairs.
  827. *
  828. * @param {number|string} [value]
  829. * The value if a single property is set.
  830. *
  831. * @return {string|null|undefined}
  832. * When used as a getter, return the value.
  833. */
  834. function attr(elem, prop, value) {
  835. var ret;
  836. // if the prop is a string
  837. if (isString(prop)) {
  838. // set the value
  839. if (defined(value)) {
  840. elem.setAttribute(prop, value);
  841. // get the value
  842. }
  843. else if (elem && elem.getAttribute) {
  844. ret = elem.getAttribute(prop);
  845. // IE7 and below cannot get class through getAttribute (#7850)
  846. if (!ret && prop === 'class') {
  847. ret = elem.getAttribute(prop + 'Name');
  848. }
  849. }
  850. // else if prop is defined, it is a hash of key/value pairs
  851. }
  852. else {
  853. objectEach(prop, function (val, key) {
  854. elem.setAttribute(key, val);
  855. });
  856. }
  857. return ret;
  858. }
  859. /**
  860. * Check if an element is an array, and if not, make it into an array.
  861. *
  862. * @function Highcharts.splat
  863. *
  864. * @param {*} obj
  865. * The object to splat.
  866. *
  867. * @return {Array}
  868. * The produced or original array.
  869. */
  870. function splat(obj) {
  871. return isArray(obj) ? obj : [obj];
  872. }
  873. /**
  874. * Set a timeout if the delay is given, otherwise perform the function
  875. * synchronously.
  876. *
  877. * @function Highcharts.syncTimeout
  878. *
  879. * @param {Function} fn
  880. * The function callback.
  881. *
  882. * @param {number} delay
  883. * Delay in milliseconds.
  884. *
  885. * @param {*} [context]
  886. * An optional context to send to the function callback.
  887. *
  888. * @return {number}
  889. * An identifier for the timeout that can later be cleared with
  890. * Highcharts.clearTimeout. Returns -1 if there is no timeout.
  891. */
  892. function syncTimeout(fn, delay, context) {
  893. if (delay > 0) {
  894. return setTimeout(fn, delay, context);
  895. }
  896. fn.call(0, context);
  897. return -1;
  898. }
  899. /**
  900. * Internal clear timeout. The function checks that the `id` was not removed
  901. * (e.g. by `chart.destroy()`). For the details see
  902. * [issue #7901](https://github.com/highcharts/highcharts/issues/7901).
  903. *
  904. * @function Highcharts.clearTimeout
  905. *
  906. * @param {number} id
  907. * Id of a timeout.
  908. *
  909. * @return {void}
  910. */
  911. function internalClearTimeout(id) {
  912. if (defined(id)) {
  913. clearTimeout(id);
  914. }
  915. }
  916. /* eslint-disable valid-jsdoc */
  917. /**
  918. * Utility function to extend an object with the members of another.
  919. *
  920. * @function Highcharts.extend<T>
  921. *
  922. * @param {T|undefined} a
  923. * The object to be extended.
  924. *
  925. * @param {object} b
  926. * The object to add to the first one.
  927. *
  928. * @return {T}
  929. * Object a, the original object.
  930. */
  931. function extend(a, b) {
  932. /* eslint-enable valid-jsdoc */
  933. var n;
  934. if (!a) {
  935. a = {};
  936. }
  937. for (n in b) { // eslint-disable-line guard-for-in
  938. a[n] = b[n];
  939. }
  940. return a;
  941. }
  942. /* eslint-disable valid-jsdoc */
  943. /**
  944. * Return the first value that is not null or undefined.
  945. *
  946. * @function Highcharts.pick<T>
  947. *
  948. * @param {...Array<T|null|undefined>} items
  949. * Variable number of arguments to inspect.
  950. *
  951. * @return {T}
  952. * The value of the first argument that is not null or undefined.
  953. */
  954. function pick() {
  955. var args = arguments;
  956. var length = args.length;
  957. for (var i = 0; i < length; i++) {
  958. var arg = args[i];
  959. if (typeof arg !== 'undefined' && arg !== null) {
  960. return arg;
  961. }
  962. }
  963. }
  964. /**
  965. * Set CSS on a given element.
  966. *
  967. * @function Highcharts.css
  968. *
  969. * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} el
  970. * An HTML DOM element.
  971. *
  972. * @param {Highcharts.CSSObject} styles
  973. * Style object with camel case property names.
  974. *
  975. * @return {void}
  976. */
  977. function css(el, styles) {
  978. if (H.isMS && !H.svg) { // #2686
  979. if (styles && typeof styles.opacity !== 'undefined') {
  980. styles.filter =
  981. 'alpha(opacity=' + (styles.opacity * 100) + ')';
  982. }
  983. }
  984. extend(el.style, styles);
  985. }
  986. /**
  987. * Utility function to create an HTML element with attributes and styles.
  988. *
  989. * @function Highcharts.createElement
  990. *
  991. * @param {string} tag
  992. * The HTML tag.
  993. *
  994. * @param {Highcharts.HTMLAttributes} [attribs]
  995. * Attributes as an object of key-value pairs.
  996. *
  997. * @param {Highcharts.CSSObject} [styles]
  998. * Styles as an object of key-value pairs.
  999. *
  1000. * @param {Highcharts.HTMLDOMElement} [parent]
  1001. * The parent HTML object.
  1002. *
  1003. * @param {boolean} [nopad=false]
  1004. * If true, remove all padding, border and margin.
  1005. *
  1006. * @return {Highcharts.HTMLDOMElement}
  1007. * The created DOM element.
  1008. */
  1009. function createElement(tag, attribs, styles, parent, nopad) {
  1010. var el = doc.createElement(tag);
  1011. if (attribs) {
  1012. extend(el, attribs);
  1013. }
  1014. if (nopad) {
  1015. css(el, { padding: '0', border: 'none', margin: '0' });
  1016. }
  1017. if (styles) {
  1018. css(el, styles);
  1019. }
  1020. if (parent) {
  1021. parent.appendChild(el);
  1022. }
  1023. return el;
  1024. }
  1025. // eslint-disable-next-line valid-jsdoc
  1026. /**
  1027. * Extend a prototyped class by new members.
  1028. *
  1029. * @function Highcharts.extendClass<T>
  1030. *
  1031. * @param {Highcharts.Class<T>} parent
  1032. * The parent prototype to inherit.
  1033. *
  1034. * @param {Highcharts.Dictionary<*>} members
  1035. * A collection of prototype members to add or override compared to the
  1036. * parent prototype.
  1037. *
  1038. * @return {Highcharts.Class<T>}
  1039. * A new prototype.
  1040. */
  1041. function extendClass(parent, members) {
  1042. var obj = (function () { });
  1043. obj.prototype = new parent(); // eslint-disable-line new-cap
  1044. extend(obj.prototype, members);
  1045. return obj;
  1046. }
  1047. /**
  1048. * Left-pad a string to a given length by adding a character repetetively.
  1049. *
  1050. * @function Highcharts.pad
  1051. *
  1052. * @param {number} number
  1053. * The input string or number.
  1054. *
  1055. * @param {number} [length]
  1056. * The desired string length.
  1057. *
  1058. * @param {string} [padder=0]
  1059. * The character to pad with.
  1060. *
  1061. * @return {string}
  1062. * The padded string.
  1063. */
  1064. function pad(number, length, padder) {
  1065. return new Array((length || 2) +
  1066. 1 -
  1067. String(number)
  1068. .replace('-', '')
  1069. .length).join(padder || '0') + number;
  1070. }
  1071. /**
  1072. * Return a length based on either the integer value, or a percentage of a base.
  1073. *
  1074. * @function Highcharts.relativeLength
  1075. *
  1076. * @param {Highcharts.RelativeSize} value
  1077. * A percentage string or a number.
  1078. *
  1079. * @param {number} base
  1080. * The full length that represents 100%.
  1081. *
  1082. * @param {number} [offset=0]
  1083. * A pixel offset to apply for percentage values. Used internally in
  1084. * axis positioning.
  1085. *
  1086. * @return {number}
  1087. * The computed length.
  1088. */
  1089. function relativeLength(value, base, offset) {
  1090. return (/%$/).test(value) ?
  1091. (base * parseFloat(value) / 100) + (offset || 0) :
  1092. parseFloat(value);
  1093. }
  1094. /**
  1095. * Wrap a method with extended functionality, preserving the original function.
  1096. *
  1097. * @function Highcharts.wrap
  1098. *
  1099. * @param {*} obj
  1100. * The context object that the method belongs to. In real cases, this is
  1101. * often a prototype.
  1102. *
  1103. * @param {string} method
  1104. * The name of the method to extend.
  1105. *
  1106. * @param {Highcharts.WrapProceedFunction} func
  1107. * A wrapper function callback. This function is called with the same
  1108. * arguments as the original function, except that the original function
  1109. * is unshifted and passed as the first argument.
  1110. */
  1111. function wrap(obj, method, func) {
  1112. var proceed = obj[method];
  1113. obj[method] = function () {
  1114. var args = Array.prototype.slice.call(arguments),
  1115. outerArgs = arguments,
  1116. ctx = this,
  1117. ret;
  1118. ctx.proceed = function () {
  1119. proceed.apply(ctx, arguments.length ? arguments : outerArgs);
  1120. };
  1121. args.unshift(proceed);
  1122. ret = func.apply(this, args);
  1123. ctx.proceed = null;
  1124. return ret;
  1125. };
  1126. }
  1127. /**
  1128. * Format a string according to a subset of the rules of Python's String.format
  1129. * method.
  1130. *
  1131. * @example
  1132. * var s = Highcharts.format(
  1133. * 'The {color} fox was {len:.2f} feet long',
  1134. * { color: 'red', len: Math.PI }
  1135. * );
  1136. * // => The red fox was 3.14 feet long
  1137. *
  1138. * @function Highcharts.format
  1139. *
  1140. * @param {string} str
  1141. * The string to format.
  1142. *
  1143. * @param {Record<string, *>} ctx
  1144. * The context, a collection of key-value pairs where each key is
  1145. * replaced by its value.
  1146. *
  1147. * @param {Highcharts.Chart} [chart]
  1148. * A `Chart` instance used to get numberFormatter and time.
  1149. *
  1150. * @return {string}
  1151. * The formatted string.
  1152. */
  1153. function format(str, ctx, chart) {
  1154. var splitter = '{',
  1155. isInside = false,
  1156. segment,
  1157. valueAndFormat,
  1158. ret = [],
  1159. val,
  1160. index;
  1161. var floatRegex = /f$/;
  1162. var decRegex = /\.([0-9])/;
  1163. var lang = H.defaultOptions.lang;
  1164. var time = chart && chart.time || H.time;
  1165. var numberFormatter = chart && chart.numberFormatter || numberFormat;
  1166. while (str) {
  1167. index = str.indexOf(splitter);
  1168. if (index === -1) {
  1169. break;
  1170. }
  1171. segment = str.slice(0, index);
  1172. if (isInside) { // we're on the closing bracket looking back
  1173. valueAndFormat = segment.split(':');
  1174. val = getNestedProperty(valueAndFormat.shift() || '', ctx);
  1175. // Format the replacement
  1176. if (valueAndFormat.length && typeof val === 'number') {
  1177. segment = valueAndFormat.join(':');
  1178. if (floatRegex.test(segment)) { // float
  1179. var decimals = parseInt((segment.match(decRegex) || ['', '-1'])[1], 10);
  1180. if (val !== null) {
  1181. val = numberFormatter(val, decimals, lang.decimalPoint, segment.indexOf(',') > -1 ? lang.thousandsSep : '');
  1182. }
  1183. }
  1184. else {
  1185. val = time.dateFormat(segment, val);
  1186. }
  1187. }
  1188. // Push the result and advance the cursor
  1189. ret.push(val);
  1190. }
  1191. else {
  1192. ret.push(segment);
  1193. }
  1194. str = str.slice(index + 1); // the rest
  1195. isInside = !isInside; // toggle
  1196. splitter = isInside ? '}' : '{'; // now look for next matching bracket
  1197. }
  1198. ret.push(str);
  1199. return ret.join('');
  1200. }
  1201. /**
  1202. * Get the magnitude of a number.
  1203. *
  1204. * @function Highcharts.getMagnitude
  1205. *
  1206. * @param {number} num
  1207. * The number.
  1208. *
  1209. * @return {number}
  1210. * The magnitude, where 1-9 are magnitude 1, 10-99 magnitude 2 etc.
  1211. */
  1212. function getMagnitude(num) {
  1213. return Math.pow(10, Math.floor(Math.log(num) / Math.LN10));
  1214. }
  1215. /**
  1216. * Take an interval and normalize it to multiples of round numbers.
  1217. *
  1218. * @deprecated
  1219. * @function Highcharts.normalizeTickInterval
  1220. *
  1221. * @param {number} interval
  1222. * The raw, un-rounded interval.
  1223. *
  1224. * @param {Array<*>} [multiples]
  1225. * Allowed multiples.
  1226. *
  1227. * @param {number} [magnitude]
  1228. * The magnitude of the number.
  1229. *
  1230. * @param {boolean} [allowDecimals]
  1231. * Whether to allow decimals.
  1232. *
  1233. * @param {boolean} [hasTickAmount]
  1234. * If it has tickAmount, avoid landing on tick intervals lower than
  1235. * original.
  1236. *
  1237. * @return {number}
  1238. * The normalized interval.
  1239. *
  1240. * @todo
  1241. * Move this function to the Axis prototype. It is here only for historical
  1242. * reasons.
  1243. */
  1244. function normalizeTickInterval(interval, multiples, magnitude, allowDecimals, hasTickAmount) {
  1245. var normalized,
  1246. i,
  1247. retInterval = interval;
  1248. // round to a tenfold of 1, 2, 2.5 or 5
  1249. magnitude = pick(magnitude, 1);
  1250. normalized = interval / magnitude;
  1251. // multiples for a linear scale
  1252. if (!multiples) {
  1253. multiples = hasTickAmount ?
  1254. // Finer grained ticks when the tick amount is hard set, including
  1255. // when alignTicks is true on multiple axes (#4580).
  1256. [1, 1.2, 1.5, 2, 2.5, 3, 4, 5, 6, 8, 10] :
  1257. // Else, let ticks fall on rounder numbers
  1258. [1, 2, 2.5, 5, 10];
  1259. // the allowDecimals option
  1260. if (allowDecimals === false) {
  1261. if (magnitude === 1) {
  1262. multiples = multiples.filter(function (num) {
  1263. return num % 1 === 0;
  1264. });
  1265. }
  1266. else if (magnitude <= 0.1) {
  1267. multiples = [1 / magnitude];
  1268. }
  1269. }
  1270. }
  1271. // normalize the interval to the nearest multiple
  1272. for (i = 0; i < multiples.length; i++) {
  1273. retInterval = multiples[i];
  1274. // only allow tick amounts smaller than natural
  1275. if ((hasTickAmount &&
  1276. retInterval * magnitude >= interval) ||
  1277. (!hasTickAmount &&
  1278. (normalized <=
  1279. (multiples[i] +
  1280. (multiples[i + 1] || multiples[i])) / 2))) {
  1281. break;
  1282. }
  1283. }
  1284. // Multiply back to the correct magnitude. Correct floats to appropriate
  1285. // precision (#6085).
  1286. retInterval = correctFloat(retInterval * magnitude, -Math.round(Math.log(0.001) / Math.LN10));
  1287. return retInterval;
  1288. }
  1289. /**
  1290. * Sort an object array and keep the order of equal items. The ECMAScript
  1291. * standard does not specify the behaviour when items are equal.
  1292. *
  1293. * @function Highcharts.stableSort
  1294. *
  1295. * @param {Array<*>} arr
  1296. * The array to sort.
  1297. *
  1298. * @param {Function} sortFunction
  1299. * The function to sort it with, like with regular Array.prototype.sort.
  1300. *
  1301. * @return {void}
  1302. */
  1303. function stableSort(arr, sortFunction) {
  1304. // @todo It seems like Chrome since v70 sorts in a stable way internally,
  1305. // plus all other browsers do it, so over time we may be able to remove this
  1306. // function
  1307. var length = arr.length,
  1308. sortValue,
  1309. i;
  1310. // Add index to each item
  1311. for (i = 0; i < length; i++) {
  1312. arr[i].safeI = i; // stable sort index
  1313. }
  1314. arr.sort(function (a, b) {
  1315. sortValue = sortFunction(a, b);
  1316. return sortValue === 0 ? a.safeI - b.safeI : sortValue;
  1317. });
  1318. // Remove index from items
  1319. for (i = 0; i < length; i++) {
  1320. delete arr[i].safeI; // stable sort index
  1321. }
  1322. }
  1323. /**
  1324. * Non-recursive method to find the lowest member of an array. `Math.min` raises
  1325. * a maximum call stack size exceeded error in Chrome when trying to apply more
  1326. * than 150.000 points. This method is slightly slower, but safe.
  1327. *
  1328. * @function Highcharts.arrayMin
  1329. *
  1330. * @param {Array<*>} data
  1331. * An array of numbers.
  1332. *
  1333. * @return {number}
  1334. * The lowest number.
  1335. */
  1336. function arrayMin(data) {
  1337. var i = data.length,
  1338. min = data[0];
  1339. while (i--) {
  1340. if (data[i] < min) {
  1341. min = data[i];
  1342. }
  1343. }
  1344. return min;
  1345. }
  1346. /**
  1347. * Non-recursive method to find the lowest member of an array. `Math.max` raises
  1348. * a maximum call stack size exceeded error in Chrome when trying to apply more
  1349. * than 150.000 points. This method is slightly slower, but safe.
  1350. *
  1351. * @function Highcharts.arrayMax
  1352. *
  1353. * @param {Array<*>} data
  1354. * An array of numbers.
  1355. *
  1356. * @return {number}
  1357. * The highest number.
  1358. */
  1359. function arrayMax(data) {
  1360. var i = data.length,
  1361. max = data[0];
  1362. while (i--) {
  1363. if (data[i] > max) {
  1364. max = data[i];
  1365. }
  1366. }
  1367. return max;
  1368. }
  1369. /**
  1370. * Utility method that destroys any SVGElement instances that are properties on
  1371. * the given object. It loops all properties and invokes destroy if there is a
  1372. * destroy method. The property is then delete.
  1373. *
  1374. * @function Highcharts.destroyObjectProperties
  1375. *
  1376. * @param {*} obj
  1377. * The object to destroy properties on.
  1378. *
  1379. * @param {*} [except]
  1380. * Exception, do not destroy this property, only delete it.
  1381. */
  1382. function destroyObjectProperties(obj, except) {
  1383. objectEach(obj, function (val, n) {
  1384. // If the object is non-null and destroy is defined
  1385. if (val && val !== except && val.destroy) {
  1386. // Invoke the destroy
  1387. val.destroy();
  1388. }
  1389. // Delete the property from the object.
  1390. delete obj[n];
  1391. });
  1392. }
  1393. /**
  1394. * Discard a HTML element by moving it to the bin and delete.
  1395. *
  1396. * @function Highcharts.discardElement
  1397. *
  1398. * @param {Highcharts.HTMLDOMElement} element
  1399. * The HTML node to discard.
  1400. */
  1401. function discardElement(element) {
  1402. // create a garbage bin element, not part of the DOM
  1403. if (!garbageBin) {
  1404. garbageBin = createElement('div');
  1405. }
  1406. // move the node and empty bin
  1407. if (element) {
  1408. garbageBin.appendChild(element);
  1409. }
  1410. garbageBin.innerHTML = '';
  1411. }
  1412. var garbageBin;
  1413. /**
  1414. * Fix JS round off float errors.
  1415. *
  1416. * @function Highcharts.correctFloat
  1417. *
  1418. * @param {number} num
  1419. * A float number to fix.
  1420. *
  1421. * @param {number} [prec=14]
  1422. * The precision.
  1423. *
  1424. * @return {number}
  1425. * The corrected float number.
  1426. */
  1427. function correctFloat(num, prec) {
  1428. return parseFloat(num.toPrecision(prec || 14));
  1429. }
  1430. /**
  1431. * The time unit lookup
  1432. *
  1433. * @ignore
  1434. */
  1435. var timeUnits = {
  1436. millisecond: 1,
  1437. second: 1000,
  1438. minute: 60000,
  1439. hour: 3600000,
  1440. day: 24 * 3600000,
  1441. week: 7 * 24 * 3600000,
  1442. month: 28 * 24 * 3600000,
  1443. year: 364 * 24 * 3600000
  1444. };
  1445. /**
  1446. * Format a number and return a string based on input settings.
  1447. *
  1448. * @sample highcharts/members/highcharts-numberformat/
  1449. * Custom number format
  1450. *
  1451. * @function Highcharts.numberFormat
  1452. *
  1453. * @param {number} number
  1454. * The input number to format.
  1455. *
  1456. * @param {number} decimals
  1457. * The amount of decimals. A value of -1 preserves the amount in the
  1458. * input number.
  1459. *
  1460. * @param {string} [decimalPoint]
  1461. * The decimal point, defaults to the one given in the lang options, or
  1462. * a dot.
  1463. *
  1464. * @param {string} [thousandsSep]
  1465. * The thousands separator, defaults to the one given in the lang
  1466. * options, or a space character.
  1467. *
  1468. * @return {string}
  1469. * The formatted number.
  1470. */
  1471. function numberFormat(number, decimals, decimalPoint, thousandsSep) {
  1472. number = +number || 0;
  1473. decimals = +decimals;
  1474. var lang = H.defaultOptions.lang, origDec = (number.toString().split('.')[1] || '').split('e')[0].length, strinteger, thousands, ret, roundedNumber, exponent = number.toString().split('e'), fractionDigits, firstDecimals = decimals;
  1475. if (decimals === -1) {
  1476. // Preserve decimals. Not huge numbers (#3793).
  1477. decimals = Math.min(origDec, 20);
  1478. }
  1479. else if (!isNumber(decimals)) {
  1480. decimals = 2;
  1481. }
  1482. else if (decimals && exponent[1] && exponent[1] < 0) {
  1483. // Expose decimals from exponential notation (#7042)
  1484. fractionDigits = decimals + +exponent[1];
  1485. if (fractionDigits >= 0) {
  1486. // remove too small part of the number while keeping the notation
  1487. exponent[0] = (+exponent[0]).toExponential(fractionDigits)
  1488. .split('e')[0];
  1489. decimals = fractionDigits;
  1490. }
  1491. else {
  1492. // fractionDigits < 0
  1493. exponent[0] = exponent[0].split('.')[0] || 0;
  1494. if (decimals < 20) {
  1495. // use number instead of exponential notation (#7405)
  1496. number = (exponent[0] * Math.pow(10, exponent[1]))
  1497. .toFixed(decimals);
  1498. }
  1499. else {
  1500. // or zero
  1501. number = 0;
  1502. }
  1503. exponent[1] = 0;
  1504. }
  1505. }
  1506. // Add another decimal to avoid rounding errors of float numbers. (#4573)
  1507. // Then use toFixed to handle rounding.
  1508. roundedNumber = (Math.abs(exponent[1] ? exponent[0] : number) +
  1509. Math.pow(10, -Math.max(decimals, origDec) - 1)).toFixed(decimals);
  1510. // A string containing the positive integer component of the number
  1511. strinteger = String(pInt(roundedNumber));
  1512. // Leftover after grouping into thousands. Can be 0, 1 or 2.
  1513. thousands = strinteger.length > 3 ? strinteger.length % 3 : 0;
  1514. // Language
  1515. decimalPoint = pick(decimalPoint, lang.decimalPoint);
  1516. thousandsSep = pick(thousandsSep, lang.thousandsSep);
  1517. // Start building the return
  1518. ret = number < 0 ? '-' : '';
  1519. // Add the leftover after grouping into thousands. For example, in the
  1520. // number 42 000 000, this line adds 42.
  1521. ret += thousands ? strinteger.substr(0, thousands) + thousandsSep : '';
  1522. if (+exponent[1] < 0 && !firstDecimals) {
  1523. ret = '0';
  1524. }
  1525. else {
  1526. // Add the remaining thousands groups, joined by the thousands separator
  1527. ret += strinteger
  1528. .substr(thousands)
  1529. .replace(/(\d{3})(?=\d)/g, '$1' + thousandsSep);
  1530. }
  1531. // Add the decimal point and the decimal component
  1532. if (decimals) {
  1533. // Get the decimal component
  1534. ret += decimalPoint + roundedNumber.slice(-decimals);
  1535. }
  1536. if (exponent[1] && +ret !== 0) {
  1537. ret += 'e' + exponent[1];
  1538. }
  1539. return ret;
  1540. }
  1541. /**
  1542. * Easing definition
  1543. *
  1544. * @private
  1545. * @function Math.easeInOutSine
  1546. *
  1547. * @param {number} pos
  1548. * Current position, ranging from 0 to 1.
  1549. *
  1550. * @return {number}
  1551. * Ease result
  1552. */
  1553. Math.easeInOutSine = function (pos) {
  1554. return -0.5 * (Math.cos(Math.PI * pos) - 1);
  1555. };
  1556. /**
  1557. * Returns the value of a property path on a given object.
  1558. *
  1559. * @private
  1560. * @function getNestedProperty
  1561. *
  1562. * @param {string} path
  1563. * Path to the property, for example `custom.myValue`.
  1564. *
  1565. * @param {unknown} obj
  1566. * Instance containing the property on the specific path.
  1567. *
  1568. * @return {unknown}
  1569. * The unknown property value.
  1570. */
  1571. function getNestedProperty(path, obj) {
  1572. if (!path) {
  1573. return obj;
  1574. }
  1575. var pathElements = path.split('.').reverse();
  1576. var subProperty = obj;
  1577. if (pathElements.length === 1) {
  1578. return subProperty[path];
  1579. }
  1580. var pathElement = pathElements.pop();
  1581. while (typeof pathElement !== 'undefined' &&
  1582. typeof subProperty !== 'undefined' &&
  1583. subProperty !== null) {
  1584. subProperty = subProperty[pathElement];
  1585. pathElement = pathElements.pop();
  1586. }
  1587. return subProperty;
  1588. }
  1589. /**
  1590. * Get the computed CSS value for given element and property, only for numerical
  1591. * properties. For width and height, the dimension of the inner box (excluding
  1592. * padding) is returned. Used for fitting the chart within the container.
  1593. *
  1594. * @function Highcharts.getStyle
  1595. *
  1596. * @param {Highcharts.HTMLDOMElement} el
  1597. * An HTML element.
  1598. *
  1599. * @param {string} prop
  1600. * The property name.
  1601. *
  1602. * @param {boolean} [toInt=true]
  1603. * Parse to integer.
  1604. *
  1605. * @return {number|string}
  1606. * The numeric value.
  1607. */
  1608. function getStyle(el, prop, toInt) {
  1609. var style;
  1610. // For width and height, return the actual inner pixel size (#4913)
  1611. if (prop === 'width') {
  1612. var offsetWidth = Math.min(el.offsetWidth,
  1613. el.scrollWidth);
  1614. // In flex boxes, we need to use getBoundingClientRect and floor it,
  1615. // because scrollWidth doesn't support subpixel precision (#6427) ...
  1616. var boundingClientRectWidth = el.getBoundingClientRect &&
  1617. el.getBoundingClientRect().width;
  1618. // ...unless if the containing div or its parents are transform-scaled
  1619. // down, in which case the boundingClientRect can't be used as it is
  1620. // also scaled down (#9871, #10498).
  1621. if (boundingClientRectWidth < offsetWidth &&
  1622. boundingClientRectWidth >= offsetWidth - 1) {
  1623. offsetWidth = Math.floor(boundingClientRectWidth);
  1624. }
  1625. return Math.max(0, // #8377
  1626. (offsetWidth -
  1627. H.getStyle(el, 'padding-left') -
  1628. H.getStyle(el, 'padding-right')));
  1629. }
  1630. if (prop === 'height') {
  1631. return Math.max(0, // #8377
  1632. Math.min(el.offsetHeight, el.scrollHeight) -
  1633. H.getStyle(el, 'padding-top') -
  1634. H.getStyle(el, 'padding-bottom'));
  1635. }
  1636. if (!win.getComputedStyle) {
  1637. // SVG not supported, forgot to load oldie.js?
  1638. error(27, true);
  1639. }
  1640. // Otherwise, get the computed style
  1641. style = win.getComputedStyle(el, undefined); // eslint-disable-line no-undefined
  1642. if (style) {
  1643. style = style.getPropertyValue(prop);
  1644. if (pick(toInt, prop !== 'opacity')) {
  1645. style = pInt(style);
  1646. }
  1647. }
  1648. return style;
  1649. }
  1650. /**
  1651. * Search for an item in an array.
  1652. *
  1653. * @function Highcharts.inArray
  1654. *
  1655. * @deprecated
  1656. *
  1657. * @param {*} item
  1658. * The item to search for.
  1659. *
  1660. * @param {Array<*>} arr
  1661. * The array or node collection to search in.
  1662. *
  1663. * @param {number} [fromIndex=0]
  1664. * The index to start searching from.
  1665. *
  1666. * @return {number}
  1667. * The index within the array, or -1 if not found.
  1668. */
  1669. function inArray(item, arr, fromIndex) {
  1670. error(32, false, void 0, { 'Highcharts.inArray': 'use Array.indexOf' });
  1671. return arr.indexOf(item, fromIndex);
  1672. }
  1673. /* eslint-disable valid-jsdoc */
  1674. /**
  1675. * Return the value of the first element in the array that satisfies the
  1676. * provided testing function.
  1677. *
  1678. * @function Highcharts.find<T>
  1679. *
  1680. * @param {Array<T>} arr
  1681. * The array to test.
  1682. *
  1683. * @param {Function} callback
  1684. * The callback function. The function receives the item as the first
  1685. * argument. Return `true` if this item satisfies the condition.
  1686. *
  1687. * @return {T|undefined}
  1688. * The value of the element.
  1689. */
  1690. var find = Array.prototype.find ?
  1691. /* eslint-enable valid-jsdoc */
  1692. function (arr,
  1693. callback) {
  1694. return arr.find(callback);
  1695. } :
  1696. // Legacy implementation. PhantomJS, IE <= 11 etc. #7223.
  1697. function (arr, callback) {
  1698. var i,
  1699. length = arr.length;
  1700. for (i = 0; i < length; i++) {
  1701. if (callback(arr[i], i)) { // eslint-disable-line callback-return
  1702. return arr[i];
  1703. }
  1704. }
  1705. };
  1706. /**
  1707. * Returns an array of a given object's own properties.
  1708. *
  1709. * @function Highcharts.keys
  1710. * @deprecated
  1711. *
  1712. * @param {*} obj
  1713. * The object of which the properties are to be returned.
  1714. *
  1715. * @return {Array<string>}
  1716. * An array of strings that represents all the properties.
  1717. */
  1718. function keys(obj) {
  1719. error(32, false, void 0, { 'Highcharts.keys': 'use Object.keys' });
  1720. return Object.keys(obj);
  1721. }
  1722. /**
  1723. * Get the element's offset position, corrected for `overflow: auto`.
  1724. *
  1725. * @function Highcharts.offset
  1726. *
  1727. * @param {global.Element} el
  1728. * The DOM element.
  1729. *
  1730. * @return {Highcharts.OffsetObject}
  1731. * An object containing `left` and `top` properties for the position in
  1732. * the page.
  1733. */
  1734. function offset(el) {
  1735. var docElem = doc.documentElement,
  1736. box = (el.parentElement || el.parentNode) ?
  1737. el.getBoundingClientRect() :
  1738. { top: 0,
  1739. left: 0,
  1740. width: 0,
  1741. height: 0 };
  1742. return {
  1743. top: box.top + (win.pageYOffset || docElem.scrollTop) -
  1744. (docElem.clientTop || 0),
  1745. left: box.left + (win.pageXOffset || docElem.scrollLeft) -
  1746. (docElem.clientLeft || 0),
  1747. width: box.width,
  1748. height: box.height
  1749. };
  1750. }
  1751. /* eslint-disable valid-jsdoc */
  1752. /**
  1753. * Iterate over object key pairs in an object.
  1754. *
  1755. * @function Highcharts.objectEach<T>
  1756. *
  1757. * @param {*} obj
  1758. * The object to iterate over.
  1759. *
  1760. * @param {Highcharts.ObjectEachCallbackFunction<T>} fn
  1761. * The iterator callback. It passes three arguments:
  1762. * * value - The property value.
  1763. * * key - The property key.
  1764. * * obj - The object that objectEach is being applied to.
  1765. *
  1766. * @param {T} [ctx]
  1767. * The context.
  1768. *
  1769. * @return {void}
  1770. */
  1771. function objectEach(obj, fn, ctx) {
  1772. /* eslint-enable valid-jsdoc */
  1773. for (var key in obj) {
  1774. if (Object.hasOwnProperty.call(obj, key)) {
  1775. fn.call(ctx || obj[key], obj[key], key, obj);
  1776. }
  1777. }
  1778. }
  1779. /**
  1780. * Iterate over an array.
  1781. *
  1782. * @deprecated
  1783. * @function Highcharts.each
  1784. *
  1785. * @param {Array<*>} arr
  1786. * The array to iterate over.
  1787. *
  1788. * @param {Function} fn
  1789. * The iterator callback. It passes three arguments:
  1790. * - `item`: The array item.
  1791. * - `index`: The item's index in the array.
  1792. * - `arr`: The array that each is being applied to.
  1793. *
  1794. * @param {*} [ctx]
  1795. * The context.
  1796. *
  1797. * @return {void}
  1798. */
  1799. /**
  1800. * Filter an array by a callback.
  1801. *
  1802. * @deprecated
  1803. * @function Highcharts.grep
  1804. *
  1805. * @param {Array<*>} arr
  1806. * The array to filter.
  1807. *
  1808. * @param {Function} callback
  1809. * The callback function. The function receives the item as the first
  1810. * argument. Return `true` if the item is to be preserved.
  1811. *
  1812. * @return {Array<*>}
  1813. * A new, filtered array.
  1814. */
  1815. /**
  1816. * Map an array by a callback.
  1817. *
  1818. * @deprecated
  1819. * @function Highcharts.map
  1820. *
  1821. * @param {Array<*>} arr
  1822. * The array to map.
  1823. *
  1824. * @param {Function} fn
  1825. * The callback function. Return the new value for the new array.
  1826. *
  1827. * @return {Array<*>}
  1828. * A new array item with modified items.
  1829. */
  1830. /**
  1831. * Reduce an array to a single value.
  1832. *
  1833. * @deprecated
  1834. * @function Highcharts.reduce
  1835. *
  1836. * @param {Array<*>} arr
  1837. * The array to reduce.
  1838. *
  1839. * @param {Function} fn
  1840. * The callback function. Return the reduced value. Receives 4
  1841. * arguments: Accumulated/reduced value, current value, current array
  1842. * index, and the array.
  1843. *
  1844. * @param {*} initialValue
  1845. * The initial value of the accumulator.
  1846. *
  1847. * @return {*}
  1848. * The reduced value.
  1849. */
  1850. /**
  1851. * Test whether at least one element in the array passes the test implemented by
  1852. * the provided function.
  1853. *
  1854. * @deprecated
  1855. * @function Highcharts.some
  1856. *
  1857. * @param {Array<*>} arr
  1858. * The array to test
  1859. *
  1860. * @param {Function} fn
  1861. * The function to run on each item. Return truty to pass the test.
  1862. * Receives arguments `currentValue`, `index` and `array`.
  1863. *
  1864. * @param {*} ctx
  1865. * The context.
  1866. *
  1867. * @return {boolean}
  1868. */
  1869. objectEach({
  1870. map: 'map',
  1871. each: 'forEach',
  1872. grep: 'filter',
  1873. reduce: 'reduce',
  1874. some: 'some'
  1875. }, function (val, key) {
  1876. H[key] = function (arr) {
  1877. var _a;
  1878. error(32, false, void 0, (_a = {}, _a["Highcharts." + key] = "use Array." + val, _a));
  1879. return Array.prototype[val].apply(arr, [].slice.call(arguments, 1));
  1880. };
  1881. });
  1882. /* eslint-disable valid-jsdoc */
  1883. /**
  1884. * Add an event listener.
  1885. *
  1886. * @function Highcharts.addEvent<T>
  1887. *
  1888. * @param {Highcharts.Class<T>|T} el
  1889. * The element or object to add a listener to. It can be a
  1890. * {@link HTMLDOMElement}, an {@link SVGElement} or any other object.
  1891. *
  1892. * @param {string} type
  1893. * The event type.
  1894. *
  1895. * @param {Highcharts.EventCallbackFunction<T>|Function} fn
  1896. * The function callback to execute when the event is fired.
  1897. *
  1898. * @param {Highcharts.EventOptionsObject} [options]
  1899. * Options for adding the event.
  1900. *
  1901. * @return {Function}
  1902. * A callback function to remove the added event.
  1903. */
  1904. function addEvent(el, type, fn, options) {
  1905. /* eslint-enable valid-jsdoc */
  1906. if (options === void 0) { options = {}; }
  1907. // Add hcEvents to either the prototype (in case we're running addEvent on a
  1908. // class) or the instance. If hasOwnProperty('hcEvents') is false, it is
  1909. // inherited down the prototype chain, in which case we need to set the
  1910. // property on this instance (which may itself be a prototype).
  1911. var owner = typeof el === 'function' && el.prototype || el;
  1912. if (!Object.hasOwnProperty.call(owner, 'hcEvents')) {
  1913. owner.hcEvents = {};
  1914. }
  1915. var events = owner.hcEvents;
  1916. // Allow click events added to points, otherwise they will be prevented by
  1917. // the TouchPointer.pinch function after a pinch zoom operation (#7091).
  1918. if (H.Point && // without H a dependency loop occurs
  1919. el instanceof H.Point &&
  1920. el.series &&
  1921. el.series.chart) {
  1922. el.series.chart.runTrackerClick = true;
  1923. }
  1924. // Handle DOM events
  1925. // If the browser supports passive events, add it to improve performance
  1926. // on touch events (#11353).
  1927. var addEventListener = (el.addEventListener || H.addEventListenerPolyfill);
  1928. if (addEventListener) {
  1929. addEventListener.call(el, type, fn, H.supportsPassiveEvents ? {
  1930. passive: options.passive === void 0 ?
  1931. type.indexOf('touch') !== -1 : options.passive,
  1932. capture: false
  1933. } : false);
  1934. }
  1935. if (!events[type]) {
  1936. events[type] = [];
  1937. }
  1938. var eventObject = {
  1939. fn: fn,
  1940. order: typeof options.order === 'number' ? options.order : Infinity
  1941. };
  1942. events[type].push(eventObject);
  1943. // Order the calls
  1944. events[type].sort(function (a, b) { return a.order - b.order; });
  1945. // Return a function that can be called to remove this event.
  1946. return function () {
  1947. removeEvent(el, type, fn);
  1948. };
  1949. }
  1950. /* eslint-disable valid-jsdoc */
  1951. /**
  1952. * Remove an event that was added with {@link Highcharts#addEvent}.
  1953. *
  1954. * @function Highcharts.removeEvent<T>
  1955. *
  1956. * @param {Highcharts.Class<T>|T} el
  1957. * The element to remove events on.
  1958. *
  1959. * @param {string} [type]
  1960. * The type of events to remove. If undefined, all events are removed
  1961. * from the element.
  1962. *
  1963. * @param {Highcharts.EventCallbackFunction<T>} [fn]
  1964. * The specific callback to remove. If undefined, all events that match
  1965. * the element and optionally the type are removed.
  1966. *
  1967. * @return {void}
  1968. */
  1969. function removeEvent(el, type, fn) {
  1970. /* eslint-enable valid-jsdoc */
  1971. /**
  1972. * @private
  1973. * @param {string} type - event type
  1974. * @param {Highcharts.EventCallbackFunction<T>} fn - callback
  1975. * @return {void}
  1976. */
  1977. function removeOneEvent(type, fn) {
  1978. var removeEventListener = (el.removeEventListener || H.removeEventListenerPolyfill);
  1979. if (removeEventListener) {
  1980. removeEventListener.call(el, type, fn, false);
  1981. }
  1982. }
  1983. /**
  1984. * @private
  1985. * @param {any} eventCollection - collection
  1986. * @return {void}
  1987. */
  1988. function removeAllEvents(eventCollection) {
  1989. var types,
  1990. len;
  1991. if (!el.nodeName) {
  1992. return; // break on non-DOM events
  1993. }
  1994. if (type) {
  1995. types = {};
  1996. types[type] = true;
  1997. }
  1998. else {
  1999. types = eventCollection;
  2000. }
  2001. objectEach(types, function (_val, n) {
  2002. if (eventCollection[n]) {
  2003. len = eventCollection[n].length;
  2004. while (len--) {
  2005. removeOneEvent(n, eventCollection[n][len].fn);
  2006. }
  2007. }
  2008. });
  2009. }
  2010. var owner = typeof el === 'function' && el.prototype || el;
  2011. if (Object.hasOwnProperty.call(owner, 'hcEvents')) {
  2012. var events = owner.hcEvents;
  2013. if (type) {
  2014. var typeEvents = (events[type] || []);
  2015. if (fn) {
  2016. events[type] = typeEvents.filter(function (obj) {
  2017. return fn !== obj.fn;
  2018. });
  2019. removeOneEvent(type, fn);
  2020. }
  2021. else {
  2022. removeAllEvents(events);
  2023. events[type] = [];
  2024. }
  2025. }
  2026. else {
  2027. removeAllEvents(events);
  2028. delete owner.hcEvents;
  2029. }
  2030. }
  2031. }
  2032. /* eslint-disable valid-jsdoc */
  2033. /**
  2034. * Fire an event that was registered with {@link Highcharts#addEvent}.
  2035. *
  2036. * @function Highcharts.fireEvent<T>
  2037. *
  2038. * @param {T} el
  2039. * The object to fire the event on. It can be a {@link HTMLDOMElement},
  2040. * an {@link SVGElement} or any other object.
  2041. *
  2042. * @param {string} type
  2043. * The type of event.
  2044. *
  2045. * @param {Highcharts.Dictionary<*>|Event} [eventArguments]
  2046. * Custom event arguments that are passed on as an argument to the event
  2047. * handler.
  2048. *
  2049. * @param {Highcharts.EventCallbackFunction<T>|Function} [defaultFunction]
  2050. * The default function to execute if the other listeners haven't
  2051. * returned false.
  2052. *
  2053. * @return {void}
  2054. */
  2055. function fireEvent(el, type, eventArguments, defaultFunction) {
  2056. /* eslint-enable valid-jsdoc */
  2057. var e,
  2058. i;
  2059. eventArguments = eventArguments || {};
  2060. if (doc.createEvent &&
  2061. (el.dispatchEvent || el.fireEvent)) {
  2062. e = doc.createEvent('Events');
  2063. e.initEvent(type, true, true);
  2064. extend(e, eventArguments);
  2065. if (el.dispatchEvent) {
  2066. el.dispatchEvent(e);
  2067. }
  2068. else {
  2069. el.fireEvent(type, e);
  2070. }
  2071. }
  2072. else if (el.hcEvents) {
  2073. if (!eventArguments.target) {
  2074. // We're running a custom event
  2075. extend(eventArguments, {
  2076. // Attach a simple preventDefault function to skip
  2077. // default handler if called. The built-in
  2078. // defaultPrevented property is not overwritable (#5112)
  2079. preventDefault: function () {
  2080. eventArguments.defaultPrevented = true;
  2081. },
  2082. // Setting target to native events fails with clicking
  2083. // the zoom-out button in Chrome.
  2084. target: el,
  2085. // If the type is not set, we're running a custom event
  2086. // (#2297). If it is set, we're running a browser event,
  2087. // and setting it will cause en error in IE8 (#2465).
  2088. type: type
  2089. });
  2090. }
  2091. var events = [];
  2092. var object = el;
  2093. var multilevel = false;
  2094. // Recurse up the inheritance chain and collect hcEvents set as own
  2095. // objects on the prototypes.
  2096. while (object.hcEvents) {
  2097. if (Object.hasOwnProperty.call(object, 'hcEvents') &&
  2098. object.hcEvents[type]) {
  2099. if (events.length) {
  2100. multilevel = true;
  2101. }
  2102. events.unshift.apply(events, object.hcEvents[type]);
  2103. }
  2104. object = Object.getPrototypeOf(object);
  2105. }
  2106. // For performance reasons, only sort the event handlers in case we are
  2107. // dealing with multiple levels in the prototype chain. Otherwise, the
  2108. // events are already sorted in the addEvent function.
  2109. if (multilevel) {
  2110. // Order the calls
  2111. events.sort(function (a, b) { return a.order - b.order; });
  2112. }
  2113. // Call the collected event handlers
  2114. events.forEach(function (obj) {
  2115. // If the event handler returns false, prevent the default handler
  2116. // from executing
  2117. if (obj.fn.call(el, eventArguments) === false) {
  2118. eventArguments.preventDefault();
  2119. }
  2120. });
  2121. }
  2122. // Run the default if not prevented
  2123. if (defaultFunction && !eventArguments.defaultPrevented) {
  2124. defaultFunction.call(el, eventArguments);
  2125. }
  2126. }
  2127. var serialMode;
  2128. /**
  2129. * Get a unique key for using in internal element id's and pointers. The key is
  2130. * composed of a random hash specific to this Highcharts instance, and a
  2131. * counter.
  2132. *
  2133. * @example
  2134. * var id = uniqueKey(); // => 'highcharts-x45f6hp-0'
  2135. *
  2136. * @function Highcharts.uniqueKey
  2137. *
  2138. * @return {string}
  2139. * A unique key.
  2140. */
  2141. var uniqueKey = (function () {
  2142. var hash = Math.random().toString(36).substring(2, 9) + '-';
  2143. var id = 0;
  2144. return function () {
  2145. return 'highcharts-' + (serialMode ? '' : hash) + id++;
  2146. };
  2147. }());
  2148. /**
  2149. * Activates a serial mode for element IDs provided by
  2150. * {@link Highcharts.uniqueKey}. This mode can be used in automated tests, where
  2151. * a simple comparison of two rendered SVG graphics is needed.
  2152. *
  2153. * **Note:** This is only for testing purposes and will break functionality in
  2154. * webpages with multiple charts.
  2155. *
  2156. * @example
  2157. * if (
  2158. * process &&
  2159. * process.env.NODE_ENV === 'development'
  2160. * ) {
  2161. * Highcharts.useSerialIds(true);
  2162. * }
  2163. *
  2164. * @function Highcharts.useSerialIds
  2165. *
  2166. * @param {boolean} [mode]
  2167. * Changes the state of serial mode.
  2168. *
  2169. * @return {boolean|undefined}
  2170. * State of the serial mode.
  2171. */
  2172. function useSerialIds(mode) {
  2173. return (serialMode = pick(mode, serialMode));
  2174. }
  2175. function isFunction(obj) {
  2176. return typeof obj === 'function';
  2177. }
  2178. /**
  2179. * Get the updated default options. Until 3.0.7, merely exposing defaultOptions
  2180. * for outside modules wasn't enough because the setOptions method created a new
  2181. * object.
  2182. *
  2183. * @function Highcharts.getOptions
  2184. *
  2185. * @return {Highcharts.Options}
  2186. */
  2187. var getOptions = H.getOptions = function () {
  2188. return H.defaultOptions;
  2189. };
  2190. /**
  2191. * Merge the default options with custom options and return the new options
  2192. * structure. Commonly used for defining reusable templates.
  2193. *
  2194. * @sample highcharts/global/useutc-false Setting a global option
  2195. * @sample highcharts/members/setoptions Applying a global theme
  2196. *
  2197. * @function Highcharts.setOptions
  2198. *
  2199. * @param {Highcharts.Options} options
  2200. * The new custom chart options.
  2201. *
  2202. * @return {Highcharts.Options}
  2203. * Updated options.
  2204. */
  2205. var setOptions = H.setOptions = function (options) {
  2206. // Copy in the default options
  2207. H.defaultOptions = merge(true,
  2208. H.defaultOptions,
  2209. options);
  2210. // Update the time object
  2211. if (options.time || options.global) {
  2212. H.time.update(merge(H.defaultOptions.global, H.defaultOptions.time, options.global, options.time));
  2213. }
  2214. return H.defaultOptions;
  2215. };
  2216. // Register Highcharts as a plugin in jQuery
  2217. if (win.jQuery) {
  2218. /**
  2219. * Highcharts-extended JQuery.
  2220. *
  2221. * @external JQuery
  2222. */
  2223. /**
  2224. * Helper function to return the chart of the current JQuery selector
  2225. * element.
  2226. *
  2227. * @function external:JQuery#highcharts
  2228. *
  2229. * @return {Highcharts.Chart}
  2230. * The chart that is linked to the JQuery selector element.
  2231. */ /**
  2232. * Factory function to create a chart in the current JQuery selector
  2233. * element.
  2234. *
  2235. * @function external:JQuery#highcharts
  2236. *
  2237. * @param {'Chart'|'Map'|'StockChart'|string} [className]
  2238. * Name of the factory class in the Highcharts namespace.
  2239. *
  2240. * @param {Highcharts.Options} [options]
  2241. * The chart options structure.
  2242. *
  2243. * @param {Highcharts.ChartCallbackFunction} [callback]
  2244. * Function to run when the chart has loaded and and all external
  2245. * images are loaded. Defining a
  2246. * [chart.events.load](https://api.highcharts.com/highcharts/chart.events.load)
  2247. * handler is equivalent.
  2248. *
  2249. * @return {JQuery}
  2250. * The current JQuery selector.
  2251. */
  2252. win.jQuery.fn.highcharts = function () {
  2253. var args = [].slice.call(arguments);
  2254. if (this[0]) { // this[0] is the renderTo div
  2255. // Create the chart
  2256. if (args[0]) {
  2257. new H[ // eslint-disable-line computed-property-spacing, no-new
  2258. // Constructor defaults to Chart
  2259. isString(args[0]) ? args.shift() : 'Chart'](this[0], args[0], args[1]);
  2260. return this;
  2261. }
  2262. // When called without parameters or with the return argument,
  2263. // return an existing chart
  2264. return charts[attr(this[0], 'data-highcharts-chart')];
  2265. }
  2266. };
  2267. }
  2268. // TODO use named exports when supported.
  2269. var utilitiesModule = {
  2270. addEvent: addEvent,
  2271. arrayMax: arrayMax,
  2272. arrayMin: arrayMin,
  2273. attr: attr,
  2274. clamp: clamp,
  2275. cleanRecursively: cleanRecursively,
  2276. clearTimeout: internalClearTimeout,
  2277. correctFloat: correctFloat,
  2278. createElement: createElement,
  2279. css: css,
  2280. defined: defined,
  2281. destroyObjectProperties: destroyObjectProperties,
  2282. discardElement: discardElement,
  2283. erase: erase,
  2284. error: error,
  2285. extend: extend,
  2286. extendClass: extendClass,
  2287. find: find,
  2288. fireEvent: fireEvent,
  2289. format: format,
  2290. getMagnitude: getMagnitude,
  2291. getNestedProperty: getNestedProperty,
  2292. getOptions: getOptions,
  2293. getStyle: getStyle,
  2294. inArray: inArray,
  2295. isArray: isArray,
  2296. isClass: isClass,
  2297. isDOMElement: isDOMElement,
  2298. isFunction: isFunction,
  2299. isNumber: isNumber,
  2300. isObject: isObject,
  2301. isString: isString,
  2302. keys: keys,
  2303. merge: merge,
  2304. normalizeTickInterval: normalizeTickInterval,
  2305. numberFormat: numberFormat,
  2306. objectEach: objectEach,
  2307. offset: offset,
  2308. pad: pad,
  2309. pick: pick,
  2310. pInt: pInt,
  2311. relativeLength: relativeLength,
  2312. removeEvent: removeEvent,
  2313. setOptions: setOptions,
  2314. splat: splat,
  2315. stableSort: stableSort,
  2316. syncTimeout: syncTimeout,
  2317. timeUnits: timeUnits,
  2318. uniqueKey: uniqueKey,
  2319. useSerialIds: useSerialIds,
  2320. wrap: wrap
  2321. };
  2322. return utilitiesModule;
  2323. });
  2324. _registerModule(_modules, 'Core/Renderer/HTML/AST.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
  2325. /* *
  2326. *
  2327. * (c) 2010-2020 Torstein Honsi
  2328. *
  2329. * License: www.highcharts.com/license
  2330. *
  2331. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  2332. *
  2333. * */
  2334. var SVG_NS = H.SVG_NS;
  2335. var attr = U.attr,
  2336. createElement = U.createElement,
  2337. discardElement = U.discardElement,
  2338. error = U.error,
  2339. isString = U.isString,
  2340. objectEach = U.objectEach,
  2341. splat = U.splat;
  2342. /**
  2343. * Serialized form of an SVG/HTML definition, including children.
  2344. *
  2345. * @interface Highcharts.ASTNode
  2346. */ /**
  2347. * @name Highcharts.ASTNode#attributes
  2348. * @type {Highcharts.SVGAttributes|undefined}
  2349. */ /**
  2350. * @name Highcharts.ASTNode#children
  2351. * @type {Array<Highcharts.ASTNode>|undefined}
  2352. */ /**
  2353. * @name Highcharts.ASTNode#tagName
  2354. * @type {string|undefined}
  2355. */ /**
  2356. * @name Highcharts.ASTNode#textContent
  2357. * @type {string|undefined}
  2358. */
  2359. ''; // detach doclets above
  2360. // In IE8, DOMParser is undefined. IE9 and PhantomJS are only able to parse XML.
  2361. var hasValidDOMParser = false;
  2362. try {
  2363. hasValidDOMParser = Boolean(new DOMParser().parseFromString('', 'text/html'));
  2364. }
  2365. catch (e) { } // eslint-disable-line no-empty
  2366. /**
  2367. * The AST class represents an abstract syntax tree of HTML or SVG content. It
  2368. * can take HTML as an argument, parse it, optionally transform it to SVG, then
  2369. * perform sanitation before inserting it into the DOM.
  2370. *
  2371. * @class
  2372. * @name Highcharts.AST
  2373. * @param {string|Highcharts.ASTNode[]} source
  2374. * Either an HTML string or an ASTNode list
  2375. * to populate the tree
  2376. */
  2377. var AST = /** @class */ (function () {
  2378. // Construct an AST from HTML markup, or wrap an array of existing AST nodes
  2379. function AST(source) {
  2380. this.nodes = typeof source === 'string' ?
  2381. this.parseMarkup(source) : source;
  2382. }
  2383. /**
  2384. * Filter an object of SVG or HTML attributes against the allow list.
  2385. *
  2386. * @static
  2387. *
  2388. * @function Highcharts.AST#filterUserAttributes
  2389. *
  2390. * @param {Highcharts.SVGAttributes} attributes The attributes to filter
  2391. *
  2392. * @return {Highcharts.SVGAttributes}
  2393. * The filtered attributes
  2394. */
  2395. AST.filterUserAttributes = function (attributes) {
  2396. objectEach(attributes, function (val, key) {
  2397. var valid = true;
  2398. if (AST.allowedAttributes.indexOf(key) === -1) {
  2399. valid = false;
  2400. }
  2401. if (['background', 'dynsrc', 'href', 'lowsrc', 'src']
  2402. .indexOf(key) !== -1) {
  2403. valid = isString(val) && AST.allowedReferences.some(function (ref) { return val.indexOf(ref) === 0; });
  2404. }
  2405. if (!valid) {
  2406. error("Highcharts warning: Invalid attribute '" + key + "' in config");
  2407. delete attributes[key];
  2408. }
  2409. });
  2410. return attributes;
  2411. };
  2412. /**
  2413. * Utility function to set html content for an element by passing in a
  2414. * markup string. The markup is safely parsed by the AST class to avoid
  2415. * XSS vulnerabilities. This function should be used instead of setting
  2416. * `innerHTML` in all cases where the content is not fully trusted.
  2417. *
  2418. * @static
  2419. *
  2420. * @function Highcharts.AST#setElementHTML
  2421. *
  2422. * @param {SVGDOMElement|HTMLDOMElement} el The node to set content of
  2423. * @param {string} html The markup string
  2424. */
  2425. AST.setElementHTML = function (el, html) {
  2426. el.innerHTML = ''; // Clear previous
  2427. if (html) {
  2428. var ast = new AST(html);
  2429. ast.addToDOM(el);
  2430. }
  2431. };
  2432. /**
  2433. * Add the tree defined as a hierarchical JS structure to the DOM
  2434. *
  2435. * @function Highcharts.AST#addToDOM
  2436. *
  2437. * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} parent
  2438. * The node where it should be added
  2439. *
  2440. * @return {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement}
  2441. * The inserted node.
  2442. */
  2443. AST.prototype.addToDOM = function (parent) {
  2444. /**
  2445. * @private
  2446. * @param {Highcharts.ASTNode} subtree - HTML/SVG definition
  2447. * @param {Element} [subParent] - parent node
  2448. * @return {Highcharts.SVGDOMElement|Highcharts.HTMLDOMElement} The inserted node.
  2449. */
  2450. function recurse(subtree, subParent) {
  2451. var ret;
  2452. splat(subtree).forEach(function (item) {
  2453. var tagName = item.tagName;
  2454. var textNode = item.textContent ?
  2455. H.doc.createTextNode(item.textContent) :
  2456. void 0;
  2457. var node;
  2458. if (tagName) {
  2459. if (tagName === '#text') {
  2460. node = textNode;
  2461. }
  2462. else if (AST.allowedTags.indexOf(tagName) !== -1) {
  2463. var NS = tagName === 'svg' ?
  2464. SVG_NS :
  2465. (subParent.namespaceURI || SVG_NS);
  2466. var element = H.doc.createElementNS(NS,
  2467. tagName);
  2468. var attributes_1 = item.attributes || {};
  2469. // Apply attributes from root of AST node, legacy from
  2470. // from before TextBuilder
  2471. objectEach(item, function (val, key) {
  2472. if (key !== 'tagName' &&
  2473. key !== 'attributes' &&
  2474. key !== 'children' &&
  2475. key !== 'textContent') {
  2476. attributes_1[key] = val;
  2477. }
  2478. });
  2479. attr(element, AST.filterUserAttributes(attributes_1));
  2480. // Add text content
  2481. if (textNode) {
  2482. element.appendChild(textNode);
  2483. }
  2484. // Recurse
  2485. recurse(item.children || [], element);
  2486. node = element;
  2487. }
  2488. else {
  2489. error("Highcharts warning: Invalid tagName '" + tagName + "' in config");
  2490. }
  2491. }
  2492. // Add to the tree
  2493. if (node) {
  2494. subParent.appendChild(node);
  2495. }
  2496. ret = node;
  2497. });
  2498. // Return last node added (on top level it's the only one)
  2499. return ret;
  2500. }
  2501. return recurse(this.nodes, parent);
  2502. };
  2503. /**
  2504. * Parse HTML/SVG markup into AST Node objects. Used internally from the
  2505. * constructor.
  2506. *
  2507. * @private
  2508. *
  2509. * @function Highcharts.AST#getNodesFromMarkup
  2510. *
  2511. * @param {string} markup The markup string.
  2512. *
  2513. * @return {Array<Highcharts.ASTNode>} The parsed nodes.
  2514. */
  2515. AST.prototype.parseMarkup = function (markup) {
  2516. var nodes = [];
  2517. var doc;
  2518. var body;
  2519. if (hasValidDOMParser) {
  2520. doc = new DOMParser().parseFromString(markup, 'text/html');
  2521. }
  2522. else {
  2523. body = createElement('div');
  2524. body.innerHTML = markup;
  2525. doc = { body: body };
  2526. }
  2527. var appendChildNodes = function (node,
  2528. addTo) {
  2529. var tagName = node.nodeName.toLowerCase();
  2530. // Add allowed tags
  2531. var astNode = {
  2532. tagName: tagName
  2533. };
  2534. if (tagName === '#text') {
  2535. var textContent = node.textContent || '';
  2536. // Whitespace text node, don't append it to the AST
  2537. if (/^[\s]*$/.test(textContent)) {
  2538. return;
  2539. }
  2540. astNode.textContent = textContent;
  2541. }
  2542. var parsedAttributes = node.attributes;
  2543. // Add attributes
  2544. if (parsedAttributes) {
  2545. var attributes_2 = {};
  2546. [].forEach.call(parsedAttributes, function (attrib) {
  2547. attributes_2[attrib.name] = attrib.value;
  2548. });
  2549. astNode.attributes = attributes_2;
  2550. }
  2551. // Handle children
  2552. if (node.childNodes.length) {
  2553. var children_1 = [];
  2554. [].forEach.call(node.childNodes, function (childNode) {
  2555. appendChildNodes(childNode, children_1);
  2556. });
  2557. if (children_1.length) {
  2558. astNode.children = children_1;
  2559. }
  2560. }
  2561. addTo.push(astNode);
  2562. };
  2563. [].forEach.call(doc.body.childNodes, function (childNode) { return appendChildNodes(childNode, nodes); });
  2564. if (body) {
  2565. discardElement(body);
  2566. }
  2567. return nodes;
  2568. };
  2569. /**
  2570. * The list of allowed SVG or HTML tags, used for sanitizing potentially
  2571. * harmful content from the chart configuration before adding to the DOM.
  2572. *
  2573. * @example
  2574. * // Allow a custom, trusted tag
  2575. * Highcharts.AST.allowedTags.push('blink'); // ;)
  2576. *
  2577. * @name Highcharts.AST.allowedTags
  2578. * @static
  2579. */
  2580. AST.allowedTags = [
  2581. 'a',
  2582. 'b',
  2583. 'br',
  2584. 'button',
  2585. 'caption',
  2586. 'circle',
  2587. 'clipPath',
  2588. 'code',
  2589. 'dd',
  2590. 'defs',
  2591. 'div',
  2592. 'dl',
  2593. 'dt',
  2594. 'em',
  2595. 'feComponentTransfer',
  2596. 'feFuncA',
  2597. 'feFuncB',
  2598. 'feFuncG',
  2599. 'feFuncR',
  2600. 'feGaussianBlur',
  2601. 'feOffset',
  2602. 'feMerge',
  2603. 'feMergeNode',
  2604. 'filter',
  2605. 'h1',
  2606. 'h2',
  2607. 'h3',
  2608. 'h4',
  2609. 'h5',
  2610. 'h6',
  2611. 'hr',
  2612. 'i',
  2613. 'img',
  2614. 'li',
  2615. 'linearGradient',
  2616. 'marker',
  2617. 'ol',
  2618. 'p',
  2619. 'path',
  2620. 'pattern',
  2621. 'pre',
  2622. 'rect',
  2623. 'small',
  2624. 'span',
  2625. 'stop',
  2626. 'strong',
  2627. 'style',
  2628. 'sub',
  2629. 'sup',
  2630. 'svg',
  2631. 'table',
  2632. 'text',
  2633. 'thead',
  2634. 'tbody',
  2635. 'tspan',
  2636. 'td',
  2637. 'th',
  2638. 'tr',
  2639. 'ul',
  2640. '#text'
  2641. ];
  2642. /**
  2643. * The list of allowed SVG or HTML attributes, used for sanitizing
  2644. * potentially harmful content from the chart configuration before adding to
  2645. * the DOM.
  2646. *
  2647. * @example
  2648. * // Allow a custom, trusted attribute
  2649. * Highcharts.AST.allowedAttributes.push('data-value');
  2650. *
  2651. * @name Highcharts.AST.allowedTags
  2652. * @static
  2653. */
  2654. AST.allowedAttributes = [
  2655. 'aria-controls',
  2656. 'aria-describedby',
  2657. 'aria-expanded',
  2658. 'aria-haspopup',
  2659. 'aria-hidden',
  2660. 'aria-label',
  2661. 'aria-labelledby',
  2662. 'aria-live',
  2663. 'aria-pressed',
  2664. 'aria-readonly',
  2665. 'aria-roledescription',
  2666. 'aria-selected',
  2667. 'class',
  2668. 'clip-path',
  2669. 'color',
  2670. 'colspan',
  2671. 'cx',
  2672. 'cy',
  2673. 'd',
  2674. 'dx',
  2675. 'dy',
  2676. 'disabled',
  2677. 'fill',
  2678. 'height',
  2679. 'href',
  2680. 'id',
  2681. 'in',
  2682. 'markerHeight',
  2683. 'markerWidth',
  2684. 'offset',
  2685. 'opacity',
  2686. 'orient',
  2687. 'padding',
  2688. 'paddingLeft',
  2689. 'patternUnits',
  2690. 'r',
  2691. 'refX',
  2692. 'refY',
  2693. 'role',
  2694. 'scope',
  2695. 'slope',
  2696. 'src',
  2697. 'startOffset',
  2698. 'stdDeviation',
  2699. 'stroke',
  2700. 'stroke-linecap',
  2701. 'stroke-width',
  2702. 'style',
  2703. 'result',
  2704. 'rowspan',
  2705. 'summary',
  2706. 'target',
  2707. 'tabindex',
  2708. 'text-align',
  2709. 'textAnchor',
  2710. 'textLength',
  2711. 'type',
  2712. 'valign',
  2713. 'width',
  2714. 'x',
  2715. 'x1',
  2716. 'xy',
  2717. 'y',
  2718. 'y1',
  2719. 'y2',
  2720. 'zIndex'
  2721. ];
  2722. /**
  2723. * The list of allowed references for referring attributes like `href` and
  2724. * `src`. Attribute values will only be allowed if they start with one of
  2725. * these strings.
  2726. *
  2727. * @example
  2728. * // Allow tel:
  2729. * Highcharts.AST.allowedReferences.push('tel:');
  2730. *
  2731. * @name Highcharts.AST.allowedReferences
  2732. * @static
  2733. */
  2734. AST.allowedReferences = [
  2735. 'https://',
  2736. 'http://',
  2737. 'mailto:',
  2738. '/',
  2739. '../',
  2740. './',
  2741. '#'
  2742. ];
  2743. return AST;
  2744. }());
  2745. return AST;
  2746. });
  2747. _registerModule(_modules, 'Core/Color/Color.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
  2748. /* *
  2749. *
  2750. * (c) 2010-2021 Torstein Honsi
  2751. *
  2752. * License: www.highcharts.com/license
  2753. *
  2754. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  2755. *
  2756. * */
  2757. var isNumber = U.isNumber,
  2758. merge = U.merge,
  2759. pInt = U.pInt;
  2760. /**
  2761. * A valid color to be parsed and handled by Highcharts. Highcharts internally
  2762. * supports hex colors like `#ffffff`, rgb colors like `rgb(255,255,255)` and
  2763. * rgba colors like `rgba(255,255,255,1)`. Other colors may be supported by the
  2764. * browsers and displayed correctly, but Highcharts is not able to process them
  2765. * and apply concepts like opacity and brightening.
  2766. *
  2767. * @typedef {string} Highcharts.ColorString
  2768. */
  2769. /**
  2770. * A valid color type than can be parsed and handled by Highcharts. It can be a
  2771. * color string, a gradient object, or a pattern object.
  2772. *
  2773. * @typedef {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject} Highcharts.ColorType
  2774. */
  2775. /**
  2776. * Gradient options instead of a solid color.
  2777. *
  2778. * @example
  2779. * // Linear gradient used as a color option
  2780. * color: {
  2781. * linearGradient: { x1: 0, x2: 0, y1: 0, y2: 1 },
  2782. * stops: [
  2783. * [0, '#003399'], // start
  2784. * [0.5, '#ffffff'], // middle
  2785. * [1, '#3366AA'] // end
  2786. * ]
  2787. * }
  2788. *
  2789. * @interface Highcharts.GradientColorObject
  2790. */ /**
  2791. * Holds an object that defines the start position and the end position relative
  2792. * to the shape.
  2793. * @name Highcharts.GradientColorObject#linearGradient
  2794. * @type {Highcharts.LinearGradientColorObject|undefined}
  2795. */ /**
  2796. * Holds an object that defines the center position and the radius.
  2797. * @name Highcharts.GradientColorObject#radialGradient
  2798. * @type {Highcharts.RadialGradientColorObject|undefined}
  2799. */ /**
  2800. * The first item in each tuple is the position in the gradient, where 0 is the
  2801. * start of the gradient and 1 is the end of the gradient. Multiple stops can be
  2802. * applied. The second item is the color for each stop. This color can also be
  2803. * given in the rgba format.
  2804. * @name Highcharts.GradientColorObject#stops
  2805. * @type {Array<Highcharts.GradientColorStopObject>}
  2806. */
  2807. /**
  2808. * Color stop tuple.
  2809. *
  2810. * @see Highcharts.GradientColorObject
  2811. *
  2812. * @interface Highcharts.GradientColorStopObject
  2813. */ /**
  2814. * @name Highcharts.GradientColorStopObject#0
  2815. * @type {number}
  2816. */ /**
  2817. * @name Highcharts.GradientColorStopObject#1
  2818. * @type {Highcharts.ColorString}
  2819. */ /**
  2820. * @name Highcharts.GradientColorStopObject#color
  2821. * @type {Highcharts.Color|undefined}
  2822. */
  2823. /**
  2824. * Defines the start position and the end position for a gradient relative
  2825. * to the shape. Start position (x1, y1) and end position (x2, y2) are relative
  2826. * to the shape, where 0 means top/left and 1 is bottom/right.
  2827. *
  2828. * @interface Highcharts.LinearGradientColorObject
  2829. */ /**
  2830. * Start horizontal position of the gradient. Float ranges 0-1.
  2831. * @name Highcharts.LinearGradientColorObject#x1
  2832. * @type {number}
  2833. */ /**
  2834. * End horizontal position of the gradient. Float ranges 0-1.
  2835. * @name Highcharts.LinearGradientColorObject#x2
  2836. * @type {number}
  2837. */ /**
  2838. * Start vertical position of the gradient. Float ranges 0-1.
  2839. * @name Highcharts.LinearGradientColorObject#y1
  2840. * @type {number}
  2841. */ /**
  2842. * End vertical position of the gradient. Float ranges 0-1.
  2843. * @name Highcharts.LinearGradientColorObject#y2
  2844. * @type {number}
  2845. */
  2846. /**
  2847. * Defines the center position and the radius for a gradient.
  2848. *
  2849. * @interface Highcharts.RadialGradientColorObject
  2850. */ /**
  2851. * Center horizontal position relative to the shape. Float ranges 0-1.
  2852. * @name Highcharts.RadialGradientColorObject#cx
  2853. * @type {number}
  2854. */ /**
  2855. * Center vertical position relative to the shape. Float ranges 0-1.
  2856. * @name Highcharts.RadialGradientColorObject#cy
  2857. * @type {number}
  2858. */ /**
  2859. * Radius relative to the shape. Float ranges 0-1.
  2860. * @name Highcharts.RadialGradientColorObject#r
  2861. * @type {number}
  2862. */
  2863. ''; // detach doclets above
  2864. /* *
  2865. *
  2866. * Class
  2867. *
  2868. * */
  2869. /* eslint-disable no-invalid-this, valid-jsdoc */
  2870. /**
  2871. * Handle color operations. Some object methods are chainable.
  2872. *
  2873. * @class
  2874. * @name Highcharts.Color
  2875. *
  2876. * @param {Highcharts.ColorType} input
  2877. * The input color in either rbga or hex format
  2878. */
  2879. var Color = /** @class */ (function () {
  2880. /* *
  2881. *
  2882. * Constructors
  2883. *
  2884. * */
  2885. function Color(input) {
  2886. // Collection of parsers. This can be extended from the outside by pushing
  2887. // parsers to Highcharts.Color.prototype.parsers.
  2888. this.parsers = [{
  2889. // RGBA color
  2890. // eslint-disable-next-line max-len
  2891. regex: /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*\)/,
  2892. parse: function (result) {
  2893. return [
  2894. pInt(result[1]),
  2895. pInt(result[2]),
  2896. pInt(result[3]),
  2897. parseFloat(result[4], 10)
  2898. ];
  2899. }
  2900. }, {
  2901. // RGB color
  2902. regex: /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/,
  2903. parse: function (result) {
  2904. return [pInt(result[1]), pInt(result[2]), pInt(result[3]), 1];
  2905. }
  2906. }];
  2907. this.rgba = [];
  2908. // Backwards compatibility, allow class overwrite
  2909. if (H.Color !== Color) {
  2910. return new H.Color(input);
  2911. }
  2912. // Backwards compatibility, allow instanciation without new (#13053)
  2913. if (!(this instanceof Color)) {
  2914. return new Color(input);
  2915. }
  2916. this.init(input);
  2917. }
  2918. /* *
  2919. *
  2920. * Static Functions
  2921. *
  2922. * */
  2923. /**
  2924. * Creates a color instance out of a color string or object.
  2925. *
  2926. * @function Highcharts.Color.parse
  2927. *
  2928. * @param {Highcharts.ColorType} input
  2929. * The input color in either rbga or hex format.
  2930. *
  2931. * @return {Highcharts.Color}
  2932. * Color instance.
  2933. */
  2934. Color.parse = function (input) {
  2935. return new Color(input);
  2936. };
  2937. /* *
  2938. *
  2939. * Functions
  2940. *
  2941. * */
  2942. /**
  2943. * Parse the input color to rgba array
  2944. *
  2945. * @private
  2946. * @function Highcharts.Color#init
  2947. *
  2948. * @param {Highcharts.ColorType} input
  2949. * The input color in either rbga or hex format
  2950. *
  2951. * @return {void}
  2952. */
  2953. Color.prototype.init = function (input) {
  2954. var result,
  2955. rgba,
  2956. i,
  2957. parser,
  2958. len;
  2959. this.input = input = Color.names[input && input.toLowerCase ?
  2960. input.toLowerCase() :
  2961. ''] || input;
  2962. // Gradients
  2963. if (input && input.stops) {
  2964. this.stops = input.stops.map(function (stop) {
  2965. return new Color(stop[1]);
  2966. });
  2967. // Solid colors
  2968. }
  2969. else {
  2970. // Bitmasking as input[0] is not working for legacy IE.
  2971. if (input &&
  2972. input.charAt &&
  2973. input.charAt() === '#') {
  2974. len = input.length;
  2975. input = parseInt(input.substr(1), 16);
  2976. // Handle long-form, e.g. #AABBCC
  2977. if (len === 7) {
  2978. rgba = [
  2979. (input & 0xFF0000) >> 16,
  2980. (input & 0xFF00) >> 8,
  2981. (input & 0xFF),
  2982. 1
  2983. ];
  2984. // Handle short-form, e.g. #ABC
  2985. // In short form, the value is assumed to be the same
  2986. // for both nibbles for each component. e.g. #ABC = #AABBCC
  2987. }
  2988. else if (len === 4) {
  2989. rgba = [
  2990. (((input & 0xF00) >> 4) |
  2991. (input & 0xF00) >> 8),
  2992. (((input & 0xF0) >> 4) |
  2993. (input & 0xF0)),
  2994. ((input & 0xF) << 4) | (input & 0xF),
  2995. 1
  2996. ];
  2997. }
  2998. }
  2999. // Otherwise, check regex parsers
  3000. if (!rgba) {
  3001. i = this.parsers.length;
  3002. while (i-- && !rgba) {
  3003. parser = this.parsers[i];
  3004. result = parser.regex.exec(input);
  3005. if (result) {
  3006. rgba = parser.parse(result);
  3007. }
  3008. }
  3009. }
  3010. }
  3011. this.rgba = rgba || [];
  3012. };
  3013. /**
  3014. * Return the color or gradient stops in the specified format
  3015. *
  3016. * @function Highcharts.Color#get
  3017. *
  3018. * @param {string} [format]
  3019. * Possible values are 'a', 'rgb', 'rgba' (default).
  3020. *
  3021. * @return {Highcharts.ColorType}
  3022. * This color as a string or gradient stops.
  3023. */
  3024. Color.prototype.get = function (format) {
  3025. var input = this.input,
  3026. rgba = this.rgba,
  3027. ret;
  3028. if (typeof this.stops !== 'undefined') {
  3029. ret = merge(input);
  3030. ret.stops = [].concat(ret.stops);
  3031. this.stops.forEach(function (stop, i) {
  3032. ret.stops[i] = [
  3033. ret.stops[i][0],
  3034. stop.get(format)
  3035. ];
  3036. });
  3037. // it's NaN if gradient colors on a column chart
  3038. }
  3039. else if (rgba && isNumber(rgba[0])) {
  3040. if (format === 'rgb' || (!format && rgba[3] === 1)) {
  3041. ret = 'rgb(' + rgba[0] + ',' + rgba[1] + ',' + rgba[2] + ')';
  3042. }
  3043. else if (format === 'a') {
  3044. ret = rgba[3];
  3045. }
  3046. else {
  3047. ret = 'rgba(' + rgba.join(',') + ')';
  3048. }
  3049. }
  3050. else {
  3051. ret = input;
  3052. }
  3053. return ret;
  3054. };
  3055. /**
  3056. * Brighten the color instance.
  3057. *
  3058. * @function Highcharts.Color#brighten
  3059. *
  3060. * @param {number} alpha
  3061. * The alpha value.
  3062. *
  3063. * @return {Highcharts.Color}
  3064. * This color with modifications.
  3065. */
  3066. Color.prototype.brighten = function (alpha) {
  3067. var i,
  3068. rgba = this.rgba;
  3069. if (this.stops) {
  3070. this.stops.forEach(function (stop) {
  3071. stop.brighten(alpha);
  3072. });
  3073. }
  3074. else if (isNumber(alpha) && alpha !== 0) {
  3075. for (i = 0; i < 3; i++) {
  3076. rgba[i] += pInt(alpha * 255);
  3077. if (rgba[i] < 0) {
  3078. rgba[i] = 0;
  3079. }
  3080. if (rgba[i] > 255) {
  3081. rgba[i] = 255;
  3082. }
  3083. }
  3084. }
  3085. return this;
  3086. };
  3087. /**
  3088. * Set the color's opacity to a given alpha value.
  3089. *
  3090. * @function Highcharts.Color#setOpacity
  3091. *
  3092. * @param {number} alpha
  3093. * Opacity between 0 and 1.
  3094. *
  3095. * @return {Highcharts.Color}
  3096. * Color with modifications.
  3097. */
  3098. Color.prototype.setOpacity = function (alpha) {
  3099. this.rgba[3] = alpha;
  3100. return this;
  3101. };
  3102. /**
  3103. * Return an intermediate color between two colors.
  3104. *
  3105. * @function Highcharts.Color#tweenTo
  3106. *
  3107. * @param {Highcharts.Color} to
  3108. * The color object to tween to.
  3109. *
  3110. * @param {number} pos
  3111. * The intermediate position, where 0 is the from color (current
  3112. * color item), and 1 is the `to` color.
  3113. *
  3114. * @return {Highcharts.ColorString}
  3115. * The intermediate color in rgba notation.
  3116. */
  3117. Color.prototype.tweenTo = function (to, pos) {
  3118. // Check for has alpha, because rgba colors perform worse due to lack of
  3119. // support in WebKit.
  3120. var fromRgba = this.rgba,
  3121. toRgba = to.rgba,
  3122. hasAlpha,
  3123. ret;
  3124. // Unsupported color, return to-color (#3920, #7034)
  3125. if (!toRgba.length || !fromRgba || !fromRgba.length) {
  3126. ret = to.input || 'none';
  3127. // Interpolate
  3128. }
  3129. else {
  3130. hasAlpha = (toRgba[3] !== 1 || fromRgba[3] !== 1);
  3131. ret = (hasAlpha ? 'rgba(' : 'rgb(') +
  3132. Math.round(toRgba[0] + (fromRgba[0] - toRgba[0]) * (1 - pos)) +
  3133. ',' +
  3134. Math.round(toRgba[1] + (fromRgba[1] - toRgba[1]) * (1 - pos)) +
  3135. ',' +
  3136. Math.round(toRgba[2] + (fromRgba[2] - toRgba[2]) * (1 - pos)) +
  3137. (hasAlpha ?
  3138. (',' +
  3139. (toRgba[3] + (fromRgba[3] - toRgba[3]) * (1 - pos))) :
  3140. '') +
  3141. ')';
  3142. }
  3143. return ret;
  3144. };
  3145. /* *
  3146. *
  3147. * Static Properties
  3148. *
  3149. * */
  3150. // Collection of named colors. Can be extended from the outside by adding
  3151. // colors to Highcharts.Color.names.
  3152. Color.names = {
  3153. white: '#ffffff',
  3154. black: '#000000'
  3155. };
  3156. return Color;
  3157. }());
  3158. H.Color = Color;
  3159. /**
  3160. * Creates a color instance out of a color string.
  3161. *
  3162. * @function Highcharts.color
  3163. *
  3164. * @param {Highcharts.ColorType} input
  3165. * The input color in either rbga or hex format
  3166. *
  3167. * @return {Highcharts.Color}
  3168. * Color instance
  3169. */
  3170. H.color = Color.parse;
  3171. /* *
  3172. *
  3173. * Export
  3174. *
  3175. * */
  3176. return Color;
  3177. });
  3178. _registerModule(_modules, 'Core/Color/Palette.js', [], function () {
  3179. var palette = {
  3180. /**
  3181. * Colors for data series and points.
  3182. */
  3183. colors: [
  3184. '#7cb5ec',
  3185. '#434348',
  3186. '#90ed7d',
  3187. '#f7a35c',
  3188. '#8085e9',
  3189. '#f15c80',
  3190. '#e4d354',
  3191. '#2b908f',
  3192. '#f45b5b',
  3193. '#91e8e1'
  3194. ],
  3195. /**
  3196. * Chart background,
  3197. point stroke for markers and columns etc
  3198. */
  3199. backgroundColor: '#ffffff',
  3200. /**
  3201. * Strong text.
  3202. */
  3203. neutralColor100: '#000000',
  3204. /**
  3205. * Main text and some strokes.
  3206. */
  3207. neutralColor80: '#333333',
  3208. /**
  3209. * Axis labels,
  3210. axis title,
  3211. connector fallback.
  3212. */
  3213. neutralColor60: '#666666',
  3214. /**
  3215. * Credits text,
  3216. export menu stroke.
  3217. */
  3218. neutralColor40: '#999999',
  3219. /**
  3220. * Disabled texts,
  3221. button strokes,
  3222. crosshair etc.
  3223. */
  3224. neutralColor20: '#cccccc',
  3225. /**
  3226. * Grid lines etc.
  3227. */
  3228. neutralColor10: '#e6e6e6',
  3229. /**
  3230. * Minor grid lines etc.
  3231. */
  3232. neutralColor5: '#f2f2f2',
  3233. /**
  3234. * Tooltip backgroud,
  3235. button fills,
  3236. map null points.
  3237. */
  3238. neutralColor3: '#f7f7f7',
  3239. /**
  3240. * Drilldown clickable labels,
  3241. color axis max color.
  3242. */
  3243. highlightColor100: '#003399',
  3244. /**
  3245. * Selection marker,
  3246. menu hover,
  3247. button hover,
  3248. chart border,
  3249. navigator series.
  3250. */
  3251. highlightColor80: '#335cad',
  3252. /**
  3253. * Navigator mask fill.
  3254. */
  3255. highlightColor60: '#6685c2',
  3256. /**
  3257. * Ticks and axis line.
  3258. */
  3259. highlightColor20: '#ccd6eb',
  3260. /**
  3261. * Pressed button,
  3262. color axis min color.
  3263. */
  3264. highlightColor10: '#e6ebf5',
  3265. /**
  3266. * Positive indicator color
  3267. */
  3268. indicatorPositiveLine: '#06b535',
  3269. /**
  3270. * Negative indicator color
  3271. */
  3272. indicatorNegativeLine: '#f21313'
  3273. };
  3274. return palette;
  3275. });
  3276. _registerModule(_modules, 'Core/Animation/Fx.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
  3277. /* *
  3278. *
  3279. * (c) 2010-2021 Torstein Honsi
  3280. *
  3281. * License: www.highcharts.com/license
  3282. *
  3283. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  3284. *
  3285. * */
  3286. var win = H.win;
  3287. var isNumber = U.isNumber,
  3288. objectEach = U.objectEach;
  3289. /* eslint-disable no-invalid-this, valid-jsdoc */
  3290. /**
  3291. * An animator object used internally. One instance applies to one property
  3292. * (attribute or style prop) on one element. Animation is always initiated
  3293. * through {@link SVGElement#animate}.
  3294. *
  3295. * @example
  3296. * var rect = renderer.rect(0, 0, 10, 10).add();
  3297. * rect.animate({ width: 100 });
  3298. *
  3299. * @private
  3300. * @class
  3301. * @name Highcharts.Fx
  3302. */
  3303. var Fx = /** @class */ (function () {
  3304. /* *
  3305. *
  3306. * Constructors
  3307. *
  3308. * */
  3309. /**
  3310. *
  3311. * @param {Highcharts.HTMLDOMElement|Highcharts.SVGElement} elem
  3312. * The element to animate.
  3313. *
  3314. * @param {Partial<Highcharts.AnimationOptionsObject>} options
  3315. * Animation options.
  3316. *
  3317. * @param {string} prop
  3318. * The single attribute or CSS property to animate.
  3319. */
  3320. function Fx(elem, options, prop) {
  3321. this.pos = NaN;
  3322. this.options = options;
  3323. this.elem = elem;
  3324. this.prop = prop;
  3325. }
  3326. /* *
  3327. *
  3328. * Functions
  3329. *
  3330. * */
  3331. /**
  3332. * Set the current step of a path definition on SVGElement.
  3333. *
  3334. * @function Highcharts.Fx#dSetter
  3335. *
  3336. * @return {void}
  3337. */
  3338. Fx.prototype.dSetter = function () {
  3339. var paths = this.paths,
  3340. start = paths && paths[0],
  3341. end = paths && paths[1],
  3342. path = [],
  3343. now = this.now || 0;
  3344. // Land on the final path without adjustment points appended in the ends
  3345. if (now === 1 || !start || !end) {
  3346. path = this.toD || [];
  3347. }
  3348. else if (start.length === end.length && now < 1) {
  3349. for (var i = 0; i < end.length; i++) {
  3350. // Tween between the start segment and the end segment. Start
  3351. // with a copy of the end segment and tween the appropriate
  3352. // numerics
  3353. var startSeg = start[i];
  3354. var endSeg = end[i];
  3355. var tweenSeg = [];
  3356. for (var j = 0; j < endSeg.length; j++) {
  3357. var startItem = startSeg[j];
  3358. var endItem = endSeg[j];
  3359. // Tween numbers
  3360. if (isNumber(startItem) &&
  3361. isNumber(endItem) &&
  3362. // Arc boolean flags
  3363. !(endSeg[0] === 'A' && (j === 4 || j === 5))) {
  3364. tweenSeg[j] = startItem + now * (endItem - startItem);
  3365. // Strings, take directly from the end segment
  3366. }
  3367. else {
  3368. tweenSeg[j] = endItem;
  3369. }
  3370. }
  3371. path.push(tweenSeg);
  3372. }
  3373. // If animation is finished or length not matching, land on right value
  3374. }
  3375. else {
  3376. path = end;
  3377. }
  3378. this.elem.attr('d', path, void 0, true);
  3379. };
  3380. /**
  3381. * Update the element with the current animation step.
  3382. *
  3383. * @function Highcharts.Fx#update
  3384. *
  3385. * @return {void}
  3386. */
  3387. Fx.prototype.update = function () {
  3388. var elem = this.elem,
  3389. prop = this.prop, // if destroyed, it is null
  3390. now = this.now,
  3391. step = this.options.step;
  3392. // Animation setter defined from outside
  3393. if (this[prop + 'Setter']) {
  3394. this[prop + 'Setter']();
  3395. // Other animations on SVGElement
  3396. }
  3397. else if (elem.attr) {
  3398. if (elem.element) {
  3399. elem.attr(prop, now, null, true);
  3400. }
  3401. // HTML styles, raw HTML content like container size
  3402. }
  3403. else {
  3404. elem.style[prop] = now + this.unit;
  3405. }
  3406. if (step) {
  3407. step.call(elem, now, this);
  3408. }
  3409. };
  3410. /**
  3411. * Run an animation.
  3412. *
  3413. * @function Highcharts.Fx#run
  3414. *
  3415. * @param {number} from
  3416. * The current value, value to start from.
  3417. *
  3418. * @param {number} to
  3419. * The end value, value to land on.
  3420. *
  3421. * @param {string} unit
  3422. * The property unit, for example `px`.
  3423. *
  3424. * @return {void}
  3425. */
  3426. Fx.prototype.run = function (from, to, unit) {
  3427. var self = this,
  3428. options = self.options,
  3429. timer = function (gotoEnd) {
  3430. return timer.stopped ? false : self.step(gotoEnd);
  3431. }, requestAnimationFrame = win.requestAnimationFrame ||
  3432. function (step) {
  3433. setTimeout(step, 13);
  3434. }, step = function () {
  3435. for (var i = 0; i < Fx.timers.length; i++) {
  3436. if (!Fx.timers[i]()) {
  3437. Fx.timers.splice(i--, 1);
  3438. }
  3439. }
  3440. if (Fx.timers.length) {
  3441. requestAnimationFrame(step);
  3442. }
  3443. };
  3444. if (from === to && !this.elem['forceAnimate:' + this.prop]) {
  3445. delete options.curAnim[this.prop];
  3446. if (options.complete && Object.keys(options.curAnim).length === 0) {
  3447. options.complete.call(this.elem);
  3448. }
  3449. }
  3450. else { // #7166
  3451. this.startTime = +new Date();
  3452. this.start = from;
  3453. this.end = to;
  3454. this.unit = unit;
  3455. this.now = this.start;
  3456. this.pos = 0;
  3457. timer.elem = this.elem;
  3458. timer.prop = this.prop;
  3459. if (timer() && Fx.timers.push(timer) === 1) {
  3460. requestAnimationFrame(step);
  3461. }
  3462. }
  3463. };
  3464. /**
  3465. * Run a single step in the animation.
  3466. *
  3467. * @function Highcharts.Fx#step
  3468. *
  3469. * @param {boolean} [gotoEnd]
  3470. * Whether to go to the endpoint of the animation after abort.
  3471. *
  3472. * @return {boolean}
  3473. * Returns `true` if animation continues.
  3474. */
  3475. Fx.prototype.step = function (gotoEnd) {
  3476. var t = +new Date(),
  3477. ret,
  3478. done,
  3479. options = this.options,
  3480. elem = this.elem,
  3481. complete = options.complete,
  3482. duration = options.duration,
  3483. curAnim = options.curAnim;
  3484. if (elem.attr && !elem.element) { // #2616, element is destroyed
  3485. ret = false;
  3486. }
  3487. else if (gotoEnd || t >= duration + this.startTime) {
  3488. this.now = this.end;
  3489. this.pos = 1;
  3490. this.update();
  3491. curAnim[this.prop] = true;
  3492. done = true;
  3493. objectEach(curAnim, function (val) {
  3494. if (val !== true) {
  3495. done = false;
  3496. }
  3497. });
  3498. if (done && complete) {
  3499. complete.call(elem);
  3500. }
  3501. ret = false;
  3502. }
  3503. else {
  3504. this.pos = options.easing((t - this.startTime) / duration);
  3505. this.now = this.start + ((this.end - this.start) * this.pos);
  3506. this.update();
  3507. ret = true;
  3508. }
  3509. return ret;
  3510. };
  3511. /**
  3512. * Prepare start and end values so that the path can be animated one to one.
  3513. *
  3514. * @function Highcharts.Fx#initPath
  3515. *
  3516. * @param {Highcharts.SVGElement} elem
  3517. * The SVGElement item.
  3518. *
  3519. * @param {Highcharts.SVGPathArray|undefined} fromD
  3520. * Starting path definition.
  3521. *
  3522. * @param {Highcharts.SVGPathArray} toD
  3523. * Ending path definition.
  3524. *
  3525. * @return {Array<Highcharts.SVGPathArray,Highcharts.SVGPathArray>}
  3526. * An array containing start and end paths in array form so that
  3527. * they can be animated in parallel.
  3528. */
  3529. Fx.prototype.initPath = function (elem, fromD, toD) {
  3530. var shift,
  3531. startX = elem.startX,
  3532. endX = elem.endX,
  3533. fullLength,
  3534. i,
  3535. start = fromD && fromD.slice(), // copy
  3536. end = toD.slice(), // copy
  3537. isArea = elem.isArea,
  3538. positionFactor = isArea ? 2 : 1,
  3539. reverse;
  3540. if (!start) {
  3541. return [end, end];
  3542. }
  3543. /**
  3544. * If shifting points, prepend a dummy point to the end path.
  3545. * @private
  3546. * @param {Highcharts.SVGPathArray} arr - array
  3547. * @param {Highcharts.SVGPathArray} other - array
  3548. * @return {void}
  3549. */
  3550. function prepend(arr, other) {
  3551. while (arr.length < fullLength) {
  3552. // Move to, line to or curve to?
  3553. var moveSegment = arr[0],
  3554. otherSegment = other[fullLength - arr.length];
  3555. if (otherSegment && moveSegment[0] === 'M') {
  3556. if (otherSegment[0] === 'C') {
  3557. arr[0] = [
  3558. 'C',
  3559. moveSegment[1],
  3560. moveSegment[2],
  3561. moveSegment[1],
  3562. moveSegment[2],
  3563. moveSegment[1],
  3564. moveSegment[2]
  3565. ];
  3566. }
  3567. else {
  3568. arr[0] = ['L', moveSegment[1], moveSegment[2]];
  3569. }
  3570. }
  3571. // Prepend a copy of the first point
  3572. arr.unshift(moveSegment);
  3573. // For areas, the bottom path goes back again to the left, so we
  3574. // need to append a copy of the last point.
  3575. if (isArea) {
  3576. arr.push(arr[arr.length - 1]);
  3577. }
  3578. }
  3579. }
  3580. /**
  3581. * Copy and append last point until the length matches the end length.
  3582. * @private
  3583. * @param {Highcharts.SVGPathArray} arr - array
  3584. * @param {Highcharts.SVGPathArray} other - array
  3585. * @return {void}
  3586. */
  3587. function append(arr, other) {
  3588. while (arr.length < fullLength) {
  3589. // Pull out the slice that is going to be appended or inserted.
  3590. // In a line graph, the positionFactor is 1, and the last point
  3591. // is sliced out. In an area graph, the positionFactor is 2,
  3592. // causing the middle two points to be sliced out, since an area
  3593. // path starts at left, follows the upper path then turns and
  3594. // follows the bottom back.
  3595. var segmentToAdd = arr[arr.length / positionFactor - 1].slice();
  3596. // Disable the first control point of curve segments
  3597. if (segmentToAdd[0] === 'C') {
  3598. segmentToAdd[1] = segmentToAdd[5];
  3599. segmentToAdd[2] = segmentToAdd[6];
  3600. }
  3601. if (!isArea) {
  3602. arr.push(segmentToAdd);
  3603. }
  3604. else {
  3605. var lowerSegmentToAdd = arr[arr.length / positionFactor].slice();
  3606. arr.splice(arr.length / 2, 0, segmentToAdd, lowerSegmentToAdd);
  3607. }
  3608. }
  3609. }
  3610. // For sideways animation, find out how much we need to shift to get the
  3611. // start path Xs to match the end path Xs.
  3612. if (startX && endX) {
  3613. for (i = 0; i < startX.length; i++) {
  3614. // Moving left, new points coming in on right
  3615. if (startX[i] === endX[0]) {
  3616. shift = i;
  3617. break;
  3618. // Moving right
  3619. }
  3620. else if (startX[0] ===
  3621. endX[endX.length - startX.length + i]) {
  3622. shift = i;
  3623. reverse = true;
  3624. break;
  3625. // Fixed from the right side, "scaling" left
  3626. }
  3627. else if (startX[startX.length - 1] ===
  3628. endX[endX.length - startX.length + i]) {
  3629. shift = startX.length - i;
  3630. break;
  3631. }
  3632. }
  3633. if (typeof shift === 'undefined') {
  3634. start = [];
  3635. }
  3636. }
  3637. if (start.length && isNumber(shift)) {
  3638. // The common target length for the start and end array, where both
  3639. // arrays are padded in opposite ends
  3640. fullLength = end.length + shift * positionFactor;
  3641. if (!reverse) {
  3642. prepend(end, start);
  3643. append(start, end);
  3644. }
  3645. else {
  3646. prepend(start, end);
  3647. append(end, start);
  3648. }
  3649. }
  3650. return [start, end];
  3651. };
  3652. /**
  3653. * Handle animation of the color attributes directly.
  3654. *
  3655. * @function Highcharts.Fx#fillSetter
  3656. *
  3657. * @return {void}
  3658. */
  3659. Fx.prototype.fillSetter = function () {
  3660. Fx.prototype.strokeSetter.apply(this, arguments);
  3661. };
  3662. /**
  3663. * Handle animation of the color attributes directly.
  3664. *
  3665. * @function Highcharts.Fx#strokeSetter
  3666. *
  3667. * @return {void}
  3668. */
  3669. Fx.prototype.strokeSetter = function () {
  3670. this.elem.attr(this.prop, H.color(this.start).tweenTo(H.color(this.end), this.pos), null, true);
  3671. };
  3672. /* *
  3673. *
  3674. * Static properties
  3675. *
  3676. * */
  3677. Fx.timers = [];
  3678. return Fx;
  3679. }());
  3680. /* *
  3681. *
  3682. * Compatibility
  3683. *
  3684. * */
  3685. H.Fx = Fx;
  3686. H.timers = Fx.timers;
  3687. /* *
  3688. *
  3689. * Default Export
  3690. *
  3691. * */
  3692. return Fx;
  3693. });
  3694. _registerModule(_modules, 'Core/Animation/AnimationUtilities.js', [_modules['Core/Animation/Fx.js'], _modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (Fx, H, U) {
  3695. /* *
  3696. *
  3697. * (c) 2010-2021 Torstein Honsi
  3698. *
  3699. * License: www.highcharts.com/license
  3700. *
  3701. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  3702. *
  3703. * */
  3704. var defined = U.defined,
  3705. getStyle = U.getStyle,
  3706. isArray = U.isArray,
  3707. isNumber = U.isNumber,
  3708. isObject = U.isObject,
  3709. merge = U.merge,
  3710. objectEach = U.objectEach,
  3711. pick = U.pick;
  3712. /**
  3713. * Set the global animation to either a given value, or fall back to the given
  3714. * chart's animation option.
  3715. *
  3716. * @function Highcharts.setAnimation
  3717. *
  3718. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>|undefined} animation
  3719. * The animation object.
  3720. *
  3721. * @param {Highcharts.Chart} chart
  3722. * The chart instance.
  3723. *
  3724. * @todo
  3725. * This function always relates to a chart, and sets a property on the renderer,
  3726. * so it should be moved to the SVGRenderer.
  3727. */
  3728. var setAnimation = H.setAnimation = function setAnimation(animation,
  3729. chart) {
  3730. chart.renderer.globalAnimation = pick(animation,
  3731. chart.options.chart.animation,
  3732. true);
  3733. };
  3734. /**
  3735. * Get the animation in object form, where a disabled animation is always
  3736. * returned as `{ duration: 0 }`.
  3737. *
  3738. * @function Highcharts.animObject
  3739. *
  3740. * @param {boolean|Highcharts.AnimationOptionsObject} [animation=0]
  3741. * An animation setting. Can be an object with duration, complete and
  3742. * easing properties, or a boolean to enable or disable.
  3743. *
  3744. * @return {Highcharts.AnimationOptionsObject}
  3745. * An object with at least a duration property.
  3746. */
  3747. var animObject = H.animObject = function animObject(animation) {
  3748. return isObject(animation) ?
  3749. merge({ duration: 500,
  3750. defer: 0 },
  3751. animation) :
  3752. { duration: animation ? 500 : 0,
  3753. defer: 0 };
  3754. };
  3755. /**
  3756. * Get the defer as a number value from series animation options.
  3757. *
  3758. * @function Highcharts.getDeferredAnimation
  3759. *
  3760. * @param {Highcharts.Chart} chart
  3761. * The chart instance.
  3762. *
  3763. * @param {boolean|Highcharts.AnimationOptionsObject} animation
  3764. * An animation setting. Can be an object with duration, complete and
  3765. * easing properties, or a boolean to enable or disable.
  3766. *
  3767. * @param {Highcharts.Series} [series]
  3768. * Series to defer animation.
  3769. *
  3770. * @return {number}
  3771. * The numeric value.
  3772. */
  3773. var getDeferredAnimation = H.getDeferredAnimation = function (chart,
  3774. animation,
  3775. series) {
  3776. var labelAnimation = animObject(animation);
  3777. var s = series ? [series] : chart.series;
  3778. var defer = 0;
  3779. var duration = 0;
  3780. s.forEach(function (series) {
  3781. var seriesAnim = animObject(series.options.animation);
  3782. defer = animation && defined(animation.defer) ?
  3783. labelAnimation.defer :
  3784. Math.max(defer, seriesAnim.duration + seriesAnim.defer);
  3785. duration = Math.min(labelAnimation.duration, seriesAnim.duration);
  3786. });
  3787. // Disable defer for exporting
  3788. if (chart.renderer.forExport) {
  3789. defer = 0;
  3790. }
  3791. var anim = {
  3792. defer: Math.max(0,
  3793. defer - duration),
  3794. duration: Math.min(defer,
  3795. duration)
  3796. };
  3797. return anim;
  3798. };
  3799. /**
  3800. * The global animate method, which uses Fx to create individual animators.
  3801. *
  3802. * @function Highcharts.animate
  3803. *
  3804. * @param {Highcharts.HTMLDOMElement|Highcharts.SVGElement} el
  3805. * The element to animate.
  3806. *
  3807. * @param {Highcharts.CSSObject|Highcharts.SVGAttributes} params
  3808. * An object containing key-value pairs of the properties to animate.
  3809. * Supports numeric as pixel-based CSS properties for HTML objects and
  3810. * attributes for SVGElements.
  3811. *
  3812. * @param {Partial<Highcharts.AnimationOptionsObject>} [opt]
  3813. * Animation options.
  3814. *
  3815. * @return {void}
  3816. */
  3817. var animate = function (el,
  3818. params,
  3819. opt) {
  3820. var start,
  3821. unit = '',
  3822. end,
  3823. fx,
  3824. args;
  3825. if (!isObject(opt)) { // Number or undefined/null
  3826. args = arguments;
  3827. opt = {
  3828. duration: args[2],
  3829. easing: args[3],
  3830. complete: args[4]
  3831. };
  3832. }
  3833. if (!isNumber(opt.duration)) {
  3834. opt.duration = 400;
  3835. }
  3836. opt.easing = typeof opt.easing === 'function' ?
  3837. opt.easing :
  3838. (Math[opt.easing] || Math.easeInOutSine);
  3839. opt.curAnim = merge(params);
  3840. objectEach(params, function (val, prop) {
  3841. // Stop current running animation of this property
  3842. stop(el, prop);
  3843. fx = new Fx(el, opt, prop);
  3844. end = null;
  3845. if (prop === 'd' && isArray(params.d)) {
  3846. fx.paths = fx.initPath(el, el.pathArray, params.d);
  3847. fx.toD = params.d;
  3848. start = 0;
  3849. end = 1;
  3850. }
  3851. else if (el.attr) {
  3852. start = el.attr(prop);
  3853. }
  3854. else {
  3855. start = parseFloat(getStyle(el, prop)) || 0;
  3856. if (prop !== 'opacity') {
  3857. unit = 'px';
  3858. }
  3859. }
  3860. if (!end) {
  3861. end = val;
  3862. }
  3863. if (end && end.match && end.match('px')) {
  3864. end = end.replace(/px/g, ''); // #4351
  3865. }
  3866. fx.run(start, end, unit);
  3867. });
  3868. };
  3869. /**
  3870. * Stop running animation.
  3871. *
  3872. * @function Highcharts.stop
  3873. *
  3874. * @param {Highcharts.SVGElement} el
  3875. * The SVGElement to stop animation on.
  3876. *
  3877. * @param {string} [prop]
  3878. * The property to stop animating. If given, the stop method will stop a
  3879. * single property from animating, while others continue.
  3880. *
  3881. * @return {void}
  3882. *
  3883. * @todo
  3884. * A possible extension to this would be to stop a single property, when
  3885. * we want to continue animating others. Then assign the prop to the timer
  3886. * in the Fx.run method, and check for the prop here. This would be an
  3887. * improvement in all cases where we stop the animation from .attr. Instead of
  3888. * stopping everything, we can just stop the actual attributes we're setting.
  3889. */
  3890. var stop = H.stop = function (el,
  3891. prop) {
  3892. var i = Fx.timers.length;
  3893. // Remove timers related to this element (#4519)
  3894. while (i--) {
  3895. if (Fx.timers[i].elem === el && (!prop || prop === Fx.timers[i].prop)) {
  3896. Fx.timers[i].stopped = true; // #4667
  3897. }
  3898. }
  3899. };
  3900. var animationExports = {
  3901. animate: animate,
  3902. animObject: animObject,
  3903. getDeferredAnimation: getDeferredAnimation,
  3904. setAnimation: setAnimation,
  3905. stop: stop
  3906. };
  3907. return animationExports;
  3908. });
  3909. _registerModule(_modules, 'Core/Renderer/SVG/SVGElement.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Renderer/HTML/AST.js'], _modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Core/Color/Palette.js'], _modules['Core/Utilities.js']], function (A, AST, Color, H, palette, U) {
  3910. /* *
  3911. *
  3912. * (c) 2010-2021 Torstein Honsi
  3913. *
  3914. * License: www.highcharts.com/license
  3915. *
  3916. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  3917. *
  3918. * */
  3919. var animate = A.animate,
  3920. animObject = A.animObject,
  3921. stop = A.stop;
  3922. var deg2rad = H.deg2rad,
  3923. doc = H.doc,
  3924. hasTouch = H.hasTouch,
  3925. noop = H.noop,
  3926. svg = H.svg,
  3927. SVG_NS = H.SVG_NS,
  3928. win = H.win;
  3929. var attr = U.attr,
  3930. createElement = U.createElement,
  3931. css = U.css,
  3932. defined = U.defined,
  3933. erase = U.erase,
  3934. extend = U.extend,
  3935. fireEvent = U.fireEvent,
  3936. isArray = U.isArray,
  3937. isFunction = U.isFunction,
  3938. isNumber = U.isNumber,
  3939. isString = U.isString,
  3940. merge = U.merge,
  3941. objectEach = U.objectEach,
  3942. pick = U.pick,
  3943. pInt = U.pInt,
  3944. syncTimeout = U.syncTimeout,
  3945. uniqueKey = U.uniqueKey;
  3946. /**
  3947. * The horizontal alignment of an element.
  3948. *
  3949. * @typedef {"center"|"left"|"right"} Highcharts.AlignValue
  3950. */
  3951. /**
  3952. * Options to align the element relative to the chart or another box.
  3953. *
  3954. * @interface Highcharts.AlignObject
  3955. */ /**
  3956. * Horizontal alignment. Can be one of `left`, `center` and `right`.
  3957. *
  3958. * @name Highcharts.AlignObject#align
  3959. * @type {Highcharts.AlignValue|undefined}
  3960. *
  3961. * @default left
  3962. */ /**
  3963. * Vertical alignment. Can be one of `top`, `middle` and `bottom`.
  3964. *
  3965. * @name Highcharts.AlignObject#verticalAlign
  3966. * @type {Highcharts.VerticalAlignValue|undefined}
  3967. *
  3968. * @default top
  3969. */ /**
  3970. * Horizontal pixel offset from alignment.
  3971. *
  3972. * @name Highcharts.AlignObject#x
  3973. * @type {number|undefined}
  3974. *
  3975. * @default 0
  3976. */ /**
  3977. * Vertical pixel offset from alignment.
  3978. *
  3979. * @name Highcharts.AlignObject#y
  3980. * @type {number|undefined}
  3981. *
  3982. * @default 0
  3983. */ /**
  3984. * Use the `transform` attribute with translateX and translateY custom
  3985. * attributes to align this elements rather than `x` and `y` attributes.
  3986. *
  3987. * @name Highcharts.AlignObject#alignByTranslate
  3988. * @type {boolean|undefined}
  3989. *
  3990. * @default false
  3991. */
  3992. /**
  3993. * Bounding box of an element.
  3994. *
  3995. * @interface Highcharts.BBoxObject
  3996. * @extends Highcharts.PositionObject
  3997. */ /**
  3998. * Height of the bounding box.
  3999. *
  4000. * @name Highcharts.BBoxObject#height
  4001. * @type {number}
  4002. */ /**
  4003. * Width of the bounding box.
  4004. *
  4005. * @name Highcharts.BBoxObject#width
  4006. * @type {number}
  4007. */ /**
  4008. * Horizontal position of the bounding box.
  4009. *
  4010. * @name Highcharts.BBoxObject#x
  4011. * @type {number}
  4012. */ /**
  4013. * Vertical position of the bounding box.
  4014. *
  4015. * @name Highcharts.BBoxObject#y
  4016. * @type {number}
  4017. */
  4018. /**
  4019. * An object of key-value pairs for SVG attributes. Attributes in Highcharts
  4020. * elements for the most parts correspond to SVG, but some are specific to
  4021. * Highcharts, like `zIndex`, `rotation`, `rotationOriginX`,
  4022. * `rotationOriginY`, `translateX`, `translateY`, `scaleX` and `scaleY`. SVG
  4023. * attributes containing a hyphen are _not_ camel-cased, they should be
  4024. * quoted to preserve the hyphen.
  4025. *
  4026. * @example
  4027. * {
  4028. * 'stroke': '#ff0000', // basic
  4029. * 'stroke-width': 2, // hyphenated
  4030. * 'rotation': 45 // custom
  4031. * 'd': ['M', 10, 10, 'L', 30, 30, 'z'] // path definition, note format
  4032. * }
  4033. *
  4034. * @interface Highcharts.SVGAttributes
  4035. */ /**
  4036. * @name Highcharts.SVGAttributes#[key:string]
  4037. * @type {*}
  4038. */ /**
  4039. * @name Highcharts.SVGAttributes#d
  4040. * @type {string|Highcharts.SVGPathArray|undefined}
  4041. */ /**
  4042. * @name Highcharts.SVGAttributes#fill
  4043. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject|undefined}
  4044. */ /**
  4045. * @name Highcharts.SVGAttributes#inverted
  4046. * @type {boolean|undefined}
  4047. */ /**
  4048. * @name Highcharts.SVGAttributes#matrix
  4049. * @type {Array<number>|undefined}
  4050. */ /**
  4051. * @name Highcharts.SVGAttributes#rotation
  4052. * @type {number|undefined}
  4053. */ /**
  4054. * @name Highcharts.SVGAttributes#rotationOriginX
  4055. * @type {number|undefined}
  4056. */ /**
  4057. * @name Highcharts.SVGAttributes#rotationOriginY
  4058. * @type {number|undefined}
  4059. */ /**
  4060. * @name Highcharts.SVGAttributes#scaleX
  4061. * @type {number|undefined}
  4062. */ /**
  4063. * @name Highcharts.SVGAttributes#scaleY
  4064. * @type {number|undefined}
  4065. */ /**
  4066. * @name Highcharts.SVGAttributes#stroke
  4067. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject|undefined}
  4068. */ /**
  4069. * @name Highcharts.SVGAttributes#style
  4070. * @type {string|Highcharts.CSSObject|undefined}
  4071. */ /**
  4072. * @name Highcharts.SVGAttributes#translateX
  4073. * @type {number|undefined}
  4074. */ /**
  4075. * @name Highcharts.SVGAttributes#translateY
  4076. * @type {number|undefined}
  4077. */ /**
  4078. * @name Highcharts.SVGAttributes#zIndex
  4079. * @type {number|undefined}
  4080. */
  4081. /**
  4082. * An SVG DOM element. The type is a reference to the regular SVGElement in the
  4083. * global scope.
  4084. *
  4085. * @typedef {globals.GlobalSVGElement} Highcharts.SVGDOMElement
  4086. *
  4087. * @see https://developer.mozilla.org/en-US/docs/Web/API/SVGElement
  4088. */
  4089. /**
  4090. * The vertical alignment of an element.
  4091. *
  4092. * @typedef {"bottom"|"middle"|"top"} Highcharts.VerticalAlignValue
  4093. */
  4094. ''; // detach doclets above
  4095. /* eslint-disable no-invalid-this, valid-jsdoc */
  4096. /**
  4097. * The SVGElement prototype is a JavaScript wrapper for SVG elements used in the
  4098. * rendering layer of Highcharts. Combined with the
  4099. * {@link Highcharts.SVGRenderer}
  4100. * object, these prototypes allow freeform annotation in the charts or even in
  4101. * HTML pages without instanciating a chart. The SVGElement can also wrap HTML
  4102. * labels, when `text` or `label` elements are created with the `useHTML`
  4103. * parameter.
  4104. *
  4105. * The SVGElement instances are created through factory functions on the
  4106. * {@link Highcharts.SVGRenderer}
  4107. * object, like
  4108. * {@link Highcharts.SVGRenderer#rect|rect},
  4109. * {@link Highcharts.SVGRenderer#path|path},
  4110. * {@link Highcharts.SVGRenderer#text|text},
  4111. * {@link Highcharts.SVGRenderer#label|label},
  4112. * {@link Highcharts.SVGRenderer#g|g}
  4113. * and more.
  4114. *
  4115. * @class
  4116. * @name Highcharts.SVGElement
  4117. */
  4118. var SVGElement = /** @class */ (function () {
  4119. function SVGElement() {
  4120. /* *
  4121. *
  4122. * Properties
  4123. *
  4124. * */
  4125. this.element = void 0;
  4126. this.height = void 0;
  4127. this.opacity = 1; // Default base for animation
  4128. this.renderer = void 0;
  4129. this.SVG_NS = SVG_NS;
  4130. // Custom attributes used for symbols, these should be filtered out when
  4131. // setting SVGElement attributes (#9375).
  4132. this.symbolCustomAttribs = [
  4133. 'x',
  4134. 'y',
  4135. 'width',
  4136. 'height',
  4137. 'r',
  4138. 'start',
  4139. 'end',
  4140. 'innerR',
  4141. 'anchorX',
  4142. 'anchorY',
  4143. 'rounded'
  4144. ];
  4145. this.width = void 0;
  4146. }
  4147. /* *
  4148. *
  4149. * Functions
  4150. *
  4151. * */
  4152. /**
  4153. * Get the current value of an attribute or pseudo attribute,
  4154. * used mainly for animation. Called internally from
  4155. * the {@link Highcharts.SVGRenderer#attr} function.
  4156. *
  4157. * @private
  4158. * @function Highcharts.SVGElement#_defaultGetter
  4159. *
  4160. * @param {string} key
  4161. * Property key.
  4162. *
  4163. * @return {number|string}
  4164. * Property value.
  4165. */
  4166. SVGElement.prototype._defaultGetter = function (key) {
  4167. var ret = pick(this[key + 'Value'], // align getter
  4168. this[key],
  4169. this.element ? this.element.getAttribute(key) : null, 0);
  4170. if (/^[\-0-9\.]+$/.test(ret)) { // is numerical
  4171. ret = parseFloat(ret);
  4172. }
  4173. return ret;
  4174. };
  4175. /**
  4176. * @private
  4177. * @function Highcharts.SVGElement#_defaultSetter
  4178. *
  4179. * @param {string} value
  4180. *
  4181. * @param {string} key
  4182. *
  4183. * @param {Highcharts.SVGDOMElement} element
  4184. *
  4185. * @return {void}
  4186. */
  4187. SVGElement.prototype._defaultSetter = function (value, key, element) {
  4188. element.setAttribute(key, value);
  4189. };
  4190. /**
  4191. * Add the element to the DOM. All elements must be added this way.
  4192. *
  4193. * @sample highcharts/members/renderer-g
  4194. * Elements added to a group
  4195. *
  4196. * @function Highcharts.SVGElement#add
  4197. *
  4198. * @param {Highcharts.SVGElement} [parent]
  4199. * The parent item to add it to. If undefined, the element is added
  4200. * to the {@link Highcharts.SVGRenderer.box}.
  4201. *
  4202. * @return {Highcharts.SVGElement}
  4203. * Returns the SVGElement for chaining.
  4204. */
  4205. SVGElement.prototype.add = function (parent) {
  4206. var renderer = this.renderer,
  4207. element = this.element,
  4208. inserted;
  4209. if (parent) {
  4210. this.parentGroup = parent;
  4211. }
  4212. // Mark as inverted
  4213. this.parentInverted = parent && parent.inverted;
  4214. // Build formatted text
  4215. if (typeof this.textStr !== 'undefined' &&
  4216. this.element.nodeName === 'text' // Not for SVGLabel instances
  4217. ) {
  4218. renderer.buildText(this);
  4219. }
  4220. // Mark as added
  4221. this.added = true;
  4222. // If we're adding to renderer root, or other elements in the group
  4223. // have a z index, we need to handle it
  4224. if (!parent || parent.handleZ || this.zIndex) {
  4225. inserted = this.zIndexSetter();
  4226. }
  4227. // If zIndex is not handled, append at the end
  4228. if (!inserted) {
  4229. (parent ?
  4230. parent.element :
  4231. renderer.box).appendChild(element);
  4232. }
  4233. // fire an event for internal hooks
  4234. if (this.onAdd) {
  4235. this.onAdd();
  4236. }
  4237. return this;
  4238. };
  4239. /**
  4240. * Add a class name to an element.
  4241. *
  4242. * @function Highcharts.SVGElement#addClass
  4243. *
  4244. * @param {string} className
  4245. * The new class name to add.
  4246. *
  4247. * @param {boolean} [replace=false]
  4248. * When true, the existing class name(s) will be overwritten with the new
  4249. * one. When false, the new one is added.
  4250. *
  4251. * @return {Highcharts.SVGElement}
  4252. * Return the SVG element for chainability.
  4253. */
  4254. SVGElement.prototype.addClass = function (className, replace) {
  4255. var currentClassName = replace ? '' : (this.attr('class') || '');
  4256. // Trim the string and remove duplicates
  4257. className = (className || '')
  4258. .split(/ /g)
  4259. .reduce(function (newClassName, name) {
  4260. if (currentClassName.indexOf(name) === -1) {
  4261. newClassName.push(name);
  4262. }
  4263. return newClassName;
  4264. }, (currentClassName ?
  4265. [currentClassName] :
  4266. []))
  4267. .join(' ');
  4268. if (className !== currentClassName) {
  4269. this.attr('class', className);
  4270. }
  4271. return this;
  4272. };
  4273. /**
  4274. * This method is executed in the end of `attr()`, after setting all
  4275. * attributes in the hash. In can be used to efficiently consolidate
  4276. * multiple attributes in one SVG property -- e.g., translate, rotate and
  4277. * scale are merged in one "transform" attribute in the SVG node.
  4278. *
  4279. * @private
  4280. * @function Highcharts.SVGElement#afterSetters
  4281. */
  4282. SVGElement.prototype.afterSetters = function () {
  4283. // Update transform. Do this outside the loop to prevent redundant
  4284. // updating for batch setting of attributes.
  4285. if (this.doTransform) {
  4286. this.updateTransform();
  4287. this.doTransform = false;
  4288. }
  4289. };
  4290. /**
  4291. * Align the element relative to the chart or another box.
  4292. *
  4293. * @function Highcharts.SVGElement#align
  4294. *
  4295. * @param {Highcharts.AlignObject} [alignOptions]
  4296. * The alignment options. The function can be called without this
  4297. * parameter in order to re-align an element after the box has been
  4298. * updated.
  4299. *
  4300. * @param {boolean} [alignByTranslate]
  4301. * Align element by translation.
  4302. *
  4303. * @param {string|Highcharts.BBoxObject} [box]
  4304. * The box to align to, needs a width and height. When the box is a
  4305. * string, it refers to an object in the Renderer. For example, when
  4306. * box is `spacingBox`, it refers to `Renderer.spacingBox` which
  4307. * holds `width`, `height`, `x` and `y` properties.
  4308. *
  4309. * @return {Highcharts.SVGElement} Returns the SVGElement for chaining.
  4310. */
  4311. SVGElement.prototype.align = function (alignOptions, alignByTranslate, box) {
  4312. var align,
  4313. vAlign,
  4314. x,
  4315. y,
  4316. attribs = {},
  4317. alignTo,
  4318. renderer = this.renderer,
  4319. alignedObjects = renderer.alignedObjects,
  4320. alignFactor,
  4321. vAlignFactor;
  4322. // First call on instanciate
  4323. if (alignOptions) {
  4324. this.alignOptions = alignOptions;
  4325. this.alignByTranslate = alignByTranslate;
  4326. if (!box || isString(box)) {
  4327. this.alignTo = alignTo = box || 'renderer';
  4328. // prevent duplicates, like legendGroup after resize
  4329. erase(alignedObjects, this);
  4330. alignedObjects.push(this);
  4331. box = void 0; // reassign it below
  4332. }
  4333. // When called on resize, no arguments are supplied
  4334. }
  4335. else {
  4336. alignOptions = this.alignOptions;
  4337. alignByTranslate = this.alignByTranslate;
  4338. alignTo = this.alignTo;
  4339. }
  4340. box = pick(box, renderer[alignTo], renderer);
  4341. // Assign variables
  4342. align = alignOptions.align;
  4343. vAlign = alignOptions.verticalAlign;
  4344. // default: left align
  4345. x = (box.x || 0) + (alignOptions.x || 0);
  4346. // default: top align
  4347. y = (box.y || 0) + (alignOptions.y || 0);
  4348. // Align
  4349. if (align === 'right') {
  4350. alignFactor = 1;
  4351. }
  4352. else if (align === 'center') {
  4353. alignFactor = 2;
  4354. }
  4355. if (alignFactor) {
  4356. x += (box.width - (alignOptions.width || 0)) /
  4357. alignFactor;
  4358. }
  4359. attribs[alignByTranslate ? 'translateX' : 'x'] = Math.round(x);
  4360. // Vertical align
  4361. if (vAlign === 'bottom') {
  4362. vAlignFactor = 1;
  4363. }
  4364. else if (vAlign === 'middle') {
  4365. vAlignFactor = 2;
  4366. }
  4367. if (vAlignFactor) {
  4368. y += (box.height - (alignOptions.height || 0)) /
  4369. vAlignFactor;
  4370. }
  4371. attribs[alignByTranslate ? 'translateY' : 'y'] = Math.round(y);
  4372. // Animate only if already placed
  4373. this[this.placed ? 'animate' : 'attr'](attribs);
  4374. this.placed = true;
  4375. this.alignAttr = attribs;
  4376. return this;
  4377. };
  4378. /**
  4379. * @private
  4380. * @function Highcharts.SVGElement#alignSetter
  4381. * @param {"left"|"center"|"right"} value
  4382. */
  4383. SVGElement.prototype.alignSetter = function (value) {
  4384. var convert = {
  4385. left: 'start',
  4386. center: 'middle',
  4387. right: 'end'
  4388. };
  4389. if (convert[value]) {
  4390. this.alignValue = value;
  4391. this.element.setAttribute('text-anchor', convert[value]);
  4392. }
  4393. };
  4394. /**
  4395. * Animate to given attributes or CSS properties.
  4396. *
  4397. * @sample highcharts/members/element-on/
  4398. * Setting some attributes by animation
  4399. *
  4400. * @function Highcharts.SVGElement#animate
  4401. *
  4402. * @param {Highcharts.SVGAttributes} params
  4403. * SVG attributes or CSS to animate.
  4404. *
  4405. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [options]
  4406. * Animation options.
  4407. *
  4408. * @param {Function} [complete]
  4409. * Function to perform at the end of animation.
  4410. *
  4411. * @return {Highcharts.SVGElement}
  4412. * Returns the SVGElement for chaining.
  4413. */
  4414. SVGElement.prototype.animate = function (params, options, complete) {
  4415. var _this = this;
  4416. var animOptions = animObject(pick(options,
  4417. this.renderer.globalAnimation,
  4418. true)),
  4419. deferTime = animOptions.defer;
  4420. // When the page is hidden save resources in the background by not
  4421. // running animation at all (#9749).
  4422. if (pick(doc.hidden, doc.msHidden, doc.webkitHidden, false)) {
  4423. animOptions.duration = 0;
  4424. }
  4425. if (animOptions.duration !== 0) {
  4426. // allows using a callback with the global animation without
  4427. // overwriting it
  4428. if (complete) {
  4429. animOptions.complete = complete;
  4430. }
  4431. // If defer option is defined delay the animation #12901
  4432. syncTimeout(function () {
  4433. if (_this.element) {
  4434. animate(_this, params, animOptions);
  4435. }
  4436. }, deferTime);
  4437. }
  4438. else {
  4439. this.attr(params, void 0, complete);
  4440. // Call the end step synchronously
  4441. objectEach(params, function (val, prop) {
  4442. if (animOptions.step) {
  4443. animOptions.step.call(this, val, { prop: prop, pos: 1, elem: this });
  4444. }
  4445. }, this);
  4446. }
  4447. return this;
  4448. };
  4449. /**
  4450. * Apply a text outline through a custom CSS property, by copying the text
  4451. * element and apply stroke to the copy. Used internally. Contrast checks at
  4452. * [example](https://jsfiddle.net/highcharts/43soe9m1/2/).
  4453. *
  4454. * @example
  4455. * // Specific color
  4456. * text.css({
  4457. * textOutline: '1px black'
  4458. * });
  4459. * // Automatic contrast
  4460. * text.css({
  4461. * color: '#000000', // black text
  4462. * textOutline: '1px contrast' // => white outline
  4463. * });
  4464. *
  4465. * @private
  4466. * @function Highcharts.SVGElement#applyTextOutline
  4467. *
  4468. * @param {string} textOutline
  4469. * A custom CSS `text-outline` setting, defined by `width color`.
  4470. */
  4471. SVGElement.prototype.applyTextOutline = function (textOutline) {
  4472. var elem = this.element,
  4473. hasContrast = textOutline.indexOf('contrast') !== -1,
  4474. styles = {};
  4475. // When the text shadow is set to contrast, use dark stroke for light
  4476. // text and vice versa.
  4477. if (hasContrast) {
  4478. styles.textOutline = textOutline = textOutline.replace(/contrast/g, this.renderer.getContrast(elem.style.fill));
  4479. }
  4480. // Extract the stroke width and color
  4481. var parts = textOutline.split(' ');
  4482. var color = parts[parts.length - 1];
  4483. var strokeWidth = parts[0];
  4484. if (strokeWidth && strokeWidth !== 'none' && H.svg) {
  4485. this.fakeTS = true; // Fake text shadow
  4486. // In order to get the right y position of the clone,
  4487. // copy over the y setter
  4488. this.ySetter = this.xSetter;
  4489. // Since the stroke is applied on center of the actual outline, we
  4490. // need to double it to get the correct stroke-width outside the
  4491. // glyphs.
  4492. strokeWidth = strokeWidth.replace(/(^[\d\.]+)(.*?)$/g, function (match, digit, unit) {
  4493. return (2 * Number(digit)) + unit;
  4494. });
  4495. // Remove shadows from previous runs.
  4496. this.removeTextOutline();
  4497. var outline_1 = doc.createElementNS(SVG_NS, 'tspan');
  4498. attr(outline_1, {
  4499. 'class': 'highcharts-text-outline',
  4500. fill: color,
  4501. stroke: color,
  4502. 'stroke-width': strokeWidth,
  4503. 'stroke-linejoin': 'round'
  4504. });
  4505. // For each of the tspans and text nodes, create a copy in the
  4506. // outline.
  4507. [].forEach.call(elem.childNodes, function (childNode) {
  4508. var clone = childNode.cloneNode(true);
  4509. if (clone.removeAttribute) {
  4510. ['fill', 'stroke', 'stroke-width', 'stroke'].forEach(function (prop) { return clone.removeAttribute(prop); });
  4511. }
  4512. outline_1.appendChild(clone);
  4513. });
  4514. // Insert an absolutely positioned break before the original text
  4515. // to keep it in place
  4516. var br = doc.createElementNS(SVG_NS, 'tspan');
  4517. br.textContent = '\u200B';
  4518. attr(br, {
  4519. x: elem.getAttribute('x'),
  4520. y: elem.getAttribute('y')
  4521. });
  4522. // Insert the outline
  4523. outline_1.appendChild(br);
  4524. elem.insertBefore(outline_1, elem.firstChild);
  4525. }
  4526. };
  4527. /**
  4528. * @function Highcharts.SVGElement#attr
  4529. * @param {string} key
  4530. * @return {number|string}
  4531. */ /**
  4532. * Apply native and custom attributes to the SVG elements.
  4533. *
  4534. * In order to set the rotation center for rotation, set x and y to 0 and
  4535. * use `translateX` and `translateY` attributes to position the element
  4536. * instead.
  4537. *
  4538. * Attributes frequently used in Highcharts are `fill`, `stroke`,
  4539. * `stroke-width`.
  4540. *
  4541. * @sample highcharts/members/renderer-rect/
  4542. * Setting some attributes
  4543. *
  4544. * @example
  4545. * // Set multiple attributes
  4546. * element.attr({
  4547. * stroke: 'red',
  4548. * fill: 'blue',
  4549. * x: 10,
  4550. * y: 10
  4551. * });
  4552. *
  4553. * // Set a single attribute
  4554. * element.attr('stroke', 'red');
  4555. *
  4556. * // Get an attribute
  4557. * element.attr('stroke'); // => 'red'
  4558. *
  4559. * @function Highcharts.SVGElement#attr
  4560. *
  4561. * @param {string|Highcharts.SVGAttributes} [hash]
  4562. * The native and custom SVG attributes.
  4563. *
  4564. * @param {number|string|Highcharts.SVGPathArray} [val]
  4565. * If the type of the first argument is `string`, the second can be a
  4566. * value, which will serve as a single attribute setter. If the first
  4567. * argument is a string and the second is undefined, the function
  4568. * serves as a getter and the current value of the property is
  4569. * returned.
  4570. *
  4571. * @param {Function} [complete]
  4572. * A callback function to execute after setting the attributes. This
  4573. * makes the function compliant and interchangeable with the
  4574. * {@link SVGElement#animate} function.
  4575. *
  4576. * @param {boolean} [continueAnimation=true]
  4577. * Used internally when `.attr` is called as part of an animation
  4578. * step. Otherwise, calling `.attr` for an attribute will stop
  4579. * animation for that attribute.
  4580. *
  4581. * @return {Highcharts.SVGElement}
  4582. * If used as a setter, it returns the current
  4583. * {@link Highcharts.SVGElement} so the calls can be chained. If
  4584. * used as a getter, the current value of the attribute is returned.
  4585. */
  4586. SVGElement.prototype.attr = function (hash, val, complete, continueAnimation) {
  4587. var key,
  4588. element = this.element,
  4589. hasSetSymbolSize,
  4590. ret = this,
  4591. skipAttr,
  4592. setter,
  4593. symbolCustomAttribs = this.symbolCustomAttribs;
  4594. // single key-value pair
  4595. if (typeof hash === 'string' && typeof val !== 'undefined') {
  4596. key = hash;
  4597. hash = {};
  4598. hash[key] = val;
  4599. }
  4600. // used as a getter: first argument is a string, second is undefined
  4601. if (typeof hash === 'string') {
  4602. ret = (this[hash + 'Getter'] ||
  4603. this._defaultGetter).call(this, hash, element);
  4604. // setter
  4605. }
  4606. else {
  4607. objectEach(hash, function eachAttribute(val, key) {
  4608. skipAttr = false;
  4609. // Unless .attr is from the animator update, stop current
  4610. // running animation of this property
  4611. if (!continueAnimation) {
  4612. stop(this, key);
  4613. }
  4614. // Special handling of symbol attributes
  4615. if (this.symbolName &&
  4616. symbolCustomAttribs.indexOf(key) !== -1) {
  4617. if (!hasSetSymbolSize) {
  4618. this.symbolAttr(hash);
  4619. hasSetSymbolSize = true;
  4620. }
  4621. skipAttr = true;
  4622. }
  4623. if (this.rotation && (key === 'x' || key === 'y')) {
  4624. this.doTransform = true;
  4625. }
  4626. if (!skipAttr) {
  4627. setter = (this[key + 'Setter'] ||
  4628. this._defaultSetter);
  4629. setter.call(this, val, key, element);
  4630. // Let the shadow follow the main element
  4631. if (!this.styledMode &&
  4632. this.shadows &&
  4633. /^(width|height|visibility|x|y|d|transform|cx|cy|r)$/.test(key)) {
  4634. this.updateShadows(key, val, setter);
  4635. }
  4636. }
  4637. }, this);
  4638. this.afterSetters();
  4639. }
  4640. // In accordance with animate, run a complete callback
  4641. if (complete) {
  4642. complete.call(this);
  4643. }
  4644. return ret;
  4645. };
  4646. /**
  4647. * Apply a clipping rectangle to this element.
  4648. *
  4649. * @function Highcharts.SVGElement#clip
  4650. *
  4651. * @param {Highcharts.ClipRectElement} [clipRect]
  4652. * The clipping rectangle. If skipped, the current clip is removed.
  4653. *
  4654. * @return {Highcharts.SVGElement}
  4655. * Returns the SVG element to allow chaining.
  4656. */
  4657. SVGElement.prototype.clip = function (clipRect) {
  4658. return this.attr('clip-path', clipRect ?
  4659. 'url(' + this.renderer.url + '#' + clipRect.id + ')' :
  4660. 'none');
  4661. };
  4662. /**
  4663. * Calculate the coordinates needed for drawing a rectangle crisply and
  4664. * return the calculated attributes.
  4665. *
  4666. * @function Highcharts.SVGElement#crisp
  4667. *
  4668. * @param {Highcharts.RectangleObject} rect
  4669. * Rectangle to crisp.
  4670. *
  4671. * @param {number} [strokeWidth]
  4672. * The stroke width to consider when computing crisp positioning. It can
  4673. * also be set directly on the rect parameter.
  4674. *
  4675. * @return {Highcharts.RectangleObject}
  4676. * The modified rectangle arguments.
  4677. */
  4678. SVGElement.prototype.crisp = function (rect, strokeWidth) {
  4679. var wrapper = this,
  4680. normalizer;
  4681. strokeWidth = strokeWidth || rect.strokeWidth || 0;
  4682. // Math.round because strokeWidth can sometimes have roundoff errors
  4683. normalizer = Math.round(strokeWidth) % 2 / 2;
  4684. // normalize for crisp edges
  4685. rect.x = Math.floor(rect.x || wrapper.x || 0) + normalizer;
  4686. rect.y = Math.floor(rect.y || wrapper.y || 0) + normalizer;
  4687. rect.width = Math.floor((rect.width || wrapper.width || 0) - 2 * normalizer);
  4688. rect.height = Math.floor((rect.height || wrapper.height || 0) - 2 * normalizer);
  4689. if (defined(rect.strokeWidth)) {
  4690. rect.strokeWidth = strokeWidth;
  4691. }
  4692. return rect;
  4693. };
  4694. /**
  4695. * Build and apply an SVG gradient out of a common JavaScript configuration
  4696. * object. This function is called from the attribute setters. An event
  4697. * hook is added for supporting other complex color types.
  4698. *
  4699. * @private
  4700. * @function Highcharts.SVGElement#complexColor
  4701. *
  4702. * @param {Highcharts.GradientColorObject|Highcharts.PatternObject} colorOptions
  4703. * The gradient or pattern options structure.
  4704. *
  4705. * @param {string} prop
  4706. * The property to apply, can either be `fill` or `stroke`.
  4707. *
  4708. * @param {Highcharts.SVGDOMElement} elem
  4709. * SVG element to apply the gradient on.
  4710. */
  4711. SVGElement.prototype.complexColor = function (colorOptions, prop, elem) {
  4712. var renderer = this.renderer,
  4713. colorObject,
  4714. gradName,
  4715. gradAttr,
  4716. radAttr,
  4717. gradients,
  4718. stops,
  4719. stopColor,
  4720. stopOpacity,
  4721. radialReference,
  4722. id,
  4723. key = [],
  4724. value;
  4725. fireEvent(this.renderer, 'complexColor', {
  4726. args: arguments
  4727. }, function () {
  4728. // Apply linear or radial gradients
  4729. if (colorOptions.radialGradient) {
  4730. gradName = 'radialGradient';
  4731. }
  4732. else if (colorOptions.linearGradient) {
  4733. gradName = 'linearGradient';
  4734. }
  4735. if (gradName) {
  4736. gradAttr = colorOptions[gradName];
  4737. gradients = renderer.gradients;
  4738. stops = colorOptions.stops;
  4739. radialReference = elem.radialReference;
  4740. // Keep < 2.2 kompatibility
  4741. if (isArray(gradAttr)) {
  4742. colorOptions[gradName] = gradAttr = {
  4743. x1: gradAttr[0],
  4744. y1: gradAttr[1],
  4745. x2: gradAttr[2],
  4746. y2: gradAttr[3],
  4747. gradientUnits: 'userSpaceOnUse'
  4748. };
  4749. }
  4750. // Correct the radial gradient for the radial reference system
  4751. if (gradName === 'radialGradient' &&
  4752. radialReference &&
  4753. !defined(gradAttr.gradientUnits)) {
  4754. // Save the radial attributes for updating
  4755. radAttr = gradAttr;
  4756. gradAttr = merge(gradAttr, renderer.getRadialAttr(radialReference, radAttr), { gradientUnits: 'userSpaceOnUse' });
  4757. }
  4758. // Build the unique key to detect whether we need to create a
  4759. // new element (#1282)
  4760. objectEach(gradAttr, function (val, n) {
  4761. if (n !== 'id') {
  4762. key.push(n, val);
  4763. }
  4764. });
  4765. objectEach(stops, function (val) {
  4766. key.push(val);
  4767. });
  4768. key = key.join(',');
  4769. // Check if a gradient object with the same config object is
  4770. // created within this renderer
  4771. if (gradients[key]) {
  4772. id = gradients[key].attr('id');
  4773. }
  4774. else {
  4775. // Set the id and create the element
  4776. gradAttr.id = id = uniqueKey();
  4777. var gradientObject_1 = gradients[key] =
  4778. renderer.createElement(gradName)
  4779. .attr(gradAttr)
  4780. .add(renderer.defs);
  4781. gradientObject_1.radAttr = radAttr;
  4782. // The gradient needs to keep a list of stops to be able to
  4783. // destroy them
  4784. gradientObject_1.stops = [];
  4785. stops.forEach(function (stop) {
  4786. var stopObject;
  4787. if (stop[1].indexOf('rgba') === 0) {
  4788. colorObject = Color.parse(stop[1]);
  4789. stopColor = colorObject.get('rgb');
  4790. stopOpacity = colorObject.get('a');
  4791. }
  4792. else {
  4793. stopColor = stop[1];
  4794. stopOpacity = 1;
  4795. }
  4796. stopObject = renderer.createElement('stop').attr({
  4797. offset: stop[0],
  4798. 'stop-color': stopColor,
  4799. 'stop-opacity': stopOpacity
  4800. }).add(gradientObject_1);
  4801. // Add the stop element to the gradient
  4802. gradientObject_1.stops.push(stopObject);
  4803. });
  4804. }
  4805. // Set the reference to the gradient object
  4806. value = 'url(' + renderer.url + '#' + id + ')';
  4807. elem.setAttribute(prop, value);
  4808. elem.gradient = key;
  4809. // Allow the color to be concatenated into tooltips formatters
  4810. // etc. (#2995)
  4811. colorOptions.toString = function () {
  4812. return value;
  4813. };
  4814. }
  4815. });
  4816. };
  4817. /**
  4818. * Set styles for the element. In addition to CSS styles supported by
  4819. * native SVG and HTML elements, there are also some custom made for
  4820. * Highcharts, like `width`, `ellipsis` and `textOverflow` for SVG text
  4821. * elements.
  4822. *
  4823. * @sample highcharts/members/renderer-text-on-chart/
  4824. * Styled text
  4825. *
  4826. * @function Highcharts.SVGElement#css
  4827. *
  4828. * @param {Highcharts.CSSObject} styles
  4829. * The new CSS styles.
  4830. *
  4831. * @return {Highcharts.SVGElement}
  4832. * Return the SVG element for chaining.
  4833. */
  4834. SVGElement.prototype.css = function (styles) {
  4835. var oldStyles = this.styles, newStyles = {}, elem = this.element, textWidth, serializedCss = '', hyphenate, hasNew = !oldStyles,
  4836. // These CSS properties are interpreted internally by the SVG
  4837. // renderer, but are not supported by SVG and should not be added to
  4838. // the DOM. In styled mode, no CSS should find its way to the DOM
  4839. // whatsoever (#6173, #6474).
  4840. svgPseudoProps = ['textOutline', 'textOverflow', 'width'];
  4841. // convert legacy
  4842. if (styles && styles.color) {
  4843. styles.fill = styles.color;
  4844. }
  4845. // Filter out existing styles to increase performance (#2640)
  4846. if (oldStyles) {
  4847. objectEach(styles, function (style, n) {
  4848. if (oldStyles && oldStyles[n] !== style) {
  4849. newStyles[n] = style;
  4850. hasNew = true;
  4851. }
  4852. });
  4853. }
  4854. if (hasNew) {
  4855. // Merge the new styles with the old ones
  4856. if (oldStyles) {
  4857. styles = extend(oldStyles, newStyles);
  4858. }
  4859. // Get the text width from style
  4860. if (styles) {
  4861. // Previously set, unset it (#8234)
  4862. if (styles.width === null || styles.width === 'auto') {
  4863. delete this.textWidth;
  4864. // Apply new
  4865. }
  4866. else if (elem.nodeName.toLowerCase() === 'text' &&
  4867. styles.width) {
  4868. textWidth = this.textWidth = pInt(styles.width);
  4869. }
  4870. }
  4871. // store object
  4872. this.styles = styles;
  4873. if (textWidth && (!svg && this.renderer.forExport)) {
  4874. delete styles.width;
  4875. }
  4876. // Serialize and set style attribute
  4877. if (elem.namespaceURI === this.SVG_NS) { // #7633
  4878. hyphenate = function (a, b) {
  4879. return '-' + b.toLowerCase();
  4880. };
  4881. objectEach(styles, function (style, n) {
  4882. if (svgPseudoProps.indexOf(n) === -1) {
  4883. serializedCss +=
  4884. n.replace(/([A-Z])/g, hyphenate) + ':' +
  4885. style + ';';
  4886. }
  4887. });
  4888. if (serializedCss) {
  4889. attr(elem, 'style', serializedCss); // #1881
  4890. }
  4891. }
  4892. else {
  4893. css(elem, styles);
  4894. }
  4895. if (this.added) {
  4896. // Rebuild text after added. Cache mechanisms in the buildText
  4897. // will prevent building if there are no significant changes.
  4898. if (this.element.nodeName === 'text') {
  4899. this.renderer.buildText(this);
  4900. }
  4901. // Apply text outline after added
  4902. if (styles && styles.textOutline) {
  4903. this.applyTextOutline(styles.textOutline);
  4904. }
  4905. }
  4906. }
  4907. return this;
  4908. };
  4909. /**
  4910. * @private
  4911. * @function Highcharts.SVGElement#dashstyleSetter
  4912. * @param {string} value
  4913. */
  4914. SVGElement.prototype.dashstyleSetter = function (value) {
  4915. var i,
  4916. strokeWidth = this['stroke-width'];
  4917. // If "inherit", like maps in IE, assume 1 (#4981). With HC5 and the new
  4918. // strokeWidth function, we should be able to use that instead.
  4919. if (strokeWidth === 'inherit') {
  4920. strokeWidth = 1;
  4921. }
  4922. value = value && value.toLowerCase();
  4923. if (value) {
  4924. var v = value
  4925. .replace('shortdashdotdot', '3,1,1,1,1,1,')
  4926. .replace('shortdashdot', '3,1,1,1')
  4927. .replace('shortdot', '1,1,')
  4928. .replace('shortdash', '3,1,')
  4929. .replace('longdash', '8,3,')
  4930. .replace(/dot/g, '1,3,')
  4931. .replace('dash', '4,3,')
  4932. .replace(/,$/, '')
  4933. .split(','); // ending comma
  4934. i = v.length;
  4935. while (i--) {
  4936. v[i] = '' + (pInt(v[i]) * pick(strokeWidth, NaN));
  4937. }
  4938. value = v.join(',').replace(/NaN/g, 'none'); // #3226
  4939. this.element.setAttribute('stroke-dasharray', value);
  4940. }
  4941. };
  4942. /**
  4943. * Destroy the element and element wrapper and clear up the DOM and event
  4944. * hooks.
  4945. *
  4946. * @function Highcharts.SVGElement#destroy
  4947. */
  4948. SVGElement.prototype.destroy = function () {
  4949. var wrapper = this,
  4950. element = wrapper.element || {},
  4951. renderer = wrapper.renderer,
  4952. parentToClean = (renderer.isSVG &&
  4953. element.nodeName === 'SPAN' &&
  4954. wrapper.parentGroup ||
  4955. void 0),
  4956. grandParent,
  4957. ownerSVGElement = element.ownerSVGElement,
  4958. i;
  4959. // remove events
  4960. element.onclick = element.onmouseout = element.onmouseover =
  4961. element.onmousemove = element.point = null;
  4962. stop(wrapper); // stop running animations
  4963. if (wrapper.clipPath && ownerSVGElement) {
  4964. var clipPath_1 = wrapper.clipPath;
  4965. // Look for existing references to this clipPath and remove them
  4966. // before destroying the element (#6196).
  4967. // The upper case version is for Edge
  4968. [].forEach.call(ownerSVGElement.querySelectorAll('[clip-path],[CLIP-PATH]'), function (el) {
  4969. var clipPathAttr = el.getAttribute('clip-path');
  4970. if (clipPathAttr.indexOf(clipPath_1.element.id) > -1) {
  4971. el.removeAttribute('clip-path');
  4972. }
  4973. });
  4974. wrapper.clipPath = clipPath_1.destroy();
  4975. }
  4976. // Destroy stops in case this is a gradient object @todo old code?
  4977. if (wrapper.stops) {
  4978. for (i = 0; i < wrapper.stops.length; i++) {
  4979. wrapper.stops[i].destroy();
  4980. }
  4981. wrapper.stops.length = 0;
  4982. wrapper.stops = void 0;
  4983. }
  4984. // remove element
  4985. wrapper.safeRemoveChild(element);
  4986. if (!renderer.styledMode) {
  4987. wrapper.destroyShadows();
  4988. }
  4989. // In case of useHTML, clean up empty containers emulating SVG groups
  4990. // (#1960, #2393, #2697).
  4991. while (parentToClean &&
  4992. parentToClean.div &&
  4993. parentToClean.div.childNodes.length === 0) {
  4994. grandParent = parentToClean.parentGroup;
  4995. wrapper.safeRemoveChild(parentToClean.div);
  4996. delete parentToClean.div;
  4997. parentToClean = grandParent;
  4998. }
  4999. // remove from alignObjects
  5000. if (wrapper.alignTo) {
  5001. erase(renderer.alignedObjects, wrapper);
  5002. }
  5003. objectEach(wrapper, function (val, key) {
  5004. // Destroy child elements of a group
  5005. if (wrapper[key] &&
  5006. wrapper[key].parentGroup === wrapper &&
  5007. wrapper[key].destroy) {
  5008. wrapper[key].destroy();
  5009. }
  5010. // Delete all properties
  5011. delete wrapper[key];
  5012. });
  5013. return;
  5014. };
  5015. /**
  5016. * Destroy shadows on the element.
  5017. *
  5018. * @private
  5019. * @function Highcharts.SVGElement#destroyShadows
  5020. *
  5021. * @return {void}
  5022. */
  5023. SVGElement.prototype.destroyShadows = function () {
  5024. (this.shadows || []).forEach(function (shadow) {
  5025. this.safeRemoveChild(shadow);
  5026. }, this);
  5027. this.shadows = void 0;
  5028. };
  5029. /**
  5030. * @private
  5031. */
  5032. SVGElement.prototype.destroyTextPath = function (elem, path) {
  5033. var textElement = elem.getElementsByTagName('text')[0];
  5034. var childNodes;
  5035. if (textElement) {
  5036. // Remove textPath attributes
  5037. textElement.removeAttribute('dx');
  5038. textElement.removeAttribute('dy');
  5039. // Remove ID's:
  5040. path.element.setAttribute('id', '');
  5041. // Check if textElement includes textPath,
  5042. if (this.textPathWrapper &&
  5043. textElement.getElementsByTagName('textPath').length) {
  5044. // Move nodes to <text>
  5045. childNodes = this.textPathWrapper.element.childNodes;
  5046. // Now move all <tspan>'s and text nodes to the <textPath> node
  5047. while (childNodes.length) {
  5048. textElement.appendChild(childNodes[0]);
  5049. }
  5050. // Remove <textPath> from the DOM
  5051. textElement.removeChild(this.textPathWrapper.element);
  5052. }
  5053. }
  5054. else if (elem.getAttribute('dx') || elem.getAttribute('dy')) {
  5055. // Remove textPath attributes from elem
  5056. // to get correct text-outline position
  5057. elem.removeAttribute('dx');
  5058. elem.removeAttribute('dy');
  5059. }
  5060. if (this.textPathWrapper) {
  5061. // Set textPathWrapper to undefined and destroy it
  5062. this.textPathWrapper = this.textPathWrapper.destroy();
  5063. }
  5064. };
  5065. /**
  5066. * @private
  5067. * @function Highcharts.SVGElement#dSettter
  5068. * @param {number|string|Highcharts.SVGPathArray} value
  5069. * @param {string} key
  5070. * @param {Highcharts.SVGDOMElement} element
  5071. */
  5072. SVGElement.prototype.dSetter = function (value, key, element) {
  5073. if (isArray(value)) {
  5074. // Backwards compatibility, convert one-dimensional array into an
  5075. // array of segments
  5076. if (typeof value[0] === 'string') {
  5077. value = this.renderer.pathToSegments(value);
  5078. }
  5079. this.pathArray = value;
  5080. value = value.reduce(function (acc, seg, i) {
  5081. if (!seg || !seg.join) {
  5082. return (seg || '').toString();
  5083. }
  5084. return (i ? acc + ' ' : '') + seg.join(' ');
  5085. }, '');
  5086. }
  5087. if (/(NaN| {2}|^$)/.test(value)) {
  5088. value = 'M 0 0';
  5089. }
  5090. // Check for cache before resetting. Resetting causes disturbance in the
  5091. // DOM, causing flickering in some cases in Edge/IE (#6747). Also
  5092. // possible performance gain.
  5093. if (this[key] !== value) {
  5094. element.setAttribute(key, value);
  5095. this[key] = value;
  5096. }
  5097. };
  5098. /**
  5099. * Fade out an element by animating its opacity down to 0, and hide it on
  5100. * complete. Used internally for the tooltip.
  5101. *
  5102. * @function Highcharts.SVGElement#fadeOut
  5103. *
  5104. * @param {number} [duration=150]
  5105. * The fade duration in milliseconds.
  5106. */
  5107. SVGElement.prototype.fadeOut = function (duration) {
  5108. var elemWrapper = this;
  5109. elemWrapper.animate({
  5110. opacity: 0
  5111. }, {
  5112. duration: pick(duration, 150),
  5113. complete: function () {
  5114. // #3088, assuming we're only using this for tooltips
  5115. elemWrapper.attr({ y: -9999 }).hide();
  5116. }
  5117. });
  5118. };
  5119. /**
  5120. * @private
  5121. * @function Highcharts.SVGElement#fillSetter
  5122. * @param {Highcharts.ColorType} value
  5123. * @param {string} key
  5124. * @param {Highcharts.SVGDOMElement} element
  5125. */
  5126. SVGElement.prototype.fillSetter = function (value, key, element) {
  5127. if (typeof value === 'string') {
  5128. element.setAttribute(key, value);
  5129. }
  5130. else if (value) {
  5131. this.complexColor(value, key, element);
  5132. }
  5133. };
  5134. /**
  5135. * Get the bounding box (width, height, x and y) for the element. Generally
  5136. * used to get rendered text size. Since this is called a lot in charts,
  5137. * the results are cached based on text properties, in order to save DOM
  5138. * traffic. The returned bounding box includes the rotation, so for example
  5139. * a single text line of rotation 90 will report a greater height, and a
  5140. * width corresponding to the line-height.
  5141. *
  5142. * @sample highcharts/members/renderer-on-chart/
  5143. * Draw a rectangle based on a text's bounding box
  5144. *
  5145. * @function Highcharts.SVGElement#getBBox
  5146. *
  5147. * @param {boolean} [reload]
  5148. * Skip the cache and get the updated DOM bouding box.
  5149. *
  5150. * @param {number} [rot]
  5151. * Override the element's rotation. This is internally used on axis
  5152. * labels with a value of 0 to find out what the bounding box would
  5153. * be have been if it were not rotated.
  5154. *
  5155. * @return {Highcharts.BBoxObject}
  5156. * The bounding box with `x`, `y`, `width` and `height` properties.
  5157. */
  5158. SVGElement.prototype.getBBox = function (reload, rot) {
  5159. var wrapper = this,
  5160. bBox, // = wrapper.bBox,
  5161. renderer = wrapper.renderer,
  5162. width,
  5163. height,
  5164. element = wrapper.element,
  5165. styles = wrapper.styles,
  5166. fontSize,
  5167. textStr = wrapper.textStr,
  5168. toggleTextShadowShim,
  5169. cache = renderer.cache,
  5170. cacheKeys = renderer.cacheKeys,
  5171. isSVG = element.namespaceURI === wrapper.SVG_NS,
  5172. cacheKey;
  5173. var rotation = pick(rot,
  5174. wrapper.rotation, 0);
  5175. fontSize = renderer.styledMode ? (element &&
  5176. SVGElement.prototype.getStyle.call(element, 'font-size')) : (styles && styles.fontSize);
  5177. // Avoid undefined and null (#7316)
  5178. if (defined(textStr)) {
  5179. cacheKey = textStr.toString();
  5180. // Since numbers are monospaced, and numerical labels appear a lot
  5181. // in a chart, we assume that a label of n characters has the same
  5182. // bounding box as others of the same length. Unless there is inner
  5183. // HTML in the label. In that case, leave the numbers as is (#5899).
  5184. if (cacheKey.indexOf('<') === -1) {
  5185. cacheKey = cacheKey.replace(/[0-9]/g, '0');
  5186. }
  5187. // Properties that affect bounding box
  5188. cacheKey += [
  5189. '',
  5190. rotation,
  5191. fontSize,
  5192. wrapper.textWidth,
  5193. styles && styles.textOverflow,
  5194. styles && styles.fontWeight // #12163
  5195. ].join(',');
  5196. }
  5197. if (cacheKey && !reload) {
  5198. bBox = cache[cacheKey];
  5199. }
  5200. // No cache found
  5201. if (!bBox) {
  5202. // SVG elements
  5203. if (isSVG || renderer.forExport) {
  5204. try { // Fails in Firefox if the container has display: none.
  5205. // When the text shadow shim is used, we need to hide the
  5206. // fake shadows to get the correct bounding box (#3872)
  5207. toggleTextShadowShim = this.fakeTS && function (display) {
  5208. var outline = element.querySelector('.highcharts-text-outline');
  5209. if (outline) {
  5210. css(outline, { display: display });
  5211. }
  5212. };
  5213. // Workaround for #3842, Firefox reporting wrong bounding
  5214. // box for shadows
  5215. if (isFunction(toggleTextShadowShim)) {
  5216. toggleTextShadowShim('none');
  5217. }
  5218. bBox = element.getBBox ?
  5219. // SVG: use extend because IE9 is not allowed to change
  5220. // width and height in case of rotation (below)
  5221. extend({}, element.getBBox()) : {
  5222. // Legacy IE in export mode
  5223. width: element.offsetWidth,
  5224. height: element.offsetHeight
  5225. };
  5226. // #3842
  5227. if (isFunction(toggleTextShadowShim)) {
  5228. toggleTextShadowShim('');
  5229. }
  5230. }
  5231. catch (e) {
  5232. '';
  5233. }
  5234. // If the bBox is not set, the try-catch block above failed. The
  5235. // other condition is for Opera that returns a width of
  5236. // -Infinity on hidden elements.
  5237. if (!bBox || bBox.width < 0) {
  5238. bBox = { width: 0, height: 0 };
  5239. }
  5240. // VML Renderer or useHTML within SVG
  5241. }
  5242. else {
  5243. bBox = wrapper.htmlGetBBox();
  5244. }
  5245. // True SVG elements as well as HTML elements in modern browsers
  5246. // using the .useHTML option need to compensated for rotation
  5247. if (renderer.isSVG) {
  5248. width = bBox.width;
  5249. height = bBox.height;
  5250. // Workaround for wrong bounding box in IE, Edge and Chrome on
  5251. // Windows. With Highcharts' default font, IE and Edge report
  5252. // a box height of 16.899 and Chrome rounds it to 17. If this
  5253. // stands uncorrected, it results in more padding added below
  5254. // the text than above when adding a label border or background.
  5255. // Also vertical positioning is affected.
  5256. // https://jsfiddle.net/highcharts/em37nvuj/
  5257. // (#1101, #1505, #1669, #2568, #6213).
  5258. if (isSVG) {
  5259. bBox.height = height = ({
  5260. '11px,17': 14,
  5261. '13px,20': 16
  5262. }[styles &&
  5263. styles.fontSize + ',' + Math.round(height)] ||
  5264. height);
  5265. }
  5266. // Adjust for rotated text
  5267. if (rotation) {
  5268. var rad = rotation * deg2rad;
  5269. bBox.width = Math.abs(height * Math.sin(rad)) +
  5270. Math.abs(width * Math.cos(rad));
  5271. bBox.height = Math.abs(height * Math.cos(rad)) +
  5272. Math.abs(width * Math.sin(rad));
  5273. }
  5274. }
  5275. // Cache it. When loading a chart in a hidden iframe in Firefox and
  5276. // IE/Edge, the bounding box height is 0, so don't cache it (#5620).
  5277. if (cacheKey && bBox.height > 0) {
  5278. // Rotate (#4681)
  5279. while (cacheKeys.length > 250) {
  5280. delete cache[cacheKeys.shift()];
  5281. }
  5282. if (!cache[cacheKey]) {
  5283. cacheKeys.push(cacheKey);
  5284. }
  5285. cache[cacheKey] = bBox;
  5286. }
  5287. }
  5288. return bBox;
  5289. };
  5290. /**
  5291. * Get the computed style. Only in styled mode.
  5292. *
  5293. * @example
  5294. * chart.series[0].points[0].graphic.getStyle('stroke-width'); // => '1px'
  5295. *
  5296. * @function Highcharts.SVGElement#getStyle
  5297. *
  5298. * @param {string} prop
  5299. * The property name to check for.
  5300. *
  5301. * @return {string}
  5302. * The current computed value.
  5303. */
  5304. SVGElement.prototype.getStyle = function (prop) {
  5305. return win
  5306. .getComputedStyle(this.element || this, '')
  5307. .getPropertyValue(prop);
  5308. };
  5309. /**
  5310. * Check if an element has the given class name.
  5311. *
  5312. * @function Highcharts.SVGElement#hasClass
  5313. *
  5314. * @param {string} className
  5315. * The class name to check for.
  5316. *
  5317. * @return {boolean}
  5318. * Whether the class name is found.
  5319. */
  5320. SVGElement.prototype.hasClass = function (className) {
  5321. return ('' + this.attr('class'))
  5322. .split(' ')
  5323. .indexOf(className) !== -1;
  5324. };
  5325. /**
  5326. * Hide the element, similar to setting the `visibility` attribute to
  5327. * `hidden`.
  5328. *
  5329. * @function Highcharts.SVGElement#hide
  5330. *
  5331. * @param {boolean} [hideByTranslation=false]
  5332. * The flag to determine if element should be hidden by moving out
  5333. * of the viewport. Used for example for dataLabels.
  5334. *
  5335. * @return {Highcharts.SVGElement}
  5336. * Returns the SVGElement for chaining.
  5337. */
  5338. SVGElement.prototype.hide = function (hideByTranslation) {
  5339. if (hideByTranslation) {
  5340. this.attr({ y: -9999 });
  5341. }
  5342. else {
  5343. this.attr({ visibility: 'hidden' });
  5344. }
  5345. return this;
  5346. };
  5347. /**
  5348. * @private
  5349. */
  5350. SVGElement.prototype.htmlGetBBox = function () {
  5351. return { height: 0, width: 0, x: 0, y: 0 };
  5352. };
  5353. /**
  5354. * Initialize the SVG element. This function only exists to make the
  5355. * initialization process overridable. It should not be called directly.
  5356. *
  5357. * @function Highcharts.SVGElement#init
  5358. *
  5359. * @param {Highcharts.SVGRenderer} renderer
  5360. * The SVGRenderer instance to initialize to.
  5361. *
  5362. * @param {string} nodeName
  5363. * The SVG node name.
  5364. */
  5365. SVGElement.prototype.init = function (renderer, nodeName) {
  5366. /**
  5367. * The primary DOM node. Each `SVGElement` instance wraps a main DOM
  5368. * node, but may also represent more nodes.
  5369. *
  5370. * @name Highcharts.SVGElement#element
  5371. * @type {Highcharts.SVGDOMElement|Highcharts.HTMLDOMElement}
  5372. */
  5373. this.element = nodeName === 'span' ?
  5374. createElement(nodeName) :
  5375. doc.createElementNS(this.SVG_NS, nodeName);
  5376. /**
  5377. * The renderer that the SVGElement belongs to.
  5378. *
  5379. * @name Highcharts.SVGElement#renderer
  5380. * @type {Highcharts.SVGRenderer}
  5381. */
  5382. this.renderer = renderer;
  5383. fireEvent(this, 'afterInit');
  5384. };
  5385. /**
  5386. * Invert a group, rotate and flip. This is used internally on inverted
  5387. * charts, where the points and graphs are drawn as if not inverted, then
  5388. * the series group elements are inverted.
  5389. *
  5390. * @function Highcharts.SVGElement#invert
  5391. *
  5392. * @param {boolean} inverted
  5393. * Whether to invert or not. An inverted shape can be un-inverted by
  5394. * setting it to false.
  5395. *
  5396. * @return {Highcharts.SVGElement}
  5397. * Return the SVGElement for chaining.
  5398. */
  5399. SVGElement.prototype.invert = function (inverted) {
  5400. var wrapper = this;
  5401. wrapper.inverted = inverted;
  5402. wrapper.updateTransform();
  5403. return wrapper;
  5404. };
  5405. /**
  5406. * Add an event listener. This is a simple setter that replaces all other
  5407. * events of the same type, opposed to the {@link Highcharts#addEvent}
  5408. * function.
  5409. *
  5410. * @sample highcharts/members/element-on/
  5411. * A clickable rectangle
  5412. *
  5413. * @function Highcharts.SVGElement#on
  5414. *
  5415. * @param {string} eventType
  5416. * The event type. If the type is `click`, Highcharts will internally
  5417. * translate it to a `touchstart` event on touch devices, to prevent the
  5418. * browser from waiting for a click event from firing.
  5419. *
  5420. * @param {Function} handler
  5421. * The handler callback.
  5422. *
  5423. * @return {Highcharts.SVGElement}
  5424. * The SVGElement for chaining.
  5425. */
  5426. SVGElement.prototype.on = function (eventType, handler) {
  5427. var svgElement = this,
  5428. element = svgElement.element,
  5429. touchStartPos,
  5430. touchEventFired;
  5431. // touch
  5432. if (hasTouch && eventType === 'click') {
  5433. element.ontouchstart = function (e) {
  5434. // save touch position for later calculation
  5435. touchStartPos = {
  5436. clientX: e.touches[0].clientX,
  5437. clientY: e.touches[0].clientY
  5438. };
  5439. };
  5440. // Instead of ontouchstart, event handlers should be called
  5441. // on touchend - similar to how current mouseup events are called
  5442. element.ontouchend = function (e) {
  5443. // hasMoved is a boolean variable containing logic if page
  5444. // was scrolled, so if touch position changed more than
  5445. // ~4px (value borrowed from general touch handler)
  5446. var hasMoved = touchStartPos.clientX ? Math.sqrt(Math.pow(touchStartPos.clientX - e.changedTouches[0].clientX, 2) +
  5447. Math.pow(touchStartPos.clientY - e.changedTouches[0].clientY, 2)) >= 4 : false;
  5448. if (!hasMoved) { // only call handlers if page was not scrolled
  5449. handler.call(element, e);
  5450. }
  5451. touchEventFired = true;
  5452. if (e.cancelable !== false) {
  5453. // prevent other events from being fired. #9682
  5454. e.preventDefault();
  5455. }
  5456. };
  5457. element.onclick = function (e) {
  5458. // Do not call onclick handler if touch event was fired already.
  5459. if (!touchEventFired) {
  5460. handler.call(element, e);
  5461. }
  5462. };
  5463. }
  5464. else {
  5465. // simplest possible event model for internal use
  5466. element['on' + eventType] = handler;
  5467. }
  5468. return this;
  5469. };
  5470. /**
  5471. * @private
  5472. * @function Highcharts.SVGElement#opacitySetter
  5473. * @param {string} value
  5474. * @param {string} key
  5475. * @param {Highcharts.SVGDOMElement} element
  5476. */
  5477. SVGElement.prototype.opacitySetter = function (value, key, element) {
  5478. // Round off to avoid float errors, like tests where opacity lands on
  5479. // 9.86957e-06 instead of 0
  5480. var opacity = Number(Number(value).toFixed(3));
  5481. this.opacity = opacity;
  5482. element.setAttribute(key, opacity);
  5483. };
  5484. /**
  5485. * Remove a class name from the element.
  5486. *
  5487. * @function Highcharts.SVGElement#removeClass
  5488. *
  5489. * @param {string|RegExp} className
  5490. * The class name to remove.
  5491. *
  5492. * @return {Highcharts.SVGElement} Returns the SVG element for chainability.
  5493. */
  5494. SVGElement.prototype.removeClass = function (className) {
  5495. return this.attr('class', ('' + this.attr('class'))
  5496. .replace(isString(className) ?
  5497. new RegExp("(^| )" + className + "( |$)") : // #12064, #13590
  5498. className, ' ')
  5499. .replace(/ +/g, ' ')
  5500. .trim());
  5501. };
  5502. /**
  5503. *
  5504. * @private
  5505. */
  5506. SVGElement.prototype.removeTextOutline = function () {
  5507. var outline = this.element
  5508. .querySelector('tspan.highcharts-text-outline');
  5509. if (outline) {
  5510. this.safeRemoveChild(outline);
  5511. }
  5512. };
  5513. /**
  5514. * Removes an element from the DOM.
  5515. *
  5516. * @private
  5517. * @function Highcharts.SVGElement#safeRemoveChild
  5518. *
  5519. * @param {Highcharts.SVGDOMElement|Highcharts.HTMLDOMElement} element
  5520. * The DOM node to remove.
  5521. */
  5522. SVGElement.prototype.safeRemoveChild = function (element) {
  5523. var parentNode = element.parentNode;
  5524. if (parentNode) {
  5525. parentNode.removeChild(element);
  5526. }
  5527. };
  5528. /**
  5529. * Set the coordinates needed to draw a consistent radial gradient across
  5530. * a shape regardless of positioning inside the chart. Used on pie slices
  5531. * to make all the slices have the same radial reference point.
  5532. *
  5533. * @function Highcharts.SVGElement#setRadialReference
  5534. *
  5535. * @param {Array<number>} coordinates
  5536. * The center reference. The format is `[centerX, centerY, diameter]` in
  5537. * pixels.
  5538. *
  5539. * @return {Highcharts.SVGElement}
  5540. * Returns the SVGElement for chaining.
  5541. */
  5542. SVGElement.prototype.setRadialReference = function (coordinates) {
  5543. var existingGradient = (this.element.gradient &&
  5544. this.renderer.gradients[this.element.gradient]);
  5545. this.element.radialReference = coordinates;
  5546. // On redrawing objects with an existing gradient, the gradient needs
  5547. // to be repositioned (#3801)
  5548. if (existingGradient && existingGradient.radAttr) {
  5549. existingGradient.animate(this.renderer.getRadialAttr(coordinates, existingGradient.radAttr));
  5550. }
  5551. return this;
  5552. };
  5553. /**
  5554. * @private
  5555. * @function Highcharts.SVGElement#setTextPath
  5556. * @param {Highcharts.SVGElement} path
  5557. * Path to follow.
  5558. * @param {Highcharts.DataLabelsTextPathOptionsObject} textPathOptions
  5559. * Options.
  5560. * @return {Highcharts.SVGElement}
  5561. * Returns the SVGElement for chaining.
  5562. */
  5563. SVGElement.prototype.setTextPath = function (path, textPathOptions) {
  5564. var elem = this.element,
  5565. textNode = this.text ? this.text.element : elem,
  5566. attribsMap = {
  5567. textAnchor: 'text-anchor'
  5568. },
  5569. attrs,
  5570. adder = false,
  5571. textPathElement,
  5572. textPathId,
  5573. textPathWrapper = this.textPathWrapper,
  5574. firstTime = !textPathWrapper;
  5575. // Defaults
  5576. textPathOptions = merge(true, {
  5577. enabled: true,
  5578. attributes: {
  5579. dy: -5,
  5580. startOffset: '50%',
  5581. textAnchor: 'middle'
  5582. }
  5583. }, textPathOptions);
  5584. attrs = AST.filterUserAttributes(textPathOptions.attributes);
  5585. if (path && textPathOptions && textPathOptions.enabled) {
  5586. // In case of fixed width for a text, string is rebuilt
  5587. // (e.g. ellipsis is applied), so we need to rebuild textPath too
  5588. if (textPathWrapper &&
  5589. textPathWrapper.element.parentNode === null) {
  5590. // When buildText functionality was triggered again
  5591. // and deletes textPathWrapper parentNode
  5592. firstTime = true;
  5593. textPathWrapper = textPathWrapper.destroy();
  5594. }
  5595. else if (textPathWrapper) {
  5596. // Case after drillup when spans were added into
  5597. // the DOM outside the textPathWrapper parentGroup
  5598. this.removeTextOutline.call(textPathWrapper.parentGroup);
  5599. }
  5600. // label() has padding, text() doesn't
  5601. if (this.options && this.options.padding) {
  5602. attrs.dx = -this.options.padding;
  5603. }
  5604. if (!textPathWrapper) {
  5605. // Create <textPath>, defer the DOM adder
  5606. this.textPathWrapper = textPathWrapper =
  5607. this.renderer.createElement('textPath');
  5608. adder = true;
  5609. }
  5610. textPathElement = textPathWrapper.element;
  5611. // Set ID for the path
  5612. textPathId = path.element.getAttribute('id');
  5613. if (!textPathId) {
  5614. path.element.setAttribute('id', textPathId = uniqueKey());
  5615. }
  5616. // Change DOM structure, by placing <textPath> tag in <text>
  5617. if (firstTime) {
  5618. // Adjust the position
  5619. textNode.setAttribute('y', 0); // Firefox
  5620. if (isNumber(attrs.dx)) {
  5621. textNode.setAttribute('x', -attrs.dx);
  5622. }
  5623. // Move all <tspan>'s and text nodes to the <textPath> node. Do
  5624. // not move other elements like <title> or <path>
  5625. var childNodes = [].slice.call(textNode.childNodes);
  5626. for (var i = 0; i < childNodes.length; i++) {
  5627. var childNode = childNodes[i];
  5628. if (childNode.nodeType === Node.TEXT_NODE ||
  5629. childNode.nodeName === 'tspan') {
  5630. textPathElement.appendChild(childNode);
  5631. }
  5632. }
  5633. }
  5634. // Add <textPath> to the DOM
  5635. if (adder && textPathWrapper) {
  5636. textPathWrapper.add({ element: textNode });
  5637. }
  5638. // Set basic options:
  5639. // Use `setAttributeNS` because Safari needs this..
  5640. textPathElement.setAttributeNS('http://www.w3.org/1999/xlink', 'href', this.renderer.url + '#' + textPathId);
  5641. // Presentation attributes:
  5642. // dx/dy options must by set on <text> (parent),
  5643. // the rest should be set on <textPath>
  5644. if (defined(attrs.dy)) {
  5645. textPathElement.parentNode
  5646. .setAttribute('dy', attrs.dy);
  5647. delete attrs.dy;
  5648. }
  5649. if (defined(attrs.dx)) {
  5650. textPathElement.parentNode
  5651. .setAttribute('dx', attrs.dx);
  5652. delete attrs.dx;
  5653. }
  5654. // Additional attributes
  5655. objectEach(attrs, function (val, key) {
  5656. textPathElement.setAttribute(attribsMap[key] || key, val);
  5657. });
  5658. // Remove translation, text that follows path does not need that
  5659. elem.removeAttribute('transform');
  5660. // Remove shadows and text outlines
  5661. this.removeTextOutline.call(textPathWrapper);
  5662. // Remove background and border for label(), see #10545
  5663. // Alternatively, we can disable setting background rects in
  5664. // series.drawDataLabels()
  5665. if (this.text && !this.renderer.styledMode) {
  5666. this.attr({
  5667. fill: 'none',
  5668. 'stroke-width': 0
  5669. });
  5670. }
  5671. // Disable some functions
  5672. this.updateTransform = noop;
  5673. this.applyTextOutline = noop;
  5674. }
  5675. else if (textPathWrapper) {
  5676. // Reset to prototype
  5677. delete this.updateTransform;
  5678. delete this.applyTextOutline;
  5679. // Restore DOM structure:
  5680. this.destroyTextPath(elem, path);
  5681. // Bring attributes back
  5682. this.updateTransform();
  5683. // Set textOutline back for text()
  5684. if (this.options && this.options.rotation) {
  5685. this.applyTextOutline(this.options.style.textOutline);
  5686. }
  5687. }
  5688. return this;
  5689. };
  5690. /**
  5691. * Add a shadow to the element. Must be called after the element is added to
  5692. * the DOM. In styled mode, this method is not used, instead use `defs` and
  5693. * filters.
  5694. *
  5695. * @example
  5696. * renderer.rect(10, 100, 100, 100)
  5697. * .attr({ fill: 'red' })
  5698. * .shadow(true);
  5699. *
  5700. * @function Highcharts.SVGElement#shadow
  5701. *
  5702. * @param {boolean|Highcharts.ShadowOptionsObject} [shadowOptions]
  5703. * The shadow options. If `true`, the default options are applied. If
  5704. * `false`, the current shadow will be removed.
  5705. *
  5706. * @param {Highcharts.SVGElement} [group]
  5707. * The SVG group element where the shadows will be applied. The
  5708. * default is to add it to the same parent as the current element.
  5709. * Internally, this is ised for pie slices, where all the shadows are
  5710. * added to an element behind all the slices.
  5711. *
  5712. * @param {boolean} [cutOff]
  5713. * Used internally for column shadows.
  5714. *
  5715. * @return {Highcharts.SVGElement}
  5716. * Returns the SVGElement for chaining.
  5717. */
  5718. SVGElement.prototype.shadow = function (shadowOptions, group, cutOff) {
  5719. var shadows = [],
  5720. i,
  5721. shadow,
  5722. element = this.element,
  5723. strokeWidth,
  5724. shadowElementOpacity,
  5725. update = false,
  5726. oldShadowOptions = this.oldShadowOptions,
  5727. // compensate for inverted plot area
  5728. transform;
  5729. var defaultShadowOptions = {
  5730. color: palette.neutralColor100,
  5731. offsetX: 1,
  5732. offsetY: 1,
  5733. opacity: 0.15,
  5734. width: 3
  5735. };
  5736. var options;
  5737. if (shadowOptions === true) {
  5738. options = defaultShadowOptions;
  5739. }
  5740. else if (typeof shadowOptions === 'object') {
  5741. options = extend(defaultShadowOptions, shadowOptions);
  5742. }
  5743. // Update shadow when options change (#12091).
  5744. if (options) {
  5745. // Go over each key to look for change
  5746. if (options && oldShadowOptions) {
  5747. objectEach(options, function (value, key) {
  5748. if (value !== oldShadowOptions[key]) {
  5749. update = true;
  5750. }
  5751. });
  5752. }
  5753. if (update) {
  5754. this.destroyShadows();
  5755. }
  5756. this.oldShadowOptions = options;
  5757. }
  5758. if (!options) {
  5759. this.destroyShadows();
  5760. }
  5761. else if (!this.shadows) {
  5762. shadowElementOpacity = options.opacity / options.width;
  5763. transform = this.parentInverted ?
  5764. 'translate(-1,-1)' :
  5765. "translate(" + options.offsetX + ", " + options.offsetY + ")";
  5766. for (i = 1; i <= options.width; i++) {
  5767. shadow = element.cloneNode(false);
  5768. strokeWidth = (options.width * 2) + 1 - (2 * i);
  5769. attr(shadow, {
  5770. stroke: (shadowOptions.color ||
  5771. palette.neutralColor100),
  5772. 'stroke-opacity': shadowElementOpacity * i,
  5773. 'stroke-width': strokeWidth,
  5774. transform: transform,
  5775. fill: 'none'
  5776. });
  5777. shadow.setAttribute('class', (shadow.getAttribute('class') || '') + ' highcharts-shadow');
  5778. if (cutOff) {
  5779. attr(shadow, 'height', Math.max(attr(shadow, 'height') - strokeWidth, 0));
  5780. shadow.cutHeight = strokeWidth;
  5781. }
  5782. if (group) {
  5783. group.element.appendChild(shadow);
  5784. }
  5785. else if (element.parentNode) {
  5786. element.parentNode.insertBefore(shadow, element);
  5787. }
  5788. shadows.push(shadow);
  5789. }
  5790. this.shadows = shadows;
  5791. }
  5792. return this;
  5793. };
  5794. /**
  5795. * Show the element after it has been hidden.
  5796. *
  5797. * @function Highcharts.SVGElement#show
  5798. *
  5799. * @param {boolean} [inherit=false]
  5800. * Set the visibility attribute to `inherit` rather than `visible`.
  5801. * The difference is that an element with `visibility="visible"`
  5802. * will be visible even if the parent is hidden.
  5803. *
  5804. * @return {Highcharts.SVGElement}
  5805. * Returns the SVGElement for chaining.
  5806. */
  5807. SVGElement.prototype.show = function (inherit) {
  5808. return this.attr({ visibility: inherit ? 'inherit' : 'visible' });
  5809. };
  5810. /**
  5811. * WebKit and Batik have problems with a stroke-width of zero, so in this
  5812. * case we remove the stroke attribute altogether. #1270, #1369, #3065,
  5813. * #3072.
  5814. *
  5815. * @private
  5816. * @function Highcharts.SVGElement#strokeSetter
  5817. * @param {number|string} value
  5818. * @param {string} key
  5819. * @param {Highcharts.SVGDOMElement} element
  5820. */
  5821. SVGElement.prototype.strokeSetter = function (value, key, element) {
  5822. this[key] = value;
  5823. // Only apply the stroke attribute if the stroke width is defined and
  5824. // larger than 0
  5825. if (this.stroke && this['stroke-width']) {
  5826. // Use prototype as instance may be overridden
  5827. SVGElement.prototype.fillSetter.call(this, this.stroke, 'stroke', element);
  5828. element.setAttribute('stroke-width', this['stroke-width']);
  5829. this.hasStroke = true;
  5830. }
  5831. else if (key === 'stroke-width' && value === 0 && this.hasStroke) {
  5832. element.removeAttribute('stroke');
  5833. this.hasStroke = false;
  5834. }
  5835. else if (this.renderer.styledMode && this['stroke-width']) {
  5836. element.setAttribute('stroke-width', this['stroke-width']);
  5837. this.hasStroke = true;
  5838. }
  5839. };
  5840. /**
  5841. * Get the computed stroke width in pixel values. This is used extensively
  5842. * when drawing shapes to ensure the shapes are rendered crisp and
  5843. * positioned correctly relative to each other. Using
  5844. * `shape-rendering: crispEdges` leaves us less control over positioning,
  5845. * for example when we want to stack columns next to each other, or position
  5846. * things pixel-perfectly within the plot box.
  5847. *
  5848. * The common pattern when placing a shape is:
  5849. * - Create the SVGElement and add it to the DOM. In styled mode, it will
  5850. * now receive a stroke width from the style sheet. In classic mode we
  5851. * will add the `stroke-width` attribute.
  5852. * - Read the computed `elem.strokeWidth()`.
  5853. * - Place it based on the stroke width.
  5854. *
  5855. * @function Highcharts.SVGElement#strokeWidth
  5856. *
  5857. * @return {number}
  5858. * The stroke width in pixels. Even if the given stroke widtch (in CSS or by
  5859. * attributes) is based on `em` or other units, the pixel size is returned.
  5860. */
  5861. SVGElement.prototype.strokeWidth = function () {
  5862. // In non-styled mode, read the stroke width as set by .attr
  5863. if (!this.renderer.styledMode) {
  5864. return this['stroke-width'] || 0;
  5865. }
  5866. // In styled mode, read computed stroke width
  5867. var val = this.getStyle('stroke-width'),
  5868. ret = 0,
  5869. dummy;
  5870. // Read pixel values directly
  5871. if (val.indexOf('px') === val.length - 2) {
  5872. ret = pInt(val);
  5873. // Other values like em, pt etc need to be measured
  5874. }
  5875. else if (val !== '') {
  5876. dummy = doc.createElementNS(SVG_NS, 'rect');
  5877. attr(dummy, {
  5878. width: val,
  5879. 'stroke-width': 0
  5880. });
  5881. this.element.parentNode.appendChild(dummy);
  5882. ret = dummy.getBBox().width;
  5883. dummy.parentNode.removeChild(dummy);
  5884. }
  5885. return ret;
  5886. };
  5887. /**
  5888. * If one of the symbol size affecting parameters are changed,
  5889. * check all the others only once for each call to an element's
  5890. * .attr() method
  5891. *
  5892. * @private
  5893. * @function Highcharts.SVGElement#symbolAttr
  5894. *
  5895. * @param {Highcharts.SVGAttributes} hash
  5896. * The attributes to set.
  5897. */
  5898. SVGElement.prototype.symbolAttr = function (hash) {
  5899. var wrapper = this;
  5900. [
  5901. 'x',
  5902. 'y',
  5903. 'r',
  5904. 'start',
  5905. 'end',
  5906. 'width',
  5907. 'height',
  5908. 'innerR',
  5909. 'anchorX',
  5910. 'anchorY',
  5911. 'clockwise'
  5912. ].forEach(function (key) {
  5913. wrapper[key] = pick(hash[key], wrapper[key]);
  5914. });
  5915. wrapper.attr({
  5916. d: wrapper.renderer.symbols[wrapper.symbolName](wrapper.x, wrapper.y, wrapper.width, wrapper.height, wrapper)
  5917. });
  5918. };
  5919. /**
  5920. * @private
  5921. * @function Highcharts.SVGElement#textSetter
  5922. * @param {string} value
  5923. */
  5924. SVGElement.prototype.textSetter = function (value) {
  5925. if (value !== this.textStr) {
  5926. // Delete size caches when the text changes
  5927. // delete this.bBox; // old code in series-label
  5928. delete this.textPxLength;
  5929. this.textStr = value;
  5930. if (this.added) {
  5931. this.renderer.buildText(this);
  5932. }
  5933. }
  5934. };
  5935. /**
  5936. * @private
  5937. * @function Highcharts.SVGElement#titleSetter
  5938. * @param {string} value
  5939. */
  5940. SVGElement.prototype.titleSetter = function (value) {
  5941. var el = this.element;
  5942. var titleNode = el.getElementsByTagName('title')[0] ||
  5943. doc.createElementNS(this.SVG_NS, 'title');
  5944. // Move to first child
  5945. if (el.insertBefore) {
  5946. el.insertBefore(titleNode, el.firstChild);
  5947. }
  5948. else {
  5949. el.appendChild(titleNode);
  5950. }
  5951. // Replace text content and escape markup
  5952. titleNode.textContent =
  5953. // #3276, #3895
  5954. String(pick(value, ''))
  5955. .replace(/<[^>]*>/g, '')
  5956. .replace(/&lt;/g, '<')
  5957. .replace(/&gt;/g, '>');
  5958. };
  5959. /**
  5960. * Bring the element to the front. Alternatively, a new zIndex can be set.
  5961. *
  5962. * @sample highcharts/members/element-tofront/
  5963. * Click an element to bring it to front
  5964. *
  5965. * @function Highcharts.SVGElement#toFront
  5966. *
  5967. * @return {Highcharts.SVGElement}
  5968. * Returns the SVGElement for chaining.
  5969. */
  5970. SVGElement.prototype.toFront = function () {
  5971. var element = this.element;
  5972. element.parentNode.appendChild(element);
  5973. return this;
  5974. };
  5975. /**
  5976. * Move an object and its children by x and y values.
  5977. *
  5978. * @function Highcharts.SVGElement#translate
  5979. *
  5980. * @param {number} x
  5981. * The x value.
  5982. *
  5983. * @param {number} y
  5984. * The y value.
  5985. *
  5986. * @return {Highcharts.SVGElement}
  5987. */
  5988. SVGElement.prototype.translate = function (x, y) {
  5989. return this.attr({
  5990. translateX: x,
  5991. translateY: y
  5992. });
  5993. };
  5994. /**
  5995. * Update the shadow elements with new attributes.
  5996. *
  5997. * @private
  5998. * @function Highcharts.SVGElement#updateShadows
  5999. *
  6000. * @param {string} key
  6001. * The attribute name.
  6002. *
  6003. * @param {number} value
  6004. * The value of the attribute.
  6005. *
  6006. * @param {Function} setter
  6007. * The setter function, inherited from the parent wrapper.
  6008. */
  6009. SVGElement.prototype.updateShadows = function (key, value, setter) {
  6010. var shadows = this.shadows;
  6011. if (shadows) {
  6012. var i = shadows.length;
  6013. while (i--) {
  6014. setter.call(shadows[i], key === 'height' ?
  6015. Math.max(value - (shadows[i].cutHeight || 0), 0) :
  6016. key === 'd' ? this.d : value, key, shadows[i]);
  6017. }
  6018. }
  6019. };
  6020. /**
  6021. * Update the transform attribute based on internal properties. Deals with
  6022. * the custom `translateX`, `translateY`, `rotation`, `scaleX` and `scaleY`
  6023. * attributes and updates the SVG `transform` attribute.
  6024. *
  6025. * @private
  6026. * @function Highcharts.SVGElement#updateTransform
  6027. */
  6028. SVGElement.prototype.updateTransform = function () {
  6029. var wrapper = this,
  6030. translateX = wrapper.translateX || 0,
  6031. translateY = wrapper.translateY || 0,
  6032. scaleX = wrapper.scaleX,
  6033. scaleY = wrapper.scaleY,
  6034. inverted = wrapper.inverted,
  6035. rotation = wrapper.rotation,
  6036. matrix = wrapper.matrix,
  6037. element = wrapper.element,
  6038. transform;
  6039. // Flipping affects translate as adjustment for flipping around the
  6040. // group's axis
  6041. if (inverted) {
  6042. translateX += wrapper.width;
  6043. translateY += wrapper.height;
  6044. }
  6045. // Apply translate. Nearly all transformed elements have translation,
  6046. // so instead of checking for translate = 0, do it always (#1767,
  6047. // #1846).
  6048. transform = ['translate(' + translateX + ',' + translateY + ')'];
  6049. // apply matrix
  6050. if (defined(matrix)) {
  6051. transform.push('matrix(' + matrix.join(',') + ')');
  6052. }
  6053. // apply rotation
  6054. if (inverted) {
  6055. transform.push('rotate(90) scale(-1,1)');
  6056. }
  6057. else if (rotation) { // text rotation
  6058. transform.push('rotate(' + rotation + ' ' +
  6059. pick(this.rotationOriginX, element.getAttribute('x'), 0) +
  6060. ' ' +
  6061. pick(this.rotationOriginY, element.getAttribute('y') || 0) + ')');
  6062. }
  6063. // apply scale
  6064. if (defined(scaleX) || defined(scaleY)) {
  6065. transform.push('scale(' + pick(scaleX, 1) + ' ' + pick(scaleY, 1) + ')');
  6066. }
  6067. if (transform.length) {
  6068. element.setAttribute('transform', transform.join(' '));
  6069. }
  6070. };
  6071. /**
  6072. * @private
  6073. * @function Highcharts.SVGElement#visibilitySetter
  6074. *
  6075. * @param {string} value
  6076. *
  6077. * @param {string} key
  6078. *
  6079. * @param {Highcharts.SVGDOMElement} element
  6080. *
  6081. * @return {void}
  6082. */
  6083. SVGElement.prototype.visibilitySetter = function (value, key, element) {
  6084. // IE9-11 doesn't handle visibilty:inherit well, so we remove the
  6085. // attribute instead (#2881, #3909)
  6086. if (value === 'inherit') {
  6087. element.removeAttribute(key);
  6088. }
  6089. else if (this[key] !== value) { // #6747
  6090. element.setAttribute(key, value);
  6091. }
  6092. this[key] = value;
  6093. };
  6094. /**
  6095. * @private
  6096. * @function Highcharts.SVGElement#xGetter
  6097. *
  6098. * @param {string} key
  6099. *
  6100. * @return {number|string|null}
  6101. */
  6102. SVGElement.prototype.xGetter = function (key) {
  6103. if (this.element.nodeName === 'circle') {
  6104. if (key === 'x') {
  6105. key = 'cx';
  6106. }
  6107. else if (key === 'y') {
  6108. key = 'cy';
  6109. }
  6110. }
  6111. return this._defaultGetter(key);
  6112. };
  6113. /**
  6114. * @private
  6115. * @function Highcharts.SVGElement#zIndexSetter
  6116. * @param {number} [value]
  6117. * @param {string} [key]
  6118. * @return {boolean}
  6119. */
  6120. SVGElement.prototype.zIndexSetter = function (value, key) {
  6121. var renderer = this.renderer,
  6122. parentGroup = this.parentGroup,
  6123. parentWrapper = parentGroup || renderer,
  6124. parentNode = parentWrapper.element || renderer.box,
  6125. childNodes,
  6126. otherElement,
  6127. otherZIndex,
  6128. element = this.element,
  6129. inserted = false,
  6130. undefinedOtherZIndex,
  6131. svgParent = parentNode === renderer.box,
  6132. run = this.added,
  6133. i;
  6134. if (defined(value)) {
  6135. // So we can read it for other elements in the group
  6136. element.setAttribute('data-z-index', value);
  6137. value = +value;
  6138. if (this[key] === value) {
  6139. // Only update when needed (#3865)
  6140. run = false;
  6141. }
  6142. }
  6143. else if (defined(this[key])) {
  6144. element.removeAttribute('data-z-index');
  6145. }
  6146. this[key] = value;
  6147. // Insert according to this and other elements' zIndex. Before .add() is
  6148. // called, nothing is done. Then on add, or by later calls to
  6149. // zIndexSetter, the node is placed on the right place in the DOM.
  6150. if (run) {
  6151. value = this.zIndex;
  6152. if (value && parentGroup) {
  6153. parentGroup.handleZ = true;
  6154. }
  6155. childNodes = parentNode.childNodes;
  6156. for (i = childNodes.length - 1; i >= 0 && !inserted; i--) {
  6157. otherElement = childNodes[i];
  6158. otherZIndex = otherElement.getAttribute('data-z-index');
  6159. undefinedOtherZIndex = !defined(otherZIndex);
  6160. if (otherElement !== element) {
  6161. if (
  6162. // Negative zIndex versus no zIndex:
  6163. // On all levels except the highest. If the parent is
  6164. // <svg>, then we don't want to put items before <desc>
  6165. // or <defs>
  6166. value < 0 &&
  6167. undefinedOtherZIndex &&
  6168. !svgParent &&
  6169. !i) {
  6170. parentNode.insertBefore(element, childNodes[i]);
  6171. inserted = true;
  6172. }
  6173. else if (
  6174. // Insert after the first element with a lower zIndex
  6175. pInt(otherZIndex) <= value ||
  6176. // If negative zIndex, add this before first undefined
  6177. // zIndex element
  6178. (undefinedOtherZIndex &&
  6179. (!defined(value) || value >= 0))) {
  6180. parentNode.insertBefore(element, childNodes[i + 1] || null // null for oldIE export
  6181. );
  6182. inserted = true;
  6183. }
  6184. }
  6185. }
  6186. if (!inserted) {
  6187. parentNode.insertBefore(element, childNodes[svgParent ? 3 : 0] || null // null for oldIE
  6188. );
  6189. inserted = true;
  6190. }
  6191. }
  6192. return inserted;
  6193. };
  6194. return SVGElement;
  6195. }());
  6196. // Some shared setters and getters
  6197. SVGElement.prototype['stroke-widthSetter'] = SVGElement.prototype.strokeSetter;
  6198. SVGElement.prototype.yGetter = SVGElement.prototype.xGetter;
  6199. SVGElement.prototype.matrixSetter =
  6200. SVGElement.prototype.rotationOriginXSetter =
  6201. SVGElement.prototype.rotationOriginYSetter =
  6202. SVGElement.prototype.rotationSetter =
  6203. SVGElement.prototype.scaleXSetter =
  6204. SVGElement.prototype.scaleYSetter =
  6205. SVGElement.prototype.translateXSetter =
  6206. SVGElement.prototype.translateYSetter =
  6207. SVGElement.prototype.verticalAlignSetter = function (value, key) {
  6208. this[key] = value;
  6209. this.doTransform = true;
  6210. };
  6211. H.SVGElement = SVGElement;
  6212. return H.SVGElement;
  6213. });
  6214. _registerModule(_modules, 'Core/Renderer/SVG/SVGLabel.js', [_modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Utilities.js']], function (SVGElement, U) {
  6215. /* *
  6216. *
  6217. * (c) 2010-2021 Torstein Honsi
  6218. *
  6219. * License: www.highcharts.com/license
  6220. *
  6221. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  6222. *
  6223. * */
  6224. var __extends = (this && this.__extends) || (function () {
  6225. var extendStatics = function (d,
  6226. b) {
  6227. extendStatics = Object.setPrototypeOf ||
  6228. ({ __proto__: [] } instanceof Array && function (d,
  6229. b) { d.__proto__ = b; }) ||
  6230. function (d,
  6231. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  6232. return extendStatics(d, b);
  6233. };
  6234. return function (d, b) {
  6235. extendStatics(d, b);
  6236. function __() { this.constructor = d; }
  6237. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  6238. };
  6239. })();
  6240. var defined = U.defined,
  6241. extend = U.extend,
  6242. isNumber = U.isNumber,
  6243. merge = U.merge,
  6244. pick = U.pick,
  6245. removeEvent = U.removeEvent;
  6246. /* eslint require-jsdoc: 0, no-invalid-this: 0 */
  6247. function paddingSetter(value, key) {
  6248. if (!isNumber(value)) {
  6249. this[key] = void 0;
  6250. }
  6251. else if (value !== this[key]) {
  6252. this[key] = value;
  6253. this.updateTextPadding();
  6254. }
  6255. }
  6256. /**
  6257. * SVG label to render text.
  6258. * @private
  6259. * @class
  6260. * @name Highcharts.SVGLabel
  6261. * @augments Highcharts.SVGElement
  6262. */
  6263. var SVGLabel = /** @class */ (function (_super) {
  6264. __extends(SVGLabel, _super);
  6265. /* *
  6266. *
  6267. * Constructors
  6268. *
  6269. * */
  6270. function SVGLabel(renderer, str, x, y, shape, anchorX, anchorY, useHTML, baseline, className) {
  6271. var _this = _super.call(this) || this;
  6272. _this.paddingSetter = paddingSetter;
  6273. _this.paddingLeftSetter = paddingSetter;
  6274. _this.paddingRightSetter = paddingSetter;
  6275. _this.init(renderer, 'g');
  6276. _this.textStr = str;
  6277. _this.x = x;
  6278. _this.y = y;
  6279. _this.anchorX = anchorX;
  6280. _this.anchorY = anchorY;
  6281. _this.baseline = baseline;
  6282. _this.className = className;
  6283. if (className !== 'button') {
  6284. _this.addClass('highcharts-label');
  6285. }
  6286. if (className) {
  6287. _this.addClass('highcharts-' + className);
  6288. }
  6289. _this.text = renderer.text('', 0, 0, useHTML)
  6290. .attr({
  6291. zIndex: 1
  6292. });
  6293. // Validate the shape argument
  6294. var hasBGImage;
  6295. if (typeof shape === 'string') {
  6296. hasBGImage = /^url\((.*?)\)$/.test(shape);
  6297. if (_this.renderer.symbols[shape] || hasBGImage) {
  6298. _this.symbolKey = shape;
  6299. }
  6300. }
  6301. _this.bBox = SVGLabel.emptyBBox;
  6302. _this.padding = 3;
  6303. _this.baselineOffset = 0;
  6304. _this.needsBox = renderer.styledMode || hasBGImage;
  6305. _this.deferredAttr = {};
  6306. _this.alignFactor = 0;
  6307. return _this;
  6308. }
  6309. /* *
  6310. *
  6311. * Functions
  6312. *
  6313. * */
  6314. SVGLabel.prototype.alignSetter = function (value) {
  6315. var alignFactor = {
  6316. left: 0,
  6317. center: 0.5,
  6318. right: 1
  6319. }[value];
  6320. if (alignFactor !== this.alignFactor) {
  6321. this.alignFactor = alignFactor;
  6322. // Bounding box exists, means we're dynamically changing
  6323. if (this.bBox && isNumber(this.xSetting)) {
  6324. this.attr({ x: this.xSetting }); // #5134
  6325. }
  6326. }
  6327. };
  6328. SVGLabel.prototype.anchorXSetter = function (value, key) {
  6329. this.anchorX = value;
  6330. this.boxAttr(key, Math.round(value) - this.getCrispAdjust() - this.xSetting);
  6331. };
  6332. SVGLabel.prototype.anchorYSetter = function (value, key) {
  6333. this.anchorY = value;
  6334. this.boxAttr(key, value - this.ySetting);
  6335. };
  6336. /*
  6337. * Set a box attribute, or defer it if the box is not yet created
  6338. */
  6339. SVGLabel.prototype.boxAttr = function (key, value) {
  6340. if (this.box) {
  6341. this.box.attr(key, value);
  6342. }
  6343. else {
  6344. this.deferredAttr[key] = value;
  6345. }
  6346. };
  6347. /*
  6348. * Pick up some properties and apply them to the text instead of the
  6349. * wrapper.
  6350. */
  6351. SVGLabel.prototype.css = function (styles) {
  6352. if (styles) {
  6353. var textStyles = {},
  6354. isWidth,
  6355. isFontStyle;
  6356. // Create a copy to avoid altering the original object
  6357. // (#537)
  6358. styles = merge(styles);
  6359. SVGLabel.textProps.forEach(function (prop) {
  6360. if (typeof styles[prop] !== 'undefined') {
  6361. textStyles[prop] = styles[prop];
  6362. delete styles[prop];
  6363. }
  6364. });
  6365. this.text.css(textStyles);
  6366. isWidth = 'width' in textStyles;
  6367. isFontStyle = 'fontSize' in textStyles ||
  6368. 'fontWeight' in textStyles;
  6369. // Update existing text, box (#9400, #12163)
  6370. if (isFontStyle) {
  6371. this.updateTextPadding();
  6372. }
  6373. else if (isWidth) {
  6374. this.updateBoxSize();
  6375. }
  6376. }
  6377. return SVGElement.prototype.css.call(this, styles);
  6378. };
  6379. /*
  6380. * Destroy and release memory.
  6381. */
  6382. SVGLabel.prototype.destroy = function () {
  6383. // Added by button implementation
  6384. removeEvent(this.element, 'mouseenter');
  6385. removeEvent(this.element, 'mouseleave');
  6386. if (this.text) {
  6387. this.text.destroy();
  6388. }
  6389. if (this.box) {
  6390. this.box = this.box.destroy();
  6391. }
  6392. // Call base implementation to destroy the rest
  6393. SVGElement.prototype.destroy.call(this);
  6394. return void 0;
  6395. };
  6396. SVGLabel.prototype.fillSetter = function (value, key) {
  6397. if (value) {
  6398. this.needsBox = true;
  6399. }
  6400. // for animation getter (#6776)
  6401. this.fill = value;
  6402. this.boxAttr(key, value);
  6403. };
  6404. /*
  6405. * Return the bounding box of the box, not the group.
  6406. */
  6407. SVGLabel.prototype.getBBox = function () {
  6408. var bBox = this.bBox;
  6409. var padding = this.padding;
  6410. var paddingLeft = pick(this.paddingLeft,
  6411. padding);
  6412. return {
  6413. width: this.width,
  6414. height: this.height,
  6415. x: bBox.x - paddingLeft,
  6416. y: bBox.y - padding
  6417. };
  6418. };
  6419. SVGLabel.prototype.getCrispAdjust = function () {
  6420. return this.renderer.styledMode && this.box ?
  6421. this.box.strokeWidth() % 2 / 2 :
  6422. (this['stroke-width'] ? parseInt(this['stroke-width'], 10) : 0) % 2 / 2;
  6423. };
  6424. SVGLabel.prototype.heightSetter = function (value) {
  6425. this.heightSetting = value;
  6426. };
  6427. // Event handling. In case of useHTML, we need to make sure that events
  6428. // are captured on the span as well, and that mouseenter/mouseleave
  6429. // between the SVG group and the HTML span are not treated as real
  6430. // enter/leave events. #13310.
  6431. SVGLabel.prototype.on = function (eventType, handler) {
  6432. var label = this;
  6433. var text = label.text;
  6434. var span = text && text.element.tagName === 'SPAN' ? text : void 0;
  6435. var selectiveHandler;
  6436. if (span) {
  6437. selectiveHandler = function (e) {
  6438. if ((eventType === 'mouseenter' ||
  6439. eventType === 'mouseleave') &&
  6440. e.relatedTarget instanceof Element &&
  6441. (
  6442. // #14110
  6443. label.element.compareDocumentPosition(e.relatedTarget) & Node.DOCUMENT_POSITION_CONTAINED_BY ||
  6444. span.element.compareDocumentPosition(e.relatedTarget) & Node.DOCUMENT_POSITION_CONTAINED_BY)) {
  6445. return;
  6446. }
  6447. handler.call(label.element, e);
  6448. };
  6449. span.on(eventType, selectiveHandler);
  6450. }
  6451. SVGElement.prototype.on.call(label, eventType, selectiveHandler || handler);
  6452. return label;
  6453. };
  6454. /*
  6455. * After the text element is added, get the desired size of the border
  6456. * box and add it before the text in the DOM.
  6457. */
  6458. SVGLabel.prototype.onAdd = function () {
  6459. var str = this.textStr;
  6460. this.text.add(this);
  6461. this.attr({
  6462. // Alignment is available now (#3295, 0 not rendered if given
  6463. // as a value)
  6464. text: (defined(str) ? str : ''),
  6465. x: this.x,
  6466. y: this.y
  6467. });
  6468. if (this.box && defined(this.anchorX)) {
  6469. this.attr({
  6470. anchorX: this.anchorX,
  6471. anchorY: this.anchorY
  6472. });
  6473. }
  6474. };
  6475. SVGLabel.prototype.rSetter = function (value, key) {
  6476. this.boxAttr(key, value);
  6477. };
  6478. SVGLabel.prototype.shadow = function (b) {
  6479. if (b && !this.renderer.styledMode) {
  6480. this.updateBoxSize();
  6481. if (this.box) {
  6482. this.box.shadow(b);
  6483. }
  6484. }
  6485. return this;
  6486. };
  6487. SVGLabel.prototype.strokeSetter = function (value, key) {
  6488. // for animation getter (#6776)
  6489. this.stroke = value;
  6490. this.boxAttr(key, value);
  6491. };
  6492. SVGLabel.prototype['stroke-widthSetter'] = function (value, key) {
  6493. if (value) {
  6494. this.needsBox = true;
  6495. }
  6496. this['stroke-width'] = value;
  6497. this.boxAttr(key, value);
  6498. };
  6499. SVGLabel.prototype['text-alignSetter'] = function (value) {
  6500. this.textAlign = value;
  6501. };
  6502. SVGLabel.prototype.textSetter = function (text) {
  6503. if (typeof text !== 'undefined') {
  6504. // Must use .attr to ensure transforms are done (#10009)
  6505. this.text.attr({ text: text });
  6506. }
  6507. this.updateTextPadding();
  6508. };
  6509. /*
  6510. * This function runs after the label is added to the DOM (when the bounding
  6511. * box is available), and after the text of the label is updated to detect
  6512. * the new bounding box and reflect it in the border box.
  6513. */
  6514. SVGLabel.prototype.updateBoxSize = function () {
  6515. var style = this.text.element.style,
  6516. crispAdjust,
  6517. attribs = {};
  6518. var padding = this.padding;
  6519. // #12165 error when width is null (auto)
  6520. // #12163 when fontweight: bold, recalculate bBox withot cache
  6521. // #3295 && 3514 box failure when string equals 0
  6522. var bBox = this.bBox = ((!isNumber(this.widthSetting) || !isNumber(this.heightSetting) || this.textAlign) &&
  6523. defined(this.text.textStr)) ?
  6524. this.text.getBBox() : SVGLabel.emptyBBox;
  6525. this.width = this.getPaddedWidth();
  6526. this.height = (this.heightSetting || bBox.height || 0) + 2 * padding;
  6527. // Update the label-scoped y offset. Math.min because of inline
  6528. // style (#9400)
  6529. this.baselineOffset = padding + Math.min(this.renderer.fontMetrics(style && style.fontSize, this.text).b,
  6530. // When the height is 0, there is no bBox, so go with the font
  6531. // metrics. Highmaps CSS demos.
  6532. bBox.height || Infinity);
  6533. if (this.needsBox) {
  6534. // Create the border box if it is not already present
  6535. if (!this.box) {
  6536. // Symbol definition exists (#5324)
  6537. var box = this.box = this.symbolKey ?
  6538. this.renderer.symbol(this.symbolKey) :
  6539. this.renderer.rect();
  6540. box.addClass(// Don't use label className for buttons
  6541. (this.className === 'button' ? '' : 'highcharts-label-box') +
  6542. (this.className ? ' highcharts-' + this.className + '-box' : ''));
  6543. box.add(this);
  6544. }
  6545. crispAdjust = this.getCrispAdjust();
  6546. attribs.x = crispAdjust;
  6547. attribs.y = (this.baseline ? -this.baselineOffset : 0) + crispAdjust;
  6548. // Apply the box attributes
  6549. attribs.width = Math.round(this.width);
  6550. attribs.height = Math.round(this.height);
  6551. this.box.attr(extend(attribs, this.deferredAttr));
  6552. this.deferredAttr = {};
  6553. }
  6554. };
  6555. /*
  6556. * This function runs after setting text or padding, but only if padding
  6557. * is changed.
  6558. */
  6559. SVGLabel.prototype.updateTextPadding = function () {
  6560. var text = this.text;
  6561. this.updateBoxSize();
  6562. // Determine y based on the baseline
  6563. var textY = this.baseline ? 0 : this.baselineOffset;
  6564. var textX = pick(this.paddingLeft,
  6565. this.padding);
  6566. // compensate for alignment
  6567. if (defined(this.widthSetting) &&
  6568. this.bBox &&
  6569. (this.textAlign === 'center' || this.textAlign === 'right')) {
  6570. textX += { center: 0.5, right: 1 }[this.textAlign] *
  6571. (this.widthSetting - this.bBox.width);
  6572. }
  6573. // update if anything changed
  6574. if (textX !== text.x || textY !== text.y) {
  6575. text.attr('x', textX);
  6576. // #8159 - prevent misplaced data labels in treemap
  6577. // (useHTML: true)
  6578. if (text.hasBoxWidthChanged) {
  6579. this.bBox = text.getBBox(true);
  6580. }
  6581. if (typeof textY !== 'undefined') {
  6582. text.attr('y', textY);
  6583. }
  6584. }
  6585. // record current values
  6586. text.x = textX;
  6587. text.y = textY;
  6588. };
  6589. SVGLabel.prototype.widthSetter = function (value) {
  6590. // width:auto => null
  6591. this.widthSetting = isNumber(value) ? value : void 0;
  6592. };
  6593. SVGLabel.prototype.getPaddedWidth = function () {
  6594. var padding = this.padding;
  6595. var paddingLeft = pick(this.paddingLeft,
  6596. padding);
  6597. var paddingRight = pick(this.paddingRight,
  6598. padding);
  6599. return (this.widthSetting || this.bBox.width || 0) + paddingLeft + paddingRight;
  6600. };
  6601. SVGLabel.prototype.xSetter = function (value) {
  6602. this.x = value; // for animation getter
  6603. if (this.alignFactor) {
  6604. value -= this.alignFactor * this.getPaddedWidth();
  6605. // Force animation even when setting to the same value (#7898)
  6606. this['forceAnimate:x'] = true;
  6607. }
  6608. this.xSetting = Math.round(value);
  6609. this.attr('translateX', this.xSetting);
  6610. };
  6611. SVGLabel.prototype.ySetter = function (value) {
  6612. this.ySetting = this.y = Math.round(value);
  6613. this.attr('translateY', this.ySetting);
  6614. };
  6615. /* *
  6616. *
  6617. * Static Properties
  6618. *
  6619. * */
  6620. SVGLabel.emptyBBox = { width: 0, height: 0, x: 0, y: 0 };
  6621. /* *
  6622. *
  6623. * Properties
  6624. *
  6625. * */
  6626. /**
  6627. * For labels, these CSS properties are applied to the `text` node directly.
  6628. *
  6629. * @private
  6630. * @name Highcharts.SVGLabel#textProps
  6631. * @type {Array<string>}
  6632. */
  6633. SVGLabel.textProps = [
  6634. 'color', 'direction', 'fontFamily', 'fontSize', 'fontStyle',
  6635. 'fontWeight', 'lineHeight', 'textAlign', 'textDecoration',
  6636. 'textOutline', 'textOverflow', 'width'
  6637. ];
  6638. return SVGLabel;
  6639. }(SVGElement));
  6640. return SVGLabel;
  6641. });
  6642. _registerModule(_modules, 'Core/Renderer/SVG/TextBuilder.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js'], _modules['Core/Renderer/HTML/AST.js']], function (H, U, AST) {
  6643. /* *
  6644. *
  6645. * (c) 2010-2020 Torstein Honsi
  6646. *
  6647. * License: www.highcharts.com/license
  6648. *
  6649. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  6650. *
  6651. * */
  6652. var doc = H.doc,
  6653. SVG_NS = H.SVG_NS;
  6654. var attr = U.attr,
  6655. erase = U.erase,
  6656. isString = U.isString,
  6657. objectEach = U.objectEach,
  6658. pick = U.pick;
  6659. /**
  6660. * SVG Text Builder
  6661. * @private
  6662. * @class
  6663. * @name Highcharts.TextBuilder
  6664. */
  6665. var TextBuilder = /** @class */ (function () {
  6666. function TextBuilder(svgElement) {
  6667. var textStyles = svgElement.styles;
  6668. this.renderer = svgElement.renderer;
  6669. this.svgElement = svgElement;
  6670. this.width = svgElement.textWidth;
  6671. this.textLineHeight = textStyles && textStyles.lineHeight;
  6672. this.textOutline = textStyles && textStyles.textOutline;
  6673. this.ellipsis = Boolean(textStyles && textStyles.textOverflow === 'ellipsis');
  6674. this.noWrap = Boolean(textStyles && textStyles.whiteSpace === 'nowrap');
  6675. this.fontSize = textStyles && textStyles.fontSize;
  6676. }
  6677. /**
  6678. * Build an SVG representation of the pseudo HTML given in the object's
  6679. * svgElement.
  6680. *
  6681. * @private
  6682. *
  6683. * @return {void}.
  6684. */
  6685. TextBuilder.prototype.buildSVG = function () {
  6686. var wrapper = this.svgElement;
  6687. var textNode = wrapper.element, renderer = wrapper.renderer, textStr = pick(wrapper.textStr, '').toString(), hasMarkup = textStr.indexOf('<') !== -1, childNodes = textNode.childNodes, textCache, i = childNodes.length, tempParent = this.width && !wrapper.added && renderer.box;
  6688. var regexMatchBreaks = /<br.*?>/g;
  6689. // The buildText code is quite heavy, so if we're not changing something
  6690. // that affects the text, skip it (#6113).
  6691. textCache = [
  6692. textStr,
  6693. this.ellipsis,
  6694. this.noWrap,
  6695. this.textLineHeight,
  6696. this.textOutline,
  6697. this.fontSize,
  6698. this.width
  6699. ].join(',');
  6700. if (textCache === wrapper.textCache) {
  6701. return;
  6702. }
  6703. wrapper.textCache = textCache;
  6704. delete wrapper.actualWidth;
  6705. // Remove old text
  6706. while (i--) {
  6707. textNode.removeChild(childNodes[i]);
  6708. }
  6709. // Simple strings, add text directly and return
  6710. if (!hasMarkup &&
  6711. !this.ellipsis &&
  6712. !this.width &&
  6713. (textStr.indexOf(' ') === -1 ||
  6714. (this.noWrap && !regexMatchBreaks.test(textStr)))) {
  6715. textNode.appendChild(doc.createTextNode(this.unescapeEntities(textStr)));
  6716. // Complex strings, add more logic
  6717. }
  6718. else if (textStr !== '') {
  6719. if (tempParent) {
  6720. // attach it to the DOM to read offset width
  6721. tempParent.appendChild(textNode);
  6722. }
  6723. // Step 1. Parse the markup safely and directly into a tree
  6724. // structure.
  6725. var ast = new AST(textStr);
  6726. // Step 2. Do as many as we can of the modifications to the tree
  6727. // structure before it is added to the DOM
  6728. this.modifyTree(ast.nodes);
  6729. ast.addToDOM(wrapper.element);
  6730. // Step 3. Some modifications can't be done until the structure is
  6731. // in the DOM, because we need to read computed metrics.
  6732. this.modifyDOM();
  6733. // Add title if an ellipsis was added
  6734. if (this.ellipsis &&
  6735. (textNode.textContent || '').indexOf('\u2026') !== -1) {
  6736. wrapper.attr('title', this.unescapeEntities(wrapper.textStr || '', ['&lt;', '&gt;']) // #7179
  6737. );
  6738. }
  6739. if (tempParent) {
  6740. tempParent.removeChild(textNode);
  6741. }
  6742. }
  6743. // Apply the text outline
  6744. if (isString(this.textOutline) && wrapper.applyTextOutline) {
  6745. wrapper.applyTextOutline(this.textOutline);
  6746. }
  6747. };
  6748. /**
  6749. * Modify the DOM of the generated SVG structure. This function only does
  6750. * operations that cannot be done until the elements are attached to the
  6751. * DOM, like doing layout based on rendered metrics of the added elements.
  6752. *
  6753. * @private
  6754. *
  6755. * @return {void}
  6756. */
  6757. TextBuilder.prototype.modifyDOM = function () {
  6758. var _this = this;
  6759. var wrapper = this.svgElement;
  6760. var x = attr(wrapper.element, 'x');
  6761. // Modify hard line breaks by applying the rendered line height
  6762. [].forEach.call(wrapper.element.querySelectorAll('tspan.highcharts-br'), function (br) {
  6763. if (br.nextSibling && br.previousSibling) { // #5261
  6764. attr(br, {
  6765. // Since the break is inserted in front of the next
  6766. // line, we need to use the next sibling for the line
  6767. // height
  6768. dy: _this.getLineHeight(br.nextSibling),
  6769. x: x
  6770. });
  6771. }
  6772. });
  6773. // Constrain the line width, either by ellipsis or wrapping
  6774. var width = this.width || 0;
  6775. if (!width) {
  6776. return;
  6777. }
  6778. // Insert soft line breaks into each text node
  6779. var modifyTextNode = function (textNode,
  6780. parentElement) {
  6781. var text = textNode.textContent || '';
  6782. var words = text
  6783. .replace(/([^\^])-/g, '$1- ') // Split on hyphens
  6784. // .trim()
  6785. .split(' '); // #1273
  6786. var hasWhiteSpace = !_this.noWrap && (words.length > 1 || wrapper.element.childNodes.length > 1);
  6787. var dy = _this.getLineHeight(parentElement);
  6788. var lineNo = 0;
  6789. var startAt = wrapper.actualWidth;
  6790. if (_this.ellipsis) {
  6791. if (text) {
  6792. _this.truncate(textNode, text, void 0, 0,
  6793. // Target width
  6794. Math.max(0,
  6795. // Substract the font face to make room for the
  6796. // ellipsis itself
  6797. width - parseInt(_this.fontSize || 12, 10)),
  6798. // Build the text to test for
  6799. function (text, currentIndex) {
  6800. return text.substring(0, currentIndex) + '\u2026';
  6801. });
  6802. }
  6803. }
  6804. else if (hasWhiteSpace) {
  6805. var lines = [];
  6806. // Remove preceding siblings in order to make the text length
  6807. // calculation correct in the truncate function
  6808. var precedingSiblings = [];
  6809. while (parentElement.firstChild &&
  6810. parentElement.firstChild !== textNode) {
  6811. precedingSiblings.push(parentElement.firstChild);
  6812. parentElement.removeChild(parentElement.firstChild);
  6813. }
  6814. while (words.length) {
  6815. // Apply the previous line
  6816. if (words.length && !_this.noWrap && lineNo > 0) {
  6817. lines.push(textNode.textContent || '');
  6818. textNode.textContent = words.join(' ')
  6819. .replace(/- /g, '-');
  6820. }
  6821. // For each line, truncate the remaining
  6822. // words into the line length.
  6823. _this.truncate(textNode, void 0, words, lineNo === 0 ? (startAt || 0) : 0, width,
  6824. // Build the text to test for
  6825. function (t, currentIndex) {
  6826. return words
  6827. .slice(0, currentIndex)
  6828. .join(' ')
  6829. .replace(/- /g, '-');
  6830. });
  6831. startAt = wrapper.actualWidth;
  6832. lineNo++;
  6833. }
  6834. // Reinsert the preceding child nodes
  6835. precedingSiblings.forEach(function (childNode) {
  6836. parentElement.insertBefore(childNode, textNode);
  6837. });
  6838. // Insert the previous lines before the original text node
  6839. lines.forEach(function (line) {
  6840. // Insert the line
  6841. parentElement.insertBefore(doc.createTextNode(line), textNode);
  6842. // Insert a break
  6843. var br = doc.createElementNS(SVG_NS, 'tspan');
  6844. br.textContent = '\u200B'; // zero-width space
  6845. attr(br, { dy: dy, x: x });
  6846. parentElement.insertBefore(br, textNode);
  6847. });
  6848. }
  6849. };
  6850. // Recurse down the DOM tree and handle line breaks for each text node
  6851. var modifyChildren = (function (node) {
  6852. var childNodes = [].slice.call(node.childNodes);
  6853. childNodes.forEach(function (childNode) {
  6854. if (childNode.nodeType === Node.TEXT_NODE) {
  6855. modifyTextNode(childNode, node);
  6856. }
  6857. else {
  6858. // Reset word-wrap width readings after hard breaks
  6859. if (childNode.className.baseVal
  6860. .indexOf('highcharts-br') !== -1) {
  6861. wrapper.actualWidth = 0;
  6862. }
  6863. // Recurse down to child node
  6864. modifyChildren(childNode);
  6865. }
  6866. });
  6867. });
  6868. modifyChildren(wrapper.element);
  6869. };
  6870. /**
  6871. * Get the rendered line height of a <text>, <tspan> or pure text node.
  6872. *
  6873. * @param {DOMElementType|Text} node The node to check for
  6874. *
  6875. * @return {number} The rendered line height
  6876. */
  6877. TextBuilder.prototype.getLineHeight = function (node) {
  6878. var fontSizeStyle;
  6879. // If the node is a text node, use its parent
  6880. var element = node.nodeType === Node.TEXT_NODE ?
  6881. node.parentElement :
  6882. node;
  6883. if (!this.renderer.styledMode) {
  6884. fontSizeStyle =
  6885. element && /(px|em)$/.test(element.style.fontSize) ?
  6886. element.style.fontSize :
  6887. (this.fontSize || this.renderer.style.fontSize || 12);
  6888. }
  6889. return this.textLineHeight ?
  6890. parseInt(this.textLineHeight.toString(), 10) :
  6891. this.renderer.fontMetrics(fontSizeStyle, element || this.svgElement.element).h;
  6892. };
  6893. /**
  6894. * Transform a pseudo HTML AST node tree into an SVG structure. We do as
  6895. * much heavy lifting as we can here, before doing the final processing in
  6896. * the modifyDOM function. The original data is mutated.
  6897. *
  6898. * @private
  6899. *
  6900. * @param {ASTNode[]} nodes The AST nodes
  6901. *
  6902. * @return {void}
  6903. */
  6904. TextBuilder.prototype.modifyTree = function (nodes) {
  6905. var _this = this;
  6906. var modifyChild = function (node,
  6907. i) {
  6908. var tagName = node.tagName;
  6909. var styledMode = _this.renderer.styledMode;
  6910. var attributes = node.attributes || {};
  6911. // Apply styling to text tags
  6912. if (tagName === 'b' || tagName === 'strong') {
  6913. if (styledMode) {
  6914. attributes['class'] = 'highcharts-strong'; // eslint-disable-line dot-notation
  6915. }
  6916. else {
  6917. attributes.style = 'font-weight:bold;' + (attributes.style || '');
  6918. }
  6919. }
  6920. else if (tagName === 'i' || tagName === 'em') {
  6921. if (styledMode) {
  6922. attributes['class'] = 'highcharts-emphasized'; // eslint-disable-line dot-notation
  6923. }
  6924. else {
  6925. attributes.style = 'font-style:italic;' + (attributes.style || '');
  6926. }
  6927. }
  6928. // Modify attributes
  6929. if (isString(attributes.style)) {
  6930. attributes.style = attributes.style.replace(/(;| |^)color([ :])/, '$1fill$2');
  6931. }
  6932. if (tagName === 'br') {
  6933. attributes['class'] = 'highcharts-br'; // eslint-disable-line dot-notation
  6934. node.textContent = '\u200B'; // zero-width space
  6935. // Trim whitespace off the beginning of new lines
  6936. var nextNode = nodes[i + 1];
  6937. if (nextNode && nextNode.textContent) {
  6938. nextNode.textContent =
  6939. nextNode.textContent.replace(/^ +/gm, '');
  6940. }
  6941. }
  6942. if (tagName !== '#text' && tagName !== 'a') {
  6943. node.tagName = 'tspan';
  6944. }
  6945. node.attributes = attributes;
  6946. // Recurse
  6947. if (node.children) {
  6948. node.children
  6949. .filter(function (c) { return c.tagName !== '#text'; })
  6950. .forEach(modifyChild);
  6951. }
  6952. };
  6953. nodes.forEach(modifyChild);
  6954. // Remove empty spans from the beginning because SVG's getBBox doesn't
  6955. // count empty lines. The use case is tooltip where the header is empty.
  6956. while (nodes[0]) {
  6957. if (nodes[0].tagName === 'tspan' && !nodes[0].children) {
  6958. nodes.splice(0, 1);
  6959. }
  6960. else {
  6961. break;
  6962. }
  6963. }
  6964. };
  6965. /*
  6966. * Truncate the text node contents to a given length. Used when the css
  6967. * width is set. If the `textOverflow` is `ellipsis`, the text is truncated
  6968. * character by character to the given length. If not, the text is
  6969. * word-wrapped line by line.
  6970. */
  6971. TextBuilder.prototype.truncate = function (textNode, text, words, startAt, width, getString) {
  6972. var svgElement = this.svgElement;
  6973. var renderer = svgElement.renderer,
  6974. rotation = svgElement.rotation;
  6975. // Cache the lengths to avoid checking the same twice
  6976. var lengths = [];
  6977. // Word wrap can not be truncated to shorter than one word, ellipsis
  6978. // text can be completely blank.
  6979. var minIndex = words ? 1 : 0;
  6980. var maxIndex = (text || words || '').length;
  6981. var currentIndex = maxIndex;
  6982. var str;
  6983. var actualWidth;
  6984. var getSubStringLength = function (charEnd,
  6985. concatenatedEnd) {
  6986. // charEnd is used when finding the character-by-character
  6987. // break for ellipsis, concatenatedEnd is used for word-by-word
  6988. // break for word wrapping.
  6989. var end = concatenatedEnd || charEnd;
  6990. var parentNode = textNode.parentNode;
  6991. if (parentNode && typeof lengths[end] === 'undefined') {
  6992. // Modern browsers
  6993. if (parentNode.getSubStringLength) {
  6994. // Fails with DOM exception on unit-tests/legend/members
  6995. // of unknown reason. Desired width is 0, text content
  6996. // is "5" and end is 1.
  6997. try {
  6998. lengths[end] = startAt +
  6999. parentNode.getSubStringLength(0, words ? end + 1 : end);
  7000. }
  7001. catch (e) {
  7002. '';
  7003. }
  7004. // Legacy
  7005. }
  7006. else if (renderer.getSpanWidth) { // #9058 jsdom
  7007. textNode.textContent = getString(text || words, charEnd);
  7008. lengths[end] = startAt +
  7009. renderer.getSpanWidth(svgElement, textNode);
  7010. }
  7011. }
  7012. return lengths[end];
  7013. };
  7014. svgElement.rotation = 0; // discard rotation when computing box
  7015. actualWidth = getSubStringLength(textNode.textContent.length);
  7016. if (startAt + actualWidth > width) {
  7017. // Do a binary search for the index where to truncate the text
  7018. while (minIndex <= maxIndex) {
  7019. currentIndex = Math.ceil((minIndex + maxIndex) / 2);
  7020. // When checking words for word-wrap, we need to build the
  7021. // string and measure the subStringLength at the concatenated
  7022. // word length.
  7023. if (words) {
  7024. str = getString(words, currentIndex);
  7025. }
  7026. actualWidth = getSubStringLength(currentIndex, str && str.length - 1);
  7027. if (minIndex === maxIndex) {
  7028. // Complete
  7029. minIndex = maxIndex + 1;
  7030. }
  7031. else if (actualWidth > width) {
  7032. // Too large. Set max index to current.
  7033. maxIndex = currentIndex - 1;
  7034. }
  7035. else {
  7036. // Within width. Set min index to current.
  7037. minIndex = currentIndex;
  7038. }
  7039. }
  7040. // If max index was 0 it means the shortest possible text was also
  7041. // too large. For ellipsis that means only the ellipsis, while for
  7042. // word wrap it means the whole first word.
  7043. if (maxIndex === 0) {
  7044. // Remove ellipsis
  7045. textNode.textContent = '';
  7046. // If the new text length is one less than the original, we don't
  7047. // need the ellipsis
  7048. }
  7049. else if (!(text && maxIndex === text.length - 1)) {
  7050. textNode.textContent = str || getString(text || words, currentIndex);
  7051. }
  7052. }
  7053. // When doing line wrapping, prepare for the next line by removing the
  7054. // items from this line.
  7055. if (words) {
  7056. words.splice(0, currentIndex);
  7057. }
  7058. svgElement.actualWidth = actualWidth;
  7059. svgElement.rotation = rotation; // Apply rotation again.
  7060. };
  7061. /*
  7062. * Un-escape HTML entities based on the public `renderer.escapes` list
  7063. *
  7064. * @private
  7065. *
  7066. * @param {string} inputStr The string to unescape
  7067. * @param {Array<string>} [except] Exceptions
  7068. *
  7069. * @return {string} The processed string
  7070. */
  7071. TextBuilder.prototype.unescapeEntities = function (inputStr, except) {
  7072. objectEach(this.renderer.escapes, function (value, key) {
  7073. if (!except || except.indexOf(value) === -1) {
  7074. inputStr = inputStr.toString().replace(new RegExp(value, 'g'), key);
  7075. }
  7076. });
  7077. return inputStr;
  7078. };
  7079. return TextBuilder;
  7080. }());
  7081. return TextBuilder;
  7082. });
  7083. _registerModule(_modules, 'Core/Renderer/SVG/SVGRenderer.js', [_modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Core/Color/Palette.js'], _modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Renderer/SVG/SVGLabel.js'], _modules['Core/Renderer/HTML/AST.js'], _modules['Core/Renderer/SVG/TextBuilder.js'], _modules['Core/Utilities.js']], function (Color, H, palette, SVGElement, SVGLabel, AST, TextBuilder, U) {
  7084. /* *
  7085. *
  7086. * (c) 2010-2021 Torstein Honsi
  7087. *
  7088. * License: www.highcharts.com/license
  7089. *
  7090. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  7091. *
  7092. * */
  7093. var addEvent = U.addEvent,
  7094. attr = U.attr,
  7095. createElement = U.createElement,
  7096. css = U.css,
  7097. defined = U.defined,
  7098. destroyObjectProperties = U.destroyObjectProperties,
  7099. extend = U.extend,
  7100. isArray = U.isArray,
  7101. isNumber = U.isNumber,
  7102. isObject = U.isObject,
  7103. isString = U.isString,
  7104. merge = U.merge,
  7105. pick = U.pick,
  7106. pInt = U.pInt,
  7107. uniqueKey = U.uniqueKey;
  7108. /**
  7109. * A clipping rectangle that can be applied to one or more {@link SVGElement}
  7110. * instances. It is instanciated with the {@link SVGRenderer#clipRect} function
  7111. * and applied with the {@link SVGElement#clip} function.
  7112. *
  7113. * @example
  7114. * var circle = renderer.circle(100, 100, 100)
  7115. * .attr({ fill: 'red' })
  7116. * .add();
  7117. * var clipRect = renderer.clipRect(100, 100, 100, 100);
  7118. *
  7119. * // Leave only the lower right quarter visible
  7120. * circle.clip(clipRect);
  7121. *
  7122. * @typedef {Highcharts.SVGElement} Highcharts.ClipRectElement
  7123. */
  7124. /**
  7125. * The font metrics.
  7126. *
  7127. * @interface Highcharts.FontMetricsObject
  7128. */ /**
  7129. * The baseline relative to the top of the box.
  7130. *
  7131. * @name Highcharts.FontMetricsObject#b
  7132. * @type {number}
  7133. */ /**
  7134. * The font size.
  7135. *
  7136. * @name Highcharts.FontMetricsObject#f
  7137. * @type {number}
  7138. */ /**
  7139. * The line height.
  7140. *
  7141. * @name Highcharts.FontMetricsObject#h
  7142. * @type {number}
  7143. */
  7144. /**
  7145. * An object containing `x` and `y` properties for the position of an element.
  7146. *
  7147. * @interface Highcharts.PositionObject
  7148. */ /**
  7149. * X position of the element.
  7150. * @name Highcharts.PositionObject#x
  7151. * @type {number}
  7152. */ /**
  7153. * Y position of the element.
  7154. * @name Highcharts.PositionObject#y
  7155. * @type {number}
  7156. */
  7157. /**
  7158. * A rectangle.
  7159. *
  7160. * @interface Highcharts.RectangleObject
  7161. */ /**
  7162. * Height of the rectangle.
  7163. * @name Highcharts.RectangleObject#height
  7164. * @type {number}
  7165. */ /**
  7166. * Width of the rectangle.
  7167. * @name Highcharts.RectangleObject#width
  7168. * @type {number}
  7169. */ /**
  7170. * Horizontal position of the rectangle.
  7171. * @name Highcharts.RectangleObject#x
  7172. * @type {number}
  7173. */ /**
  7174. * Vertical position of the rectangle.
  7175. * @name Highcharts.RectangleObject#y
  7176. * @type {number}
  7177. */
  7178. /**
  7179. * The shadow options.
  7180. *
  7181. * @interface Highcharts.ShadowOptionsObject
  7182. */ /**
  7183. * The shadow color.
  7184. * @name Highcharts.ShadowOptionsObject#color
  7185. * @type {Highcharts.ColorString|undefined}
  7186. * @default ${palette.neutralColor100}
  7187. */ /**
  7188. * The horizontal offset from the element.
  7189. *
  7190. * @name Highcharts.ShadowOptionsObject#offsetX
  7191. * @type {number|undefined}
  7192. * @default 1
  7193. */ /**
  7194. * The vertical offset from the element.
  7195. * @name Highcharts.ShadowOptionsObject#offsetY
  7196. * @type {number|undefined}
  7197. * @default 1
  7198. */ /**
  7199. * The shadow opacity.
  7200. *
  7201. * @name Highcharts.ShadowOptionsObject#opacity
  7202. * @type {number|undefined}
  7203. * @default 0.15
  7204. */ /**
  7205. * The shadow width or distance from the element.
  7206. * @name Highcharts.ShadowOptionsObject#width
  7207. * @type {number|undefined}
  7208. * @default 3
  7209. */
  7210. /**
  7211. * @interface Highcharts.SizeObject
  7212. */ /**
  7213. * @name Highcharts.SizeObject#height
  7214. * @type {number}
  7215. */ /**
  7216. * @name Highcharts.SizeObject#width
  7217. * @type {number}
  7218. */
  7219. /**
  7220. * Array of path commands, that will go into the `d` attribute of an SVG
  7221. * element.
  7222. *
  7223. * @typedef {Array<(Array<Highcharts.SVGPathCommand>|Array<Highcharts.SVGPathCommand,number>|Array<Highcharts.SVGPathCommand,number,number>|Array<Highcharts.SVGPathCommand,number,number,number,number>|Array<Highcharts.SVGPathCommand,number,number,number,number,number,number>|Array<Highcharts.SVGPathCommand,number,number,number,number,number,number,number>)>} Highcharts.SVGPathArray
  7224. */
  7225. /**
  7226. * Possible path commands in an SVG path array. Valid values are `A`, `C`, `H`,
  7227. * `L`, `M`, `Q`, `S`, `T`, `V`, `Z`.
  7228. *
  7229. * @typedef {string} Highcharts.SVGPathCommand
  7230. * @validvalue ["a","c","h","l","m","q","s","t","v","z","A","C","H","L","M","Q","S","T","V","Z"]
  7231. */
  7232. /**
  7233. * An extendable collection of functions for defining symbol paths. Symbols are
  7234. * used internally for point markers, button and label borders and backgrounds,
  7235. * or custom shapes. Extendable by adding to {@link SVGRenderer#symbols}.
  7236. *
  7237. * @interface Highcharts.SymbolDictionary
  7238. */ /**
  7239. * @name Highcharts.SymbolDictionary#[key:string]
  7240. * @type {Function|undefined}
  7241. */ /**
  7242. * @name Highcharts.SymbolDictionary#arc
  7243. * @type {Function|undefined}
  7244. */ /**
  7245. * @name Highcharts.SymbolDictionary#callout
  7246. * @type {Function|undefined}
  7247. */ /**
  7248. * @name Highcharts.SymbolDictionary#circle
  7249. * @type {Function|undefined}
  7250. */ /**
  7251. * @name Highcharts.SymbolDictionary#diamond
  7252. * @type {Function|undefined}
  7253. */ /**
  7254. * @name Highcharts.SymbolDictionary#square
  7255. * @type {Function|undefined}
  7256. */ /**
  7257. * @name Highcharts.SymbolDictionary#triangle
  7258. * @type {Function|undefined}
  7259. */
  7260. /**
  7261. * Can be one of `arc`, `callout`, `circle`, `diamond`, `square`, `triangle`,
  7262. * and `triangle-down`. Symbols are used internally for point markers, button
  7263. * and label borders and backgrounds, or custom shapes. Extendable by adding to
  7264. * {@link SVGRenderer#symbols}.
  7265. *
  7266. * @typedef {"arc"|"callout"|"circle"|"diamond"|"square"|"triangle"|"triangle-down"} Highcharts.SymbolKeyValue
  7267. */
  7268. /**
  7269. * Additional options, depending on the actual symbol drawn.
  7270. *
  7271. * @interface Highcharts.SymbolOptionsObject
  7272. */ /**
  7273. * The anchor X position for the `callout` symbol. This is where the chevron
  7274. * points to.
  7275. *
  7276. * @name Highcharts.SymbolOptionsObject#anchorX
  7277. * @type {number|undefined}
  7278. */ /**
  7279. * The anchor Y position for the `callout` symbol. This is where the chevron
  7280. * points to.
  7281. *
  7282. * @name Highcharts.SymbolOptionsObject#anchorY
  7283. * @type {number|undefined}
  7284. */ /**
  7285. * The end angle of an `arc` symbol.
  7286. *
  7287. * @name Highcharts.SymbolOptionsObject#end
  7288. * @type {number|undefined}
  7289. */ /**
  7290. * Whether to draw `arc` symbol open or closed.
  7291. *
  7292. * @name Highcharts.SymbolOptionsObject#open
  7293. * @type {boolean|undefined}
  7294. */ /**
  7295. * The radius of an `arc` symbol, or the border radius for the `callout` symbol.
  7296. *
  7297. * @name Highcharts.SymbolOptionsObject#r
  7298. * @type {number|undefined}
  7299. */ /**
  7300. * The start angle of an `arc` symbol.
  7301. *
  7302. * @name Highcharts.SymbolOptionsObject#start
  7303. * @type {number|undefined}
  7304. */
  7305. /* eslint-disable no-invalid-this, valid-jsdoc */
  7306. var charts = H.charts,
  7307. deg2rad = H.deg2rad,
  7308. doc = H.doc,
  7309. isFirefox = H.isFirefox,
  7310. isMS = H.isMS,
  7311. isWebKit = H.isWebKit,
  7312. noop = H.noop,
  7313. SVG_NS = H.SVG_NS,
  7314. symbolSizes = H.symbolSizes,
  7315. win = H.win,
  7316. hasInternalReferenceBug;
  7317. /**
  7318. * Allows direct access to the Highcharts rendering layer in order to draw
  7319. * primitive shapes like circles, rectangles, paths or text directly on a chart,
  7320. * or independent from any chart. The SVGRenderer represents a wrapper object
  7321. * for SVG in modern browsers. Through the VMLRenderer, part of the `oldie.js`
  7322. * module, it also brings vector graphics to IE <= 8.
  7323. *
  7324. * An existing chart's renderer can be accessed through {@link Chart.renderer}.
  7325. * The renderer can also be used completely decoupled from a chart.
  7326. *
  7327. * @sample highcharts/members/renderer-on-chart
  7328. * Annotating a chart programmatically.
  7329. * @sample highcharts/members/renderer-basic
  7330. * Independent SVG drawing.
  7331. *
  7332. * @example
  7333. * // Use directly without a chart object.
  7334. * var renderer = new Highcharts.Renderer(parentNode, 600, 400);
  7335. *
  7336. * @class
  7337. * @name Highcharts.SVGRenderer
  7338. *
  7339. * @param {Highcharts.HTMLDOMElement} container
  7340. * Where to put the SVG in the web page.
  7341. *
  7342. * @param {number} width
  7343. * The width of the SVG.
  7344. *
  7345. * @param {number} height
  7346. * The height of the SVG.
  7347. *
  7348. * @param {Highcharts.CSSObject} [style]
  7349. * The box style, if not in styleMode
  7350. *
  7351. * @param {boolean} [forExport=false]
  7352. * Whether the rendered content is intended for export.
  7353. *
  7354. * @param {boolean} [allowHTML=true]
  7355. * Whether the renderer is allowed to include HTML text, which will be
  7356. * projected on top of the SVG.
  7357. *
  7358. * @param {boolean} [styledMode=false]
  7359. * Whether the renderer belongs to a chart that is in styled mode.
  7360. * If it does, it will avoid setting presentational attributes in
  7361. * some cases, but not when set explicitly through `.attr` and `.css`
  7362. * etc.
  7363. */
  7364. var SVGRenderer = /** @class */ (function () {
  7365. /* *
  7366. *
  7367. * Constructors
  7368. *
  7369. * */
  7370. function SVGRenderer(container, width, height, style, forExport, allowHTML, styledMode) {
  7371. /* *
  7372. *
  7373. * Properties
  7374. *
  7375. * */
  7376. this.alignedObjects = void 0;
  7377. /**
  7378. * The root `svg` node of the renderer.
  7379. *
  7380. * @name Highcharts.SVGRenderer#box
  7381. * @type {Highcharts.SVGDOMElement}
  7382. */
  7383. this.box = void 0;
  7384. /**
  7385. * The wrapper for the root `svg` node of the renderer.
  7386. *
  7387. * @name Highcharts.SVGRenderer#boxWrapper
  7388. * @type {Highcharts.SVGElement}
  7389. */
  7390. this.boxWrapper = void 0;
  7391. this.cache = void 0;
  7392. this.cacheKeys = void 0;
  7393. this.chartIndex = void 0;
  7394. /**
  7395. * A pointer to the `defs` node of the root SVG.
  7396. *
  7397. * @name Highcharts.SVGRenderer#defs
  7398. * @type {Highcharts.SVGElement}
  7399. */
  7400. this.defs = void 0;
  7401. this.globalAnimation = void 0;
  7402. this.gradients = void 0;
  7403. this.height = void 0;
  7404. this.imgCount = void 0;
  7405. this.isSVG = void 0;
  7406. this.style = void 0;
  7407. /**
  7408. * Page url used for internal references.
  7409. *
  7410. * @private
  7411. * @name Highcharts.SVGRenderer#url
  7412. * @type {string}
  7413. */
  7414. this.url = void 0;
  7415. this.width = void 0;
  7416. this.init(container, width, height, style, forExport, allowHTML, styledMode);
  7417. }
  7418. /* *
  7419. *
  7420. * Functions
  7421. *
  7422. * */
  7423. /**
  7424. * Initialize the SVGRenderer. Overridable initializer function that takes
  7425. * the same parameters as the constructor.
  7426. *
  7427. * @function Highcharts.SVGRenderer#init
  7428. *
  7429. * @param {Highcharts.HTMLDOMElement} container
  7430. * Where to put the SVG in the web page.
  7431. *
  7432. * @param {number} width
  7433. * The width of the SVG.
  7434. *
  7435. * @param {number} height
  7436. * The height of the SVG.
  7437. *
  7438. * @param {Highcharts.CSSObject} [style]
  7439. * The box style, if not in styleMode
  7440. *
  7441. * @param {boolean} [forExport=false]
  7442. * Whether the rendered content is intended for export.
  7443. *
  7444. * @param {boolean} [allowHTML=true]
  7445. * Whether the renderer is allowed to include HTML text, which will be
  7446. * projected on top of the SVG.
  7447. *
  7448. * @param {boolean} [styledMode=false]
  7449. * Whether the renderer belongs to a chart that is in styled mode. If it
  7450. * does, it will avoid setting presentational attributes in some cases, but
  7451. * not when set explicitly through `.attr` and `.css` etc.
  7452. */
  7453. SVGRenderer.prototype.init = function (container, width, height, style, forExport, allowHTML, styledMode) {
  7454. var renderer = this,
  7455. boxWrapper,
  7456. element,
  7457. desc;
  7458. boxWrapper = renderer.createElement('svg')
  7459. .attr({
  7460. version: '1.1',
  7461. 'class': 'highcharts-root'
  7462. });
  7463. if (!styledMode) {
  7464. boxWrapper.css(this.getStyle(style));
  7465. }
  7466. element = boxWrapper.element;
  7467. container.appendChild(element);
  7468. // Always use ltr on the container, otherwise text-anchor will be
  7469. // flipped and text appear outside labels, buttons, tooltip etc (#3482)
  7470. attr(container, 'dir', 'ltr');
  7471. // For browsers other than IE, add the namespace attribute (#1978)
  7472. if (container.innerHTML.indexOf('xmlns') === -1) {
  7473. attr(element, 'xmlns', this.SVG_NS);
  7474. }
  7475. // object properties
  7476. renderer.isSVG = true;
  7477. this.box = element;
  7478. this.boxWrapper = boxWrapper;
  7479. renderer.alignedObjects = [];
  7480. this.url = this.getReferenceURL();
  7481. // Add description
  7482. desc = this.createElement('desc').add();
  7483. desc.element.appendChild(doc.createTextNode('Created with Highcharts 9.0.1'));
  7484. renderer.defs = this.createElement('defs').add();
  7485. renderer.allowHTML = allowHTML;
  7486. renderer.forExport = forExport;
  7487. renderer.styledMode = styledMode;
  7488. renderer.gradients = {}; // Object where gradient SvgElements are stored
  7489. renderer.cache = {}; // Cache for numerical bounding boxes
  7490. renderer.cacheKeys = [];
  7491. renderer.imgCount = 0;
  7492. renderer.setSize(width, height, false);
  7493. // Issue 110 workaround:
  7494. // In Firefox, if a div is positioned by percentage, its pixel position
  7495. // may land between pixels. The container itself doesn't display this,
  7496. // but an SVG element inside this container will be drawn at subpixel
  7497. // precision. In order to draw sharp lines, this must be compensated
  7498. // for. This doesn't seem to work inside iframes though (like in
  7499. // jsFiddle).
  7500. var subPixelFix,
  7501. rect;
  7502. if (isFirefox && container.getBoundingClientRect) {
  7503. subPixelFix = function () {
  7504. css(container, { left: 0, top: 0 });
  7505. rect = container.getBoundingClientRect();
  7506. css(container, {
  7507. left: (Math.ceil(rect.left) - rect.left) + 'px',
  7508. top: (Math.ceil(rect.top) - rect.top) + 'px'
  7509. });
  7510. };
  7511. // run the fix now
  7512. subPixelFix();
  7513. // run it on resize
  7514. renderer.unSubPixelFix = addEvent(win, 'resize', subPixelFix);
  7515. }
  7516. };
  7517. /**
  7518. * General method for adding a definition to the SVG `defs` tag. Can be used
  7519. * for gradients, fills, filters etc. Styled mode only. A hook for adding
  7520. * general definitions to the SVG's defs tag. Definitions can be referenced
  7521. * from the CSS by its `id`. Read more in
  7522. * [gradients, shadows and patterns](https://www.highcharts.com/docs/chart-design-and-style/gradients-shadows-and-patterns).
  7523. * Styled mode only.
  7524. *
  7525. * @function Highcharts.SVGRenderer#definition
  7526. *
  7527. * @param {Highcharts.ASTNode} def
  7528. * A serialized form of an SVG definition, including children.
  7529. *
  7530. * @return {Highcharts.SVGElement}
  7531. * The inserted node.
  7532. */
  7533. SVGRenderer.prototype.definition = function (def) {
  7534. var ast = new AST([def]);
  7535. return ast.addToDOM(this.defs.element);
  7536. };
  7537. /**
  7538. * Get the prefix needed for internal URL references to work in certain
  7539. * cases. Some older browser versions had a bug where internal url
  7540. * references in SVG attributes, on the form `url(#some-id)`, would fail if
  7541. * a base tag was present in the page. There were also issues with
  7542. * `history.pushState` related to this prefix.
  7543. *
  7544. * Related issues: #24, #672, #1070, #5244.
  7545. *
  7546. * The affected browsers are:
  7547. * - Chrome <= 53 (May 2018)
  7548. * - Firefox <= 51 (January 2017)
  7549. * - Safari/Mac <= 12.1 (2018 or 2019)
  7550. * - Safari/iOS <= 13
  7551. *
  7552. * @todo Remove this hack when time has passed. All the affected browsers
  7553. * are evergreens, so it is increasingly unlikely that users are affected by
  7554. * the bug.
  7555. *
  7556. * @return {string}
  7557. * The prefix to use. An empty string for modern browsers.
  7558. */
  7559. SVGRenderer.prototype.getReferenceURL = function () {
  7560. if ((isFirefox || isWebKit) &&
  7561. doc.getElementsByTagName('base').length) {
  7562. // Detect if a clip path is taking effect by performing a hit test
  7563. // outside the clipped area. If the hit element is the rectangle
  7564. // that was supposed to be clipped, the bug is present. This only
  7565. // has to be performed once per page load, so we store the result
  7566. // locally in the module.
  7567. if (!defined(hasInternalReferenceBug)) {
  7568. var id = uniqueKey();
  7569. var ast = new AST([{
  7570. tagName: 'svg',
  7571. attributes: {
  7572. width: 8,
  7573. height: 8
  7574. },
  7575. children: [{
  7576. tagName: 'defs',
  7577. children: [{
  7578. tagName: 'clipPath',
  7579. attributes: {
  7580. id: id
  7581. },
  7582. children: [{
  7583. tagName: 'rect',
  7584. attributes: {
  7585. width: 4,
  7586. height: 4
  7587. }
  7588. }]
  7589. }]
  7590. }, {
  7591. tagName: 'rect',
  7592. attributes: {
  7593. id: 'hitme',
  7594. width: 8,
  7595. height: 8,
  7596. 'clip-path': "url(#" + id + ")",
  7597. fill: 'rgba(0,0,0,0.001)'
  7598. }
  7599. }]
  7600. }]);
  7601. var svg = ast.addToDOM(doc.body);
  7602. css(svg, {
  7603. position: 'fixed',
  7604. top: 0,
  7605. left: 0,
  7606. zIndex: 9e5
  7607. });
  7608. var hitElement = doc.elementFromPoint(6, 6);
  7609. hasInternalReferenceBug =
  7610. (hitElement && hitElement.id) === 'hitme';
  7611. doc.body.removeChild(svg);
  7612. }
  7613. if (hasInternalReferenceBug) {
  7614. return win.location.href
  7615. .split('#')[0] // remove the hash
  7616. .replace(/<[^>]*>/g, '') // wing cut HTML
  7617. // escape parantheses and quotes
  7618. .replace(/([\('\)])/g, '\\$1')
  7619. // replace spaces (needed for Safari only)
  7620. .replace(/ /g, '%20');
  7621. }
  7622. }
  7623. return '';
  7624. };
  7625. /**
  7626. * Get the global style setting for the renderer.
  7627. *
  7628. * @private
  7629. * @function Highcharts.SVGRenderer#getStyle
  7630. *
  7631. * @param {Highcharts.CSSObject} style
  7632. * Style settings.
  7633. *
  7634. * @return {Highcharts.CSSObject}
  7635. * The style settings mixed with defaults.
  7636. */
  7637. SVGRenderer.prototype.getStyle = function (style) {
  7638. this.style = extend({
  7639. fontFamily: '"Lucida Grande", "Lucida Sans Unicode", ' +
  7640. 'Arial, Helvetica, sans-serif',
  7641. fontSize: '12px'
  7642. }, style);
  7643. return this.style;
  7644. };
  7645. /**
  7646. * Apply the global style on the renderer, mixed with the default styles.
  7647. *
  7648. * @function Highcharts.SVGRenderer#setStyle
  7649. *
  7650. * @param {Highcharts.CSSObject} style
  7651. * CSS to apply.
  7652. */
  7653. SVGRenderer.prototype.setStyle = function (style) {
  7654. this.boxWrapper.css(this.getStyle(style));
  7655. };
  7656. /**
  7657. * Detect whether the renderer is hidden. This happens when one of the
  7658. * parent elements has `display: none`. Used internally to detect when we
  7659. * needto render preliminarily in another div to get the text bounding boxes
  7660. * right.
  7661. *
  7662. * @function Highcharts.SVGRenderer#isHidden
  7663. *
  7664. * @return {boolean}
  7665. * True if it is hidden.
  7666. */
  7667. SVGRenderer.prototype.isHidden = function () {
  7668. return !this.boxWrapper.getBBox().width;
  7669. };
  7670. /**
  7671. * Destroys the renderer and its allocated members.
  7672. *
  7673. * @function Highcharts.SVGRenderer#destroy
  7674. *
  7675. * @return {null}
  7676. */
  7677. SVGRenderer.prototype.destroy = function () {
  7678. var renderer = this,
  7679. rendererDefs = renderer.defs;
  7680. renderer.box = null;
  7681. renderer.boxWrapper = renderer.boxWrapper.destroy();
  7682. // Call destroy on all gradient elements
  7683. destroyObjectProperties(renderer.gradients || {});
  7684. renderer.gradients = null;
  7685. // Defs are null in VMLRenderer
  7686. // Otherwise, destroy them here.
  7687. if (rendererDefs) {
  7688. renderer.defs = rendererDefs.destroy();
  7689. }
  7690. // Remove sub pixel fix handler (#982)
  7691. if (renderer.unSubPixelFix) {
  7692. renderer.unSubPixelFix();
  7693. }
  7694. renderer.alignedObjects = null;
  7695. return null;
  7696. };
  7697. /**
  7698. * Create a wrapper for an SVG element. Serves as a factory for
  7699. * {@link SVGElement}, but this function is itself mostly called from
  7700. * primitive factories like {@link SVGRenderer#path}, {@link
  7701. * SVGRenderer#rect} or {@link SVGRenderer#text}.
  7702. *
  7703. * @function Highcharts.SVGRenderer#createElement
  7704. *
  7705. * @param {string} nodeName
  7706. * The node name, for example `rect`, `g` etc.
  7707. *
  7708. * @return {Highcharts.SVGElement}
  7709. * The generated SVGElement.
  7710. */
  7711. SVGRenderer.prototype.createElement = function (nodeName) {
  7712. var wrapper = new this.Element();
  7713. wrapper.init(this, nodeName);
  7714. return wrapper;
  7715. };
  7716. /**
  7717. * Get converted radial gradient attributes according to the radial
  7718. * reference. Used internally from the {@link SVGElement#colorGradient}
  7719. * function.
  7720. *
  7721. * @private
  7722. * @function Highcharts.SVGRenderer#getRadialAttr
  7723. */
  7724. SVGRenderer.prototype.getRadialAttr = function (radialReference, gradAttr) {
  7725. return {
  7726. cx: (radialReference[0] - radialReference[2] / 2) +
  7727. gradAttr.cx * radialReference[2],
  7728. cy: (radialReference[1] - radialReference[2] / 2) +
  7729. gradAttr.cy * radialReference[2],
  7730. r: gradAttr.r * radialReference[2]
  7731. };
  7732. };
  7733. /**
  7734. * Parse a simple HTML string into SVG tspans. Called internally when text
  7735. * is set on an SVGElement. The function supports a subset of HTML tags, CSS
  7736. * text features like `width`, `text-overflow`, `white-space`, and also
  7737. * attributes like `href` and `style`.
  7738. *
  7739. * @private
  7740. * @function Highcharts.SVGRenderer#buildText
  7741. *
  7742. * @param {Highcharts.SVGElement} wrapper
  7743. * The parent SVGElement.
  7744. */
  7745. SVGRenderer.prototype.buildText = function (wrapper) {
  7746. new TextBuilder(wrapper).buildSVG();
  7747. };
  7748. /**
  7749. * Returns white for dark colors and black for bright colors.
  7750. *
  7751. * @function Highcharts.SVGRenderer#getContrast
  7752. *
  7753. * @param {Highcharts.ColorString} rgba
  7754. * The color to get the contrast for.
  7755. *
  7756. * @return {Highcharts.ColorString}
  7757. * The contrast color, either `#000000` or `#FFFFFF`.
  7758. */
  7759. SVGRenderer.prototype.getContrast = function (rgba) {
  7760. rgba = Color.parse(rgba).rgba;
  7761. // The threshold may be discussed. Here's a proposal for adding
  7762. // different weight to the color channels (#6216)
  7763. rgba[0] *= 1; // red
  7764. rgba[1] *= 1.2; // green
  7765. rgba[2] *= 0.5; // blue
  7766. return rgba[0] + rgba[1] + rgba[2] >
  7767. 1.8 * 255 ?
  7768. '#000000' :
  7769. '#FFFFFF';
  7770. };
  7771. /**
  7772. * Create a button with preset states.
  7773. *
  7774. * @function Highcharts.SVGRenderer#button
  7775. *
  7776. * @param {string} text
  7777. * The text or HTML to draw.
  7778. *
  7779. * @param {number} x
  7780. * The x position of the button's left side.
  7781. *
  7782. * @param {number} y
  7783. * The y position of the button's top side.
  7784. *
  7785. * @param {Highcharts.EventCallbackFunction<Highcharts.SVGElement>} callback
  7786. * The function to execute on button click or touch.
  7787. *
  7788. * @param {Highcharts.SVGAttributes} [theme]
  7789. * SVG attributes for the normal state.
  7790. *
  7791. * @param {Highcharts.SVGAttributes} [hoverState]
  7792. * SVG attributes for the hover state.
  7793. *
  7794. * @param {Highcharts.SVGAttributes} [pressedState]
  7795. * SVG attributes for the pressed state.
  7796. *
  7797. * @param {Highcharts.SVGAttributes} [disabledState]
  7798. * SVG attributes for the disabled state.
  7799. *
  7800. * @param {Highcharts.SymbolKeyValue} [shape=rect]
  7801. * The shape type.
  7802. *
  7803. * @param {boolean} [useHTML=false]
  7804. * Wether to use HTML to render the label.
  7805. *
  7806. * @return {Highcharts.SVGElement}
  7807. * The button element.
  7808. */
  7809. SVGRenderer.prototype.button = function (text, x, y, callback, theme, hoverState, pressedState, disabledState, shape, useHTML) {
  7810. var label = this.label(text,
  7811. x,
  7812. y,
  7813. shape,
  7814. void 0,
  7815. void 0,
  7816. useHTML,
  7817. void 0, 'button'),
  7818. curState = 0,
  7819. styledMode = this.styledMode,
  7820. // Make a copy of normalState (#13798)
  7821. // (reference to options.rangeSelector.buttonTheme)
  7822. normalState = theme ? merge(theme) : {},
  7823. userNormalStyle = normalState && normalState.style || {};
  7824. // Remove stylable attributes
  7825. normalState = AST.filterUserAttributes(normalState);
  7826. // Default, non-stylable attributes
  7827. label.attr(merge({ padding: 8, r: 2 }, normalState));
  7828. if (!styledMode) {
  7829. // Presentational
  7830. var normalStyle,
  7831. hoverStyle,
  7832. pressedStyle,
  7833. disabledStyle;
  7834. // Normal state - prepare the attributes
  7835. normalState = merge({
  7836. fill: palette.neutralColor3,
  7837. stroke: palette.neutralColor20,
  7838. 'stroke-width': 1,
  7839. style: {
  7840. color: palette.neutralColor80,
  7841. cursor: 'pointer',
  7842. fontWeight: 'normal'
  7843. }
  7844. }, {
  7845. style: userNormalStyle
  7846. }, normalState);
  7847. normalStyle = normalState.style;
  7848. delete normalState.style;
  7849. // Hover state
  7850. hoverState = merge(normalState, {
  7851. fill: palette.neutralColor10
  7852. }, AST.filterUserAttributes(hoverState || {}));
  7853. hoverStyle = hoverState.style;
  7854. delete hoverState.style;
  7855. // Pressed state
  7856. pressedState = merge(normalState, {
  7857. fill: palette.highlightColor10,
  7858. style: {
  7859. color: palette.neutralColor100,
  7860. fontWeight: 'bold'
  7861. }
  7862. }, AST.filterUserAttributes(pressedState || {}));
  7863. pressedStyle = pressedState.style;
  7864. delete pressedState.style;
  7865. // Disabled state
  7866. disabledState = merge(normalState, {
  7867. style: {
  7868. color: palette.neutralColor20
  7869. }
  7870. }, AST.filterUserAttributes(disabledState || {}));
  7871. disabledStyle = disabledState.style;
  7872. delete disabledState.style;
  7873. }
  7874. // Add the events. IE9 and IE10 need mouseover and mouseout to funciton
  7875. // (#667).
  7876. addEvent(label.element, isMS ? 'mouseover' : 'mouseenter', function () {
  7877. if (curState !== 3) {
  7878. label.setState(1);
  7879. }
  7880. });
  7881. addEvent(label.element, isMS ? 'mouseout' : 'mouseleave', function () {
  7882. if (curState !== 3) {
  7883. label.setState(curState);
  7884. }
  7885. });
  7886. label.setState = function (state) {
  7887. // Hover state is temporary, don't record it
  7888. if (state !== 1) {
  7889. label.state = curState = state;
  7890. }
  7891. // Update visuals
  7892. label
  7893. .removeClass(/highcharts-button-(normal|hover|pressed|disabled)/)
  7894. .addClass('highcharts-button-' +
  7895. ['normal', 'hover', 'pressed', 'disabled'][state || 0]);
  7896. if (!styledMode) {
  7897. label
  7898. .attr([
  7899. normalState,
  7900. hoverState,
  7901. pressedState,
  7902. disabledState
  7903. ][state || 0])
  7904. .css([
  7905. normalStyle,
  7906. hoverStyle,
  7907. pressedStyle,
  7908. disabledStyle
  7909. ][state || 0]);
  7910. }
  7911. };
  7912. // Presentational attributes
  7913. if (!styledMode) {
  7914. label
  7915. .attr(normalState)
  7916. .css(extend({ cursor: 'default' }, normalStyle));
  7917. }
  7918. return label
  7919. .on('click', function (e) {
  7920. if (curState !== 3) {
  7921. callback.call(label, e);
  7922. }
  7923. });
  7924. };
  7925. /**
  7926. * Make a straight line crisper by not spilling out to neighbour pixels.
  7927. *
  7928. * @function Highcharts.SVGRenderer#crispLine
  7929. *
  7930. * @param {Highcharts.SVGPathArray} points
  7931. * The original points on the format `[['M', 0, 0], ['L', 100, 0]]`.
  7932. *
  7933. * @param {number} width
  7934. * The width of the line.
  7935. *
  7936. * @param {string} roundingFunction
  7937. * The rounding function name on the `Math` object, can be one of
  7938. * `round`, `floor` or `ceil`.
  7939. *
  7940. * @return {Highcharts.SVGPathArray}
  7941. * The original points array, but modified to render crisply.
  7942. */
  7943. SVGRenderer.prototype.crispLine = function (points, width, roundingFunction) {
  7944. if (roundingFunction === void 0) { roundingFunction = 'round'; }
  7945. var start = points[0];
  7946. var end = points[1];
  7947. // Normalize to a crisp line
  7948. if (start[1] === end[1]) {
  7949. // Substract due to #1129. Now bottom and left axis gridlines behave
  7950. // the same.
  7951. start[1] = end[1] =
  7952. Math[roundingFunction](start[1]) - (width % 2 / 2);
  7953. }
  7954. if (start[2] === end[2]) {
  7955. start[2] = end[2] =
  7956. Math[roundingFunction](start[2]) + (width % 2 / 2);
  7957. }
  7958. return points;
  7959. };
  7960. /**
  7961. * Draw a path, wraps the SVG `path` element.
  7962. *
  7963. * @sample highcharts/members/renderer-path-on-chart/
  7964. * Draw a path in a chart
  7965. * @sample highcharts/members/renderer-path/
  7966. * Draw a path independent from a chart
  7967. *
  7968. * @example
  7969. * var path = renderer.path(['M', 10, 10, 'L', 30, 30, 'z'])
  7970. * .attr({ stroke: '#ff00ff' })
  7971. * .add();
  7972. *
  7973. * @function Highcharts.SVGRenderer#path
  7974. *
  7975. * @param {Highcharts.SVGPathArray} [path]
  7976. * An SVG path definition in array form.
  7977. *
  7978. * @return {Highcharts.SVGElement}
  7979. * The generated wrapper element.
  7980. *
  7981. */ /**
  7982. * Draw a path, wraps the SVG `path` element.
  7983. *
  7984. * @function Highcharts.SVGRenderer#path
  7985. *
  7986. * @param {Highcharts.SVGAttributes} [attribs]
  7987. * The initial attributes.
  7988. *
  7989. * @return {Highcharts.SVGElement}
  7990. * The generated wrapper element.
  7991. */
  7992. SVGRenderer.prototype.path = function (path) {
  7993. var attribs = (this.styledMode ? {} : {
  7994. fill: 'none'
  7995. });
  7996. if (isArray(path)) {
  7997. attribs.d = path;
  7998. }
  7999. else if (isObject(path)) { // attributes
  8000. extend(attribs, path);
  8001. }
  8002. return this.createElement('path').attr(attribs);
  8003. };
  8004. /**
  8005. * Draw a circle, wraps the SVG `circle` element.
  8006. *
  8007. * @sample highcharts/members/renderer-circle/
  8008. * Drawing a circle
  8009. *
  8010. * @function Highcharts.SVGRenderer#circle
  8011. *
  8012. * @param {number} [x]
  8013. * The center x position.
  8014. *
  8015. * @param {number} [y]
  8016. * The center y position.
  8017. *
  8018. * @param {number} [r]
  8019. * The radius.
  8020. *
  8021. * @return {Highcharts.SVGElement}
  8022. * The generated wrapper element.
  8023. */ /**
  8024. * Draw a circle, wraps the SVG `circle` element.
  8025. *
  8026. * @function Highcharts.SVGRenderer#circle
  8027. *
  8028. * @param {Highcharts.SVGAttributes} [attribs]
  8029. * The initial attributes.
  8030. *
  8031. * @return {Highcharts.SVGElement}
  8032. * The generated wrapper element.
  8033. */
  8034. SVGRenderer.prototype.circle = function (x, y, r) {
  8035. var attribs = (isObject(x) ?
  8036. x :
  8037. typeof x === 'undefined' ? {} : { x: x, y: y, r: r }), wrapper = this.createElement('circle');
  8038. // Setting x or y translates to cx and cy
  8039. wrapper.xSetter = wrapper.ySetter = function (value, key, element) {
  8040. element.setAttribute('c' + key, value);
  8041. };
  8042. return wrapper.attr(attribs);
  8043. };
  8044. /**
  8045. * Draw and return an arc.
  8046. *
  8047. * @sample highcharts/members/renderer-arc/
  8048. * Drawing an arc
  8049. *
  8050. * @function Highcharts.SVGRenderer#arc
  8051. *
  8052. * @param {number} [x=0]
  8053. * Center X position.
  8054. *
  8055. * @param {number} [y=0]
  8056. * Center Y position.
  8057. *
  8058. * @param {number} [r=0]
  8059. * The outer radius' of the arc.
  8060. *
  8061. * @param {number} [innerR=0]
  8062. * Inner radius like used in donut charts.
  8063. *
  8064. * @param {number} [start=0]
  8065. * The starting angle of the arc in radians, where 0 is to the right and
  8066. * `-Math.PI/2` is up.
  8067. *
  8068. * @param {number} [end=0]
  8069. * The ending angle of the arc in radians, where 0 is to the right and
  8070. * `-Math.PI/2` is up.
  8071. *
  8072. * @return {Highcharts.SVGElement}
  8073. * The generated wrapper element.
  8074. */ /**
  8075. * Draw and return an arc. Overloaded function that takes arguments object.
  8076. *
  8077. * @function Highcharts.SVGRenderer#arc
  8078. *
  8079. * @param {Highcharts.SVGAttributes} attribs
  8080. * Initial SVG attributes.
  8081. *
  8082. * @return {Highcharts.SVGElement}
  8083. * The generated wrapper element.
  8084. */
  8085. SVGRenderer.prototype.arc = function (x, y, r, innerR, start, end) {
  8086. var arc,
  8087. options;
  8088. if (isObject(x)) {
  8089. options = x;
  8090. y = options.y;
  8091. r = options.r;
  8092. innerR = options.innerR;
  8093. start = options.start;
  8094. end = options.end;
  8095. x = options.x;
  8096. }
  8097. else {
  8098. options = {
  8099. innerR: innerR,
  8100. start: start,
  8101. end: end
  8102. };
  8103. }
  8104. // Arcs are defined as symbols for the ability to set
  8105. // attributes in attr and animate
  8106. arc = this.symbol('arc', x, y, r, r, options);
  8107. arc.r = r; // #959
  8108. return arc;
  8109. };
  8110. /**
  8111. * Draw and return a rectangle.
  8112. *
  8113. * @function Highcharts.SVGRenderer#rect
  8114. *
  8115. * @param {number} [x]
  8116. * Left position.
  8117. *
  8118. * @param {number} [y]
  8119. * Top position.
  8120. *
  8121. * @param {number} [width]
  8122. * Width of the rectangle.
  8123. *
  8124. * @param {number} [height]
  8125. * Height of the rectangle.
  8126. *
  8127. * @param {number} [r]
  8128. * Border corner radius.
  8129. *
  8130. * @param {number} [strokeWidth]
  8131. * A stroke width can be supplied to allow crisp drawing.
  8132. *
  8133. * @return {Highcharts.SVGElement}
  8134. * The generated wrapper element.
  8135. */ /**
  8136. * Draw and return a rectangle.
  8137. *
  8138. * @sample highcharts/members/renderer-rect-on-chart/
  8139. * Draw a rectangle in a chart
  8140. * @sample highcharts/members/renderer-rect/
  8141. * Draw a rectangle independent from a chart
  8142. *
  8143. * @function Highcharts.SVGRenderer#rect
  8144. *
  8145. * @param {Highcharts.SVGAttributes} [attributes]
  8146. * General SVG attributes for the rectangle.
  8147. *
  8148. * @return {Highcharts.SVGElement}
  8149. * The generated wrapper element.
  8150. */
  8151. SVGRenderer.prototype.rect = function (x, y, width, height, r, strokeWidth) {
  8152. r = isObject(x) ? x.r : r;
  8153. var wrapper = this.createElement('rect'),
  8154. attribs = isObject(x) ?
  8155. x :
  8156. typeof x === 'undefined' ?
  8157. {} :
  8158. {
  8159. x: x,
  8160. y: y,
  8161. width: Math.max(width, 0),
  8162. height: Math.max(height, 0)
  8163. };
  8164. if (!this.styledMode) {
  8165. if (typeof strokeWidth !== 'undefined') {
  8166. attribs.strokeWidth = strokeWidth;
  8167. attribs = wrapper.crisp(attribs);
  8168. }
  8169. attribs.fill = 'none';
  8170. }
  8171. if (r) {
  8172. attribs.r = r;
  8173. }
  8174. wrapper.rSetter = function (value, key, element) {
  8175. wrapper.r = value;
  8176. attr(element, {
  8177. rx: value,
  8178. ry: value
  8179. });
  8180. };
  8181. wrapper.rGetter = function () {
  8182. return wrapper.r;
  8183. };
  8184. return wrapper.attr(attribs);
  8185. };
  8186. /**
  8187. * Resize the {@link SVGRenderer#box} and re-align all aligned child
  8188. * elements.
  8189. *
  8190. * @sample highcharts/members/renderer-g/
  8191. * Show and hide grouped objects
  8192. *
  8193. * @function Highcharts.SVGRenderer#setSize
  8194. *
  8195. * @param {number} width
  8196. * The new pixel width.
  8197. *
  8198. * @param {number} height
  8199. * The new pixel height.
  8200. *
  8201. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animate=true]
  8202. * Whether and how to animate.
  8203. */
  8204. SVGRenderer.prototype.setSize = function (width, height, animate) {
  8205. var renderer = this,
  8206. alignedObjects = renderer.alignedObjects,
  8207. i = alignedObjects.length;
  8208. renderer.width = width;
  8209. renderer.height = height;
  8210. renderer.boxWrapper.animate({
  8211. width: width,
  8212. height: height
  8213. }, {
  8214. step: function () {
  8215. this.attr({
  8216. viewBox: '0 0 ' + this.attr('width') + ' ' +
  8217. this.attr('height')
  8218. });
  8219. },
  8220. duration: pick(animate, true) ? void 0 : 0
  8221. });
  8222. while (i--) {
  8223. alignedObjects[i].align();
  8224. }
  8225. };
  8226. /**
  8227. * Create and return an svg group element. Child
  8228. * {@link Highcharts.SVGElement} objects are added to the group by using the
  8229. * group as the first parameter in {@link Highcharts.SVGElement#add|add()}.
  8230. *
  8231. * @function Highcharts.SVGRenderer#g
  8232. *
  8233. * @param {string} [name]
  8234. * The group will be given a class name of `highcharts-{name}`. This
  8235. * can be used for styling and scripting.
  8236. *
  8237. * @return {Highcharts.SVGElement}
  8238. * The generated wrapper element.
  8239. */
  8240. SVGRenderer.prototype.g = function (name) {
  8241. var elem = this.createElement('g');
  8242. return name ?
  8243. elem.attr({ 'class': 'highcharts-' + name }) :
  8244. elem;
  8245. };
  8246. /**
  8247. * Display an image.
  8248. *
  8249. * @sample highcharts/members/renderer-image-on-chart/
  8250. * Add an image in a chart
  8251. * @sample highcharts/members/renderer-image/
  8252. * Add an image independent of a chart
  8253. *
  8254. * @function Highcharts.SVGRenderer#image
  8255. *
  8256. * @param {string} src
  8257. * The image source.
  8258. *
  8259. * @param {number} [x]
  8260. * The X position.
  8261. *
  8262. * @param {number} [y]
  8263. * The Y position.
  8264. *
  8265. * @param {number} [width]
  8266. * The image width. If omitted, it defaults to the image file width.
  8267. *
  8268. * @param {number} [height]
  8269. * The image height. If omitted it defaults to the image file
  8270. * height.
  8271. *
  8272. * @param {Function} [onload]
  8273. * Event handler for image load.
  8274. *
  8275. * @return {Highcharts.SVGElement}
  8276. * The generated wrapper element.
  8277. */
  8278. SVGRenderer.prototype.image = function (src, x, y, width, height, onload) {
  8279. var attribs = { preserveAspectRatio: 'none' }, elemWrapper, dummy, setSVGImageSource = function (el, src) {
  8280. // Set the href in the xlink namespace
  8281. if (el.setAttributeNS) {
  8282. el.setAttributeNS('http://www.w3.org/1999/xlink', 'href', src);
  8283. }
  8284. else {
  8285. // could be exporting in IE
  8286. // using href throws "not supported" in ie7 and under,
  8287. // requries regex shim to fix later
  8288. el.setAttribute('hc-svg-href', src);
  8289. }
  8290. }, onDummyLoad = function (e) {
  8291. setSVGImageSource(elemWrapper.element, src);
  8292. onload.call(elemWrapper, e);
  8293. };
  8294. // optional properties
  8295. if (arguments.length > 1) {
  8296. extend(attribs, {
  8297. x: x,
  8298. y: y,
  8299. width: width,
  8300. height: height
  8301. });
  8302. }
  8303. elemWrapper = this.createElement('image').attr(attribs);
  8304. // Add load event if supplied
  8305. if (onload) {
  8306. // We have to use a dummy HTML image since IE support for SVG image
  8307. // load events is very buggy. First set a transparent src, wait for
  8308. // dummy to load, and then add the real src to the SVG image.
  8309. setSVGImageSource(elemWrapper.element, 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' /* eslint-disable-line */);
  8310. dummy = new win.Image();
  8311. addEvent(dummy, 'load', onDummyLoad);
  8312. dummy.src = src;
  8313. if (dummy.complete) {
  8314. onDummyLoad({});
  8315. }
  8316. }
  8317. else {
  8318. setSVGImageSource(elemWrapper.element, src);
  8319. }
  8320. return elemWrapper;
  8321. };
  8322. /**
  8323. * Draw a symbol out of pre-defined shape paths from
  8324. * {@link SVGRenderer#symbols}.
  8325. * It is used in Highcharts for point makers, which cake a `symbol` option,
  8326. * and label and button backgrounds like in the tooltip and stock flags.
  8327. *
  8328. * @function Highcharts.SVGRenderer#symbol
  8329. *
  8330. * @param {string} symbol
  8331. * The symbol name.
  8332. *
  8333. * @param {number} [x]
  8334. * The X coordinate for the top left position.
  8335. *
  8336. * @param {number} [y]
  8337. * The Y coordinate for the top left position.
  8338. *
  8339. * @param {number} [width]
  8340. * The pixel width.
  8341. *
  8342. * @param {number} [height]
  8343. * The pixel height.
  8344. *
  8345. * @param {Highcharts.SymbolOptionsObject} [options]
  8346. * Additional options, depending on the actual symbol drawn.
  8347. *
  8348. * @return {Highcharts.SVGElement}
  8349. */
  8350. SVGRenderer.prototype.symbol = function (symbol, x, y, width, height, options) {
  8351. var ren = this,
  8352. obj,
  8353. imageRegex = /^url\((.*?)\)$/,
  8354. isImage = imageRegex.test(symbol),
  8355. sym = (!isImage && (this.symbols[symbol] ? symbol : 'circle')),
  8356. // get the symbol definition function
  8357. symbolFn = (sym && this.symbols[sym]),
  8358. path,
  8359. imageSrc,
  8360. centerImage;
  8361. if (symbolFn) {
  8362. // Check if there's a path defined for this symbol
  8363. if (typeof x === 'number') {
  8364. path = symbolFn.call(this.symbols, Math.round(x || 0), Math.round(y || 0), width || 0, height || 0, options);
  8365. }
  8366. obj = this.path(path);
  8367. if (!ren.styledMode) {
  8368. obj.attr('fill', 'none');
  8369. }
  8370. // expando properties for use in animate and attr
  8371. extend(obj, {
  8372. symbolName: sym,
  8373. x: x,
  8374. y: y,
  8375. width: width,
  8376. height: height
  8377. });
  8378. if (options) {
  8379. extend(obj, options);
  8380. }
  8381. // Image symbols
  8382. }
  8383. else if (isImage) {
  8384. imageSrc = symbol.match(imageRegex)[1];
  8385. // Create the image synchronously, add attribs async
  8386. obj = this.image(imageSrc);
  8387. // The image width is not always the same as the symbol width. The
  8388. // image may be centered within the symbol, as is the case when
  8389. // image shapes are used as label backgrounds, for example in flags.
  8390. obj.imgwidth = pick(symbolSizes[imageSrc] && symbolSizes[imageSrc].width, options && options.width);
  8391. obj.imgheight = pick(symbolSizes[imageSrc] && symbolSizes[imageSrc].height, options && options.height);
  8392. /**
  8393. * Set the size and position
  8394. */
  8395. centerImage = function () {
  8396. obj.attr({
  8397. width: obj.width,
  8398. height: obj.height
  8399. });
  8400. };
  8401. /**
  8402. * Width and height setters that take both the image's physical size
  8403. * and the label size into consideration, and translates the image
  8404. * to center within the label.
  8405. */
  8406. ['width', 'height'].forEach(function (key) {
  8407. obj[key + 'Setter'] = function (value, key) {
  8408. var attribs = {}, imgSize = this['img' + key], trans = key === 'width' ? 'translateX' : 'translateY';
  8409. this[key] = value;
  8410. if (defined(imgSize)) {
  8411. // Scale and center the image within its container.
  8412. // The name `backgroundSize` is taken from the CSS spec,
  8413. // but the value `within` is made up. Other possible
  8414. // values in the spec, `cover` and `contain`, can be
  8415. // implemented if needed.
  8416. if (options &&
  8417. options.backgroundSize === 'within' &&
  8418. this.width &&
  8419. this.height) {
  8420. imgSize = Math.round(imgSize * Math.min(this.width / this.imgwidth, this.height / this.imgheight));
  8421. }
  8422. if (this.element) {
  8423. this.element.setAttribute(key, imgSize);
  8424. }
  8425. if (!this.alignByTranslate) {
  8426. attribs[trans] = ((this[key] || 0) - imgSize) / 2;
  8427. this.attr(attribs);
  8428. }
  8429. }
  8430. };
  8431. });
  8432. if (defined(x)) {
  8433. obj.attr({
  8434. x: x,
  8435. y: y
  8436. });
  8437. }
  8438. obj.isImg = true;
  8439. if (defined(obj.imgwidth) && defined(obj.imgheight)) {
  8440. centerImage();
  8441. }
  8442. else {
  8443. // Initialize image to be 0 size so export will still function
  8444. // if there's no cached sizes.
  8445. obj.attr({ width: 0, height: 0 });
  8446. // Create a dummy JavaScript image to get the width and height.
  8447. createElement('img', {
  8448. onload: function () {
  8449. var chart = charts[ren.chartIndex];
  8450. // Special case for SVGs on IE11, the width is not
  8451. // accessible until the image is part of the DOM
  8452. // (#2854).
  8453. if (this.width === 0) {
  8454. css(this, {
  8455. position: 'absolute',
  8456. top: '-999em'
  8457. });
  8458. doc.body.appendChild(this);
  8459. }
  8460. // Center the image
  8461. symbolSizes[imageSrc] = {
  8462. width: this.width,
  8463. height: this.height
  8464. };
  8465. obj.imgwidth = this.width;
  8466. obj.imgheight = this.height;
  8467. if (obj.element) {
  8468. centerImage();
  8469. }
  8470. // Clean up after #2854 workaround.
  8471. if (this.parentNode) {
  8472. this.parentNode.removeChild(this);
  8473. }
  8474. // Fire the load event when all external images are
  8475. // loaded
  8476. ren.imgCount--;
  8477. if (!ren.imgCount && chart && !chart.hasLoaded) {
  8478. chart.onload();
  8479. }
  8480. },
  8481. src: imageSrc
  8482. });
  8483. this.imgCount++;
  8484. }
  8485. }
  8486. return obj;
  8487. };
  8488. /**
  8489. * Define a clipping rectangle. The clipping rectangle is later applied
  8490. * to {@link SVGElement} objects through the {@link SVGElement#clip}
  8491. * function.
  8492. *
  8493. * @example
  8494. * var circle = renderer.circle(100, 100, 100)
  8495. * .attr({ fill: 'red' })
  8496. * .add();
  8497. * var clipRect = renderer.clipRect(100, 100, 100, 100);
  8498. *
  8499. * // Leave only the lower right quarter visible
  8500. * circle.clip(clipRect);
  8501. *
  8502. * @function Highcharts.SVGRenderer#clipRect
  8503. *
  8504. * @param {number} [x]
  8505. *
  8506. * @param {number} [y]
  8507. *
  8508. * @param {number} [width]
  8509. *
  8510. * @param {number} [height]
  8511. *
  8512. * @return {Highcharts.ClipRectElement}
  8513. * A clipping rectangle.
  8514. */
  8515. SVGRenderer.prototype.clipRect = function (x, y, width, height) {
  8516. var wrapper,
  8517. // Add a hyphen at the end to avoid confusion in testing indexes
  8518. // -1 and -10, -11 etc (#6550)
  8519. id = uniqueKey() + '-', clipPath = this.createElement('clipPath').attr({
  8520. id: id
  8521. }).add(this.defs);
  8522. wrapper = this.rect(x, y, width, height, 0).add(clipPath);
  8523. wrapper.id = id;
  8524. wrapper.clipPath = clipPath;
  8525. wrapper.count = 0;
  8526. return wrapper;
  8527. };
  8528. /**
  8529. * Draw text. The text can contain a subset of HTML, like spans and anchors
  8530. * and some basic text styling of these. For more advanced features like
  8531. * border and background, use {@link Highcharts.SVGRenderer#label} instead.
  8532. * To update the text after render, run `text.attr({ text: 'New text' })`.
  8533. *
  8534. * @sample highcharts/members/renderer-text-on-chart/
  8535. * Annotate the chart freely
  8536. * @sample highcharts/members/renderer-on-chart/
  8537. * Annotate with a border and in response to the data
  8538. * @sample highcharts/members/renderer-text/
  8539. * Formatted text
  8540. *
  8541. * @function Highcharts.SVGRenderer#text
  8542. *
  8543. * @param {string} [str]
  8544. * The text of (subset) HTML to draw.
  8545. *
  8546. * @param {number} [x]
  8547. * The x position of the text's lower left corner.
  8548. *
  8549. * @param {number} [y]
  8550. * The y position of the text's lower left corner.
  8551. *
  8552. * @param {boolean} [useHTML=false]
  8553. * Use HTML to render the text.
  8554. *
  8555. * @return {Highcharts.SVGElement}
  8556. * The text object.
  8557. */
  8558. SVGRenderer.prototype.text = function (str, x, y, useHTML) {
  8559. // declare variables
  8560. var renderer = this,
  8561. wrapper,
  8562. attribs = {};
  8563. if (useHTML && (renderer.allowHTML || !renderer.forExport)) {
  8564. return renderer.html(str, x, y);
  8565. }
  8566. attribs.x = Math.round(x || 0); // X always needed for line-wrap logic
  8567. if (y) {
  8568. attribs.y = Math.round(y);
  8569. }
  8570. if (defined(str)) {
  8571. attribs.text = str;
  8572. }
  8573. wrapper = renderer.createElement('text')
  8574. .attr(attribs);
  8575. if (!useHTML) {
  8576. wrapper.xSetter = function (value, key, element) {
  8577. var tspans = element.getElementsByTagName('tspan'),
  8578. tspan,
  8579. parentVal = element.getAttribute(key),
  8580. i;
  8581. for (i = 0; i < tspans.length; i++) {
  8582. tspan = tspans[i];
  8583. // If the x values are equal, the tspan represents a
  8584. // linebreak
  8585. if (tspan.getAttribute(key) === parentVal) {
  8586. tspan.setAttribute(key, value);
  8587. }
  8588. }
  8589. element.setAttribute(key, value);
  8590. };
  8591. }
  8592. return wrapper;
  8593. };
  8594. /**
  8595. * Utility to return the baseline offset and total line height from the font
  8596. * size.
  8597. *
  8598. * @function Highcharts.SVGRenderer#fontMetrics
  8599. *
  8600. * @param {number|string} [fontSize]
  8601. * The current font size to inspect. If not given, the font size
  8602. * will be found from the DOM element.
  8603. *
  8604. * @param {Highcharts.SVGElement|Highcharts.SVGDOMElement} [elem]
  8605. * The element to inspect for a current font size.
  8606. *
  8607. * @return {Highcharts.FontMetricsObject}
  8608. * The font metrics.
  8609. */
  8610. SVGRenderer.prototype.fontMetrics = function (fontSize, elem) {
  8611. var lineHeight,
  8612. baseline;
  8613. if ((this.styledMode || !/px/.test(fontSize)) &&
  8614. win.getComputedStyle // old IE doesn't support it
  8615. ) {
  8616. fontSize = elem && SVGElement.prototype.getStyle.call(elem, 'font-size');
  8617. }
  8618. else {
  8619. fontSize = fontSize ||
  8620. // When the elem is a DOM element (#5932)
  8621. (elem && elem.style && elem.style.fontSize) ||
  8622. // Fall back on the renderer style default
  8623. (this.style && this.style.fontSize);
  8624. }
  8625. // Handle different units
  8626. if (/px/.test(fontSize)) {
  8627. fontSize = pInt(fontSize);
  8628. }
  8629. else {
  8630. fontSize = 12;
  8631. }
  8632. // Empirical values found by comparing font size and bounding box
  8633. // height. Applies to the default font family.
  8634. // https://jsfiddle.net/highcharts/7xvn7/
  8635. lineHeight = fontSize < 24 ? fontSize + 3 : Math.round(fontSize * 1.2);
  8636. baseline = Math.round(lineHeight * 0.8);
  8637. return {
  8638. h: lineHeight,
  8639. b: baseline,
  8640. f: fontSize
  8641. };
  8642. };
  8643. /**
  8644. * Correct X and Y positioning of a label for rotation (#1764).
  8645. *
  8646. * @private
  8647. * @function Highcharts.SVGRenderer#rotCorr
  8648. *
  8649. * @param {number} baseline
  8650. *
  8651. * @param {number} rotation
  8652. *
  8653. * @param {boolean} [alterY]
  8654. *
  8655. * @param {Highcharts.PositionObject}
  8656. */
  8657. SVGRenderer.prototype.rotCorr = function (baseline, rotation, alterY) {
  8658. var y = baseline;
  8659. if (rotation && alterY) {
  8660. y = Math.max(y * Math.cos(rotation * deg2rad), 4);
  8661. }
  8662. return {
  8663. x: (-baseline / 3) * Math.sin(rotation * deg2rad),
  8664. y: y
  8665. };
  8666. };
  8667. /**
  8668. * Compatibility function to convert the legacy one-dimensional path array
  8669. * into an array of segments.
  8670. *
  8671. * It is used in maps to parse the `path` option, and in SVGRenderer.dSetter
  8672. * to support legacy paths from demos.
  8673. *
  8674. * @private
  8675. * @function Highcharts.SVGRenderer#pathToSegments
  8676. */
  8677. SVGRenderer.prototype.pathToSegments = function (path) {
  8678. var ret = [];
  8679. var segment = [];
  8680. var commandLength = {
  8681. A: 8,
  8682. C: 7,
  8683. H: 2,
  8684. L: 3,
  8685. M: 3,
  8686. Q: 5,
  8687. S: 5,
  8688. T: 3,
  8689. V: 2
  8690. };
  8691. // Short, non-typesafe parsing of the one-dimensional array. It splits
  8692. // the path on any string. This is not type checked against the tuple
  8693. // types, but is shorter, and doesn't require specific checks for any
  8694. // command type in SVG.
  8695. for (var i = 0; i < path.length; i++) {
  8696. // Command skipped, repeat previous or insert L/l for M/m
  8697. if (isString(segment[0]) &&
  8698. isNumber(path[i]) &&
  8699. segment.length === commandLength[(segment[0].toUpperCase())]) {
  8700. path.splice(i, 0, segment[0].replace('M', 'L').replace('m', 'l'));
  8701. }
  8702. // Split on string
  8703. if (typeof path[i] === 'string') {
  8704. if (segment.length) {
  8705. ret.push(segment.slice(0));
  8706. }
  8707. segment.length = 0;
  8708. }
  8709. segment.push(path[i]);
  8710. }
  8711. ret.push(segment.slice(0));
  8712. return ret;
  8713. /*
  8714. // Fully type-safe version where each tuple type is checked. The
  8715. // downside is filesize and a lack of flexibility for unsupported
  8716. // commands
  8717. const ret: SVGPath = [],
  8718. commands = {
  8719. A: 7,
  8720. C: 6,
  8721. H: 1,
  8722. L: 2,
  8723. M: 2,
  8724. Q: 4,
  8725. S: 4,
  8726. T: 2,
  8727. V: 1,
  8728. Z: 0
  8729. };
  8730. let i = 0,
  8731. lastI = 0,
  8732. lastCommand;
  8733. while (i < path.length) {
  8734. const item = path[i];
  8735. let command;
  8736. if (typeof item === 'string') {
  8737. command = item;
  8738. i += 1;
  8739. } else {
  8740. command = lastCommand || 'M';
  8741. }
  8742. // Upper case
  8743. const commandUC = command.toUpperCase();
  8744. if (commandUC in commands) {
  8745. // No numeric parameters
  8746. if (command === 'Z' || command === 'z') {
  8747. ret.push([command]);
  8748. // One numeric parameter
  8749. } else {
  8750. const val0 = path[i];
  8751. if (typeof val0 === 'number') {
  8752. // Horizontal line to
  8753. if (command === 'H' || command === 'h') {
  8754. ret.push([command, val0]);
  8755. i += 1;
  8756. // Vertical line to
  8757. } else if (command === 'V' || command === 'v') {
  8758. ret.push([command, val0]);
  8759. i += 1;
  8760. // Two numeric parameters
  8761. } else {
  8762. const val1 = path[i + 1];
  8763. if (typeof val1 === 'number') {
  8764. // lineTo
  8765. if (command === 'L' || command === 'l') {
  8766. ret.push([command, val0, val1]);
  8767. i += 2;
  8768. // moveTo
  8769. } else if (command === 'M' || command === 'm') {
  8770. ret.push([command, val0, val1]);
  8771. i += 2;
  8772. // Smooth quadratic bezier
  8773. } else if (command === 'T' || command === 't') {
  8774. ret.push([command, val0, val1]);
  8775. i += 2;
  8776. // Four numeric parameters
  8777. } else {
  8778. const val2 = path[i + 2],
  8779. val3 = path[i + 3];
  8780. if (
  8781. typeof val2 === 'number' &&
  8782. typeof val3 === 'number'
  8783. ) {
  8784. // Quadratic bezier to
  8785. if (
  8786. command === 'Q' ||
  8787. command === 'q'
  8788. ) {
  8789. ret.push([
  8790. command,
  8791. val0,
  8792. val1,
  8793. val2,
  8794. val3
  8795. ]);
  8796. i += 4;
  8797. // Smooth cubic bezier to
  8798. } else if (
  8799. command === 'S' ||
  8800. command === 's'
  8801. ) {
  8802. ret.push([
  8803. command,
  8804. val0,
  8805. val1,
  8806. val2,
  8807. val3
  8808. ]);
  8809. i += 4;
  8810. // Six numeric parameters
  8811. } else {
  8812. const val4 = path[i + 4],
  8813. val5 = path[i + 5];
  8814. if (
  8815. typeof val4 === 'number' &&
  8816. typeof val5 === 'number'
  8817. ) {
  8818. // Curve to
  8819. if (
  8820. command === 'C' ||
  8821. command === 'c'
  8822. ) {
  8823. ret.push([
  8824. command,
  8825. val0,
  8826. val1,
  8827. val2,
  8828. val3,
  8829. val4,
  8830. val5
  8831. ]);
  8832. i += 6;
  8833. // Seven numeric parameters
  8834. } else {
  8835. const val6 = path[i + 6];
  8836. // Arc to
  8837. if (
  8838. typeof val6 ===
  8839. 'number' &&
  8840. (
  8841. command === 'A' ||
  8842. command === 'a'
  8843. )
  8844. ) {
  8845. ret.push([
  8846. command,
  8847. val0,
  8848. val1,
  8849. val2,
  8850. val3,
  8851. val4,
  8852. val5,
  8853. val6
  8854. ]);
  8855. i += 7;
  8856. }
  8857. }
  8858. }
  8859. }
  8860. }
  8861. }
  8862. }
  8863. }
  8864. }
  8865. }
  8866. }
  8867. // An unmarked command following a moveTo is a lineTo
  8868. lastCommand = command === 'M' ? 'L' : command;
  8869. if (i === lastI) {
  8870. break;
  8871. }
  8872. lastI = i;
  8873. }
  8874. return ret;
  8875. */
  8876. };
  8877. /**
  8878. * Draw a label, which is an extended text element with support for border
  8879. * and background. Highcharts creates a `g` element with a text and a `path`
  8880. * or `rect` inside, to make it behave somewhat like a HTML div. Border and
  8881. * background are set through `stroke`, `stroke-width` and `fill` attributes
  8882. * using the {@link Highcharts.SVGElement#attr|attr} method. To update the
  8883. * text after render, run `label.attr({ text: 'New text' })`.
  8884. *
  8885. * @sample highcharts/members/renderer-label-on-chart/
  8886. * A label on the chart
  8887. *
  8888. * @function Highcharts.SVGRenderer#label
  8889. *
  8890. * @param {string} str
  8891. * The initial text string or (subset) HTML to render.
  8892. *
  8893. * @param {number} x
  8894. * The x position of the label's left side.
  8895. *
  8896. * @param {number} [y]
  8897. * The y position of the label's top side or baseline, depending on
  8898. * the `baseline` parameter.
  8899. *
  8900. * @param {string} [shape='rect']
  8901. * The shape of the label's border/background, if any. Defaults to
  8902. * `rect`. Other possible values are `callout` or other shapes
  8903. * defined in {@link Highcharts.SVGRenderer#symbols}.
  8904. *
  8905. * @param {number} [anchorX]
  8906. * In case the `shape` has a pointer, like a flag, this is the
  8907. * coordinates it should be pinned to.
  8908. *
  8909. * @param {number} [anchorY]
  8910. * In case the `shape` has a pointer, like a flag, this is the
  8911. * coordinates it should be pinned to.
  8912. *
  8913. * @param {boolean} [useHTML=false]
  8914. * Wether to use HTML to render the label.
  8915. *
  8916. * @param {boolean} [baseline=false]
  8917. * Whether to position the label relative to the text baseline,
  8918. * like {@link Highcharts.SVGRenderer#text|renderer.text}, or to the
  8919. * upper border of the rectangle.
  8920. *
  8921. * @param {string} [className]
  8922. * Class name for the group.
  8923. *
  8924. * @return {Highcharts.SVGElement}
  8925. * The generated label.
  8926. */
  8927. SVGRenderer.prototype.label = function (str, x, y, shape, anchorX, anchorY, useHTML, baseline, className) {
  8928. return new SVGLabel(this, str, x, y, shape, anchorX, anchorY, useHTML, baseline, className);
  8929. };
  8930. return SVGRenderer;
  8931. }());
  8932. /**
  8933. * A pointer to the renderer's associated Element class. The VMLRenderer
  8934. * will have a pointer to VMLElement here.
  8935. *
  8936. * @name Highcharts.SVGRenderer#Element
  8937. * @type {Highcharts.SVGElement}
  8938. */
  8939. SVGRenderer.prototype.Element = SVGElement;
  8940. /**
  8941. * @private
  8942. */
  8943. SVGRenderer.prototype.SVG_NS = SVG_NS;
  8944. /**
  8945. * Dummy function for plugins, called every time the renderer is updated.
  8946. * Prior to Highcharts 5, this was used for the canvg renderer.
  8947. *
  8948. * @deprecated
  8949. * @function Highcharts.SVGRenderer#draw
  8950. */
  8951. SVGRenderer.prototype.draw = noop;
  8952. /**
  8953. * A collection of characters mapped to HTML entities. When `useHTML` on an
  8954. * element is true, these entities will be rendered correctly by HTML. In
  8955. * the SVG pseudo-HTML, they need to be unescaped back to simple characters,
  8956. * so for example `&lt;` will render as `<`.
  8957. *
  8958. * @example
  8959. * // Add support for unescaping quotes
  8960. * Highcharts.SVGRenderer.prototype.escapes['"'] = '&quot;';
  8961. *
  8962. * @name Highcharts.SVGRenderer#escapes
  8963. * @type {Highcharts.Dictionary<string>}
  8964. */
  8965. SVGRenderer.prototype.escapes = {
  8966. '&': '&amp;',
  8967. '<': '&lt;',
  8968. '>': '&gt;',
  8969. "'": '&#39;',
  8970. '"': '&quot;'
  8971. };
  8972. /**
  8973. * An extendable collection of functions for defining symbol paths.
  8974. *
  8975. * @name Highcharts.SVGRenderer#symbols
  8976. * @type {Highcharts.SymbolDictionary}
  8977. */
  8978. SVGRenderer.prototype.symbols = {
  8979. circle: function (x, y, w, h) {
  8980. // Return a full arc
  8981. return this.arc(x + w / 2, y + h / 2, w / 2, h / 2, {
  8982. start: Math.PI * 0.5,
  8983. end: Math.PI * 2.5,
  8984. open: false
  8985. });
  8986. },
  8987. square: function (x, y, w, h) {
  8988. return [
  8989. ['M', x, y],
  8990. ['L', x + w, y],
  8991. ['L', x + w, y + h],
  8992. ['L', x, y + h],
  8993. ['Z']
  8994. ];
  8995. },
  8996. triangle: function (x, y, w, h) {
  8997. return [
  8998. ['M', x + w / 2, y],
  8999. ['L', x + w, y + h],
  9000. ['L', x, y + h],
  9001. ['Z']
  9002. ];
  9003. },
  9004. 'triangle-down': function (x, y, w, h) {
  9005. return [
  9006. ['M', x, y],
  9007. ['L', x + w, y],
  9008. ['L', x + w / 2, y + h],
  9009. ['Z']
  9010. ];
  9011. },
  9012. diamond: function (x, y, w, h) {
  9013. return [
  9014. ['M', x + w / 2, y],
  9015. ['L', x + w, y + h / 2],
  9016. ['L', x + w / 2, y + h],
  9017. ['L', x, y + h / 2],
  9018. ['Z']
  9019. ];
  9020. },
  9021. arc: function (x, y, w, h, options) {
  9022. var arc = [];
  9023. if (options) {
  9024. var start = options.start || 0,
  9025. end = options.end || 0,
  9026. rx = options.r || w,
  9027. ry = options.r || h || w,
  9028. proximity = 0.001,
  9029. fullCircle = Math.abs(end - start - 2 * Math.PI) <
  9030. proximity,
  9031. // Substract a small number to prevent cos and sin of start and
  9032. // end from becoming equal on 360 arcs (related: #1561)
  9033. end = end - proximity,
  9034. innerRadius = options.innerR,
  9035. open = pick(options.open,
  9036. fullCircle),
  9037. cosStart = Math.cos(start),
  9038. sinStart = Math.sin(start),
  9039. cosEnd = Math.cos(end),
  9040. sinEnd = Math.sin(end),
  9041. // Proximity takes care of rounding errors around PI (#6971)
  9042. longArc = pick(options.longArc,
  9043. end - start - Math.PI < proximity ? 0 : 1);
  9044. arc.push([
  9045. 'M',
  9046. x + rx * cosStart,
  9047. y + ry * sinStart
  9048. ], [
  9049. 'A',
  9050. rx,
  9051. ry,
  9052. 0,
  9053. longArc,
  9054. pick(options.clockwise, 1),
  9055. x + rx * cosEnd,
  9056. y + ry * sinEnd
  9057. ]);
  9058. if (defined(innerRadius)) {
  9059. arc.push(open ?
  9060. [
  9061. 'M',
  9062. x + innerRadius * cosEnd,
  9063. y + innerRadius * sinEnd
  9064. ] : [
  9065. 'L',
  9066. x + innerRadius * cosEnd,
  9067. y + innerRadius * sinEnd
  9068. ], [
  9069. 'A',
  9070. innerRadius,
  9071. innerRadius,
  9072. 0,
  9073. longArc,
  9074. // Clockwise - opposite to the outer arc clockwise
  9075. defined(options.clockwise) ? 1 - options.clockwise : 0,
  9076. x + innerRadius * cosStart,
  9077. y + innerRadius * sinStart
  9078. ]);
  9079. }
  9080. if (!open) {
  9081. arc.push(['Z']);
  9082. }
  9083. }
  9084. return arc;
  9085. },
  9086. /**
  9087. * Callout shape used for default tooltips, also used for rounded
  9088. * rectangles in VML
  9089. */
  9090. callout: function (x, y, w, h, options) {
  9091. var arrowLength = 6,
  9092. halfDistance = 6,
  9093. r = Math.min((options && options.r) || 0,
  9094. w,
  9095. h),
  9096. safeDistance = r + halfDistance,
  9097. anchorX = options && options.anchorX,
  9098. anchorY = options && options.anchorY || 0,
  9099. path;
  9100. path = [
  9101. ['M', x + r, y],
  9102. ['L', x + w - r, y],
  9103. ['C', x + w, y, x + w, y, x + w, y + r],
  9104. ['L', x + w, y + h - r],
  9105. ['C', x + w, y + h, x + w, y + h, x + w - r, y + h],
  9106. ['L', x + r, y + h],
  9107. ['C', x, y + h, x, y + h, x, y + h - r],
  9108. ['L', x, y + r],
  9109. ['C', x, y, x, y, x + r, y] // top-left corner
  9110. ];
  9111. if (!isNumber(anchorX)) {
  9112. return path;
  9113. }
  9114. // Anchor on right side
  9115. if (x + anchorX >= w) {
  9116. // Chevron
  9117. if (anchorY > y + safeDistance &&
  9118. anchorY < y + h - safeDistance) {
  9119. path.splice(3, 1, ['L', x + w, anchorY - halfDistance], ['L', x + w + arrowLength, anchorY], ['L', x + w, anchorY + halfDistance], ['L', x + w, y + h - r]);
  9120. // Simple connector
  9121. }
  9122. else {
  9123. path.splice(3, 1, ['L', x + w, h / 2], ['L', anchorX, anchorY], ['L', x + w, h / 2], ['L', x + w, y + h - r]);
  9124. }
  9125. // Anchor on left side
  9126. }
  9127. else if (x + anchorX <= 0) {
  9128. // Chevron
  9129. if (anchorY > y + safeDistance &&
  9130. anchorY < y + h - safeDistance) {
  9131. path.splice(7, 1, ['L', x, anchorY + halfDistance], ['L', x - arrowLength, anchorY], ['L', x, anchorY - halfDistance], ['L', x, y + r]);
  9132. // Simple connector
  9133. }
  9134. else {
  9135. path.splice(7, 1, ['L', x, h / 2], ['L', anchorX, anchorY], ['L', x, h / 2], ['L', x, y + r]);
  9136. }
  9137. }
  9138. else if ( // replace bottom
  9139. anchorY &&
  9140. anchorY > h &&
  9141. anchorX > x + safeDistance &&
  9142. anchorX < x + w - safeDistance) {
  9143. path.splice(5, 1, ['L', anchorX + halfDistance, y + h], ['L', anchorX, y + h + arrowLength], ['L', anchorX - halfDistance, y + h], ['L', x + r, y + h]);
  9144. }
  9145. else if ( // replace top
  9146. anchorY &&
  9147. anchorY < 0 &&
  9148. anchorX > x + safeDistance &&
  9149. anchorX < x + w - safeDistance) {
  9150. path.splice(1, 1, ['L', anchorX - halfDistance, y], ['L', anchorX, y - arrowLength], ['L', anchorX + halfDistance, y], ['L', w - r, y]);
  9151. }
  9152. return path;
  9153. }
  9154. };
  9155. H.SVGRenderer = SVGRenderer;
  9156. H.Renderer = H.SVGRenderer;
  9157. return H.Renderer;
  9158. });
  9159. _registerModule(_modules, 'Core/Renderer/HTML/HTMLElement.js', [_modules['Core/Globals.js'], _modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Utilities.js']], function (H, SVGElement, U) {
  9160. /* *
  9161. *
  9162. * (c) 2010-2021 Torstein Honsi
  9163. *
  9164. * License: www.highcharts.com/license
  9165. *
  9166. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  9167. *
  9168. * */
  9169. var css = U.css,
  9170. defined = U.defined,
  9171. extend = U.extend,
  9172. pick = U.pick,
  9173. pInt = U.pInt;
  9174. /**
  9175. * Element placebo
  9176. * @private
  9177. */
  9178. var HTMLElement = SVGElement;
  9179. var isFirefox = H.isFirefox;
  9180. /* eslint-disable valid-jsdoc */
  9181. // Extend SvgElement for useHTML option.
  9182. extend(HTMLElement.prototype, /** @lends SVGElement.prototype */ {
  9183. /**
  9184. * Apply CSS to HTML elements. This is used in text within SVG rendering and
  9185. * by the VML renderer
  9186. *
  9187. * @private
  9188. * @function Highcharts.SVGElement#htmlCss
  9189. *
  9190. * @param {Highcharts.CSSObject} styles
  9191. *
  9192. * @return {Highcharts.SVGElement}
  9193. */
  9194. htmlCss: function (styles) {
  9195. var wrapper = this,
  9196. element = wrapper.element,
  9197. // When setting or unsetting the width style, we need to update
  9198. // transform (#8809)
  9199. isSettingWidth = (element.tagName === 'SPAN' &&
  9200. styles &&
  9201. 'width' in styles),
  9202. textWidth = pick(isSettingWidth && styles.width,
  9203. void 0),
  9204. doTransform;
  9205. if (isSettingWidth) {
  9206. delete styles.width;
  9207. wrapper.textWidth = textWidth;
  9208. doTransform = true;
  9209. }
  9210. if (styles && styles.textOverflow === 'ellipsis') {
  9211. styles.whiteSpace = 'nowrap';
  9212. styles.overflow = 'hidden';
  9213. }
  9214. wrapper.styles = extend(wrapper.styles, styles);
  9215. css(wrapper.element, styles);
  9216. // Now that all styles are applied, to the transform
  9217. if (doTransform) {
  9218. wrapper.htmlUpdateTransform();
  9219. }
  9220. return wrapper;
  9221. },
  9222. /**
  9223. * VML and useHTML method for calculating the bounding box based on offsets.
  9224. *
  9225. * @private
  9226. * @function Highcharts.SVGElement#htmlGetBBox
  9227. *
  9228. * @param {boolean} refresh
  9229. * Whether to force a fresh value from the DOM or to use the cached
  9230. * value.
  9231. *
  9232. * @return {Highcharts.BBoxObject}
  9233. * A hash containing values for x, y, width and height.
  9234. */
  9235. htmlGetBBox: function () {
  9236. var wrapper = this,
  9237. element = wrapper.element;
  9238. return {
  9239. x: element.offsetLeft,
  9240. y: element.offsetTop,
  9241. width: element.offsetWidth,
  9242. height: element.offsetHeight
  9243. };
  9244. },
  9245. /**
  9246. * VML override private method to update elements based on internal
  9247. * properties based on SVG transform.
  9248. *
  9249. * @private
  9250. * @function Highcharts.SVGElement#htmlUpdateTransform
  9251. * @return {void}
  9252. */
  9253. htmlUpdateTransform: function () {
  9254. // aligning non added elements is expensive
  9255. if (!this.added) {
  9256. this.alignOnAdd = true;
  9257. return;
  9258. }
  9259. var wrapper = this,
  9260. renderer = wrapper.renderer,
  9261. elem = wrapper.element,
  9262. translateX = wrapper.translateX || 0,
  9263. translateY = wrapper.translateY || 0,
  9264. x = wrapper.x || 0,
  9265. y = wrapper.y || 0,
  9266. align = wrapper.textAlign || 'left',
  9267. alignCorrection = {
  9268. left: 0,
  9269. center: 0.5,
  9270. right: 1
  9271. }[align],
  9272. styles = wrapper.styles,
  9273. whiteSpace = styles && styles.whiteSpace;
  9274. /**
  9275. * @private
  9276. * @return {number}
  9277. */
  9278. function getTextPxLength() {
  9279. // Reset multiline/ellipsis in order to read width (#4928,
  9280. // #5417)
  9281. css(elem, {
  9282. width: '',
  9283. whiteSpace: whiteSpace || 'nowrap'
  9284. });
  9285. return elem.offsetWidth;
  9286. }
  9287. // apply translate
  9288. css(elem, {
  9289. marginLeft: translateX,
  9290. marginTop: translateY
  9291. });
  9292. if (!renderer.styledMode && wrapper.shadows) { // used in labels/tooltip
  9293. wrapper.shadows.forEach(function (shadow) {
  9294. css(shadow, {
  9295. marginLeft: translateX + 1,
  9296. marginTop: translateY + 1
  9297. });
  9298. });
  9299. }
  9300. // apply inversion
  9301. if (wrapper.inverted) { // wrapper is a group
  9302. [].forEach.call(elem.childNodes, function (child) {
  9303. renderer.invertChild(child, elem);
  9304. });
  9305. }
  9306. if (elem.tagName === 'SPAN') {
  9307. var rotation = wrapper.rotation, baseline, textWidth = wrapper.textWidth && pInt(wrapper.textWidth), currentTextTransform = [
  9308. rotation,
  9309. align,
  9310. elem.innerHTML,
  9311. wrapper.textWidth,
  9312. wrapper.textAlign
  9313. ].join(',');
  9314. // Update textWidth. Use the memoized textPxLength if possible, to
  9315. // avoid the getTextPxLength function using elem.offsetWidth.
  9316. // Calling offsetWidth affects rendering time as it forces layout
  9317. // (#7656).
  9318. if (textWidth !== wrapper.oldTextWidth &&
  9319. ((textWidth > wrapper.oldTextWidth) ||
  9320. (wrapper.textPxLength || getTextPxLength()) > textWidth) && (
  9321. // Only set the width if the text is able to word-wrap, or
  9322. // text-overflow is ellipsis (#9537)
  9323. /[ \-]/.test(elem.textContent || elem.innerText) ||
  9324. elem.style.textOverflow === 'ellipsis')) { // #983, #1254
  9325. css(elem, {
  9326. width: textWidth + 'px',
  9327. display: 'block',
  9328. whiteSpace: whiteSpace || 'normal' // #3331
  9329. });
  9330. wrapper.oldTextWidth = textWidth;
  9331. wrapper.hasBoxWidthChanged = true; // #8159
  9332. }
  9333. else {
  9334. wrapper.hasBoxWidthChanged = false; // #8159
  9335. }
  9336. // Do the calculations and DOM access only if properties changed
  9337. if (currentTextTransform !== wrapper.cTT) {
  9338. baseline = renderer.fontMetrics(elem.style.fontSize, elem).b;
  9339. // Renderer specific handling of span rotation, but only if we
  9340. // have something to update.
  9341. if (defined(rotation) &&
  9342. ((rotation !== (wrapper.oldRotation || 0)) ||
  9343. (align !== wrapper.oldAlign))) {
  9344. wrapper.setSpanRotation(rotation, alignCorrection, baseline);
  9345. }
  9346. wrapper.getSpanCorrection(
  9347. // Avoid elem.offsetWidth if we can, it affects rendering
  9348. // time heavily (#7656)
  9349. ((!defined(rotation) && wrapper.textPxLength) || // #7920
  9350. elem.offsetWidth), baseline, alignCorrection, rotation, align);
  9351. }
  9352. // apply position with correction
  9353. css(elem, {
  9354. left: (x + (wrapper.xCorr || 0)) + 'px',
  9355. top: (y + (wrapper.yCorr || 0)) + 'px'
  9356. });
  9357. // record current text transform
  9358. wrapper.cTT = currentTextTransform;
  9359. wrapper.oldRotation = rotation;
  9360. wrapper.oldAlign = align;
  9361. }
  9362. },
  9363. /**
  9364. * Set the rotation of an individual HTML span.
  9365. *
  9366. * @private
  9367. * @function Highcharts.SVGElement#setSpanRotation
  9368. * @param {number} rotation
  9369. * @param {number} alignCorrection
  9370. * @param {number} baseline
  9371. * @return {void}
  9372. */
  9373. setSpanRotation: function (rotation, alignCorrection, baseline) {
  9374. var rotationStyle = {},
  9375. cssTransformKey = this.renderer.getTransformKey();
  9376. rotationStyle[cssTransformKey] = rotationStyle.transform =
  9377. 'rotate(' + rotation + 'deg)';
  9378. rotationStyle[cssTransformKey + (isFirefox ? 'Origin' : '-origin')] =
  9379. rotationStyle.transformOrigin =
  9380. (alignCorrection * 100) + '% ' + baseline + 'px';
  9381. css(this.element, rotationStyle);
  9382. },
  9383. /**
  9384. * Get the correction in X and Y positioning as the element is rotated.
  9385. *
  9386. * @private
  9387. * @function Highcharts.SVGElement#getSpanCorrection
  9388. * @param {number} width
  9389. * @param {number} baseline
  9390. * @param {number} alignCorrection
  9391. * @return {void}
  9392. */
  9393. getSpanCorrection: function (width, baseline, alignCorrection) {
  9394. this.xCorr = -width * alignCorrection;
  9395. this.yCorr = -baseline;
  9396. }
  9397. });
  9398. return HTMLElement;
  9399. });
  9400. _registerModule(_modules, 'Core/Renderer/HTML/HTMLRenderer.js', [_modules['Core/Globals.js'], _modules['Core/Renderer/HTML/AST.js'], _modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Renderer/SVG/SVGRenderer.js'], _modules['Core/Utilities.js']], function (H, AST, SVGElement, SVGRenderer, U) {
  9401. /* *
  9402. *
  9403. * (c) 2010-2021 Torstein Honsi
  9404. *
  9405. * License: www.highcharts.com/license
  9406. *
  9407. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  9408. *
  9409. * */
  9410. var isFirefox = H.isFirefox,
  9411. isMS = H.isMS,
  9412. isWebKit = H.isWebKit,
  9413. win = H.win;
  9414. var attr = U.attr,
  9415. createElement = U.createElement,
  9416. extend = U.extend,
  9417. pick = U.pick;
  9418. /**
  9419. * Renderer placebo
  9420. * @private
  9421. */
  9422. var HTMLRenderer = SVGRenderer;
  9423. /* eslint-disable valid-jsdoc */
  9424. // Extend SvgRenderer for useHTML option.
  9425. extend(SVGRenderer.prototype, /** @lends SVGRenderer.prototype */ {
  9426. /**
  9427. * @private
  9428. * @function Highcharts.SVGRenderer#getTransformKey
  9429. *
  9430. * @return {string}
  9431. */
  9432. getTransformKey: function () {
  9433. return isMS && !/Edge/.test(win.navigator.userAgent) ?
  9434. '-ms-transform' :
  9435. isWebKit ?
  9436. '-webkit-transform' :
  9437. isFirefox ?
  9438. 'MozTransform' :
  9439. win.opera ?
  9440. '-o-transform' :
  9441. '';
  9442. },
  9443. /**
  9444. * Create HTML text node. This is used by the VML renderer as well as the
  9445. * SVG renderer through the useHTML option.
  9446. *
  9447. * @private
  9448. * @function Highcharts.SVGRenderer#html
  9449. *
  9450. * @param {string} str
  9451. * The text of (subset) HTML to draw.
  9452. *
  9453. * @param {number} x
  9454. * The x position of the text's lower left corner.
  9455. *
  9456. * @param {number} y
  9457. * The y position of the text's lower left corner.
  9458. *
  9459. * @return {Highcharts.HTMLDOMElement}
  9460. */
  9461. html: function (str, x, y) {
  9462. var wrapper = this.createElement('span'), element = wrapper.element, renderer = wrapper.renderer, isSVG = renderer.isSVG, addSetters = function (gWrapper, style) {
  9463. // These properties are set as attributes on the SVG group, and
  9464. // as identical CSS properties on the div. (#3542)
  9465. ['opacity', 'visibility'].forEach(function (prop) {
  9466. gWrapper[prop + 'Setter'] = function (value, key, elem) {
  9467. var styleObject = gWrapper.div ?
  9468. gWrapper.div.style :
  9469. style;
  9470. SVGElement.prototype[prop + 'Setter']
  9471. .call(this, value, key, elem);
  9472. if (styleObject) {
  9473. styleObject[key] = value;
  9474. }
  9475. };
  9476. });
  9477. gWrapper.addedSetters = true;
  9478. };
  9479. // Text setter
  9480. wrapper.textSetter = function (value) {
  9481. if (value !== this.textStr) {
  9482. delete this.bBox;
  9483. delete this.oldTextWidth;
  9484. AST.setElementHTML(this.element, pick(value, ''));
  9485. this.textStr = value;
  9486. wrapper.doTransform = true;
  9487. }
  9488. };
  9489. // Add setters for the element itself (#4938)
  9490. if (isSVG) { // #4938, only for HTML within SVG
  9491. addSetters(wrapper, wrapper.element.style);
  9492. }
  9493. // Various setters which rely on update transform
  9494. wrapper.xSetter =
  9495. wrapper.ySetter =
  9496. wrapper.alignSetter =
  9497. wrapper.rotationSetter =
  9498. function (value, key) {
  9499. if (key === 'align') {
  9500. // Do not overwrite the SVGElement.align method. Same as VML.
  9501. wrapper.alignValue = wrapper.textAlign = value;
  9502. }
  9503. else {
  9504. wrapper[key] = value;
  9505. }
  9506. wrapper.doTransform = true;
  9507. };
  9508. // Runs at the end of .attr()
  9509. wrapper.afterSetters = function () {
  9510. // Update transform. Do this outside the loop to prevent redundant
  9511. // updating for batch setting of attributes.
  9512. if (this.doTransform) {
  9513. this.htmlUpdateTransform();
  9514. this.doTransform = false;
  9515. }
  9516. };
  9517. // Set the default attributes
  9518. wrapper
  9519. .attr({
  9520. text: str,
  9521. x: Math.round(x),
  9522. y: Math.round(y)
  9523. })
  9524. .css({
  9525. position: 'absolute'
  9526. });
  9527. if (!renderer.styledMode) {
  9528. wrapper.css({
  9529. fontFamily: this.style.fontFamily,
  9530. fontSize: this.style.fontSize
  9531. });
  9532. }
  9533. // Keep the whiteSpace style outside the wrapper.styles collection
  9534. element.style.whiteSpace = 'nowrap';
  9535. // Use the HTML specific .css method
  9536. wrapper.css = wrapper.htmlCss;
  9537. // This is specific for HTML within SVG
  9538. if (isSVG) {
  9539. wrapper.add = function (svgGroupWrapper) {
  9540. var htmlGroup,
  9541. container = renderer.box.parentNode,
  9542. parentGroup,
  9543. parents = [];
  9544. this.parentGroup = svgGroupWrapper;
  9545. // Create a mock group to hold the HTML elements
  9546. if (svgGroupWrapper) {
  9547. htmlGroup = svgGroupWrapper.div;
  9548. if (!htmlGroup) {
  9549. // Read the parent chain into an array and read from top
  9550. // down
  9551. parentGroup = svgGroupWrapper;
  9552. while (parentGroup) {
  9553. parents.push(parentGroup);
  9554. // Move up to the next parent group
  9555. parentGroup = parentGroup.parentGroup;
  9556. }
  9557. // Ensure dynamically updating position when any parent
  9558. // is translated
  9559. parents.reverse().forEach(function (parentGroup) {
  9560. var htmlGroupStyle,
  9561. cls = attr(parentGroup.element, 'class');
  9562. /**
  9563. * Common translate setter for X and Y on the HTML
  9564. * group. Reverted the fix for #6957 du to
  9565. * positioning problems and offline export (#7254,
  9566. * #7280, #7529)
  9567. * @private
  9568. * @param {*} value
  9569. * @param {string} key
  9570. * @return {void}
  9571. */
  9572. function translateSetter(value, key) {
  9573. parentGroup[key] = value;
  9574. if (key === 'translateX') {
  9575. htmlGroupStyle.left = value + 'px';
  9576. }
  9577. else {
  9578. htmlGroupStyle.top = value + 'px';
  9579. }
  9580. parentGroup.doTransform = true;
  9581. }
  9582. // Create a HTML div and append it to the parent div
  9583. // to emulate the SVG group structure
  9584. var parentGroupStyles = parentGroup.styles || {};
  9585. htmlGroup =
  9586. parentGroup.div =
  9587. parentGroup.div || createElement('div', cls ? { className: cls } : void 0, {
  9588. position: 'absolute',
  9589. left: (parentGroup.translateX || 0) + 'px',
  9590. top: (parentGroup.translateY || 0) + 'px',
  9591. display: parentGroup.display,
  9592. opacity: parentGroup.opacity,
  9593. cursor: parentGroupStyles.cursor,
  9594. pointerEvents: parentGroupStyles.pointerEvents // #5595
  9595. // the top group is appended to container
  9596. }, htmlGroup || container);
  9597. // Shortcut
  9598. htmlGroupStyle = htmlGroup.style;
  9599. // Set listeners to update the HTML div's position
  9600. // whenever the SVG group position is changed.
  9601. extend(parentGroup, {
  9602. // (#7287) Pass htmlGroup to use
  9603. // the related group
  9604. classSetter: (function (htmlGroup) {
  9605. return function (value) {
  9606. this.element.setAttribute('class', value);
  9607. htmlGroup.className = value;
  9608. };
  9609. }(htmlGroup)),
  9610. on: function () {
  9611. if (parents[0].div) { // #6418
  9612. wrapper.on.apply({ element: parents[0].div }, arguments);
  9613. }
  9614. return parentGroup;
  9615. },
  9616. translateXSetter: translateSetter,
  9617. translateYSetter: translateSetter
  9618. });
  9619. if (!parentGroup.addedSetters) {
  9620. addSetters(parentGroup);
  9621. }
  9622. });
  9623. }
  9624. }
  9625. else {
  9626. htmlGroup = container;
  9627. }
  9628. htmlGroup.appendChild(element);
  9629. // Shared with VML:
  9630. wrapper.added = true;
  9631. if (wrapper.alignOnAdd) {
  9632. wrapper.htmlUpdateTransform();
  9633. }
  9634. return wrapper;
  9635. };
  9636. }
  9637. return wrapper;
  9638. }
  9639. });
  9640. return HTMLRenderer;
  9641. });
  9642. _registerModule(_modules, 'Core/Time.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
  9643. /* *
  9644. *
  9645. * (c) 2010-2021 Torstein Honsi
  9646. *
  9647. * License: www.highcharts.com/license
  9648. *
  9649. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  9650. *
  9651. * */
  9652. var win = H.win;
  9653. var defined = U.defined,
  9654. error = U.error,
  9655. extend = U.extend,
  9656. isObject = U.isObject,
  9657. merge = U.merge,
  9658. objectEach = U.objectEach,
  9659. pad = U.pad,
  9660. pick = U.pick,
  9661. splat = U.splat,
  9662. timeUnits = U.timeUnits;
  9663. /**
  9664. * Normalized interval.
  9665. *
  9666. * @interface Highcharts.TimeNormalizedObject
  9667. */ /**
  9668. * The count.
  9669. *
  9670. * @name Highcharts.TimeNormalizedObject#count
  9671. * @type {number}
  9672. */ /**
  9673. * The interval in axis values (ms).
  9674. *
  9675. * @name Highcharts.TimeNormalizedObject#unitRange
  9676. * @type {number}
  9677. */
  9678. /**
  9679. * Function of an additional date format specifier.
  9680. *
  9681. * @callback Highcharts.TimeFormatCallbackFunction
  9682. *
  9683. * @param {number} timestamp
  9684. * The time to format.
  9685. *
  9686. * @return {string}
  9687. * The formatted portion of the date.
  9688. */
  9689. /**
  9690. * Time ticks.
  9691. *
  9692. * @interface Highcharts.AxisTickPositionsArray
  9693. * @extends global.Array<number>
  9694. */ /**
  9695. * @name Highcharts.AxisTickPositionsArray#info
  9696. * @type {Highcharts.TimeTicksInfoObject|undefined}
  9697. */
  9698. /**
  9699. * A callback to return the time zone offset for a given datetime. It
  9700. * takes the timestamp in terms of milliseconds since January 1 1970,
  9701. * and returns the timezone offset in minutes. This provides a hook
  9702. * for drawing time based charts in specific time zones using their
  9703. * local DST crossover dates, with the help of external libraries.
  9704. *
  9705. * @callback Highcharts.TimezoneOffsetCallbackFunction
  9706. *
  9707. * @param {number} timestamp
  9708. * Timestamp in terms of milliseconds since January 1 1970.
  9709. *
  9710. * @return {number}
  9711. * Timezone offset in minutes.
  9712. */
  9713. /**
  9714. * Allows to manually load the `moment.js` library from Highcharts options
  9715. * instead of the `window`.
  9716. * In case of loading the library from a `script` tag,
  9717. * this option is not needed, it will be loaded from there by default.
  9718. *
  9719. * @type {function}
  9720. * @since 8.2.0
  9721. * @apioption time.moment
  9722. */
  9723. ''; // detach doclets above
  9724. /* eslint-disable no-invalid-this, valid-jsdoc */
  9725. /**
  9726. * The Time class. Time settings are applied in general for each page using
  9727. * `Highcharts.setOptions`, or individually for each Chart item through the
  9728. * [time](https://api.highcharts.com/highcharts/time) options set.
  9729. *
  9730. * The Time object is available from {@link Highcharts.Chart#time},
  9731. * which refers to `Highcharts.time` if no individual time settings are
  9732. * applied.
  9733. *
  9734. * @example
  9735. * // Apply time settings globally
  9736. * Highcharts.setOptions({
  9737. * time: {
  9738. * timezone: 'Europe/London'
  9739. * }
  9740. * });
  9741. *
  9742. * // Apply time settings by instance
  9743. * var chart = Highcharts.chart('container', {
  9744. * time: {
  9745. * timezone: 'America/New_York'
  9746. * },
  9747. * series: [{
  9748. * data: [1, 4, 3, 5]
  9749. * }]
  9750. * });
  9751. *
  9752. * // Use the Time object
  9753. * console.log(
  9754. * 'Current time in New York',
  9755. * chart.time.dateFormat('%Y-%m-%d %H:%M:%S', Date.now())
  9756. * );
  9757. *
  9758. * @since 6.0.5
  9759. *
  9760. * @class
  9761. * @name Highcharts.Time
  9762. *
  9763. * @param {Highcharts.TimeOptions} options
  9764. * Time options as defined in [chart.options.time](/highcharts/time).
  9765. */
  9766. var Time = /** @class */ (function () {
  9767. /* *
  9768. *
  9769. * Constructors
  9770. *
  9771. * */
  9772. function Time(options) {
  9773. /* *
  9774. *
  9775. * Properties
  9776. *
  9777. * */
  9778. this.options = {};
  9779. this.useUTC = false;
  9780. this.variableTimezone = false;
  9781. this.Date = win.Date;
  9782. /**
  9783. * Get the time zone offset based on the current timezone information as
  9784. * set in the global options.
  9785. *
  9786. * @function Highcharts.Time#getTimezoneOffset
  9787. *
  9788. * @param {number} timestamp
  9789. * The JavaScript timestamp to inspect.
  9790. *
  9791. * @return {number}
  9792. * The timezone offset in minutes compared to UTC.
  9793. */
  9794. this.getTimezoneOffset = this.timezoneOffsetFunction();
  9795. this.update(options);
  9796. }
  9797. /* *
  9798. *
  9799. * Functions
  9800. *
  9801. * */
  9802. /**
  9803. * Time units used in `Time.get` and `Time.set`
  9804. *
  9805. * @typedef {"Date"|"Day"|"FullYear"|"Hours"|"Milliseconds"|"Minutes"|"Month"|"Seconds"} Highcharts.TimeUnitValue
  9806. */
  9807. /**
  9808. * Get the value of a date object in given units, and subject to the Time
  9809. * object's current timezone settings. This function corresponds directly to
  9810. * JavaScripts `Date.getXXX / Date.getUTCXXX`, so instead of calling
  9811. * `date.getHours()` or `date.getUTCHours()` we will call
  9812. * `time.get('Hours')`.
  9813. *
  9814. * @function Highcharts.Time#get
  9815. *
  9816. * @param {Highcharts.TimeUnitValue} unit
  9817. * @param {Date} date
  9818. *
  9819. * @return {number}
  9820. * The given time unit
  9821. */
  9822. Time.prototype.get = function (unit, date) {
  9823. if (this.variableTimezone || this.timezoneOffset) {
  9824. var realMs = date.getTime();
  9825. var ms = realMs - this.getTimezoneOffset(date);
  9826. date.setTime(ms); // Temporary adjust to timezone
  9827. var ret = date['getUTC' + unit]();
  9828. date.setTime(realMs); // Reset
  9829. return ret;
  9830. }
  9831. // UTC time with no timezone handling
  9832. if (this.useUTC) {
  9833. return date['getUTC' + unit]();
  9834. }
  9835. // Else, local time
  9836. return date['get' + unit]();
  9837. };
  9838. /**
  9839. * Set the value of a date object in given units, and subject to the Time
  9840. * object's current timezone settings. This function corresponds directly to
  9841. * JavaScripts `Date.setXXX / Date.setUTCXXX`, so instead of calling
  9842. * `date.setHours(0)` or `date.setUTCHours(0)` we will call
  9843. * `time.set('Hours', 0)`.
  9844. *
  9845. * @function Highcharts.Time#set
  9846. *
  9847. * @param {Highcharts.TimeUnitValue} unit
  9848. * @param {Date} date
  9849. * @param {number} value
  9850. *
  9851. * @return {number}
  9852. * The epoch milliseconds of the updated date
  9853. */
  9854. Time.prototype.set = function (unit, date, value) {
  9855. // UTC time with timezone handling
  9856. if (this.variableTimezone || this.timezoneOffset) {
  9857. // For lower order time units, just set it directly using UTC
  9858. // time
  9859. if (unit === 'Milliseconds' ||
  9860. unit === 'Seconds' ||
  9861. (unit === 'Minutes' && this.getTimezoneOffset(date) % 3600000 === 0) // #13961
  9862. ) {
  9863. return date['setUTC' + unit](value);
  9864. }
  9865. // Higher order time units need to take the time zone into
  9866. // account
  9867. // Adjust by timezone
  9868. var offset = this.getTimezoneOffset(date);
  9869. var ms = date.getTime() - offset;
  9870. date.setTime(ms);
  9871. date['setUTC' + unit](value);
  9872. var newOffset = this.getTimezoneOffset(date);
  9873. ms = date.getTime() + newOffset;
  9874. return date.setTime(ms);
  9875. }
  9876. // UTC time with no timezone handling
  9877. if (this.useUTC) {
  9878. return date['setUTC' + unit](value);
  9879. }
  9880. // Else, local time
  9881. return date['set' + unit](value);
  9882. };
  9883. /**
  9884. * Update the Time object with current options. It is called internally on
  9885. * initializing Highcharts, after running `Highcharts.setOptions` and on
  9886. * `Chart.update`.
  9887. *
  9888. * @private
  9889. * @function Highcharts.Time#update
  9890. *
  9891. * @param {Highcharts.TimeOptions} options
  9892. *
  9893. * @return {void}
  9894. */
  9895. Time.prototype.update = function (options) {
  9896. var useUTC = pick(options && options.useUTC,
  9897. true),
  9898. time = this;
  9899. this.options = options = merge(true, this.options || {}, options);
  9900. // Allow using a different Date class
  9901. this.Date = options.Date || win.Date || Date;
  9902. this.useUTC = useUTC;
  9903. this.timezoneOffset = (useUTC && options.timezoneOffset);
  9904. this.getTimezoneOffset = this.timezoneOffsetFunction();
  9905. /*
  9906. * The time object has options allowing for variable time zones, meaning
  9907. * the axis ticks or series data needs to consider this.
  9908. */
  9909. this.variableTimezone = useUTC && !!(options.getTimezoneOffset ||
  9910. options.timezone);
  9911. };
  9912. /**
  9913. * Make a time and returns milliseconds. Interprets the inputs as UTC time,
  9914. * local time or a specific timezone time depending on the current time
  9915. * settings.
  9916. *
  9917. * @function Highcharts.Time#makeTime
  9918. *
  9919. * @param {number} year
  9920. * The year
  9921. *
  9922. * @param {number} month
  9923. * The month. Zero-based, so January is 0.
  9924. *
  9925. * @param {number} [date=1]
  9926. * The day of the month
  9927. *
  9928. * @param {number} [hours=0]
  9929. * The hour of the day, 0-23.
  9930. *
  9931. * @param {number} [minutes=0]
  9932. * The minutes
  9933. *
  9934. * @param {number} [seconds=0]
  9935. * The seconds
  9936. *
  9937. * @return {number}
  9938. * The time in milliseconds since January 1st 1970.
  9939. */
  9940. Time.prototype.makeTime = function (year, month, date, hours, minutes, seconds) {
  9941. var d,
  9942. offset,
  9943. newOffset;
  9944. if (this.useUTC) {
  9945. d = this.Date.UTC.apply(0, arguments);
  9946. offset = this.getTimezoneOffset(d);
  9947. d += offset;
  9948. newOffset = this.getTimezoneOffset(d);
  9949. if (offset !== newOffset) {
  9950. d += newOffset - offset;
  9951. // A special case for transitioning from summer time to winter time.
  9952. // When the clock is set back, the same time is repeated twice, i.e.
  9953. // 02:30 am is repeated since the clock is set back from 3 am to
  9954. // 2 am. We need to make the same time as local Date does.
  9955. }
  9956. else if (offset - 36e5 === this.getTimezoneOffset(d - 36e5) &&
  9957. !H.isSafari) {
  9958. d -= 36e5;
  9959. }
  9960. }
  9961. else {
  9962. d = new this.Date(year, month, pick(date, 1), pick(hours, 0), pick(minutes, 0), pick(seconds, 0)).getTime();
  9963. }
  9964. return d;
  9965. };
  9966. /**
  9967. * Sets the getTimezoneOffset function. If the `timezone` option is set, a
  9968. * default getTimezoneOffset function with that timezone is returned. If
  9969. * a `getTimezoneOffset` option is defined, it is returned. If neither are
  9970. * specified, the function using the `timezoneOffset` option or 0 offset is
  9971. * returned.
  9972. *
  9973. * @private
  9974. * @function Highcharts.Time#timezoneOffsetFunction
  9975. *
  9976. * @return {Function}
  9977. * A getTimezoneOffset function
  9978. */
  9979. Time.prototype.timezoneOffsetFunction = function () {
  9980. var time = this,
  9981. options = this.options,
  9982. moment = options.moment || win.moment;
  9983. if (!this.useUTC) {
  9984. return function (timestamp) {
  9985. return new Date(timestamp.toString()).getTimezoneOffset() * 60000;
  9986. };
  9987. }
  9988. if (options.timezone) {
  9989. if (!moment) {
  9990. // getTimezoneOffset-function stays undefined because it depends
  9991. // on Moment.js
  9992. error(25);
  9993. }
  9994. else {
  9995. return function (timestamp) {
  9996. return -moment.tz(timestamp, options.timezone).utcOffset() * 60000;
  9997. };
  9998. }
  9999. }
  10000. // If not timezone is set, look for the getTimezoneOffset callback
  10001. if (this.useUTC && options.getTimezoneOffset) {
  10002. return function (timestamp) {
  10003. return options.getTimezoneOffset(timestamp.valueOf()) * 60000;
  10004. };
  10005. }
  10006. // Last, use the `timezoneOffset` option if set
  10007. return function () {
  10008. return (time.timezoneOffset || 0) * 60000;
  10009. };
  10010. };
  10011. /**
  10012. * Formats a JavaScript date timestamp (milliseconds since Jan 1st 1970)
  10013. * into a human readable date string. The available format keys are listed
  10014. * below. Additional formats can be given in the
  10015. * {@link Highcharts.dateFormats} hook.
  10016. *
  10017. * Supported format keys:
  10018. * - `%a`: Short weekday, like 'Mon'
  10019. * - `%A`: Long weekday, like 'Monday'
  10020. * - `%d`: Two digit day of the month, 01 to 31
  10021. * - `%e`: Day of the month, 1 through 31
  10022. * - `%w`: Day of the week, 0 through 6
  10023. * - `%b`: Short month, like 'Jan'
  10024. * - `%B`: Long month, like 'January'
  10025. * - `%m`: Two digit month number, 01 through 12
  10026. * - `%y`: Two digits year, like 09 for 2009
  10027. * - `%Y`: Four digits year, like 2009
  10028. * - `%H`: Two digits hours in 24h format, 00 through 23
  10029. * - `%k`: Hours in 24h format, 0 through 23
  10030. * - `%I`: Two digits hours in 12h format, 00 through 11
  10031. * - `%l`: Hours in 12h format, 1 through 12
  10032. * - `%M`: Two digits minutes, 00 through 59
  10033. * - `%p`: Upper case AM or PM
  10034. * - `%P`: Lower case AM or PM
  10035. * - `%S`: Two digits seconds, 00 through 59
  10036. * - `%L`: Milliseconds (naming from Ruby)
  10037. *
  10038. * @example
  10039. * const time = new Highcharts.Time();
  10040. * const s = time.dateFormat('%Y-%m-%d %H:%M:%S', Date.UTC(2020, 0, 1));
  10041. * console.log(s); // => 2020-01-01 00:00:00
  10042. *
  10043. * @function Highcharts.Time#dateFormat
  10044. *
  10045. * @param {string} format
  10046. * The desired format where various time representations are
  10047. * prefixed with %.
  10048. *
  10049. * @param {number} [timestamp]
  10050. * The JavaScript timestamp.
  10051. *
  10052. * @param {boolean} [capitalize=false]
  10053. * Upper case first letter in the return.
  10054. *
  10055. * @return {string}
  10056. * The formatted date.
  10057. */
  10058. Time.prototype.dateFormat = function (format, timestamp, capitalize) {
  10059. var _a;
  10060. if (!defined(timestamp) || isNaN(timestamp)) {
  10061. return ((_a = H.defaultOptions.lang) === null || _a === void 0 ? void 0 : _a.invalidDate) || '';
  10062. }
  10063. format = pick(format, '%Y-%m-%d %H:%M:%S');
  10064. var time = this, date = new this.Date(timestamp),
  10065. // get the basic time values
  10066. hours = this.get('Hours', date), day = this.get('Day', date), dayOfMonth = this.get('Date', date), month = this.get('Month', date), fullYear = this.get('FullYear', date), lang = H.defaultOptions.lang, langWeekdays = lang === null || lang === void 0 ? void 0 : lang.weekdays, shortWeekdays = lang === null || lang === void 0 ? void 0 : lang.shortWeekdays,
  10067. // List all format keys. Custom formats can be added from the
  10068. // outside.
  10069. replacements = extend({
  10070. // Day
  10071. // Short weekday, like 'Mon'
  10072. a: shortWeekdays ?
  10073. shortWeekdays[day] :
  10074. langWeekdays[day].substr(0, 3),
  10075. // Long weekday, like 'Monday'
  10076. A: langWeekdays[day],
  10077. // Two digit day of the month, 01 to 31
  10078. d: pad(dayOfMonth),
  10079. // Day of the month, 1 through 31
  10080. e: pad(dayOfMonth, 2, ' '),
  10081. // Day of the week, 0 through 6
  10082. w: day,
  10083. // Week (none implemented)
  10084. // 'W': weekNumber(),
  10085. // Month
  10086. // Short month, like 'Jan'
  10087. b: lang.shortMonths[month],
  10088. // Long month, like 'January'
  10089. B: lang.months[month],
  10090. // Two digit month number, 01 through 12
  10091. m: pad(month + 1),
  10092. // Month number, 1 through 12 (#8150)
  10093. o: month + 1,
  10094. // Year
  10095. // Two digits year, like 09 for 2009
  10096. y: fullYear.toString().substr(2, 2),
  10097. // Four digits year, like 2009
  10098. Y: fullYear,
  10099. // Time
  10100. // Two digits hours in 24h format, 00 through 23
  10101. H: pad(hours),
  10102. // Hours in 24h format, 0 through 23
  10103. k: hours,
  10104. // Two digits hours in 12h format, 00 through 11
  10105. I: pad((hours % 12) || 12),
  10106. // Hours in 12h format, 1 through 12
  10107. l: (hours % 12) || 12,
  10108. // Two digits minutes, 00 through 59
  10109. M: pad(this.get('Minutes', date)),
  10110. // Upper case AM or PM
  10111. p: hours < 12 ? 'AM' : 'PM',
  10112. // Lower case AM or PM
  10113. P: hours < 12 ? 'am' : 'pm',
  10114. // Two digits seconds, 00 through 59
  10115. S: pad(date.getSeconds()),
  10116. // Milliseconds (naming from Ruby)
  10117. L: pad(Math.floor(timestamp % 1000), 3)
  10118. }, H.dateFormats);
  10119. // Do the replaces
  10120. objectEach(replacements, function (val, key) {
  10121. // Regex would do it in one line, but this is faster
  10122. while (format.indexOf('%' + key) !== -1) {
  10123. format = format.replace('%' + key, typeof val === 'function' ? val.call(time, timestamp) : val);
  10124. }
  10125. });
  10126. // Optionally capitalize the string and return
  10127. return capitalize ?
  10128. (format.substr(0, 1).toUpperCase() +
  10129. format.substr(1)) :
  10130. format;
  10131. };
  10132. /**
  10133. * Resolve legacy formats of dateTimeLabelFormats (strings and arrays) into
  10134. * an object.
  10135. * @private
  10136. * @param {string|Array<T>|Highcharts.Dictionary<T>} f - General format description
  10137. * @return {Highcharts.Dictionary<T>} - The object definition
  10138. */
  10139. Time.prototype.resolveDTLFormat = function (f) {
  10140. if (!isObject(f, true)) { // check for string or array
  10141. f = splat(f);
  10142. return {
  10143. main: f[0],
  10144. from: f[1],
  10145. to: f[2]
  10146. };
  10147. }
  10148. return f;
  10149. };
  10150. /**
  10151. * Return an array with time positions distributed on round time values
  10152. * right and right after min and max. Used in datetime axes as well as for
  10153. * grouping data on a datetime axis.
  10154. *
  10155. * @function Highcharts.Time#getTimeTicks
  10156. *
  10157. * @param {Highcharts.TimeNormalizedObject} normalizedInterval
  10158. * The interval in axis values (ms) and the count
  10159. *
  10160. * @param {number} [min]
  10161. * The minimum in axis values
  10162. *
  10163. * @param {number} [max]
  10164. * The maximum in axis values
  10165. *
  10166. * @param {number} [startOfWeek=1]
  10167. *
  10168. * @return {Highcharts.AxisTickPositionsArray}
  10169. */
  10170. Time.prototype.getTimeTicks = function (normalizedInterval, min, max, startOfWeek) {
  10171. var time = this,
  10172. Date = time.Date,
  10173. tickPositions = [],
  10174. i,
  10175. higherRanks = {},
  10176. minYear, // used in months and years as a basis for Date.UTC()
  10177. // When crossing DST, use the max. Resolves #6278.
  10178. minDate = new Date(min),
  10179. interval = normalizedInterval.unitRange,
  10180. count = normalizedInterval.count || 1,
  10181. variableDayLength,
  10182. minDay;
  10183. startOfWeek = pick(startOfWeek, 1);
  10184. if (defined(min)) { // #1300
  10185. time.set('Milliseconds', minDate, interval >= timeUnits.second ?
  10186. 0 : // #3935
  10187. count * Math.floor(time.get('Milliseconds', minDate) / count)); // #3652, #3654
  10188. if (interval >= timeUnits.second) { // second
  10189. time.set('Seconds', minDate, interval >= timeUnits.minute ?
  10190. 0 : // #3935
  10191. count * Math.floor(time.get('Seconds', minDate) / count));
  10192. }
  10193. if (interval >= timeUnits.minute) { // minute
  10194. time.set('Minutes', minDate, interval >= timeUnits.hour ?
  10195. 0 :
  10196. count * Math.floor(time.get('Minutes', minDate) / count));
  10197. }
  10198. if (interval >= timeUnits.hour) { // hour
  10199. time.set('Hours', minDate, interval >= timeUnits.day ?
  10200. 0 :
  10201. count * Math.floor(time.get('Hours', minDate) / count));
  10202. }
  10203. if (interval >= timeUnits.day) { // day
  10204. time.set('Date', minDate, interval >= timeUnits.month ?
  10205. 1 :
  10206. Math.max(1, count * Math.floor(time.get('Date', minDate) / count)));
  10207. }
  10208. if (interval >= timeUnits.month) { // month
  10209. time.set('Month', minDate, interval >= timeUnits.year ? 0 :
  10210. count * Math.floor(time.get('Month', minDate) / count));
  10211. minYear = time.get('FullYear', minDate);
  10212. }
  10213. if (interval >= timeUnits.year) { // year
  10214. minYear -= minYear % count;
  10215. time.set('FullYear', minDate, minYear);
  10216. }
  10217. // week is a special case that runs outside the hierarchy
  10218. if (interval === timeUnits.week) {
  10219. // get start of current week, independent of count
  10220. minDay = time.get('Day', minDate);
  10221. time.set('Date', minDate, (time.get('Date', minDate) -
  10222. minDay + startOfWeek +
  10223. // We don't want to skip days that are before
  10224. // startOfWeek (#7051)
  10225. (minDay < startOfWeek ? -7 : 0)));
  10226. }
  10227. // Get basics for variable time spans
  10228. minYear = time.get('FullYear', minDate);
  10229. var minMonth = time.get('Month', minDate), minDateDate = time.get('Date', minDate), minHours = time.get('Hours', minDate);
  10230. // Redefine min to the floored/rounded minimum time (#7432)
  10231. min = minDate.getTime();
  10232. // Handle local timezone offset
  10233. if ((time.variableTimezone || !time.useUTC) && defined(max)) {
  10234. // Detect whether we need to take the DST crossover into
  10235. // consideration. If we're crossing over DST, the day length may
  10236. // be 23h or 25h and we need to compute the exact clock time for
  10237. // each tick instead of just adding hours. This comes at a cost,
  10238. // so first we find out if it is needed (#4951).
  10239. variableDayLength = (
  10240. // Long range, assume we're crossing over.
  10241. max - min > 4 * timeUnits.month ||
  10242. // Short range, check if min and max are in different time
  10243. // zones.
  10244. time.getTimezoneOffset(min) !==
  10245. time.getTimezoneOffset(max));
  10246. }
  10247. // Iterate and add tick positions at appropriate values
  10248. var t = minDate.getTime();
  10249. i = 1;
  10250. while (t < max) {
  10251. tickPositions.push(t);
  10252. // if the interval is years, use Date.UTC to increase years
  10253. if (interval === timeUnits.year) {
  10254. t = time.makeTime(minYear + i * count, 0);
  10255. // if the interval is months, use Date.UTC to increase months
  10256. }
  10257. else if (interval === timeUnits.month) {
  10258. t = time.makeTime(minYear, minMonth + i * count);
  10259. // if we're using global time, the interval is not fixed as it
  10260. // jumps one hour at the DST crossover
  10261. }
  10262. else if (variableDayLength &&
  10263. (interval === timeUnits.day || interval === timeUnits.week)) {
  10264. t = time.makeTime(minYear, minMonth, minDateDate +
  10265. i * count * (interval === timeUnits.day ? 1 : 7));
  10266. }
  10267. else if (variableDayLength &&
  10268. interval === timeUnits.hour &&
  10269. count > 1) {
  10270. // make sure higher ranks are preserved across DST (#6797,
  10271. // #7621)
  10272. t = time.makeTime(minYear, minMonth, minDateDate, minHours + i * count);
  10273. // else, the interval is fixed and we use simple addition
  10274. }
  10275. else {
  10276. t += interval * count;
  10277. }
  10278. i++;
  10279. }
  10280. // push the last time
  10281. tickPositions.push(t);
  10282. // Handle higher ranks. Mark new days if the time is on midnight
  10283. // (#950, #1649, #1760, #3349). Use a reasonable dropout threshold
  10284. // to prevent looping over dense data grouping (#6156).
  10285. if (interval <= timeUnits.hour && tickPositions.length < 10000) {
  10286. tickPositions.forEach(function (t) {
  10287. if (
  10288. // Speed optimization, no need to run dateFormat unless
  10289. // we're on a full or half hour
  10290. t % 1800000 === 0 &&
  10291. // Check for local or global midnight
  10292. time.dateFormat('%H%M%S%L', t) === '000000000') {
  10293. higherRanks[t] = 'day';
  10294. }
  10295. });
  10296. }
  10297. }
  10298. // record information on the chosen unit - for dynamic label formatter
  10299. tickPositions.info = extend(normalizedInterval, {
  10300. higherRanks: higherRanks,
  10301. totalRange: interval * count
  10302. });
  10303. return tickPositions;
  10304. };
  10305. return Time;
  10306. }());
  10307. H.Time = Time;
  10308. return H.Time;
  10309. });
  10310. _registerModule(_modules, 'Core/Options.js', [_modules['Core/Globals.js'], _modules['Core/Color/Color.js'], _modules['Core/Color/Palette.js'], _modules['Core/Time.js'], _modules['Core/Utilities.js']], function (H, Color, palette, Time, U) {
  10311. /* *
  10312. *
  10313. * (c) 2010-2021 Torstein Honsi
  10314. *
  10315. * License: www.highcharts.com/license
  10316. *
  10317. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  10318. *
  10319. * */
  10320. var isTouchDevice = H.isTouchDevice,
  10321. svg = H.svg;
  10322. var color = Color.parse;
  10323. var merge = U.merge;
  10324. /**
  10325. * @typedef {"plotBox"|"spacingBox"} Highcharts.ButtonRelativeToValue
  10326. */
  10327. /**
  10328. * Gets fired when a series is added to the chart after load time, using the
  10329. * `addSeries` method. Returning `false` prevents the series from being added.
  10330. *
  10331. * @callback Highcharts.ChartAddSeriesCallbackFunction
  10332. *
  10333. * @param {Highcharts.Chart} this
  10334. * The chart on which the event occured.
  10335. *
  10336. * @param {Highcharts.ChartAddSeriesEventObject} event
  10337. * The event that occured.
  10338. */
  10339. /**
  10340. * Contains common event information. Through the `options` property you can
  10341. * access the series options that were passed to the `addSeries` method.
  10342. *
  10343. * @interface Highcharts.ChartAddSeriesEventObject
  10344. */ /**
  10345. * The series options that were passed to the `addSeries` method.
  10346. * @name Highcharts.ChartAddSeriesEventObject#options
  10347. * @type {Highcharts.SeriesOptionsType}
  10348. */ /**
  10349. * Prevents the default behaviour of the event.
  10350. * @name Highcharts.ChartAddSeriesEventObject#preventDefault
  10351. * @type {Function}
  10352. */ /**
  10353. * The event target.
  10354. * @name Highcharts.ChartAddSeriesEventObject#target
  10355. * @type {Highcharts.Chart}
  10356. */ /**
  10357. * The event type.
  10358. * @name Highcharts.ChartAddSeriesEventObject#type
  10359. * @type {"addSeries"}
  10360. */
  10361. /**
  10362. * Gets fired when clicking on the plot background.
  10363. *
  10364. * @callback Highcharts.ChartClickCallbackFunction
  10365. *
  10366. * @param {Highcharts.Chart} this
  10367. * The chart on which the event occured.
  10368. *
  10369. * @param {Highcharts.PointerEventObject} event
  10370. * The event that occured.
  10371. */
  10372. /**
  10373. * Contains an axes of the clicked spot.
  10374. *
  10375. * @interface Highcharts.ChartClickEventAxisObject
  10376. */ /**
  10377. * Axis at the clicked spot.
  10378. * @name Highcharts.ChartClickEventAxisObject#axis
  10379. * @type {Highcharts.Axis}
  10380. */ /**
  10381. * Axis value at the clicked spot.
  10382. * @name Highcharts.ChartClickEventAxisObject#value
  10383. * @type {number}
  10384. */
  10385. /**
  10386. * Contains information about the clicked spot on the chart. Remember the unit
  10387. * of a datetime axis is milliseconds since 1970-01-01 00:00:00.
  10388. *
  10389. * @interface Highcharts.ChartClickEventObject
  10390. * @extends Highcharts.PointerEventObject
  10391. */ /**
  10392. * Information about the x-axis on the clicked spot.
  10393. * @name Highcharts.ChartClickEventObject#xAxis
  10394. * @type {Array<Highcharts.ChartClickEventAxisObject>}
  10395. */ /**
  10396. * Information about the y-axis on the clicked spot.
  10397. * @name Highcharts.ChartClickEventObject#yAxis
  10398. * @type {Array<Highcharts.ChartClickEventAxisObject>}
  10399. */ /**
  10400. * Information about the z-axis on the clicked spot.
  10401. * @name Highcharts.ChartClickEventObject#zAxis
  10402. * @type {Array<Highcharts.ChartClickEventAxisObject>|undefined}
  10403. */
  10404. /**
  10405. * Gets fired when the chart is finished loading.
  10406. *
  10407. * @callback Highcharts.ChartLoadCallbackFunction
  10408. *
  10409. * @param {Highcharts.Chart} this
  10410. * The chart on which the event occured.
  10411. *
  10412. * @param {global.Event} event
  10413. * The event that occured.
  10414. */
  10415. /**
  10416. * Fires when the chart is redrawn, either after a call to `chart.redraw()` or
  10417. * after an axis, series or point is modified with the `redraw` option set to
  10418. * `true`.
  10419. *
  10420. * @callback Highcharts.ChartRedrawCallbackFunction
  10421. *
  10422. * @param {Highcharts.Chart} this
  10423. * The chart on which the event occured.
  10424. *
  10425. * @param {global.Event} event
  10426. * The event that occured.
  10427. */
  10428. /**
  10429. * Gets fired after initial load of the chart (directly after the `load` event),
  10430. * and after each redraw (directly after the `redraw` event).
  10431. *
  10432. * @callback Highcharts.ChartRenderCallbackFunction
  10433. *
  10434. * @param {Highcharts.Chart} this
  10435. * The chart on which the event occured.
  10436. *
  10437. * @param {global.Event} event
  10438. * The event that occured.
  10439. */
  10440. /**
  10441. * Gets fired when an area of the chart has been selected. The default action
  10442. * for the selection event is to zoom the chart to the selected area. It can be
  10443. * prevented by calling `event.preventDefault()` or return false.
  10444. *
  10445. * @callback Highcharts.ChartSelectionCallbackFunction
  10446. *
  10447. * @param {Highcharts.Chart} this
  10448. * The chart on which the event occured.
  10449. *
  10450. * @param {global.ChartSelectionContextObject} event
  10451. * Event informations
  10452. *
  10453. * @return {boolean|undefined}
  10454. * Return false to prevent the default action, usually zoom.
  10455. */
  10456. /**
  10457. * The primary axes are `xAxis[0]` and `yAxis[0]`. Remember the unit of a
  10458. * datetime axis is milliseconds since 1970-01-01 00:00:00.
  10459. *
  10460. * @interface Highcharts.ChartSelectionContextObject
  10461. * @extends global.Event
  10462. */ /**
  10463. * Arrays containing the axes of each dimension and each axis' min and max
  10464. * values.
  10465. * @name Highcharts.ChartSelectionContextObject#xAxis
  10466. * @type {Array<Highcharts.ChartSelectionAxisContextObject>}
  10467. */ /**
  10468. * Arrays containing the axes of each dimension and each axis' min and max
  10469. * values.
  10470. * @name Highcharts.ChartSelectionContextObject#yAxis
  10471. * @type {Array<Highcharts.ChartSelectionAxisContextObject>}
  10472. */
  10473. /**
  10474. * Axis context of the selection.
  10475. *
  10476. * @interface Highcharts.ChartSelectionAxisContextObject
  10477. */ /**
  10478. * The selected Axis.
  10479. * @name Highcharts.ChartSelectionAxisContextObject#axis
  10480. * @type {Highcharts.Axis}
  10481. */ /**
  10482. * The maximum axis value, either automatic or set manually.
  10483. * @name Highcharts.ChartSelectionAxisContextObject#max
  10484. * @type {number}
  10485. */ /**
  10486. * The minimum axis value, either automatic or set manually.
  10487. * @name Highcharts.ChartSelectionAxisContextObject#min
  10488. * @type {number}
  10489. */
  10490. ''; // detach doclets above
  10491. /* ************************************************************************** *
  10492. * Handle the options *
  10493. * ************************************************************************** */
  10494. /**
  10495. * Global default settings.
  10496. *
  10497. * @name Highcharts.defaultOptions
  10498. * @type {Highcharts.Options}
  10499. */ /**
  10500. * @optionparent
  10501. */
  10502. H.defaultOptions = {
  10503. /**
  10504. * An array containing the default colors for the chart's series. When
  10505. * all colors are used, new colors are pulled from the start again.
  10506. *
  10507. * Default colors can also be set on a series or series.type basis,
  10508. * see [column.colors](#plotOptions.column.colors),
  10509. * [pie.colors](#plotOptions.pie.colors).
  10510. *
  10511. * In styled mode, the colors option doesn't exist. Instead, colors
  10512. * are defined in CSS and applied either through series or point class
  10513. * names, or through the [chart.colorCount](#chart.colorCount) option.
  10514. *
  10515. *
  10516. * ### Legacy
  10517. *
  10518. * In Highcharts 3.x, the default colors were:
  10519. * ```js
  10520. * colors: ['#2f7ed8', '#0d233a', '#8bbc21', '#910000', '#1aadce',
  10521. * '#492970', '#f28f43', '#77a1e5', '#c42525', '#a6c96a']
  10522. * ```
  10523. *
  10524. * In Highcharts 2.x, the default colors were:
  10525. * ```js
  10526. * colors: ['#4572A7', '#AA4643', '#89A54E', '#80699B', '#3D96AE',
  10527. * '#DB843D', '#92A8CD', '#A47D7C', '#B5CA92']
  10528. * ```
  10529. *
  10530. * @sample {highcharts} highcharts/chart/colors/
  10531. * Assign a global color theme
  10532. *
  10533. * @type {Array<Highcharts.ColorString>}
  10534. * @default ["#7cb5ec", "#434348", "#90ed7d", "#f7a35c", "#8085e9",
  10535. * "#f15c80", "#e4d354", "#2b908f", "#f45b5b", "#91e8e1"]
  10536. */
  10537. colors: palette.colors,
  10538. /**
  10539. * Styled mode only. Configuration object for adding SVG definitions for
  10540. * reusable elements. See [gradients, shadows and
  10541. * patterns](https://www.highcharts.com/docs/chart-design-and-style/gradients-shadows-and-patterns)
  10542. * for more information and code examples.
  10543. *
  10544. * @type {*}
  10545. * @since 5.0.0
  10546. * @apioption defs
  10547. */
  10548. /**
  10549. * @ignore-option
  10550. */
  10551. symbols: ['circle', 'diamond', 'square', 'triangle', 'triangle-down'],
  10552. /**
  10553. * The language object is global and it can't be set on each chart
  10554. * initialization. Instead, use `Highcharts.setOptions` to set it before any
  10555. * chart is initialized.
  10556. *
  10557. * ```js
  10558. * Highcharts.setOptions({
  10559. * lang: {
  10560. * months: [
  10561. * 'Janvier', 'Février', 'Mars', 'Avril',
  10562. * 'Mai', 'Juin', 'Juillet', 'Août',
  10563. * 'Septembre', 'Octobre', 'Novembre', 'Décembre'
  10564. * ],
  10565. * weekdays: [
  10566. * 'Dimanche', 'Lundi', 'Mardi', 'Mercredi',
  10567. * 'Jeudi', 'Vendredi', 'Samedi'
  10568. * ]
  10569. * }
  10570. * });
  10571. * ```
  10572. */
  10573. lang: {
  10574. /**
  10575. * The loading text that appears when the chart is set into the loading
  10576. * state following a call to `chart.showLoading`.
  10577. */
  10578. loading: 'Loading...',
  10579. /**
  10580. * An array containing the months names. Corresponds to the `%B` format
  10581. * in `Highcharts.dateFormat()`.
  10582. *
  10583. * @type {Array<string>}
  10584. * @default ["January", "February", "March", "April", "May", "June",
  10585. * "July", "August", "September", "October", "November",
  10586. * "December"]
  10587. */
  10588. months: [
  10589. 'January', 'February', 'March', 'April', 'May', 'June', 'July',
  10590. 'August', 'September', 'October', 'November', 'December'
  10591. ],
  10592. /**
  10593. * An array containing the months names in abbreviated form. Corresponds
  10594. * to the `%b` format in `Highcharts.dateFormat()`.
  10595. *
  10596. * @type {Array<string>}
  10597. * @default ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
  10598. * "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
  10599. */
  10600. shortMonths: [
  10601. 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul',
  10602. 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
  10603. ],
  10604. /**
  10605. * An array containing the weekday names.
  10606. *
  10607. * @type {Array<string>}
  10608. * @default ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
  10609. * "Friday", "Saturday"]
  10610. */
  10611. weekdays: [
  10612. 'Sunday', 'Monday', 'Tuesday', 'Wednesday',
  10613. 'Thursday', 'Friday', 'Saturday'
  10614. ],
  10615. /**
  10616. * Short week days, starting Sunday. If not specified, Highcharts uses
  10617. * the first three letters of the `lang.weekdays` option.
  10618. *
  10619. * @sample highcharts/lang/shortweekdays/
  10620. * Finnish two-letter abbreviations
  10621. *
  10622. * @type {Array<string>}
  10623. * @since 4.2.4
  10624. * @apioption lang.shortWeekdays
  10625. */
  10626. /**
  10627. * What to show in a date field for invalid dates. Defaults to an empty
  10628. * string.
  10629. *
  10630. * @type {string}
  10631. * @since 4.1.8
  10632. * @product highcharts highstock
  10633. * @apioption lang.invalidDate
  10634. */
  10635. /**
  10636. * The title appearing on hovering the zoom in button. The text itself
  10637. * defaults to "+" and can be changed in the button options.
  10638. *
  10639. * @type {string}
  10640. * @default Zoom in
  10641. * @product highmaps
  10642. * @apioption lang.zoomIn
  10643. */
  10644. /**
  10645. * The title appearing on hovering the zoom out button. The text itself
  10646. * defaults to "-" and can be changed in the button options.
  10647. *
  10648. * @type {string}
  10649. * @default Zoom out
  10650. * @product highmaps
  10651. * @apioption lang.zoomOut
  10652. */
  10653. /**
  10654. * The default decimal point used in the `Highcharts.numberFormat`
  10655. * method unless otherwise specified in the function arguments.
  10656. *
  10657. * @since 1.2.2
  10658. */
  10659. decimalPoint: '.',
  10660. /**
  10661. * [Metric prefixes](https://en.wikipedia.org/wiki/Metric_prefix) used
  10662. * to shorten high numbers in axis labels. Replacing any of the
  10663. * positions with `null` causes the full number to be written. Setting
  10664. * `numericSymbols` to `null` disables shortening altogether.
  10665. *
  10666. * @sample {highcharts} highcharts/lang/numericsymbols/
  10667. * Replacing the symbols with text
  10668. * @sample {highstock} highcharts/lang/numericsymbols/
  10669. * Replacing the symbols with text
  10670. *
  10671. * @type {Array<string>}
  10672. * @default ["k", "M", "G", "T", "P", "E"]
  10673. * @since 2.3.0
  10674. */
  10675. numericSymbols: ['k', 'M', 'G', 'T', 'P', 'E'],
  10676. /**
  10677. * The magnitude of [numericSymbols](#lang.numericSymbol) replacements.
  10678. * Use 10000 for Japanese, Korean and various Chinese locales, which
  10679. * use symbols for 10^4, 10^8 and 10^12.
  10680. *
  10681. * @sample highcharts/lang/numericsymbolmagnitude/
  10682. * 10000 magnitude for Japanese
  10683. *
  10684. * @type {number}
  10685. * @default 1000
  10686. * @since 5.0.3
  10687. * @apioption lang.numericSymbolMagnitude
  10688. */
  10689. /**
  10690. * The text for the label appearing when a chart is zoomed.
  10691. *
  10692. * @since 1.2.4
  10693. */
  10694. resetZoom: 'Reset zoom',
  10695. /**
  10696. * The tooltip title for the label appearing when a chart is zoomed.
  10697. *
  10698. * @since 1.2.4
  10699. */
  10700. resetZoomTitle: 'Reset zoom level 1:1',
  10701. /**
  10702. * The default thousands separator used in the `Highcharts.numberFormat`
  10703. * method unless otherwise specified in the function arguments. Defaults
  10704. * to a single space character, which is recommended in
  10705. * [ISO 31-0](https://en.wikipedia.org/wiki/ISO_31-0#Numbers) and works
  10706. * across Anglo-American and continental European languages.
  10707. *
  10708. * @default \u0020
  10709. * @since 1.2.2
  10710. */
  10711. thousandsSep: ' '
  10712. },
  10713. /**
  10714. * Global options that don't apply to each chart. These options, like
  10715. * the `lang` options, must be set using the `Highcharts.setOptions`
  10716. * method.
  10717. *
  10718. * ```js
  10719. * Highcharts.setOptions({
  10720. * global: {
  10721. * useUTC: false
  10722. * }
  10723. * });
  10724. * ```
  10725. */
  10726. /**
  10727. * _Canvg rendering for Android 2.x is removed as of Highcharts 5.0\.
  10728. * Use the [libURL](#exporting.libURL) option to configure exporting._
  10729. *
  10730. * The URL to the additional file to lazy load for Android 2.x devices.
  10731. * These devices don't support SVG, so we download a helper file that
  10732. * contains [canvg](https://github.com/canvg/canvg), its dependency
  10733. * rbcolor, and our own CanVG Renderer class. To avoid hotlinking to
  10734. * our site, you can install canvas-tools.js on your own server and
  10735. * change this option accordingly.
  10736. *
  10737. * @deprecated
  10738. *
  10739. * @type {string}
  10740. * @default https://code.highcharts.com/{version}/modules/canvas-tools.js
  10741. * @product highcharts highmaps
  10742. * @apioption global.canvasToolsURL
  10743. */
  10744. /**
  10745. * This option is deprecated since v6.0.5. Instead, use
  10746. * [time.useUTC](#time.useUTC) that supports individual time settings
  10747. * per chart.
  10748. *
  10749. * @deprecated
  10750. *
  10751. * @type {boolean}
  10752. * @apioption global.useUTC
  10753. */
  10754. /**
  10755. * This option is deprecated since v6.0.5. Instead, use
  10756. * [time.Date](#time.Date) that supports individual time settings
  10757. * per chart.
  10758. *
  10759. * @deprecated
  10760. *
  10761. * @type {Function}
  10762. * @product highcharts highstock
  10763. * @apioption global.Date
  10764. */
  10765. /**
  10766. * This option is deprecated since v6.0.5. Instead, use
  10767. * [time.getTimezoneOffset](#time.getTimezoneOffset) that supports
  10768. * individual time settings per chart.
  10769. *
  10770. * @deprecated
  10771. *
  10772. * @type {Function}
  10773. * @product highcharts highstock
  10774. * @apioption global.getTimezoneOffset
  10775. */
  10776. /**
  10777. * This option is deprecated since v6.0.5. Instead, use
  10778. * [time.timezone](#time.timezone) that supports individual time
  10779. * settings per chart.
  10780. *
  10781. * @deprecated
  10782. *
  10783. * @type {string}
  10784. * @product highcharts highstock
  10785. * @apioption global.timezone
  10786. */
  10787. /**
  10788. * This option is deprecated since v6.0.5. Instead, use
  10789. * [time.timezoneOffset](#time.timezoneOffset) that supports individual
  10790. * time settings per chart.
  10791. *
  10792. * @deprecated
  10793. *
  10794. * @type {number}
  10795. * @product highcharts highstock
  10796. * @apioption global.timezoneOffset
  10797. */
  10798. global: {},
  10799. /**
  10800. * Time options that can apply globally or to individual charts. These
  10801. * settings affect how `datetime` axes are laid out, how tooltips are
  10802. * formatted, how series
  10803. * [pointIntervalUnit](#plotOptions.series.pointIntervalUnit) works and how
  10804. * the Highstock range selector handles time.
  10805. *
  10806. * The common use case is that all charts in the same Highcharts object
  10807. * share the same time settings, in which case the global settings are set
  10808. * using `setOptions`.
  10809. *
  10810. * ```js
  10811. * // Apply time settings globally
  10812. * Highcharts.setOptions({
  10813. * time: {
  10814. * timezone: 'Europe/London'
  10815. * }
  10816. * });
  10817. * // Apply time settings by instance
  10818. * var chart = Highcharts.chart('container', {
  10819. * time: {
  10820. * timezone: 'America/New_York'
  10821. * },
  10822. * series: [{
  10823. * data: [1, 4, 3, 5]
  10824. * }]
  10825. * });
  10826. *
  10827. * // Use the Time object
  10828. * console.log(
  10829. * 'Current time in New York',
  10830. * chart.time.dateFormat('%Y-%m-%d %H:%M:%S', Date.now())
  10831. * );
  10832. * ```
  10833. *
  10834. * Since v6.0.5, the time options were moved from the `global` obect to the
  10835. * `time` object, and time options can be set on each individual chart.
  10836. *
  10837. * @sample {highcharts|highstock}
  10838. * highcharts/time/timezone/
  10839. * Set the timezone globally
  10840. * @sample {highcharts}
  10841. * highcharts/time/individual/
  10842. * Set the timezone per chart instance
  10843. * @sample {highstock}
  10844. * stock/time/individual/
  10845. * Set the timezone per chart instance
  10846. *
  10847. * @since 6.0.5
  10848. * @optionparent time
  10849. */
  10850. time: {
  10851. /**
  10852. * A custom `Date` class for advanced date handling. For example,
  10853. * [JDate](https://github.com/tahajahangir/jdate) can be hooked in to
  10854. * handle Jalali dates.
  10855. *
  10856. * @type {*}
  10857. * @since 4.0.4
  10858. * @product highcharts highstock gantt
  10859. */
  10860. Date: void 0,
  10861. /**
  10862. * A callback to return the time zone offset for a given datetime. It
  10863. * takes the timestamp in terms of milliseconds since January 1 1970,
  10864. * and returns the timezone offset in minutes. This provides a hook
  10865. * for drawing time based charts in specific time zones using their
  10866. * local DST crossover dates, with the help of external libraries.
  10867. *
  10868. * @see [global.timezoneOffset](#global.timezoneOffset)
  10869. *
  10870. * @sample {highcharts|highstock} highcharts/time/gettimezoneoffset/
  10871. * Use moment.js to draw Oslo time regardless of browser locale
  10872. *
  10873. * @type {Highcharts.TimezoneOffsetCallbackFunction}
  10874. * @since 4.1.0
  10875. * @product highcharts highstock gantt
  10876. */
  10877. getTimezoneOffset: void 0,
  10878. /**
  10879. * Requires [moment.js](https://momentjs.com/). If the timezone option
  10880. * is specified, it creates a default
  10881. * [getTimezoneOffset](#time.getTimezoneOffset) function that looks
  10882. * up the specified timezone in moment.js. If moment.js is not included,
  10883. * this throws a Highcharts error in the console, but does not crash the
  10884. * chart.
  10885. *
  10886. * @see [getTimezoneOffset](#time.getTimezoneOffset)
  10887. *
  10888. * @sample {highcharts|highstock} highcharts/time/timezone/
  10889. * Europe/Oslo
  10890. *
  10891. * @type {string}
  10892. * @since 5.0.7
  10893. * @product highcharts highstock gantt
  10894. */
  10895. timezone: void 0,
  10896. /**
  10897. * The timezone offset in minutes. Positive values are west, negative
  10898. * values are east of UTC, as in the ECMAScript
  10899. * [getTimezoneOffset](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset)
  10900. * method. Use this to display UTC based data in a predefined time zone.
  10901. *
  10902. * @see [time.getTimezoneOffset](#time.getTimezoneOffset)
  10903. *
  10904. * @sample {highcharts|highstock} highcharts/time/timezoneoffset/
  10905. * Timezone offset
  10906. *
  10907. * @since 3.0.8
  10908. * @product highcharts highstock gantt
  10909. */
  10910. timezoneOffset: 0,
  10911. /**
  10912. * Whether to use UTC time for axis scaling, tickmark placement and
  10913. * time display in `Highcharts.dateFormat`. Advantages of using UTC
  10914. * is that the time displays equally regardless of the user agent's
  10915. * time zone settings. Local time can be used when the data is loaded
  10916. * in real time or when correct Daylight Saving Time transitions are
  10917. * required.
  10918. *
  10919. * @sample {highcharts} highcharts/time/useutc-true/
  10920. * True by default
  10921. * @sample {highcharts} highcharts/time/useutc-false/
  10922. * False
  10923. */
  10924. useUTC: true
  10925. },
  10926. /**
  10927. * General options for the chart.
  10928. */
  10929. chart: {
  10930. /**
  10931. * Default `mapData` for all series. If set to a string, it functions
  10932. * as an index into the `Highcharts.maps` array. Otherwise it is
  10933. * interpreted as map data.
  10934. *
  10935. * @see [mapData](#series.map.mapData)
  10936. *
  10937. * @sample maps/demo/geojson
  10938. * Loading geoJSON data
  10939. * @sample maps/chart/topojson
  10940. * Loading topoJSON converted to geoJSON
  10941. *
  10942. * @type {string|Array<*>|Highcharts.GeoJSON}
  10943. * @since 5.0.0
  10944. * @product highmaps
  10945. * @apioption chart.map
  10946. */
  10947. /**
  10948. * Set lat/lon transformation definitions for the chart. If not defined,
  10949. * these are extracted from the map data.
  10950. *
  10951. * @type {*}
  10952. * @since 5.0.0
  10953. * @product highmaps
  10954. * @apioption chart.mapTransforms
  10955. */
  10956. /**
  10957. * When using multiple axis, the ticks of two or more opposite axes
  10958. * will automatically be aligned by adding ticks to the axis or axes
  10959. * with the least ticks, as if `tickAmount` were specified.
  10960. *
  10961. * This can be prevented by setting `alignTicks` to false. If the grid
  10962. * lines look messy, it's a good idea to hide them for the secondary
  10963. * axis by setting `gridLineWidth` to 0.
  10964. *
  10965. * If `startOnTick` or `endOnTick` in an Axis options are set to false,
  10966. * then the `alignTicks ` will be disabled for the Axis.
  10967. *
  10968. * Disabled for logarithmic axes.
  10969. *
  10970. * @sample {highcharts} highcharts/chart/alignticks-true/
  10971. * True by default
  10972. * @sample {highcharts} highcharts/chart/alignticks-false/
  10973. * False
  10974. * @sample {highstock} stock/chart/alignticks-true/
  10975. * True by default
  10976. * @sample {highstock} stock/chart/alignticks-false/
  10977. * False
  10978. *
  10979. * @type {boolean}
  10980. * @default true
  10981. * @product highcharts highstock gantt
  10982. * @apioption chart.alignTicks
  10983. */
  10984. /**
  10985. * Set the overall animation for all chart updating. Animation can be
  10986. * disabled throughout the chart by setting it to false here. It can
  10987. * be overridden for each individual API method as a function parameter.
  10988. * The only animation not affected by this option is the initial series
  10989. * animation, see [plotOptions.series.animation](
  10990. * #plotOptions.series.animation).
  10991. *
  10992. * The animation can either be set as a boolean or a configuration
  10993. * object. If `true`, it will use the 'swing' jQuery easing and a
  10994. * duration of 500 ms. If used as a configuration object, the following
  10995. * properties are supported:
  10996. *
  10997. * - `defer`: The animation delay time in milliseconds.
  10998. *
  10999. * - `duration`: The duration of the animation in milliseconds.
  11000. *
  11001. * - `easing`: A string reference to an easing function set on the
  11002. * `Math` object. See
  11003. * [the easing demo](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/series-animation-easing/).
  11004. *
  11005. * When zooming on a series with less than 100 points, the chart redraw
  11006. * will be done with animation, but in case of more data points, it is
  11007. * necessary to set this option to ensure animation on zoom.
  11008. *
  11009. * @sample {highcharts} highcharts/chart/animation-none/
  11010. * Updating with no animation
  11011. * @sample {highcharts} highcharts/chart/animation-duration/
  11012. * With a longer duration
  11013. * @sample {highcharts} highcharts/chart/animation-easing/
  11014. * With a jQuery UI easing
  11015. * @sample {highmaps} maps/chart/animation-none/
  11016. * Updating with no animation
  11017. * @sample {highmaps} maps/chart/animation-duration/
  11018. * With a longer duration
  11019. *
  11020. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  11021. * @default undefined
  11022. * @apioption chart.animation
  11023. */
  11024. /**
  11025. * A CSS class name to apply to the charts container `div`, allowing
  11026. * unique CSS styling for each chart.
  11027. *
  11028. * @type {string}
  11029. * @apioption chart.className
  11030. */
  11031. /**
  11032. * Event listeners for the chart.
  11033. *
  11034. * @apioption chart.events
  11035. */
  11036. /**
  11037. * Fires when a series is added to the chart after load time, using the
  11038. * `addSeries` method. One parameter, `event`, is passed to the
  11039. * function, containing common event information. Through
  11040. * `event.options` you can access the series options that were passed to
  11041. * the `addSeries` method. Returning false prevents the series from
  11042. * being added.
  11043. *
  11044. * @sample {highcharts} highcharts/chart/events-addseries/
  11045. * Alert on add series
  11046. * @sample {highstock} stock/chart/events-addseries/
  11047. * Alert on add series
  11048. *
  11049. * @type {Highcharts.ChartAddSeriesCallbackFunction}
  11050. * @since 1.2.0
  11051. * @context Highcharts.Chart
  11052. * @apioption chart.events.addSeries
  11053. */
  11054. /**
  11055. * Fires when clicking on the plot background. One parameter, `event`,
  11056. * is passed to the function, containing common event information.
  11057. *
  11058. * Information on the clicked spot can be found through `event.xAxis`
  11059. * and `event.yAxis`, which are arrays containing the axes of each
  11060. * dimension and each axis' value at the clicked spot. The primary axes
  11061. * are `event.xAxis[0]` and `event.yAxis[0]`. Remember the unit of a
  11062. * datetime axis is milliseconds since 1970-01-01 00:00:00.
  11063. *
  11064. * ```js
  11065. * click: function(e) {
  11066. * console.log(
  11067. * Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', e.xAxis[0].value),
  11068. * e.yAxis[0].value
  11069. * )
  11070. * }
  11071. * ```
  11072. *
  11073. * @sample {highcharts} highcharts/chart/events-click/
  11074. * Alert coordinates on click
  11075. * @sample {highcharts} highcharts/chart/events-container/
  11076. * Alternatively, attach event to container
  11077. * @sample {highstock} stock/chart/events-click/
  11078. * Alert coordinates on click
  11079. * @sample {highstock} highcharts/chart/events-container/
  11080. * Alternatively, attach event to container
  11081. * @sample {highmaps} maps/chart/events-click/
  11082. * Record coordinates on click
  11083. * @sample {highmaps} highcharts/chart/events-container/
  11084. * Alternatively, attach event to container
  11085. *
  11086. * @type {Highcharts.ChartClickCallbackFunction}
  11087. * @since 1.2.0
  11088. * @context Highcharts.Chart
  11089. * @apioption chart.events.click
  11090. */
  11091. /**
  11092. * Fires when the chart is finished loading. Since v4.2.2, it also waits
  11093. * for images to be loaded, for example from point markers. One
  11094. * parameter, `event`, is passed to the function, containing common
  11095. * event information.
  11096. *
  11097. * There is also a second parameter to the chart constructor where a
  11098. * callback function can be passed to be executed on chart.load.
  11099. *
  11100. * @sample {highcharts} highcharts/chart/events-load/
  11101. * Alert on chart load
  11102. * @sample {highstock} stock/chart/events-load/
  11103. * Alert on chart load
  11104. * @sample {highmaps} maps/chart/events-load/
  11105. * Add series on chart load
  11106. *
  11107. * @type {Highcharts.ChartLoadCallbackFunction}
  11108. * @context Highcharts.Chart
  11109. * @apioption chart.events.load
  11110. */
  11111. /**
  11112. * Fires when the chart is redrawn, either after a call to
  11113. * `chart.redraw()` or after an axis, series or point is modified with
  11114. * the `redraw` option set to `true`. One parameter, `event`, is passed
  11115. * to the function, containing common event information.
  11116. *
  11117. * @sample {highcharts} highcharts/chart/events-redraw/
  11118. * Alert on chart redraw
  11119. * @sample {highstock} stock/chart/events-redraw/
  11120. * Alert on chart redraw when adding a series or moving the
  11121. * zoomed range
  11122. * @sample {highmaps} maps/chart/events-redraw/
  11123. * Set subtitle on chart redraw
  11124. *
  11125. * @type {Highcharts.ChartRedrawCallbackFunction}
  11126. * @since 1.2.0
  11127. * @context Highcharts.Chart
  11128. * @apioption chart.events.redraw
  11129. */
  11130. /**
  11131. * Fires after initial load of the chart (directly after the `load`
  11132. * event), and after each redraw (directly after the `redraw` event).
  11133. *
  11134. * @type {Highcharts.ChartRenderCallbackFunction}
  11135. * @since 5.0.7
  11136. * @context Highcharts.Chart
  11137. * @apioption chart.events.render
  11138. */
  11139. /**
  11140. * Fires when an area of the chart has been selected. Selection is
  11141. * enabled by setting the chart's zoomType. One parameter, `event`, is
  11142. * passed to the function, containing common event information. The
  11143. * default action for the selection event is to zoom the chart to the
  11144. * selected area. It can be prevented by calling
  11145. * `event.preventDefault()` or return false.
  11146. *
  11147. * Information on the selected area can be found through `event.xAxis`
  11148. * and `event.yAxis`, which are arrays containing the axes of each
  11149. * dimension and each axis' min and max values. The primary axes are
  11150. * `event.xAxis[0]` and `event.yAxis[0]`. Remember the unit of a
  11151. * datetime axis is milliseconds since 1970-01-01 00:00:00.
  11152. *
  11153. * ```js
  11154. * selection: function(event) {
  11155. * // log the min and max of the primary, datetime x-axis
  11156. * console.log(
  11157. * Highcharts.dateFormat(
  11158. * '%Y-%m-%d %H:%M:%S',
  11159. * event.xAxis[0].min
  11160. * ),
  11161. * Highcharts.dateFormat(
  11162. * '%Y-%m-%d %H:%M:%S',
  11163. * event.xAxis[0].max
  11164. * )
  11165. * );
  11166. * // log the min and max of the y axis
  11167. * console.log(event.yAxis[0].min, event.yAxis[0].max);
  11168. * }
  11169. * ```
  11170. *
  11171. * @sample {highcharts} highcharts/chart/events-selection/
  11172. * Report on selection and reset
  11173. * @sample {highcharts} highcharts/chart/events-selection-points/
  11174. * Select a range of points through a drag selection
  11175. * @sample {highstock} stock/chart/events-selection/
  11176. * Report on selection and reset
  11177. * @sample {highstock} highcharts/chart/events-selection-points/
  11178. * Select a range of points through a drag selection
  11179. * (Highcharts)
  11180. *
  11181. * @type {Highcharts.ChartSelectionCallbackFunction}
  11182. * @apioption chart.events.selection
  11183. */
  11184. /**
  11185. * The margin between the outer edge of the chart and the plot area.
  11186. * The numbers in the array designate top, right, bottom and left
  11187. * respectively. Use the options `marginTop`, `marginRight`,
  11188. * `marginBottom` and `marginLeft` for shorthand setting of one option.
  11189. *
  11190. * By default there is no margin. The actual space is dynamically
  11191. * calculated from the offset of axis labels, axis title, title,
  11192. * subtitle and legend in addition to the `spacingTop`, `spacingRight`,
  11193. * `spacingBottom` and `spacingLeft` options.
  11194. *
  11195. * @sample {highcharts} highcharts/chart/margins-zero/
  11196. * Zero margins
  11197. * @sample {highstock} stock/chart/margin-zero/
  11198. * Zero margins
  11199. *
  11200. * @type {number|Array<number>}
  11201. * @apioption chart.margin
  11202. */
  11203. /**
  11204. * The margin between the bottom outer edge of the chart and the plot
  11205. * area. Use this to set a fixed pixel value for the margin as opposed
  11206. * to the default dynamic margin. See also `spacingBottom`.
  11207. *
  11208. * @sample {highcharts} highcharts/chart/marginbottom/
  11209. * 100px bottom margin
  11210. * @sample {highstock} stock/chart/marginbottom/
  11211. * 100px bottom margin
  11212. * @sample {highmaps} maps/chart/margin/
  11213. * 100px margins
  11214. *
  11215. * @type {number}
  11216. * @since 2.0
  11217. * @apioption chart.marginBottom
  11218. */
  11219. /**
  11220. * The margin between the left outer edge of the chart and the plot
  11221. * area. Use this to set a fixed pixel value for the margin as opposed
  11222. * to the default dynamic margin. See also `spacingLeft`.
  11223. *
  11224. * @sample {highcharts} highcharts/chart/marginleft/
  11225. * 150px left margin
  11226. * @sample {highstock} stock/chart/marginleft/
  11227. * 150px left margin
  11228. * @sample {highmaps} maps/chart/margin/
  11229. * 100px margins
  11230. *
  11231. * @type {number}
  11232. * @since 2.0
  11233. * @apioption chart.marginLeft
  11234. */
  11235. /**
  11236. * The margin between the right outer edge of the chart and the plot
  11237. * area. Use this to set a fixed pixel value for the margin as opposed
  11238. * to the default dynamic margin. See also `spacingRight`.
  11239. *
  11240. * @sample {highcharts} highcharts/chart/marginright/
  11241. * 100px right margin
  11242. * @sample {highstock} stock/chart/marginright/
  11243. * 100px right margin
  11244. * @sample {highmaps} maps/chart/margin/
  11245. * 100px margins
  11246. *
  11247. * @type {number}
  11248. * @since 2.0
  11249. * @apioption chart.marginRight
  11250. */
  11251. /**
  11252. * The margin between the top outer edge of the chart and the plot area.
  11253. * Use this to set a fixed pixel value for the margin as opposed to
  11254. * the default dynamic margin. See also `spacingTop`.
  11255. *
  11256. * @sample {highcharts} highcharts/chart/margintop/ 100px top margin
  11257. * @sample {highstock} stock/chart/margintop/
  11258. * 100px top margin
  11259. * @sample {highmaps} maps/chart/margin/
  11260. * 100px margins
  11261. *
  11262. * @type {number}
  11263. * @since 2.0
  11264. * @apioption chart.marginTop
  11265. */
  11266. /**
  11267. * Callback function to override the default function that formats all
  11268. * the numbers in the chart. Returns a string with the formatted number.
  11269. *
  11270. * @sample highcharts/members/highcharts-numberformat
  11271. * Arabic digits in Highcharts
  11272. * @type {Highcharts.NumberFormatterCallbackFunction}
  11273. * @since 8.0.0
  11274. * @apioption chart.numberFormatter
  11275. */
  11276. /**
  11277. * Allows setting a key to switch between zooming and panning. Can be
  11278. * one of `alt`, `ctrl`, `meta` (the command key on Mac and Windows
  11279. * key on Windows) or `shift`. The keys are mapped directly to the key
  11280. * properties of the click event argument (`event.altKey`,
  11281. * `event.ctrlKey`, `event.metaKey` and `event.shiftKey`).
  11282. *
  11283. * @type {string}
  11284. * @since 4.0.3
  11285. * @product highcharts gantt
  11286. * @validvalue ["alt", "ctrl", "meta", "shift"]
  11287. * @apioption chart.panKey
  11288. */
  11289. /**
  11290. * Allow panning in a chart. Best used with [panKey](#chart.panKey)
  11291. * to combine zooming and panning.
  11292. *
  11293. * On touch devices, when the [tooltip.followTouchMove](
  11294. * #tooltip.followTouchMove) option is `true` (default), panning
  11295. * requires two fingers. To allow panning with one finger, set
  11296. * `followTouchMove` to `false`.
  11297. *
  11298. * @sample {highcharts} highcharts/chart/pankey/ Zooming and panning
  11299. * @sample {highstock} stock/chart/panning/ Zooming and xy panning
  11300. *
  11301. * @product highcharts highstock gantt
  11302. * @apioption chart.panning
  11303. */
  11304. /**
  11305. * Enable or disable chart panning.
  11306. *
  11307. * @type {boolean}
  11308. * @default {highcharts} false
  11309. * @default {highstock} true
  11310. * @apioption chart.panning.enabled
  11311. */
  11312. /**
  11313. * Decides in what dimensions the user can pan the chart. Can be
  11314. * one of `x`, `y`, or `xy`.
  11315. *
  11316. * @sample {highcharts} highcharts/chart/panning-type
  11317. * Zooming and xy panning
  11318. *
  11319. * @type {string}
  11320. * @validvalue ["x", "y", "xy"]
  11321. * @default x
  11322. * @apioption chart.panning.type
  11323. */
  11324. /**
  11325. * Equivalent to [zoomType](#chart.zoomType), but for multitouch
  11326. * gestures only. By default, the `pinchType` is the same as the
  11327. * `zoomType` setting. However, pinching can be enabled separately in
  11328. * some cases, for example in stock charts where a mouse drag pans the
  11329. * chart, while pinching is enabled. When [tooltip.followTouchMove](
  11330. * #tooltip.followTouchMove) is true, pinchType only applies to
  11331. * two-finger touches.
  11332. *
  11333. * @type {string}
  11334. * @default {highcharts} undefined
  11335. * @default {highstock} x
  11336. * @since 3.0
  11337. * @product highcharts highstock gantt
  11338. * @validvalue ["x", "y", "xy"]
  11339. * @apioption chart.pinchType
  11340. */
  11341. /**
  11342. * Whether to apply styled mode. When in styled mode, no presentational
  11343. * attributes or CSS are applied to the chart SVG. Instead, CSS rules
  11344. * are required to style the chart. The default style sheet is
  11345. * available from `https://code.highcharts.com/css/highcharts.css`.
  11346. *
  11347. * @type {boolean}
  11348. * @default false
  11349. * @since 7.0
  11350. * @apioption chart.styledMode
  11351. */
  11352. styledMode: false,
  11353. /**
  11354. * The corner radius of the outer chart border.
  11355. *
  11356. * @sample {highcharts} highcharts/chart/borderradius/
  11357. * 20px radius
  11358. * @sample {highstock} stock/chart/border/
  11359. * 10px radius
  11360. * @sample {highmaps} maps/chart/border/
  11361. * Border options
  11362. *
  11363. */
  11364. borderRadius: 0,
  11365. /**
  11366. * In styled mode, this sets how many colors the class names
  11367. * should rotate between. With ten colors, series (or points) are
  11368. * given class names like `highcharts-color-0`, `highcharts-color-0`
  11369. * [...] `highcharts-color-9`. The equivalent in non-styled mode
  11370. * is to set colors using the [colors](#colors) setting.
  11371. *
  11372. * @since 5.0.0
  11373. */
  11374. colorCount: 10,
  11375. /**
  11376. * Alias of `type`.
  11377. *
  11378. * @sample {highcharts} highcharts/chart/defaultseriestype/
  11379. * Bar
  11380. *
  11381. * @deprecated
  11382. *
  11383. * @product highcharts
  11384. */
  11385. defaultSeriesType: 'line',
  11386. /**
  11387. * If true, the axes will scale to the remaining visible series once
  11388. * one series is hidden. If false, hiding and showing a series will
  11389. * not affect the axes or the other series. For stacks, once one series
  11390. * within the stack is hidden, the rest of the stack will close in
  11391. * around it even if the axis is not affected.
  11392. *
  11393. * @sample {highcharts} highcharts/chart/ignorehiddenseries-true/
  11394. * True by default
  11395. * @sample {highcharts} highcharts/chart/ignorehiddenseries-false/
  11396. * False
  11397. * @sample {highcharts} highcharts/chart/ignorehiddenseries-true-stacked/
  11398. * True with stack
  11399. * @sample {highstock} stock/chart/ignorehiddenseries-true/
  11400. * True by default
  11401. * @sample {highstock} stock/chart/ignorehiddenseries-false/
  11402. * False
  11403. *
  11404. * @since 1.2.0
  11405. * @product highcharts highstock gantt
  11406. */
  11407. ignoreHiddenSeries: true,
  11408. /**
  11409. * Whether to invert the axes so that the x axis is vertical and y axis
  11410. * is horizontal. When `true`, the x axis is [reversed](#xAxis.reversed)
  11411. * by default.
  11412. *
  11413. * @productdesc {highcharts}
  11414. * If a bar series is present in the chart, it will be inverted
  11415. * automatically. Inverting the chart doesn't have an effect if there
  11416. * are no cartesian series in the chart, or if the chart is
  11417. * [polar](#chart.polar).
  11418. *
  11419. * @sample {highcharts} highcharts/chart/inverted/
  11420. * Inverted line
  11421. * @sample {highstock} stock/navigator/inverted/
  11422. * Inverted stock chart
  11423. *
  11424. * @type {boolean}
  11425. * @default false
  11426. * @product highcharts highstock gantt
  11427. * @apioption chart.inverted
  11428. */
  11429. /**
  11430. * The distance between the outer edge of the chart and the content,
  11431. * like title or legend, or axis title and labels if present. The
  11432. * numbers in the array designate top, right, bottom and left
  11433. * respectively. Use the options spacingTop, spacingRight, spacingBottom
  11434. * and spacingLeft options for shorthand setting of one option.
  11435. *
  11436. * @type {Array<number>}
  11437. * @see [chart.margin](#chart.margin)
  11438. * @default [10, 10, 15, 10]
  11439. * @since 3.0.6
  11440. */
  11441. spacing: [10, 10, 15, 10],
  11442. /**
  11443. * The button that appears after a selection zoom, allowing the user
  11444. * to reset zoom.
  11445. */
  11446. resetZoomButton: {
  11447. /**
  11448. * What frame the button placement should be related to. Can be
  11449. * either `plotBox` or `spacingBox`.
  11450. *
  11451. * @sample {highcharts} highcharts/chart/resetzoombutton-relativeto/
  11452. * Relative to the chart
  11453. * @sample {highstock} highcharts/chart/resetzoombutton-relativeto/
  11454. * Relative to the chart
  11455. *
  11456. * @type {Highcharts.ButtonRelativeToValue}
  11457. * @default plot
  11458. * @since 2.2
  11459. * @apioption chart.resetZoomButton.relativeTo
  11460. */
  11461. /**
  11462. * A collection of attributes for the button. The object takes SVG
  11463. * attributes like `fill`, `stroke`, `stroke-width` or `r`, the
  11464. * border radius. The theme also supports `style`, a collection of
  11465. * CSS properties for the text. Equivalent attributes for the hover
  11466. * state are given in `theme.states.hover`.
  11467. *
  11468. * @sample {highcharts} highcharts/chart/resetzoombutton-theme/
  11469. * Theming the button
  11470. * @sample {highstock} highcharts/chart/resetzoombutton-theme/
  11471. * Theming the button
  11472. *
  11473. * @type {Highcharts.SVGAttributes}
  11474. * @since 2.2
  11475. */
  11476. theme: {
  11477. /** @internal */
  11478. zIndex: 6
  11479. },
  11480. /**
  11481. * The position of the button.
  11482. *
  11483. * @sample {highcharts} highcharts/chart/resetzoombutton-position/
  11484. * Above the plot area
  11485. * @sample {highstock} highcharts/chart/resetzoombutton-position/
  11486. * Above the plot area
  11487. * @sample {highmaps} highcharts/chart/resetzoombutton-position/
  11488. * Above the plot area
  11489. *
  11490. * @type {Highcharts.AlignObject}
  11491. * @since 2.2
  11492. */
  11493. position: {
  11494. /**
  11495. * The horizontal alignment of the button.
  11496. */
  11497. align: 'right',
  11498. /**
  11499. * The horizontal offset of the button.
  11500. */
  11501. x: -10,
  11502. /**
  11503. * The vertical alignment of the button.
  11504. *
  11505. * @type {Highcharts.VerticalAlignValue}
  11506. * @default top
  11507. * @apioption chart.resetZoomButton.position.verticalAlign
  11508. */
  11509. /**
  11510. * The vertical offset of the button.
  11511. */
  11512. y: 10
  11513. }
  11514. },
  11515. /**
  11516. * The pixel width of the plot area border.
  11517. *
  11518. * @sample {highcharts} highcharts/chart/plotborderwidth/
  11519. * 1px border
  11520. * @sample {highstock} stock/chart/plotborder/
  11521. * 2px border
  11522. * @sample {highmaps} maps/chart/plotborder/
  11523. * Plot border options
  11524. *
  11525. * @type {number}
  11526. * @default 0
  11527. * @apioption chart.plotBorderWidth
  11528. */
  11529. /**
  11530. * Whether to apply a drop shadow to the plot area. Requires that
  11531. * plotBackgroundColor be set. The shadow can be an object configuration
  11532. * containing `color`, `offsetX`, `offsetY`, `opacity` and `width`.
  11533. *
  11534. * @sample {highcharts} highcharts/chart/plotshadow/
  11535. * Plot shadow
  11536. * @sample {highstock} stock/chart/plotshadow/
  11537. * Plot shadow
  11538. * @sample {highmaps} maps/chart/plotborder/
  11539. * Plot border options
  11540. *
  11541. * @type {boolean|Highcharts.CSSObject}
  11542. * @default false
  11543. * @apioption chart.plotShadow
  11544. */
  11545. /**
  11546. * When true, cartesian charts like line, spline, area and column are
  11547. * transformed into the polar coordinate system. This produces _polar
  11548. * charts_, also known as _radar charts_.
  11549. *
  11550. * @sample {highcharts} highcharts/demo/polar/
  11551. * Polar chart
  11552. * @sample {highcharts} highcharts/demo/polar-wind-rose/
  11553. * Wind rose, stacked polar column chart
  11554. * @sample {highcharts} highcharts/demo/polar-spider/
  11555. * Spider web chart
  11556. * @sample {highcharts} highcharts/parallel-coordinates/polar/
  11557. * Star plot, multivariate data in a polar chart
  11558. *
  11559. * @type {boolean}
  11560. * @default false
  11561. * @since 2.3.0
  11562. * @product highcharts
  11563. * @requires highcharts-more
  11564. * @apioption chart.polar
  11565. */
  11566. /**
  11567. * Whether to reflow the chart to fit the width of the container div
  11568. * on resizing the window.
  11569. *
  11570. * @sample {highcharts} highcharts/chart/reflow-true/
  11571. * True by default
  11572. * @sample {highcharts} highcharts/chart/reflow-false/
  11573. * False
  11574. * @sample {highstock} stock/chart/reflow-true/
  11575. * True by default
  11576. * @sample {highstock} stock/chart/reflow-false/
  11577. * False
  11578. * @sample {highmaps} maps/chart/reflow-true/
  11579. * True by default
  11580. * @sample {highmaps} maps/chart/reflow-false/
  11581. * False
  11582. *
  11583. * @type {boolean}
  11584. * @default true
  11585. * @since 2.1
  11586. * @apioption chart.reflow
  11587. */
  11588. /**
  11589. * The HTML element where the chart will be rendered. If it is a string,
  11590. * the element by that id is used. The HTML element can also be passed
  11591. * by direct reference, or as the first argument of the chart
  11592. * constructor, in which case the option is not needed.
  11593. *
  11594. * @sample {highcharts} highcharts/chart/reflow-true/
  11595. * String
  11596. * @sample {highcharts} highcharts/chart/renderto-object/
  11597. * Object reference
  11598. * @sample {highstock} stock/chart/renderto-string/
  11599. * String
  11600. * @sample {highstock} stock/chart/renderto-object/
  11601. * Object reference
  11602. *
  11603. * @type {string|Highcharts.HTMLDOMElement}
  11604. * @apioption chart.renderTo
  11605. */
  11606. /**
  11607. * The background color of the marker square when selecting (zooming
  11608. * in on) an area of the chart.
  11609. *
  11610. * @see In styled mode, the selection marker fill is set with the
  11611. * `.highcharts-selection-marker` class.
  11612. *
  11613. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  11614. * @default rgba(51,92,173,0.25)
  11615. * @since 2.1.7
  11616. * @apioption chart.selectionMarkerFill
  11617. */
  11618. /**
  11619. * Whether to apply a drop shadow to the outer chart area. Requires
  11620. * that backgroundColor be set. The shadow can be an object
  11621. * configuration containing `color`, `offsetX`, `offsetY`, `opacity` and
  11622. * `width`.
  11623. *
  11624. * @sample {highcharts} highcharts/chart/shadow/
  11625. * Shadow
  11626. * @sample {highstock} stock/chart/shadow/
  11627. * Shadow
  11628. * @sample {highmaps} maps/chart/border/
  11629. * Chart border and shadow
  11630. *
  11631. * @type {boolean|Highcharts.CSSObject}
  11632. * @default false
  11633. * @apioption chart.shadow
  11634. */
  11635. /**
  11636. * Whether to show the axes initially. This only applies to empty charts
  11637. * where series are added dynamically, as axes are automatically added
  11638. * to cartesian series.
  11639. *
  11640. * @sample {highcharts} highcharts/chart/showaxes-false/
  11641. * False by default
  11642. * @sample {highcharts} highcharts/chart/showaxes-true/
  11643. * True
  11644. *
  11645. * @type {boolean}
  11646. * @since 1.2.5
  11647. * @product highcharts gantt
  11648. * @apioption chart.showAxes
  11649. */
  11650. /**
  11651. * The space between the bottom edge of the chart and the content (plot
  11652. * area, axis title and labels, title, subtitle or legend in top
  11653. * position).
  11654. *
  11655. * @sample {highcharts} highcharts/chart/spacingbottom/
  11656. * Spacing bottom set to 100
  11657. * @sample {highstock} stock/chart/spacingbottom/
  11658. * Spacing bottom set to 100
  11659. * @sample {highmaps} maps/chart/spacing/
  11660. * Spacing 100 all around
  11661. *
  11662. * @type {number}
  11663. * @default 15
  11664. * @since 2.1
  11665. * @apioption chart.spacingBottom
  11666. */
  11667. /**
  11668. * The space between the left edge of the chart and the content (plot
  11669. * area, axis title and labels, title, subtitle or legend in top
  11670. * position).
  11671. *
  11672. * @sample {highcharts} highcharts/chart/spacingleft/
  11673. * Spacing left set to 100
  11674. * @sample {highstock} stock/chart/spacingleft/
  11675. * Spacing left set to 100
  11676. * @sample {highmaps} maps/chart/spacing/
  11677. * Spacing 100 all around
  11678. *
  11679. * @type {number}
  11680. * @default 10
  11681. * @since 2.1
  11682. * @apioption chart.spacingLeft
  11683. */
  11684. /**
  11685. * The space between the right edge of the chart and the content (plot
  11686. * area, axis title and labels, title, subtitle or legend in top
  11687. * position).
  11688. *
  11689. * @sample {highcharts} highcharts/chart/spacingright-100/
  11690. * Spacing set to 100
  11691. * @sample {highcharts} highcharts/chart/spacingright-legend/
  11692. * Legend in right position with default spacing
  11693. * @sample {highstock} stock/chart/spacingright/
  11694. * Spacing set to 100
  11695. * @sample {highmaps} maps/chart/spacing/
  11696. * Spacing 100 all around
  11697. *
  11698. * @type {number}
  11699. * @default 10
  11700. * @since 2.1
  11701. * @apioption chart.spacingRight
  11702. */
  11703. /**
  11704. * The space between the top edge of the chart and the content (plot
  11705. * area, axis title and labels, title, subtitle or legend in top
  11706. * position).
  11707. *
  11708. * @sample {highcharts} highcharts/chart/spacingtop-100/
  11709. * A top spacing of 100
  11710. * @sample {highcharts} highcharts/chart/spacingtop-10/
  11711. * Floating chart title makes the plot area align to the default
  11712. * spacingTop of 10.
  11713. * @sample {highstock} stock/chart/spacingtop/
  11714. * A top spacing of 100
  11715. * @sample {highmaps} maps/chart/spacing/
  11716. * Spacing 100 all around
  11717. *
  11718. * @type {number}
  11719. * @default 10
  11720. * @since 2.1
  11721. * @apioption chart.spacingTop
  11722. */
  11723. /**
  11724. * Additional CSS styles to apply inline to the container `div`. Note
  11725. * that since the default font styles are applied in the renderer, it
  11726. * is ignorant of the individual chart options and must be set globally.
  11727. *
  11728. * @see In styled mode, general chart styles can be set with the
  11729. * `.highcharts-root` class.
  11730. * @sample {highcharts} highcharts/chart/style-serif-font/
  11731. * Using a serif type font
  11732. * @sample {highcharts} highcharts/css/em/
  11733. * Styled mode with relative font sizes
  11734. * @sample {highstock} stock/chart/style/
  11735. * Using a serif type font
  11736. * @sample {highmaps} maps/chart/style-serif-font/
  11737. * Using a serif type font
  11738. *
  11739. * @type {Highcharts.CSSObject}
  11740. * @default {"fontFamily": "\"Lucida Grande\", \"Lucida Sans Unicode\", Verdana, Arial, Helvetica, sans-serif","fontSize":"12px"}
  11741. * @apioption chart.style
  11742. */
  11743. /**
  11744. * The default series type for the chart. Can be any of the chart types
  11745. * listed under [plotOptions](#plotOptions) and [series](#series) or can
  11746. * be a series provided by an additional module.
  11747. *
  11748. * In TypeScript this option has no effect in sense of typing and
  11749. * instead the `type` option must always be set in the series.
  11750. *
  11751. * @sample {highcharts} highcharts/chart/type-bar/
  11752. * Bar
  11753. * @sample {highstock} stock/chart/type/
  11754. * Areaspline
  11755. * @sample {highmaps} maps/chart/type-mapline/
  11756. * Mapline
  11757. *
  11758. * @type {string}
  11759. * @default {highcharts} line
  11760. * @default {highstock} line
  11761. * @default {highmaps} map
  11762. * @since 2.1.0
  11763. * @apioption chart.type
  11764. */
  11765. /**
  11766. * Decides in what dimensions the user can zoom by dragging the mouse.
  11767. * Can be one of `x`, `y` or `xy`.
  11768. *
  11769. * @see [panKey](#chart.panKey)
  11770. *
  11771. * @sample {highcharts} highcharts/chart/zoomtype-none/
  11772. * None by default
  11773. * @sample {highcharts} highcharts/chart/zoomtype-x/
  11774. * X
  11775. * @sample {highcharts} highcharts/chart/zoomtype-y/
  11776. * Y
  11777. * @sample {highcharts} highcharts/chart/zoomtype-xy/
  11778. * Xy
  11779. * @sample {highstock} stock/demo/basic-line/
  11780. * None by default
  11781. * @sample {highstock} stock/chart/zoomtype-x/
  11782. * X
  11783. * @sample {highstock} stock/chart/zoomtype-y/
  11784. * Y
  11785. * @sample {highstock} stock/chart/zoomtype-xy/
  11786. * Xy
  11787. *
  11788. * @type {string}
  11789. * @product highcharts highstock gantt
  11790. * @validvalue ["x", "y", "xy"]
  11791. * @apioption chart.zoomType
  11792. */
  11793. /**
  11794. * Enables zooming by a single touch, in combination with
  11795. * [chart.zoomType](#chart.zoomType). When enabled, two-finger pinch
  11796. * will still work as set up by [chart.pinchType](#chart.pinchType).
  11797. * However, `zoomBySingleTouch` will interfere with touch-dragging the
  11798. * chart to read the tooltip. And especially when vertical zooming is
  11799. * enabled, it will make it hard to scroll vertically on the page.
  11800. * @since 9.0.0
  11801. * @sample highcharts/chart/zoombysingletouch
  11802. * Zoom by single touch enabled, with buttons to toggle
  11803. * @product highcharts highstock gantt
  11804. */
  11805. zoomBySingleTouch: false,
  11806. /**
  11807. * An explicit width for the chart. By default (when `null`) the width
  11808. * is calculated from the offset width of the containing element.
  11809. *
  11810. * @sample {highcharts} highcharts/chart/width/
  11811. * 800px wide
  11812. * @sample {highstock} stock/chart/width/
  11813. * 800px wide
  11814. * @sample {highmaps} maps/chart/size/
  11815. * Chart with explicit size
  11816. *
  11817. * @type {null|number|string}
  11818. */
  11819. width: null,
  11820. /**
  11821. * An explicit height for the chart. If a _number_, the height is
  11822. * given in pixels. If given a _percentage string_ (for example
  11823. * `'56%'`), the height is given as the percentage of the actual chart
  11824. * width. This allows for preserving the aspect ratio across responsive
  11825. * sizes.
  11826. *
  11827. * By default (when `null`) the height is calculated from the offset
  11828. * height of the containing element, or 400 pixels if the containing
  11829. * element's height is 0.
  11830. *
  11831. * @sample {highcharts} highcharts/chart/height/
  11832. * 500px height
  11833. * @sample {highstock} stock/chart/height/
  11834. * 300px height
  11835. * @sample {highmaps} maps/chart/size/
  11836. * Chart with explicit size
  11837. * @sample highcharts/chart/height-percent/
  11838. * Highcharts with percentage height
  11839. *
  11840. * @type {null|number|string}
  11841. */
  11842. height: null,
  11843. /**
  11844. * The color of the outer chart border.
  11845. *
  11846. * @see In styled mode, the stroke is set with the
  11847. * `.highcharts-background` class.
  11848. *
  11849. * @sample {highcharts} highcharts/chart/bordercolor/
  11850. * Brown border
  11851. * @sample {highstock} stock/chart/border/
  11852. * Brown border
  11853. * @sample {highmaps} maps/chart/border/
  11854. * Border options
  11855. *
  11856. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  11857. */
  11858. borderColor: palette.highlightColor80,
  11859. /**
  11860. * The pixel width of the outer chart border.
  11861. *
  11862. * @see In styled mode, the stroke is set with the
  11863. * `.highcharts-background` class.
  11864. *
  11865. * @sample {highcharts} highcharts/chart/borderwidth/
  11866. * 5px border
  11867. * @sample {highstock} stock/chart/border/
  11868. * 2px border
  11869. * @sample {highmaps} maps/chart/border/
  11870. * Border options
  11871. *
  11872. * @type {number}
  11873. * @default 0
  11874. * @apioption chart.borderWidth
  11875. */
  11876. /**
  11877. * The background color or gradient for the outer chart area.
  11878. *
  11879. * @see In styled mode, the background is set with the
  11880. * `.highcharts-background` class.
  11881. *
  11882. * @sample {highcharts} highcharts/chart/backgroundcolor-color/
  11883. * Color
  11884. * @sample {highcharts} highcharts/chart/backgroundcolor-gradient/
  11885. * Gradient
  11886. * @sample {highstock} stock/chart/backgroundcolor-color/
  11887. * Color
  11888. * @sample {highstock} stock/chart/backgroundcolor-gradient/
  11889. * Gradient
  11890. * @sample {highmaps} maps/chart/backgroundcolor-color/
  11891. * Color
  11892. * @sample {highmaps} maps/chart/backgroundcolor-gradient/
  11893. * Gradient
  11894. *
  11895. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  11896. */
  11897. backgroundColor: palette.backgroundColor,
  11898. /**
  11899. * The background color or gradient for the plot area.
  11900. *
  11901. * @see In styled mode, the plot background is set with the
  11902. * `.highcharts-plot-background` class.
  11903. *
  11904. * @sample {highcharts} highcharts/chart/plotbackgroundcolor-color/
  11905. * Color
  11906. * @sample {highcharts} highcharts/chart/plotbackgroundcolor-gradient/
  11907. * Gradient
  11908. * @sample {highstock} stock/chart/plotbackgroundcolor-color/
  11909. * Color
  11910. * @sample {highstock} stock/chart/plotbackgroundcolor-gradient/
  11911. * Gradient
  11912. * @sample {highmaps} maps/chart/plotbackgroundcolor-color/
  11913. * Color
  11914. * @sample {highmaps} maps/chart/plotbackgroundcolor-gradient/
  11915. * Gradient
  11916. *
  11917. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  11918. * @apioption chart.plotBackgroundColor
  11919. */
  11920. /**
  11921. * The URL for an image to use as the plot background. To set an image
  11922. * as the background for the entire chart, set a CSS background image
  11923. * to the container element. Note that for the image to be applied to
  11924. * exported charts, its URL needs to be accessible by the export server.
  11925. *
  11926. * @see In styled mode, a plot background image can be set with the
  11927. * `.highcharts-plot-background` class and a [custom pattern](
  11928. * https://www.highcharts.com/docs/chart-design-and-style/
  11929. * gradients-shadows-and-patterns).
  11930. *
  11931. * @sample {highcharts} highcharts/chart/plotbackgroundimage/
  11932. * Skies
  11933. * @sample {highstock} stock/chart/plotbackgroundimage/
  11934. * Skies
  11935. *
  11936. * @type {string}
  11937. * @apioption chart.plotBackgroundImage
  11938. */
  11939. /**
  11940. * The color of the inner chart or plot area border.
  11941. *
  11942. * @see In styled mode, a plot border stroke can be set with the
  11943. * `.highcharts-plot-border` class.
  11944. *
  11945. * @sample {highcharts} highcharts/chart/plotbordercolor/
  11946. * Blue border
  11947. * @sample {highstock} stock/chart/plotborder/
  11948. * Blue border
  11949. * @sample {highmaps} maps/chart/plotborder/
  11950. * Plot border options
  11951. *
  11952. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  11953. */
  11954. plotBorderColor: palette.neutralColor20
  11955. },
  11956. /**
  11957. * The chart's main title.
  11958. *
  11959. * @sample {highmaps} maps/title/title/
  11960. * Title options demonstrated
  11961. */
  11962. title: {
  11963. /**
  11964. * When the title is floating, the plot area will not move to make space
  11965. * for it.
  11966. *
  11967. * @sample {highcharts} highcharts/chart/zoomtype-none/
  11968. * False by default
  11969. * @sample {highcharts} highcharts/title/floating/
  11970. * True - title on top of the plot area
  11971. * @sample {highstock} stock/chart/title-floating/
  11972. * True - title on top of the plot area
  11973. *
  11974. * @type {boolean}
  11975. * @default false
  11976. * @since 2.1
  11977. * @apioption title.floating
  11978. */
  11979. /**
  11980. * CSS styles for the title. Use this for font styling, but use `align`,
  11981. * `x` and `y` for text alignment.
  11982. *
  11983. * In styled mode, the title style is given in the `.highcharts-title`
  11984. * class.
  11985. *
  11986. * @sample {highcharts} highcharts/title/style/
  11987. * Custom color and weight
  11988. * @sample {highstock} stock/chart/title-style/
  11989. * Custom color and weight
  11990. * @sample highcharts/css/titles/
  11991. * Styled mode
  11992. *
  11993. * @type {Highcharts.CSSObject}
  11994. * @default {highcharts|highmaps} { "color": "#333333", "fontSize": "18px" }
  11995. * @default {highstock} { "color": "#333333", "fontSize": "16px" }
  11996. * @apioption title.style
  11997. */
  11998. /**
  11999. * Whether to
  12000. * [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  12001. * to render the text.
  12002. *
  12003. * @type {boolean}
  12004. * @default false
  12005. * @apioption title.useHTML
  12006. */
  12007. /**
  12008. * The vertical alignment of the title. Can be one of `"top"`,
  12009. * `"middle"` and `"bottom"`. When a value is given, the title behaves
  12010. * as if [floating](#title.floating) were `true`.
  12011. *
  12012. * @sample {highcharts} highcharts/title/verticalalign/
  12013. * Chart title in bottom right corner
  12014. * @sample {highstock} stock/chart/title-verticalalign/
  12015. * Chart title in bottom right corner
  12016. *
  12017. * @type {Highcharts.VerticalAlignValue}
  12018. * @since 2.1
  12019. * @apioption title.verticalAlign
  12020. */
  12021. /**
  12022. * The x position of the title relative to the alignment within
  12023. * `chart.spacingLeft` and `chart.spacingRight`.
  12024. *
  12025. * @sample {highcharts} highcharts/title/align/
  12026. * Aligned to the plot area (x = 70px = margin left - spacing
  12027. * left)
  12028. * @sample {highstock} stock/chart/title-align/
  12029. * Aligned to the plot area (x = 50px = margin left - spacing
  12030. * left)
  12031. *
  12032. * @type {number}
  12033. * @default 0
  12034. * @since 2.0
  12035. * @apioption title.x
  12036. */
  12037. /**
  12038. * The y position of the title relative to the alignment within
  12039. * [chart.spacingTop](#chart.spacingTop) and [chart.spacingBottom](
  12040. * #chart.spacingBottom). By default it depends on the font size.
  12041. *
  12042. * @sample {highcharts} highcharts/title/y/
  12043. * Title inside the plot area
  12044. * @sample {highstock} stock/chart/title-verticalalign/
  12045. * Chart title in bottom right corner
  12046. *
  12047. * @type {number}
  12048. * @since 2.0
  12049. * @apioption title.y
  12050. */
  12051. /**
  12052. * The title of the chart. To disable the title, set the `text` to
  12053. * `undefined`.
  12054. *
  12055. * @sample {highcharts} highcharts/title/text/
  12056. * Custom title
  12057. * @sample {highstock} stock/chart/title-text/
  12058. * Custom title
  12059. *
  12060. * @default {highcharts|highmaps} Chart title
  12061. * @default {highstock} undefined
  12062. */
  12063. text: 'Chart title',
  12064. /**
  12065. * The horizontal alignment of the title. Can be one of "left", "center"
  12066. * and "right".
  12067. *
  12068. * @sample {highcharts} highcharts/title/align/
  12069. * Aligned to the plot area (x = 70px = margin left - spacing
  12070. * left)
  12071. * @sample {highstock} stock/chart/title-align/
  12072. * Aligned to the plot area (x = 50px = margin left - spacing
  12073. * left)
  12074. *
  12075. * @type {Highcharts.AlignValue}
  12076. * @since 2.0
  12077. */
  12078. align: 'center',
  12079. /**
  12080. * The margin between the title and the plot area, or if a subtitle
  12081. * is present, the margin between the subtitle and the plot area.
  12082. *
  12083. * @sample {highcharts} highcharts/title/margin-50/
  12084. * A chart title margin of 50
  12085. * @sample {highcharts} highcharts/title/margin-subtitle/
  12086. * The same margin applied with a subtitle
  12087. * @sample {highstock} stock/chart/title-margin/
  12088. * A chart title margin of 50
  12089. *
  12090. * @since 2.1
  12091. */
  12092. margin: 15,
  12093. /**
  12094. * Adjustment made to the title width, normally to reserve space for
  12095. * the exporting burger menu.
  12096. *
  12097. * @sample highcharts/title/widthadjust/
  12098. * Wider menu, greater padding
  12099. *
  12100. * @since 4.2.5
  12101. */
  12102. widthAdjust: -44
  12103. },
  12104. /**
  12105. * The chart's subtitle. This can be used both to display a subtitle below
  12106. * the main title, and to display random text anywhere in the chart. The
  12107. * subtitle can be updated after chart initialization through the
  12108. * `Chart.setTitle` method.
  12109. *
  12110. * @sample {highmaps} maps/title/subtitle/
  12111. * Subtitle options demonstrated
  12112. */
  12113. subtitle: {
  12114. /**
  12115. * When the subtitle is floating, the plot area will not move to make
  12116. * space for it.
  12117. *
  12118. * @sample {highcharts} highcharts/subtitle/floating/
  12119. * Floating title and subtitle
  12120. * @sample {highstock} stock/chart/subtitle-footnote
  12121. * Footnote floating at bottom right of plot area
  12122. *
  12123. * @type {boolean}
  12124. * @default false
  12125. * @since 2.1
  12126. * @apioption subtitle.floating
  12127. */
  12128. /**
  12129. * CSS styles for the title.
  12130. *
  12131. * In styled mode, the subtitle style is given in the
  12132. * `.highcharts-subtitle` class.
  12133. *
  12134. * @sample {highcharts} highcharts/subtitle/style/
  12135. * Custom color and weight
  12136. * @sample {highcharts} highcharts/css/titles/
  12137. * Styled mode
  12138. * @sample {highstock} stock/chart/subtitle-style
  12139. * Custom color and weight
  12140. * @sample {highstock} highcharts/css/titles/
  12141. * Styled mode
  12142. * @sample {highmaps} highcharts/css/titles/
  12143. * Styled mode
  12144. *
  12145. * @type {Highcharts.CSSObject}
  12146. * @default {"color": "#666666"}
  12147. * @apioption subtitle.style
  12148. */
  12149. /**
  12150. * Whether to
  12151. * [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  12152. * to render the text.
  12153. *
  12154. * @type {boolean}
  12155. * @default false
  12156. * @apioption subtitle.useHTML
  12157. */
  12158. /**
  12159. * The vertical alignment of the title. Can be one of `"top"`,
  12160. * `"middle"` and `"bottom"`. When middle, the subtitle behaves as
  12161. * floating.
  12162. *
  12163. * @sample {highcharts} highcharts/subtitle/verticalalign/
  12164. * Footnote at the bottom right of plot area
  12165. * @sample {highstock} stock/chart/subtitle-footnote
  12166. * Footnote at the bottom right of plot area
  12167. *
  12168. * @type {Highcharts.VerticalAlignValue}
  12169. * @since 2.1
  12170. * @apioption subtitle.verticalAlign
  12171. */
  12172. /**
  12173. * The x position of the subtitle relative to the alignment within
  12174. * `chart.spacingLeft` and `chart.spacingRight`.
  12175. *
  12176. * @sample {highcharts} highcharts/subtitle/align/
  12177. * Footnote at right of plot area
  12178. * @sample {highstock} stock/chart/subtitle-footnote
  12179. * Footnote at the bottom right of plot area
  12180. *
  12181. * @type {number}
  12182. * @default 0
  12183. * @since 2.0
  12184. * @apioption subtitle.x
  12185. */
  12186. /**
  12187. * The y position of the subtitle relative to the alignment within
  12188. * `chart.spacingTop` and `chart.spacingBottom`. By default the subtitle
  12189. * is laid out below the title unless the title is floating.
  12190. *
  12191. * @sample {highcharts} highcharts/subtitle/verticalalign/
  12192. * Footnote at the bottom right of plot area
  12193. * @sample {highstock} stock/chart/subtitle-footnote
  12194. * Footnote at the bottom right of plot area
  12195. *
  12196. * @type {number}
  12197. * @since 2.0
  12198. * @apioption subtitle.y
  12199. */
  12200. /**
  12201. * The subtitle of the chart.
  12202. *
  12203. * @sample {highcharts|highstock} highcharts/subtitle/text/
  12204. * Custom subtitle
  12205. * @sample {highcharts|highstock} highcharts/subtitle/text-formatted/
  12206. * Formatted and linked text.
  12207. */
  12208. text: '',
  12209. /**
  12210. * The horizontal alignment of the subtitle. Can be one of "left",
  12211. * "center" and "right".
  12212. *
  12213. * @sample {highcharts} highcharts/subtitle/align/
  12214. * Footnote at right of plot area
  12215. * @sample {highstock} stock/chart/subtitle-footnote
  12216. * Footnote at bottom right of plot area
  12217. *
  12218. * @type {Highcharts.AlignValue}
  12219. * @since 2.0
  12220. */
  12221. align: 'center',
  12222. /**
  12223. * Adjustment made to the subtitle width, normally to reserve space
  12224. * for the exporting burger menu.
  12225. *
  12226. * @see [title.widthAdjust](#title.widthAdjust)
  12227. *
  12228. * @sample highcharts/title/widthadjust/
  12229. * Wider menu, greater padding
  12230. *
  12231. * @since 4.2.5
  12232. */
  12233. widthAdjust: -44
  12234. },
  12235. /**
  12236. * The chart's caption, which will render below the chart and will be part
  12237. * of exported charts. The caption can be updated after chart initialization
  12238. * through the `Chart.update` or `Chart.caption.update` methods.
  12239. *
  12240. * @sample highcharts/caption/text/
  12241. * A chart with a caption
  12242. * @since 7.2.0
  12243. */
  12244. caption: {
  12245. /**
  12246. * When the caption is floating, the plot area will not move to make
  12247. * space for it.
  12248. *
  12249. * @type {boolean}
  12250. * @default false
  12251. * @apioption caption.floating
  12252. */
  12253. /**
  12254. * The margin between the caption and the plot area.
  12255. */
  12256. margin: 15,
  12257. /**
  12258. * CSS styles for the caption.
  12259. *
  12260. * In styled mode, the caption style is given in the
  12261. * `.highcharts-caption` class.
  12262. *
  12263. * @sample {highcharts} highcharts/css/titles/
  12264. * Styled mode
  12265. *
  12266. * @type {Highcharts.CSSObject}
  12267. * @default {"color": "#666666"}
  12268. * @apioption caption.style
  12269. */
  12270. /**
  12271. * Whether to
  12272. * [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  12273. * to render the text.
  12274. *
  12275. * @type {boolean}
  12276. * @default false
  12277. * @apioption caption.useHTML
  12278. */
  12279. /**
  12280. * The x position of the caption relative to the alignment within
  12281. * `chart.spacingLeft` and `chart.spacingRight`.
  12282. *
  12283. * @type {number}
  12284. * @default 0
  12285. * @apioption caption.x
  12286. */
  12287. /**
  12288. * The y position of the caption relative to the alignment within
  12289. * `chart.spacingTop` and `chart.spacingBottom`.
  12290. *
  12291. * @type {number}
  12292. * @apioption caption.y
  12293. */
  12294. /**
  12295. * The caption text of the chart.
  12296. *
  12297. * @sample {highcharts} highcharts/caption/text/
  12298. * Custom caption
  12299. */
  12300. text: '',
  12301. /**
  12302. * The horizontal alignment of the caption. Can be one of "left",
  12303. * "center" and "right".
  12304. *
  12305. * @type {Highcharts.AlignValue}
  12306. */
  12307. align: 'left',
  12308. /**
  12309. * The vertical alignment of the caption. Can be one of `"top"`,
  12310. * `"middle"` and `"bottom"`. When middle, the caption behaves as
  12311. * floating.
  12312. *
  12313. * @type {Highcharts.VerticalAlignValue}
  12314. */
  12315. verticalAlign: 'bottom'
  12316. },
  12317. /**
  12318. * The plotOptions is a wrapper object for config objects for each series
  12319. * type. The config objects for each series can also be overridden for
  12320. * each series item as given in the series array.
  12321. *
  12322. * Configuration options for the series are given in three levels. Options
  12323. * for all series in a chart are given in the [plotOptions.series](
  12324. * #plotOptions.series) object. Then options for all series of a specific
  12325. * type are given in the plotOptions of that type, for example
  12326. * `plotOptions.line`. Next, options for one single series are given in
  12327. * [the series array](#series).
  12328. */
  12329. plotOptions: {},
  12330. /**
  12331. * HTML labels that can be positioned anywhere in the chart area.
  12332. *
  12333. * This option is deprecated since v7.1.2. Instead, use
  12334. * [annotations](#annotations) that support labels.
  12335. *
  12336. * @deprecated
  12337. * @product highcharts highstock
  12338. */
  12339. labels: {
  12340. /**
  12341. * An HTML label that can be positioned anywhere in the chart area.
  12342. *
  12343. * @deprecated
  12344. * @type {Array<*>}
  12345. * @apioption labels.items
  12346. */
  12347. /**
  12348. * Inner HTML or text for the label.
  12349. *
  12350. * @deprecated
  12351. * @type {string}
  12352. * @apioption labels.items.html
  12353. */
  12354. /**
  12355. * CSS styles for each label. To position the label, use left and top
  12356. * like this:
  12357. * ```js
  12358. * style: {
  12359. * left: '100px',
  12360. * top: '100px'
  12361. * }
  12362. * ```
  12363. *
  12364. * @deprecated
  12365. * @type {Highcharts.CSSObject}
  12366. * @apioption labels.items.style
  12367. */
  12368. /**
  12369. * Shared CSS styles for all labels.
  12370. *
  12371. * @deprecated
  12372. * @type {Highcharts.CSSObject}
  12373. * @default {"color": "#333333", "position": "absolute"}
  12374. */
  12375. style: {
  12376. /**
  12377. * @ignore-option
  12378. */
  12379. position: 'absolute',
  12380. /**
  12381. * @ignore-option
  12382. */
  12383. color: palette.neutralColor80
  12384. }
  12385. },
  12386. /**
  12387. * The legend is a box containing a symbol and name for each series
  12388. * item or point item in the chart. Each series (or points in case
  12389. * of pie charts) is represented by a symbol and its name in the legend.
  12390. *
  12391. * It is possible to override the symbol creator function and create
  12392. * [custom legend symbols](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/studies/legend-custom-symbol/).
  12393. *
  12394. * @productdesc {highmaps}
  12395. * A Highmaps legend by default contains one legend item per series, but if
  12396. * a `colorAxis` is defined, the axis will be displayed in the legend.
  12397. * Either as a gradient, or as multiple legend items for `dataClasses`.
  12398. */
  12399. legend: {
  12400. /**
  12401. * The background color of the legend.
  12402. *
  12403. * @see In styled mode, the legend background fill can be applied with
  12404. * the `.highcharts-legend-box` class.
  12405. *
  12406. * @sample {highcharts} highcharts/legend/backgroundcolor/
  12407. * Yellowish background
  12408. * @sample {highstock} stock/legend/align/
  12409. * Various legend options
  12410. * @sample {highmaps} maps/legend/border-background/
  12411. * Border and background options
  12412. *
  12413. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  12414. * @apioption legend.backgroundColor
  12415. */
  12416. /**
  12417. * The width of the drawn border around the legend.
  12418. *
  12419. * @see In styled mode, the legend border stroke width can be applied
  12420. * with the `.highcharts-legend-box` class.
  12421. *
  12422. * @sample {highcharts} highcharts/legend/borderwidth/
  12423. * 2px border width
  12424. * @sample {highstock} stock/legend/align/
  12425. * Various legend options
  12426. * @sample {highmaps} maps/legend/border-background/
  12427. * Border and background options
  12428. *
  12429. * @type {number}
  12430. * @default 0
  12431. * @apioption legend.borderWidth
  12432. */
  12433. /**
  12434. * Enable or disable the legend. There is also a series-specific option,
  12435. * [showInLegend](#plotOptions.series.showInLegend), that can hide the
  12436. * series from the legend. In some series types this is `false` by
  12437. * default, so it must set to `true` in order to show the legend for the
  12438. * series.
  12439. *
  12440. * @sample {highcharts} highcharts/legend/enabled-false/ Legend disabled
  12441. * @sample {highstock} stock/legend/align/ Various legend options
  12442. * @sample {highmaps} maps/legend/enabled-false/ Legend disabled
  12443. *
  12444. * @default {highstock} false
  12445. * @default {highmaps} true
  12446. * @default {gantt} false
  12447. */
  12448. enabled: true,
  12449. /**
  12450. * The horizontal alignment of the legend box within the chart area.
  12451. * Valid values are `left`, `center` and `right`.
  12452. *
  12453. * In the case that the legend is aligned in a corner position, the
  12454. * `layout` option will determine whether to place it above/below
  12455. * or on the side of the plot area.
  12456. *
  12457. * @sample {highcharts} highcharts/legend/align/
  12458. * Legend at the right of the chart
  12459. * @sample {highstock} stock/legend/align/
  12460. * Various legend options
  12461. * @sample {highmaps} maps/legend/alignment/
  12462. * Legend alignment
  12463. *
  12464. * @type {Highcharts.AlignValue}
  12465. * @since 2.0
  12466. */
  12467. align: 'center',
  12468. /**
  12469. * If the [layout](legend.layout) is `horizontal` and the legend items
  12470. * span over two lines or more, whether to align the items into vertical
  12471. * columns. Setting this to `false` makes room for more items, but will
  12472. * look more messy.
  12473. *
  12474. * @since 6.1.0
  12475. */
  12476. alignColumns: true,
  12477. /**
  12478. * When the legend is floating, the plot area ignores it and is allowed
  12479. * to be placed below it.
  12480. *
  12481. * @sample {highcharts} highcharts/legend/floating-false/
  12482. * False by default
  12483. * @sample {highcharts} highcharts/legend/floating-true/
  12484. * True
  12485. * @sample {highmaps} maps/legend/alignment/
  12486. * Floating legend
  12487. *
  12488. * @type {boolean}
  12489. * @default false
  12490. * @since 2.1
  12491. * @apioption legend.floating
  12492. */
  12493. /**
  12494. * The layout of the legend items. Can be one of `horizontal` or
  12495. * `vertical` or `proximate`. When `proximate`, the legend items will be
  12496. * placed as close as possible to the graphs they're representing,
  12497. * except in inverted charts or when the legend position doesn't allow
  12498. * it.
  12499. *
  12500. * @sample {highcharts} highcharts/legend/layout-horizontal/
  12501. * Horizontal by default
  12502. * @sample {highcharts} highcharts/legend/layout-vertical/
  12503. * Vertical
  12504. * @sample highcharts/legend/layout-proximate
  12505. * Labels proximate to the data
  12506. * @sample {highstock} stock/legend/layout-horizontal/
  12507. * Horizontal by default
  12508. * @sample {highmaps} maps/legend/padding-itemmargin/
  12509. * Vertical with data classes
  12510. * @sample {highmaps} maps/legend/layout-vertical/
  12511. * Vertical with color axis gradient
  12512. *
  12513. * @validvalue ["horizontal", "vertical", "proximate"]
  12514. */
  12515. layout: 'horizontal',
  12516. /**
  12517. * In a legend with horizontal layout, the itemDistance defines the
  12518. * pixel distance between each item.
  12519. *
  12520. * @sample {highcharts} highcharts/legend/layout-horizontal/
  12521. * 50px item distance
  12522. * @sample {highstock} highcharts/legend/layout-horizontal/
  12523. * 50px item distance
  12524. *
  12525. * @type {number}
  12526. * @default {highcharts} 20
  12527. * @default {highstock} 20
  12528. * @default {highmaps} 8
  12529. * @since 3.0.3
  12530. * @apioption legend.itemDistance
  12531. */
  12532. /**
  12533. * The pixel bottom margin for each legend item.
  12534. *
  12535. * @sample {highcharts|highstock} highcharts/legend/padding-itemmargin/
  12536. * Padding and item margins demonstrated
  12537. * @sample {highmaps} maps/legend/padding-itemmargin/
  12538. * Padding and item margins demonstrated
  12539. *
  12540. * @type {number}
  12541. * @default 0
  12542. * @since 2.2.0
  12543. * @apioption legend.itemMarginBottom
  12544. */
  12545. /**
  12546. * The pixel top margin for each legend item.
  12547. *
  12548. * @sample {highcharts|highstock} highcharts/legend/padding-itemmargin/
  12549. * Padding and item margins demonstrated
  12550. * @sample {highmaps} maps/legend/padding-itemmargin/
  12551. * Padding and item margins demonstrated
  12552. *
  12553. * @type {number}
  12554. * @default 0
  12555. * @since 2.2.0
  12556. * @apioption legend.itemMarginTop
  12557. */
  12558. /**
  12559. * The width for each legend item. By default the items are laid out
  12560. * successively. In a [horizontal layout](legend.layout), if the items
  12561. * are laid out across two rows or more, they will be vertically aligned
  12562. * depending on the [legend.alignColumns](legend.alignColumns) option.
  12563. *
  12564. * @sample {highcharts} highcharts/legend/itemwidth-default/
  12565. * Undefined by default
  12566. * @sample {highcharts} highcharts/legend/itemwidth-80/
  12567. * 80 for aligned legend items
  12568. *
  12569. * @type {number}
  12570. * @since 2.0
  12571. * @apioption legend.itemWidth
  12572. */
  12573. /**
  12574. * A [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
  12575. * for each legend label. Available variables relates to properties on
  12576. * the series, or the point in case of pies.
  12577. *
  12578. * @type {string}
  12579. * @default {name}
  12580. * @since 1.3
  12581. * @apioption legend.labelFormat
  12582. */
  12583. /* eslint-disable valid-jsdoc */
  12584. /**
  12585. * Callback function to format each of the series' labels. The `this`
  12586. * keyword refers to the series object, or the point object in case of
  12587. * pie charts. By default the series or point name is printed.
  12588. *
  12589. * @productdesc {highmaps}
  12590. * In Highmaps the context can also be a data class in case of a
  12591. * `colorAxis`.
  12592. *
  12593. * @sample {highcharts} highcharts/legend/labelformatter/
  12594. * Add text
  12595. * @sample {highmaps} maps/legend/labelformatter/
  12596. * Data classes with label formatter
  12597. *
  12598. * @type {Highcharts.FormatterCallbackFunction<Point|Series>}
  12599. */
  12600. labelFormatter: function () {
  12601. /** eslint-enable valid-jsdoc */
  12602. return this.name;
  12603. },
  12604. /**
  12605. * Line height for the legend items. Deprecated as of 2.1\. Instead,
  12606. * the line height for each item can be set using
  12607. * `itemStyle.lineHeight`, and the padding between items using
  12608. * `itemMarginTop` and `itemMarginBottom`.
  12609. *
  12610. * @sample {highcharts} highcharts/legend/lineheight/
  12611. * Setting padding
  12612. *
  12613. * @deprecated
  12614. *
  12615. * @type {number}
  12616. * @default 16
  12617. * @since 2.0
  12618. * @product highcharts gantt
  12619. * @apioption legend.lineHeight
  12620. */
  12621. /**
  12622. * If the plot area sized is calculated automatically and the legend is
  12623. * not floating, the legend margin is the space between the legend and
  12624. * the axis labels or plot area.
  12625. *
  12626. * @sample {highcharts} highcharts/legend/margin-default/
  12627. * 12 pixels by default
  12628. * @sample {highcharts} highcharts/legend/margin-30/
  12629. * 30 pixels
  12630. *
  12631. * @type {number}
  12632. * @default 12
  12633. * @since 2.1
  12634. * @apioption legend.margin
  12635. */
  12636. /**
  12637. * Maximum pixel height for the legend. When the maximum height is
  12638. * extended, navigation will show.
  12639. *
  12640. * @type {number}
  12641. * @since 2.3.0
  12642. * @apioption legend.maxHeight
  12643. */
  12644. /**
  12645. * The color of the drawn border around the legend.
  12646. *
  12647. * @see In styled mode, the legend border stroke can be applied with the
  12648. * `.highcharts-legend-box` class.
  12649. *
  12650. * @sample {highcharts} highcharts/legend/bordercolor/
  12651. * Brown border
  12652. * @sample {highstock} stock/legend/align/
  12653. * Various legend options
  12654. * @sample {highmaps} maps/legend/border-background/
  12655. * Border and background options
  12656. *
  12657. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  12658. */
  12659. borderColor: palette.neutralColor40,
  12660. /**
  12661. * The border corner radius of the legend.
  12662. *
  12663. * @sample {highcharts} highcharts/legend/borderradius-default/
  12664. * Square by default
  12665. * @sample {highcharts} highcharts/legend/borderradius-round/
  12666. * 5px rounded
  12667. * @sample {highmaps} maps/legend/border-background/
  12668. * Border and background options
  12669. */
  12670. borderRadius: 0,
  12671. /**
  12672. * Options for the paging or navigation appearing when the legend is
  12673. * overflown. Navigation works well on screen, but not in static
  12674. * exported images. One way of working around that is to
  12675. * [increase the chart height in
  12676. * export](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/legend/navigation-enabled-false/).
  12677. */
  12678. navigation: {
  12679. /**
  12680. * How to animate the pages when navigating up or down. A value of
  12681. * `true` applies the default navigation given in the
  12682. * `chart.animation` option. Additional options can be given as an
  12683. * object containing values for easing and duration.
  12684. *
  12685. * @sample {highcharts} highcharts/legend/navigation/
  12686. * Legend page navigation demonstrated
  12687. * @sample {highstock} highcharts/legend/navigation/
  12688. * Legend page navigation demonstrated
  12689. *
  12690. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  12691. * @default true
  12692. * @since 2.2.4
  12693. * @apioption legend.navigation.animation
  12694. */
  12695. /**
  12696. * The pixel size of the up and down arrows in the legend paging
  12697. * navigation.
  12698. *
  12699. * @sample {highcharts} highcharts/legend/navigation/
  12700. * Legend page navigation demonstrated
  12701. * @sample {highstock} highcharts/legend/navigation/
  12702. * Legend page navigation demonstrated
  12703. *
  12704. * @type {number}
  12705. * @default 12
  12706. * @since 2.2.4
  12707. * @apioption legend.navigation.arrowSize
  12708. */
  12709. /**
  12710. * Whether to enable the legend navigation. In most cases, disabling
  12711. * the navigation results in an unwanted overflow.
  12712. *
  12713. * See also the [adapt chart to legend](
  12714. * https://www.highcharts.com/products/plugin-registry/single/8/Adapt-Chart-To-Legend)
  12715. * plugin for a solution to extend the chart height to make room for
  12716. * the legend, optionally in exported charts only.
  12717. *
  12718. * @type {boolean}
  12719. * @default true
  12720. * @since 4.2.4
  12721. * @apioption legend.navigation.enabled
  12722. */
  12723. /**
  12724. * Text styles for the legend page navigation.
  12725. *
  12726. * @see In styled mode, the navigation items are styled with the
  12727. * `.highcharts-legend-navigation` class.
  12728. *
  12729. * @sample {highcharts} highcharts/legend/navigation/
  12730. * Legend page navigation demonstrated
  12731. * @sample {highstock} highcharts/legend/navigation/
  12732. * Legend page navigation demonstrated
  12733. *
  12734. * @type {Highcharts.CSSObject}
  12735. * @since 2.2.4
  12736. * @apioption legend.navigation.style
  12737. */
  12738. /**
  12739. * The color for the active up or down arrow in the legend page
  12740. * navigation.
  12741. *
  12742. * @see In styled mode, the active arrow be styled with the
  12743. * `.highcharts-legend-nav-active` class.
  12744. *
  12745. * @sample {highcharts} highcharts/legend/navigation/
  12746. * Legend page navigation demonstrated
  12747. * @sample {highstock} highcharts/legend/navigation/
  12748. * Legend page navigation demonstrated
  12749. *
  12750. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  12751. * @since 2.2.4
  12752. */
  12753. activeColor: palette.highlightColor100,
  12754. /**
  12755. * The color of the inactive up or down arrow in the legend page
  12756. * navigation. .
  12757. *
  12758. * @see In styled mode, the inactive arrow be styled with the
  12759. * `.highcharts-legend-nav-inactive` class.
  12760. *
  12761. * @sample {highcharts} highcharts/legend/navigation/
  12762. * Legend page navigation demonstrated
  12763. * @sample {highstock} highcharts/legend/navigation/
  12764. * Legend page navigation demonstrated
  12765. *
  12766. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  12767. * @since 2.2.4
  12768. */
  12769. inactiveColor: palette.neutralColor20
  12770. },
  12771. /**
  12772. * The inner padding of the legend box.
  12773. *
  12774. * @sample {highcharts|highstock} highcharts/legend/padding-itemmargin/
  12775. * Padding and item margins demonstrated
  12776. * @sample {highmaps} maps/legend/padding-itemmargin/
  12777. * Padding and item margins demonstrated
  12778. *
  12779. * @type {number}
  12780. * @default 8
  12781. * @since 2.2.0
  12782. * @apioption legend.padding
  12783. */
  12784. /**
  12785. * Whether to reverse the order of the legend items compared to the
  12786. * order of the series or points as defined in the configuration object.
  12787. *
  12788. * @see [yAxis.reversedStacks](#yAxis.reversedStacks),
  12789. * [series.legendIndex](#series.legendIndex)
  12790. *
  12791. * @sample {highcharts} highcharts/legend/reversed/
  12792. * Stacked bar with reversed legend
  12793. *
  12794. * @type {boolean}
  12795. * @default false
  12796. * @since 1.2.5
  12797. * @apioption legend.reversed
  12798. */
  12799. /**
  12800. * Whether to show the symbol on the right side of the text rather than
  12801. * the left side. This is common in Arabic and Hebraic.
  12802. *
  12803. * @sample {highcharts} highcharts/legend/rtl/
  12804. * Symbol to the right
  12805. *
  12806. * @type {boolean}
  12807. * @default false
  12808. * @since 2.2
  12809. * @apioption legend.rtl
  12810. */
  12811. /**
  12812. * CSS styles for the legend area. In the 1.x versions the position
  12813. * of the legend area was determined by CSS. In 2.x, the position is
  12814. * determined by properties like `align`, `verticalAlign`, `x` and `y`,
  12815. * but the styles are still parsed for backwards compatibility.
  12816. *
  12817. * @deprecated
  12818. *
  12819. * @type {Highcharts.CSSObject}
  12820. * @product highcharts highstock
  12821. * @apioption legend.style
  12822. */
  12823. /**
  12824. * CSS styles for each legend item. Only a subset of CSS is supported,
  12825. * notably those options related to text. The default `textOverflow`
  12826. * property makes long texts truncate. Set it to `undefined` to wrap
  12827. * text instead. A `width` property can be added to control the text
  12828. * width.
  12829. *
  12830. * @see In styled mode, the legend items can be styled with the
  12831. * `.highcharts-legend-item` class.
  12832. *
  12833. * @sample {highcharts} highcharts/legend/itemstyle/
  12834. * Bold black text
  12835. * @sample {highmaps} maps/legend/itemstyle/
  12836. * Item text styles
  12837. *
  12838. * @type {Highcharts.CSSObject}
  12839. * @default {"color": "#333333", "cursor": "pointer", "fontSize": "12px", "fontWeight": "bold", "textOverflow": "ellipsis"}
  12840. */
  12841. itemStyle: {
  12842. /**
  12843. * @ignore
  12844. */
  12845. color: palette.neutralColor80,
  12846. /**
  12847. * @ignore
  12848. */
  12849. cursor: 'pointer',
  12850. /**
  12851. * @ignore
  12852. */
  12853. fontSize: '12px',
  12854. /**
  12855. * @ignore
  12856. */
  12857. fontWeight: 'bold',
  12858. /**
  12859. * @ignore
  12860. */
  12861. textOverflow: 'ellipsis'
  12862. },
  12863. /**
  12864. * CSS styles for each legend item in hover mode. Only a subset of
  12865. * CSS is supported, notably those options related to text. Properties
  12866. * are inherited from `style` unless overridden here.
  12867. *
  12868. * @see In styled mode, the hovered legend items can be styled with
  12869. * the `.highcharts-legend-item:hover` pesudo-class.
  12870. *
  12871. * @sample {highcharts} highcharts/legend/itemhoverstyle/
  12872. * Red on hover
  12873. * @sample {highmaps} maps/legend/itemstyle/
  12874. * Item text styles
  12875. *
  12876. * @type {Highcharts.CSSObject}
  12877. * @default {"color": "#000000"}
  12878. */
  12879. itemHoverStyle: {
  12880. /**
  12881. * @ignore
  12882. */
  12883. color: palette.neutralColor100
  12884. },
  12885. /**
  12886. * CSS styles for each legend item when the corresponding series or
  12887. * point is hidden. Only a subset of CSS is supported, notably those
  12888. * options related to text. Properties are inherited from `style`
  12889. * unless overridden here.
  12890. *
  12891. * @see In styled mode, the hidden legend items can be styled with
  12892. * the `.highcharts-legend-item-hidden` class.
  12893. *
  12894. * @sample {highcharts} highcharts/legend/itemhiddenstyle/
  12895. * Darker gray color
  12896. *
  12897. * @type {Highcharts.CSSObject}
  12898. * @default {"color": "#cccccc"}
  12899. */
  12900. itemHiddenStyle: {
  12901. /**
  12902. * @ignore
  12903. */
  12904. color: palette.neutralColor20
  12905. },
  12906. /**
  12907. * Whether to apply a drop shadow to the legend. A `backgroundColor`
  12908. * also needs to be applied for this to take effect. The shadow can be
  12909. * an object configuration containing `color`, `offsetX`, `offsetY`,
  12910. * `opacity` and `width`.
  12911. *
  12912. * @sample {highcharts} highcharts/legend/shadow/
  12913. * White background and drop shadow
  12914. * @sample {highstock} stock/legend/align/
  12915. * Various legend options
  12916. * @sample {highmaps} maps/legend/border-background/
  12917. * Border and background options
  12918. *
  12919. * @type {boolean|Highcharts.CSSObject}
  12920. */
  12921. shadow: false,
  12922. /**
  12923. * Default styling for the checkbox next to a legend item when
  12924. * `showCheckbox` is true.
  12925. *
  12926. * @type {Highcharts.CSSObject}
  12927. * @default {"width": "13px", "height": "13px", "position":"absolute"}
  12928. */
  12929. itemCheckboxStyle: {
  12930. /**
  12931. * @ignore
  12932. */
  12933. position: 'absolute',
  12934. /**
  12935. * @ignore
  12936. */
  12937. width: '13px',
  12938. /**
  12939. * @ignore
  12940. */
  12941. height: '13px'
  12942. },
  12943. // itemWidth: undefined,
  12944. /**
  12945. * When this is true, the legend symbol width will be the same as
  12946. * the symbol height, which in turn defaults to the font size of the
  12947. * legend items.
  12948. *
  12949. * @since 5.0.0
  12950. */
  12951. squareSymbol: true,
  12952. /**
  12953. * The pixel height of the symbol for series types that use a rectangle
  12954. * in the legend. Defaults to the font size of legend items.
  12955. *
  12956. * @productdesc {highmaps}
  12957. * In Highmaps, when the symbol is the gradient of a vertical color
  12958. * axis, the height defaults to 200.
  12959. *
  12960. * @sample {highmaps} maps/legend/layout-vertical-sized/
  12961. * Sized vertical gradient
  12962. * @sample {highmaps} maps/legend/padding-itemmargin/
  12963. * No distance between data classes
  12964. *
  12965. * @type {number}
  12966. * @since 3.0.8
  12967. * @apioption legend.symbolHeight
  12968. */
  12969. /**
  12970. * The border radius of the symbol for series types that use a rectangle
  12971. * in the legend. Defaults to half the `symbolHeight`.
  12972. *
  12973. * @sample {highcharts} highcharts/legend/symbolradius/
  12974. * Round symbols
  12975. * @sample {highstock} highcharts/legend/symbolradius/
  12976. * Round symbols
  12977. * @sample {highmaps} highcharts/legend/symbolradius/
  12978. * Round symbols
  12979. *
  12980. * @type {number}
  12981. * @since 3.0.8
  12982. * @apioption legend.symbolRadius
  12983. */
  12984. /**
  12985. * The pixel width of the legend item symbol. When the `squareSymbol`
  12986. * option is set, this defaults to the `symbolHeight`, otherwise 16.
  12987. *
  12988. * @productdesc {highmaps}
  12989. * In Highmaps, when the symbol is the gradient of a horizontal color
  12990. * axis, the width defaults to 200.
  12991. *
  12992. * @sample {highcharts} highcharts/legend/symbolwidth/
  12993. * Greater symbol width and padding
  12994. * @sample {highmaps} maps/legend/padding-itemmargin/
  12995. * Padding and item margins demonstrated
  12996. * @sample {highmaps} maps/legend/layout-vertical-sized/
  12997. * Sized vertical gradient
  12998. *
  12999. * @type {number}
  13000. * @apioption legend.symbolWidth
  13001. */
  13002. /**
  13003. * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  13004. * to render the legend item texts.
  13005. *
  13006. * Prior to 4.1.7, when using HTML, [legend.navigation](
  13007. * #legend.navigation) was disabled.
  13008. *
  13009. * @type {boolean}
  13010. * @default false
  13011. * @apioption legend.useHTML
  13012. */
  13013. /**
  13014. * The width of the legend box. If a number is set, it translates to
  13015. * pixels. Since v7.0.2 it allows setting a percent string of the full
  13016. * chart width, for example `40%`.
  13017. *
  13018. * Defaults to the full chart width for legends below or above the
  13019. * chart, half the chart width for legends to the left and right.
  13020. *
  13021. * @sample {highcharts} highcharts/legend/width/
  13022. * Aligned to the plot area
  13023. * @sample {highcharts} highcharts/legend/width-percent/
  13024. * A percent of the chart width
  13025. *
  13026. * @type {number|string}
  13027. * @since 2.0
  13028. * @apioption legend.width
  13029. */
  13030. /**
  13031. * The pixel padding between the legend item symbol and the legend
  13032. * item text.
  13033. *
  13034. * @sample {highcharts} highcharts/legend/symbolpadding/
  13035. * Greater symbol width and padding
  13036. */
  13037. symbolPadding: 5,
  13038. /**
  13039. * The vertical alignment of the legend box. Can be one of `top`,
  13040. * `middle` or `bottom`. Vertical position can be further determined
  13041. * by the `y` option.
  13042. *
  13043. * In the case that the legend is aligned in a corner position, the
  13044. * `layout` option will determine whether to place it above/below
  13045. * or on the side of the plot area.
  13046. *
  13047. * When the [layout](#legend.layout) option is `proximate`, the
  13048. * `verticalAlign` option doesn't apply.
  13049. *
  13050. * @sample {highcharts} highcharts/legend/verticalalign/
  13051. * Legend 100px from the top of the chart
  13052. * @sample {highstock} stock/legend/align/
  13053. * Various legend options
  13054. * @sample {highmaps} maps/legend/alignment/
  13055. * Legend alignment
  13056. *
  13057. * @type {Highcharts.VerticalAlignValue}
  13058. * @since 2.0
  13059. */
  13060. verticalAlign: 'bottom',
  13061. // width: undefined,
  13062. /**
  13063. * The x offset of the legend relative to its horizontal alignment
  13064. * `align` within chart.spacingLeft and chart.spacingRight. Negative
  13065. * x moves it to the left, positive x moves it to the right.
  13066. *
  13067. * @sample {highcharts} highcharts/legend/width/
  13068. * Aligned to the plot area
  13069. *
  13070. * @since 2.0
  13071. */
  13072. x: 0,
  13073. /**
  13074. * The vertical offset of the legend relative to it's vertical alignment
  13075. * `verticalAlign` within chart.spacingTop and chart.spacingBottom.
  13076. * Negative y moves it up, positive y moves it down.
  13077. *
  13078. * @sample {highcharts} highcharts/legend/verticalalign/
  13079. * Legend 100px from the top of the chart
  13080. * @sample {highstock} stock/legend/align/
  13081. * Various legend options
  13082. * @sample {highmaps} maps/legend/alignment/
  13083. * Legend alignment
  13084. *
  13085. * @since 2.0
  13086. */
  13087. y: 0,
  13088. /**
  13089. * A title to be added on top of the legend.
  13090. *
  13091. * @sample {highcharts} highcharts/legend/title/
  13092. * Legend title
  13093. * @sample {highmaps} maps/legend/alignment/
  13094. * Legend with title
  13095. *
  13096. * @since 3.0
  13097. */
  13098. title: {
  13099. /**
  13100. * A text or HTML string for the title.
  13101. *
  13102. * @type {string}
  13103. * @since 3.0
  13104. * @apioption legend.title.text
  13105. */
  13106. /**
  13107. * Generic CSS styles for the legend title.
  13108. *
  13109. * @see In styled mode, the legend title is styled with the
  13110. * `.highcharts-legend-title` class.
  13111. *
  13112. * @type {Highcharts.CSSObject}
  13113. * @default {"fontWeight": "bold"}
  13114. * @since 3.0
  13115. */
  13116. style: {
  13117. /**
  13118. * @ignore
  13119. */
  13120. fontWeight: 'bold'
  13121. }
  13122. }
  13123. },
  13124. /**
  13125. * The loading options control the appearance of the loading screen
  13126. * that covers the plot area on chart operations. This screen only
  13127. * appears after an explicit call to `chart.showLoading()`. It is a
  13128. * utility for developers to communicate to the end user that something
  13129. * is going on, for example while retrieving new data via an XHR connection.
  13130. * The "Loading..." text itself is not part of this configuration
  13131. * object, but part of the `lang` object.
  13132. */
  13133. loading: {
  13134. /**
  13135. * The duration in milliseconds of the fade out effect.
  13136. *
  13137. * @sample highcharts/loading/hideduration/
  13138. * Fade in and out over a second
  13139. *
  13140. * @type {number}
  13141. * @default 100
  13142. * @since 1.2.0
  13143. * @apioption loading.hideDuration
  13144. */
  13145. /**
  13146. * The duration in milliseconds of the fade in effect.
  13147. *
  13148. * @sample highcharts/loading/hideduration/
  13149. * Fade in and out over a second
  13150. *
  13151. * @type {number}
  13152. * @default 100
  13153. * @since 1.2.0
  13154. * @apioption loading.showDuration
  13155. */
  13156. /**
  13157. * CSS styles for the loading label `span`.
  13158. *
  13159. * @see In styled mode, the loading label is styled with the
  13160. * `.highcharts-loading-inner` class.
  13161. *
  13162. * @sample {highcharts|highmaps} highcharts/loading/labelstyle/
  13163. * Vertically centered
  13164. * @sample {highstock} stock/loading/general/
  13165. * Label styles
  13166. *
  13167. * @type {Highcharts.CSSObject}
  13168. * @default {"fontWeight": "bold", "position": "relative", "top": "45%"}
  13169. * @since 1.2.0
  13170. */
  13171. labelStyle: {
  13172. /**
  13173. * @ignore
  13174. */
  13175. fontWeight: 'bold',
  13176. /**
  13177. * @ignore
  13178. */
  13179. position: 'relative',
  13180. /**
  13181. * @ignore
  13182. */
  13183. top: '45%'
  13184. },
  13185. /**
  13186. * CSS styles for the loading screen that covers the plot area.
  13187. *
  13188. * In styled mode, the loading label is styled with the
  13189. * `.highcharts-loading` class.
  13190. *
  13191. * @sample {highcharts|highmaps} highcharts/loading/style/
  13192. * Gray plot area, white text
  13193. * @sample {highstock} stock/loading/general/
  13194. * Gray plot area, white text
  13195. *
  13196. * @type {Highcharts.CSSObject}
  13197. * @default {"position": "absolute", "backgroundColor": "#ffffff", "opacity": 0.5, "textAlign": "center"}
  13198. * @since 1.2.0
  13199. */
  13200. style: {
  13201. /**
  13202. * @ignore
  13203. */
  13204. position: 'absolute',
  13205. /**
  13206. * @ignore
  13207. */
  13208. backgroundColor: palette.backgroundColor,
  13209. /**
  13210. * @ignore
  13211. */
  13212. opacity: 0.5,
  13213. /**
  13214. * @ignore
  13215. */
  13216. textAlign: 'center'
  13217. }
  13218. },
  13219. /**
  13220. * Options for the tooltip that appears when the user hovers over a
  13221. * series or point.
  13222. *
  13223. * @declare Highcharts.TooltipOptions
  13224. */
  13225. tooltip: {
  13226. /**
  13227. * The color of the tooltip border. When `undefined`, the border takes
  13228. * the color of the corresponding series or point.
  13229. *
  13230. * @sample {highcharts} highcharts/tooltip/bordercolor-default/
  13231. * Follow series by default
  13232. * @sample {highcharts} highcharts/tooltip/bordercolor-black/
  13233. * Black border
  13234. * @sample {highstock} stock/tooltip/general/
  13235. * Styled tooltip
  13236. * @sample {highmaps} maps/tooltip/background-border/
  13237. * Background and border demo
  13238. *
  13239. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  13240. * @apioption tooltip.borderColor
  13241. */
  13242. /**
  13243. * A CSS class name to apply to the tooltip's container div,
  13244. * allowing unique CSS styling for each chart.
  13245. *
  13246. * @type {string}
  13247. * @apioption tooltip.className
  13248. */
  13249. /**
  13250. * Since 4.1, the crosshair definitions are moved to the Axis object
  13251. * in order for a better separation from the tooltip. See
  13252. * [xAxis.crosshair](#xAxis.crosshair).
  13253. *
  13254. * @sample {highcharts} highcharts/tooltip/crosshairs-x/
  13255. * Enable a crosshair for the x value
  13256. *
  13257. * @deprecated
  13258. *
  13259. * @type {*}
  13260. * @default true
  13261. * @apioption tooltip.crosshairs
  13262. */
  13263. /**
  13264. * Distance from point to tooltip in pixels.
  13265. *
  13266. * @type {number}
  13267. * @default 16
  13268. * @apioption tooltip.distance
  13269. */
  13270. /**
  13271. * Whether the tooltip should follow the mouse as it moves across
  13272. * columns, pie slices and other point types with an extent.
  13273. * By default it behaves this way for pie, polygon, map, sankey
  13274. * and wordcloud series by override in the `plotOptions`
  13275. * for those series types.
  13276. *
  13277. * For touch moves to behave the same way, [followTouchMove](
  13278. * #tooltip.followTouchMove) must be `true` also.
  13279. *
  13280. * @type {boolean}
  13281. * @default {highcharts} false
  13282. * @default {highstock} false
  13283. * @default {highmaps} true
  13284. * @since 3.0
  13285. * @apioption tooltip.followPointer
  13286. */
  13287. /**
  13288. * Whether the tooltip should update as the finger moves on a touch
  13289. * device. If this is `true` and [chart.panning](#chart.panning) is
  13290. * set,`followTouchMove` will take over one-finger touches, so the user
  13291. * needs to use two fingers for zooming and panning.
  13292. *
  13293. * Note the difference to [followPointer](#tooltip.followPointer) that
  13294. * only defines the _position_ of the tooltip. If `followPointer` is
  13295. * false in for example a column series, the tooltip will show above or
  13296. * below the column, but as `followTouchMove` is true, the tooltip will
  13297. * jump from column to column as the user swipes across the plot area.
  13298. *
  13299. * @type {boolean}
  13300. * @default {highcharts} true
  13301. * @default {highstock} true
  13302. * @default {highmaps} false
  13303. * @since 3.0.1
  13304. * @apioption tooltip.followTouchMove
  13305. */
  13306. /**
  13307. * Callback function to format the text of the tooltip from scratch. In
  13308. * case of single or [shared](#tooltip.shared) tooltips, a string should
  13309. * be returned. In case of [split](#tooltip.split) tooltips, it should
  13310. * return an array where the first item is the header, and subsequent
  13311. * items are mapped to the points. Return `false` to disable tooltip for
  13312. * a specific point on series.
  13313. *
  13314. * A subset of HTML is supported. Unless `useHTML` is true, the HTML of
  13315. * the tooltip is parsed and converted to SVG, therefore this isn't a
  13316. * complete HTML renderer. The following HTML tags are supported: `b`,
  13317. * `br`, `em`, `i`, `span`, `strong`. Spans can be styled with a `style`
  13318. * attribute, but only text-related CSS, that is shared with SVG, is
  13319. * handled.
  13320. *
  13321. * The available data in the formatter differ a bit depending on whether
  13322. * the tooltip is shared or split, or belongs to a single point. In a
  13323. * shared/split tooltip, all properties except `x`, which is common for
  13324. * all points, are kept in an array, `this.points`.
  13325. *
  13326. * Available data are:
  13327. *
  13328. * - **this.percentage (not shared) /**
  13329. * **this.points[i].percentage (shared)**:
  13330. * Stacked series and pies only. The point's percentage of the total.
  13331. *
  13332. * - **this.point (not shared) / this.points[i].point (shared)**:
  13333. * The point object. The point name, if defined, is available through
  13334. * `this.point.name`.
  13335. *
  13336. * - **this.points**:
  13337. * In a shared tooltip, this is an array containing all other
  13338. * properties for each point.
  13339. *
  13340. * - **this.series (not shared) / this.points[i].series (shared)**:
  13341. * The series object. The series name is available through
  13342. * `this.series.name`.
  13343. *
  13344. * - **this.total (not shared) / this.points[i].total (shared)**:
  13345. * Stacked series only. The total value at this point's x value.
  13346. *
  13347. * - **this.x**:
  13348. * The x value. This property is the same regardless of the tooltip
  13349. * being shared or not.
  13350. *
  13351. * - **this.y (not shared) / this.points[i].y (shared)**:
  13352. * The y value.
  13353. *
  13354. * @sample {highcharts} highcharts/tooltip/formatter-simple/
  13355. * Simple string formatting
  13356. * @sample {highcharts} highcharts/tooltip/formatter-shared/
  13357. * Formatting with shared tooltip
  13358. * @sample {highcharts|highstock} highcharts/tooltip/formatter-split/
  13359. * Formatting with split tooltip
  13360. * @sample highcharts/tooltip/formatter-conditional-default/
  13361. * Extending default formatter
  13362. * @sample {highstock} stock/tooltip/formatter/
  13363. * Formatting with shared tooltip
  13364. * @sample {highmaps} maps/tooltip/formatter/
  13365. * String formatting
  13366. *
  13367. * @type {Highcharts.TooltipFormatterCallbackFunction}
  13368. * @apioption tooltip.formatter
  13369. */
  13370. /**
  13371. * Callback function to format the text of the tooltip for
  13372. * visible null points.
  13373. * Works analogously to [formatter](#tooltip.formatter).
  13374. *
  13375. * @sample highcharts/plotoptions/series-nullformat
  13376. * Format data label and tooltip for null point.
  13377. *
  13378. * @type {Highcharts.TooltipFormatterCallbackFunction}
  13379. * @apioption tooltip.nullFormatter
  13380. */
  13381. /**
  13382. * The number of milliseconds to wait until the tooltip is hidden when
  13383. * mouse out from a point or chart.
  13384. *
  13385. * @type {number}
  13386. * @default 500
  13387. * @since 3.0
  13388. * @apioption tooltip.hideDelay
  13389. */
  13390. /**
  13391. * Whether to allow the tooltip to render outside the chart's SVG
  13392. * element box. By default (`false`), the tooltip is rendered within the
  13393. * chart's SVG element, which results in the tooltip being aligned
  13394. * inside the chart area. For small charts, this may result in clipping
  13395. * or overlapping. When `true`, a separate SVG element is created and
  13396. * overlaid on the page, allowing the tooltip to be aligned inside the
  13397. * page itself.
  13398. *
  13399. * Defaults to `true` if `chart.scrollablePlotArea` is activated,
  13400. * otherwise `false`.
  13401. *
  13402. * @sample highcharts/tooltip/outside
  13403. * Small charts with tooltips outside
  13404. *
  13405. * @type {boolean|undefined}
  13406. * @default undefined
  13407. * @since 6.1.1
  13408. * @apioption tooltip.outside
  13409. */
  13410. /**
  13411. * A callback function for formatting the HTML output for a single point
  13412. * in the tooltip. Like the `pointFormat` string, but with more
  13413. * flexibility.
  13414. *
  13415. * @type {Highcharts.FormatterCallbackFunction<Highcharts.Point>}
  13416. * @since 4.1.0
  13417. * @context Highcharts.Point
  13418. * @apioption tooltip.pointFormatter
  13419. */
  13420. /**
  13421. * A callback function to place the tooltip in a default position. The
  13422. * callback receives three parameters: `labelWidth`, `labelHeight` and
  13423. * `point`, where point contains values for `plotX` and `plotY` telling
  13424. * where the reference point is in the plot area. Add `chart.plotLeft`
  13425. * and `chart.plotTop` to get the full coordinates.
  13426. *
  13427. * Since v7, when [tooltip.split](#tooltip.split) option is enabled,
  13428. * positioner is called for each of the boxes separately, including
  13429. * xAxis header. xAxis header is not a point, instead `point` argument
  13430. * contains info:
  13431. * `{ plotX: Number, plotY: Number, isHeader: Boolean }`
  13432. *
  13433. *
  13434. * The return should be an object containing x and y values, for example
  13435. * `{ x: 100, y: 100 }`.
  13436. *
  13437. * @sample {highcharts} highcharts/tooltip/positioner/
  13438. * A fixed tooltip position
  13439. * @sample {highstock} stock/tooltip/positioner/
  13440. * A fixed tooltip position on top of the chart
  13441. * @sample {highmaps} maps/tooltip/positioner/
  13442. * A fixed tooltip position
  13443. * @sample {highstock} stock/tooltip/split-positioner/
  13444. * Split tooltip with fixed positions
  13445. * @sample {highstock} stock/tooltip/positioner-scrollable-plotarea/
  13446. * Scrollable plot area combined with tooltip positioner
  13447. *
  13448. * @type {Highcharts.TooltipPositionerCallbackFunction}
  13449. * @since 2.2.4
  13450. * @apioption tooltip.positioner
  13451. */
  13452. /**
  13453. * The name of a symbol to use for the border around the tooltip. Can
  13454. * be one of: `"callout"`, `"circle"`, or `"square"`. When
  13455. * [tooltip.split](#tooltip.split)
  13456. * option is enabled, shape is applied to all boxes except header, which
  13457. * is controlled by
  13458. * [tooltip.headerShape](#tooltip.headerShape).
  13459. *
  13460. * Custom callbacks for symbol path generation can also be added to
  13461. * `Highcharts.SVGRenderer.prototype.symbols` the same way as for
  13462. * [series.marker.symbol](plotOptions.line.marker.symbol).
  13463. *
  13464. * @type {Highcharts.TooltipShapeValue}
  13465. * @default callout
  13466. * @since 4.0
  13467. * @apioption tooltip.shape
  13468. */
  13469. /**
  13470. * The name of a symbol to use for the border around the tooltip
  13471. * header. Applies only when [tooltip.split](#tooltip.split) is
  13472. * enabled.
  13473. *
  13474. * Custom callbacks for symbol path generation can also be added to
  13475. * `Highcharts.SVGRenderer.prototype.symbols` the same way as for
  13476. * [series.marker.symbol](plotOptions.line.marker.symbol).
  13477. *
  13478. * @see [tooltip.shape](#tooltip.shape)
  13479. *
  13480. * @sample {highstock} stock/tooltip/split-positioner/
  13481. * Different shapes for header and split boxes
  13482. *
  13483. * @type {Highcharts.TooltipShapeValue}
  13484. * @default callout
  13485. * @validvalue ["callout", "square"]
  13486. * @since 7.0
  13487. * @apioption tooltip.headerShape
  13488. */
  13489. /**
  13490. * When the tooltip is shared, the entire plot area will capture mouse
  13491. * movement or touch events. Tooltip texts for series types with ordered
  13492. * data (not pie, scatter, flags etc) will be shown in a single bubble.
  13493. * This is recommended for single series charts and for tablet/mobile
  13494. * optimized charts.
  13495. *
  13496. * See also [tooltip.split](#tooltip.split), that is better suited for
  13497. * charts with many series, especially line-type series. The
  13498. * `tooltip.split` option takes precedence over `tooltip.shared`.
  13499. *
  13500. * @sample {highcharts} highcharts/tooltip/shared-false/
  13501. * False by default
  13502. * @sample {highcharts} highcharts/tooltip/shared-true/
  13503. * True
  13504. * @sample {highcharts} highcharts/tooltip/shared-x-crosshair/
  13505. * True with x axis crosshair
  13506. * @sample {highcharts} highcharts/tooltip/shared-true-mixed-types/
  13507. * True with mixed series types
  13508. *
  13509. * @type {boolean}
  13510. * @default false
  13511. * @since 2.1
  13512. * @product highcharts highstock
  13513. * @apioption tooltip.shared
  13514. */
  13515. /**
  13516. * Split the tooltip into one label per series, with the header close
  13517. * to the axis. This is recommended over [shared](#tooltip.shared)
  13518. * tooltips for charts with multiple line series, generally making them
  13519. * easier to read. This option takes precedence over `tooltip.shared`.
  13520. *
  13521. * @productdesc {highstock} In Highstock, tooltips are split by default
  13522. * since v6.0.0. Stock charts typically contain multi-dimension points
  13523. * and multiple panes, making split tooltips the preferred layout over
  13524. * the previous `shared` tooltip.
  13525. *
  13526. * @sample highcharts/tooltip/split/
  13527. * Split tooltip
  13528. * @sample {highcharts|highstock} highcharts/tooltip/formatter-split/
  13529. * Split tooltip and custom formatter callback
  13530. *
  13531. * @type {boolean}
  13532. * @default {highcharts} false
  13533. * @default {highstock} true
  13534. * @since 5.0.0
  13535. * @product highcharts highstock
  13536. * @apioption tooltip.split
  13537. */
  13538. /**
  13539. * Prevents the tooltip from switching or closing, when touched or
  13540. * pointed.
  13541. *
  13542. * @sample highcharts/tooltip/stickoncontact/
  13543. * Tooltip sticks on pointer contact
  13544. *
  13545. * @type {boolean}
  13546. * @since 8.0.1
  13547. * @apioption tooltip.stickOnContact
  13548. */
  13549. /**
  13550. * Use HTML to render the contents of the tooltip instead of SVG. Using
  13551. * HTML allows advanced formatting like tables and images in the
  13552. * tooltip. It is also recommended for rtl languages as it works around
  13553. * rtl bugs in early Firefox.
  13554. *
  13555. * @sample {highcharts|highstock} highcharts/tooltip/footerformat/
  13556. * A table for value alignment
  13557. * @sample {highcharts|highstock} highcharts/tooltip/fullhtml/
  13558. * Full HTML tooltip
  13559. * @sample {highmaps} maps/tooltip/usehtml/
  13560. * Pure HTML tooltip
  13561. *
  13562. * @type {boolean}
  13563. * @default false
  13564. * @since 2.2
  13565. * @apioption tooltip.useHTML
  13566. */
  13567. /**
  13568. * How many decimals to show in each series' y value. This is
  13569. * overridable in each series' tooltip options object. The default is to
  13570. * preserve all decimals.
  13571. *
  13572. * @sample {highcharts|highstock} highcharts/tooltip/valuedecimals/
  13573. * Set decimals, prefix and suffix for the value
  13574. * @sample {highmaps} maps/tooltip/valuedecimals/
  13575. * Set decimals, prefix and suffix for the value
  13576. *
  13577. * @type {number}
  13578. * @since 2.2
  13579. * @apioption tooltip.valueDecimals
  13580. */
  13581. /**
  13582. * A string to prepend to each series' y value. Overridable in each
  13583. * series' tooltip options object.
  13584. *
  13585. * @sample {highcharts|highstock} highcharts/tooltip/valuedecimals/
  13586. * Set decimals, prefix and suffix for the value
  13587. * @sample {highmaps} maps/tooltip/valuedecimals/
  13588. * Set decimals, prefix and suffix for the value
  13589. *
  13590. * @type {string}
  13591. * @since 2.2
  13592. * @apioption tooltip.valuePrefix
  13593. */
  13594. /**
  13595. * A string to append to each series' y value. Overridable in each
  13596. * series' tooltip options object.
  13597. *
  13598. * @sample {highcharts|highstock} highcharts/tooltip/valuedecimals/
  13599. * Set decimals, prefix and suffix for the value
  13600. * @sample {highmaps} maps/tooltip/valuedecimals/
  13601. * Set decimals, prefix and suffix for the value
  13602. *
  13603. * @type {string}
  13604. * @since 2.2
  13605. * @apioption tooltip.valueSuffix
  13606. */
  13607. /**
  13608. * The format for the date in the tooltip header if the X axis is a
  13609. * datetime axis. The default is a best guess based on the smallest
  13610. * distance between points in the chart.
  13611. *
  13612. * @sample {highcharts} highcharts/tooltip/xdateformat/
  13613. * A different format
  13614. *
  13615. * @type {string}
  13616. * @product highcharts highstock gantt
  13617. * @apioption tooltip.xDateFormat
  13618. */
  13619. /**
  13620. * How many decimals to show for the `point.change` value when the
  13621. * `series.compare` option is set. This is overridable in each series'
  13622. * tooltip options object. The default is to preserve all decimals.
  13623. *
  13624. * @type {number}
  13625. * @since 1.0.1
  13626. * @product highstock
  13627. * @apioption tooltip.changeDecimals
  13628. */
  13629. /**
  13630. * Enable or disable the tooltip.
  13631. *
  13632. * @sample {highcharts} highcharts/tooltip/enabled/
  13633. * Disabled
  13634. * @sample {highcharts} highcharts/plotoptions/series-point-events-mouseover/
  13635. * Disable tooltip and show values on chart instead
  13636. */
  13637. enabled: true,
  13638. /**
  13639. * Enable or disable animation of the tooltip.
  13640. *
  13641. * @type {boolean}
  13642. * @default true
  13643. * @since 2.3.0
  13644. */
  13645. animation: svg,
  13646. /**
  13647. * The radius of the rounded border corners.
  13648. *
  13649. * @sample {highcharts} highcharts/tooltip/bordercolor-default/
  13650. * 5px by default
  13651. * @sample {highcharts} highcharts/tooltip/borderradius-0/
  13652. * Square borders
  13653. * @sample {highmaps} maps/tooltip/background-border/
  13654. * Background and border demo
  13655. */
  13656. borderRadius: 3,
  13657. /**
  13658. * For series on datetime axes, the date format in the tooltip's
  13659. * header will by default be guessed based on the closest data points.
  13660. * This member gives the default string representations used for
  13661. * each unit. For an overview of the replacement codes, see
  13662. * [dateFormat](/class-reference/Highcharts#dateFormat).
  13663. *
  13664. * @see [xAxis.dateTimeLabelFormats](#xAxis.dateTimeLabelFormats)
  13665. *
  13666. * @type {Highcharts.Dictionary<string>}
  13667. * @product highcharts highstock gantt
  13668. */
  13669. dateTimeLabelFormats: {
  13670. /** @internal */
  13671. millisecond: '%A, %b %e, %H:%M:%S.%L',
  13672. /** @internal */
  13673. second: '%A, %b %e, %H:%M:%S',
  13674. /** @internal */
  13675. minute: '%A, %b %e, %H:%M',
  13676. /** @internal */
  13677. hour: '%A, %b %e, %H:%M',
  13678. /** @internal */
  13679. day: '%A, %b %e, %Y',
  13680. /** @internal */
  13681. week: 'Week from %A, %b %e, %Y',
  13682. /** @internal */
  13683. month: '%B %Y',
  13684. /** @internal */
  13685. year: '%Y'
  13686. },
  13687. /**
  13688. * A string to append to the tooltip format.
  13689. *
  13690. * @sample {highcharts} highcharts/tooltip/footerformat/
  13691. * A table for value alignment
  13692. * @sample {highmaps} maps/tooltip/format/
  13693. * Format demo
  13694. *
  13695. * @since 2.2
  13696. */
  13697. footerFormat: '',
  13698. /**
  13699. * Padding inside the tooltip, in pixels.
  13700. *
  13701. * @since 5.0.0
  13702. */
  13703. padding: 8,
  13704. /**
  13705. * Proximity snap for graphs or single points. It defaults to 10 for
  13706. * mouse-powered devices and 25 for touch devices.
  13707. *
  13708. * Note that in most cases the whole plot area captures the mouse
  13709. * movement, and in these cases `tooltip.snap` doesn't make sense. This
  13710. * applies when [stickyTracking](#plotOptions.series.stickyTracking)
  13711. * is `true` (default) and when the tooltip is [shared](#tooltip.shared)
  13712. * or [split](#tooltip.split).
  13713. *
  13714. * @sample {highcharts} highcharts/tooltip/bordercolor-default/
  13715. * 10 px by default
  13716. * @sample {highcharts} highcharts/tooltip/snap-50/
  13717. * 50 px on graph
  13718. *
  13719. * @type {number}
  13720. * @default 10/25
  13721. * @since 1.2.0
  13722. * @product highcharts highstock
  13723. */
  13724. snap: isTouchDevice ? 25 : 10,
  13725. /**
  13726. * The HTML of the tooltip header line. Variables are enclosed by
  13727. * curly brackets. Available variables are `point.key`, `series.name`,
  13728. * `series.color` and other members from the `point` and `series`
  13729. * objects. The `point.key` variable contains the category name, x
  13730. * value or datetime string depending on the type of axis. For datetime
  13731. * axes, the `point.key` date format can be set using
  13732. * `tooltip.xDateFormat`.
  13733. *
  13734. * @sample {highcharts} highcharts/tooltip/footerformat/
  13735. * An HTML table in the tooltip
  13736. * @sample {highstock} highcharts/tooltip/footerformat/
  13737. * An HTML table in the tooltip
  13738. * @sample {highmaps} maps/tooltip/format/
  13739. * Format demo
  13740. *
  13741. * @type {string}
  13742. * @apioption tooltip.headerFormat
  13743. */
  13744. headerFormat: '<span style="font-size: 10px">{point.key}</span><br/>',
  13745. /**
  13746. * The HTML of the null point's line in the tooltip. Works analogously
  13747. * to [pointFormat](#tooltip.pointFormat).
  13748. *
  13749. * @sample {highcharts} highcharts/plotoptions/series-nullformat
  13750. * Format data label and tooltip for null point.
  13751. *
  13752. * @type {string}
  13753. * @apioption tooltip.nullFormat
  13754. */
  13755. /**
  13756. * The HTML of the point's line in the tooltip. Variables are enclosed
  13757. * by curly brackets. Available variables are `point.x`, `point.y`,
  13758. * `series.name` and `series.color` and other properties on the same
  13759. * form. Furthermore, `point.y` can be extended by the
  13760. * `tooltip.valuePrefix` and `tooltip.valueSuffix` variables. This can
  13761. * also be overridden for each series, which makes it a good hook for
  13762. * displaying units.
  13763. *
  13764. * In styled mode, the dot is colored by a class name rather
  13765. * than the point color.
  13766. *
  13767. * @sample {highcharts} highcharts/tooltip/pointformat/
  13768. * A different point format with value suffix
  13769. * @sample {highmaps} maps/tooltip/format/
  13770. * Format demo
  13771. *
  13772. * @type {string}
  13773. * @since 2.2
  13774. * @apioption tooltip.pointFormat
  13775. */
  13776. pointFormat: '<span style="color:{point.color}">\u25CF</span> {series.name}: <b>{point.y}</b><br/>',
  13777. /**
  13778. * The background color or gradient for the tooltip.
  13779. *
  13780. * In styled mode, the stroke width is set in the
  13781. * `.highcharts-tooltip-box` class.
  13782. *
  13783. * @sample {highcharts} highcharts/tooltip/backgroundcolor-solid/
  13784. * Yellowish background
  13785. * @sample {highcharts} highcharts/tooltip/backgroundcolor-gradient/
  13786. * Gradient
  13787. * @sample {highcharts} highcharts/css/tooltip-border-background/
  13788. * Tooltip in styled mode
  13789. * @sample {highstock} stock/tooltip/general/
  13790. * Custom tooltip
  13791. * @sample {highstock} highcharts/css/tooltip-border-background/
  13792. * Tooltip in styled mode
  13793. * @sample {highmaps} maps/tooltip/background-border/
  13794. * Background and border demo
  13795. * @sample {highmaps} highcharts/css/tooltip-border-background/
  13796. * Tooltip in styled mode
  13797. *
  13798. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  13799. */
  13800. backgroundColor: color(palette.neutralColor3)
  13801. .setOpacity(0.85).get(),
  13802. /**
  13803. * The pixel width of the tooltip border.
  13804. *
  13805. * In styled mode, the stroke width is set in the
  13806. * `.highcharts-tooltip-box` class.
  13807. *
  13808. * @sample {highcharts} highcharts/tooltip/bordercolor-default/
  13809. * 2px by default
  13810. * @sample {highcharts} highcharts/tooltip/borderwidth/
  13811. * No border (shadow only)
  13812. * @sample {highcharts} highcharts/css/tooltip-border-background/
  13813. * Tooltip in styled mode
  13814. * @sample {highstock} stock/tooltip/general/
  13815. * Custom tooltip
  13816. * @sample {highstock} highcharts/css/tooltip-border-background/
  13817. * Tooltip in styled mode
  13818. * @sample {highmaps} maps/tooltip/background-border/
  13819. * Background and border demo
  13820. * @sample {highmaps} highcharts/css/tooltip-border-background/
  13821. * Tooltip in styled mode
  13822. */
  13823. borderWidth: 1,
  13824. /**
  13825. * Whether to apply a drop shadow to the tooltip.
  13826. *
  13827. * @sample {highcharts} highcharts/tooltip/bordercolor-default/
  13828. * True by default
  13829. * @sample {highcharts} highcharts/tooltip/shadow/
  13830. * False
  13831. * @sample {highmaps} maps/tooltip/positioner/
  13832. * Fixed tooltip position, border and shadow disabled
  13833. *
  13834. * @type {boolean|Highcharts.ShadowOptionsObject}
  13835. */
  13836. shadow: true,
  13837. /**
  13838. * CSS styles for the tooltip. The tooltip can also be styled through
  13839. * the CSS class `.highcharts-tooltip`.
  13840. *
  13841. * Note that the default `pointerEvents` style makes the tooltip ignore
  13842. * mouse events, so in order to use clickable tooltips, this value must
  13843. * be set to `auto`.
  13844. *
  13845. * @sample {highcharts} highcharts/tooltip/style/
  13846. * Greater padding, bold text
  13847. *
  13848. * @type {Highcharts.CSSObject}
  13849. */
  13850. style: {
  13851. /** @internal */
  13852. color: palette.neutralColor80,
  13853. /** @internal */
  13854. cursor: 'default',
  13855. /** @internal */
  13856. fontSize: '12px',
  13857. /** @internal */
  13858. whiteSpace: 'nowrap'
  13859. }
  13860. },
  13861. /**
  13862. * Highchart by default puts a credits label in the lower right corner
  13863. * of the chart. This can be changed using these options.
  13864. */
  13865. credits: {
  13866. /**
  13867. * Credits for map source to be concatenated with conventional credit
  13868. * text. By default this is a format string that collects copyright
  13869. * information from the map if available.
  13870. *
  13871. * @see [mapTextFull](#credits.mapTextFull)
  13872. * @see [text](#credits.text)
  13873. *
  13874. * @type {string}
  13875. * @default \u00a9 <a href="{geojson.copyrightUrl}">{geojson.copyrightShort}</a>
  13876. * @since 4.2.2
  13877. * @product highmaps
  13878. * @apioption credits.mapText
  13879. */
  13880. /**
  13881. * Detailed credits for map source to be displayed on hover of credits
  13882. * text. By default this is a format string that collects copyright
  13883. * information from the map if available.
  13884. *
  13885. * @see [mapText](#credits.mapText)
  13886. * @see [text](#credits.text)
  13887. *
  13888. * @type {string}
  13889. * @default {geojson.copyright}
  13890. * @since 4.2.2
  13891. * @product highmaps
  13892. * @apioption credits.mapTextFull
  13893. */
  13894. /**
  13895. * Whether to show the credits text.
  13896. *
  13897. * @sample {highcharts} highcharts/credits/enabled-false/
  13898. * Credits disabled
  13899. * @sample {highstock} stock/credits/enabled/
  13900. * Credits disabled
  13901. * @sample {highmaps} maps/credits/enabled-false/
  13902. * Credits disabled
  13903. */
  13904. enabled: true,
  13905. /**
  13906. * The URL for the credits label.
  13907. *
  13908. * @sample {highcharts} highcharts/credits/href/
  13909. * Custom URL and text
  13910. * @sample {highmaps} maps/credits/customized/
  13911. * Custom URL and text
  13912. */
  13913. href: 'https://www.highcharts.com?credits',
  13914. /**
  13915. * Position configuration for the credits label.
  13916. *
  13917. * @sample {highcharts} highcharts/credits/position-left/
  13918. * Left aligned
  13919. * @sample {highcharts} highcharts/credits/position-left/
  13920. * Left aligned
  13921. * @sample {highmaps} maps/credits/customized/
  13922. * Left aligned
  13923. * @sample {highmaps} maps/credits/customized/
  13924. * Left aligned
  13925. *
  13926. * @type {Highcharts.AlignObject}
  13927. * @since 2.1
  13928. */
  13929. position: {
  13930. /** @internal */
  13931. align: 'right',
  13932. /** @internal */
  13933. x: -10,
  13934. /** @internal */
  13935. verticalAlign: 'bottom',
  13936. /** @internal */
  13937. y: -5
  13938. },
  13939. /**
  13940. * CSS styles for the credits label.
  13941. *
  13942. * @see In styled mode, credits styles can be set with the
  13943. * `.highcharts-credits` class.
  13944. *
  13945. * @type {Highcharts.CSSObject}
  13946. */
  13947. style: {
  13948. /** @internal */
  13949. cursor: 'pointer',
  13950. /** @internal */
  13951. color: palette.neutralColor40,
  13952. /** @internal */
  13953. fontSize: '9px'
  13954. },
  13955. /**
  13956. * The text for the credits label.
  13957. *
  13958. * @productdesc {highmaps}
  13959. * If a map is loaded as GeoJSON, the text defaults to
  13960. * `Highcharts @ {map-credits}`. Otherwise, it defaults to
  13961. * `Highcharts.com`.
  13962. *
  13963. * @sample {highcharts} highcharts/credits/href/
  13964. * Custom URL and text
  13965. * @sample {highmaps} maps/credits/customized/
  13966. * Custom URL and text
  13967. */
  13968. text: 'Highcharts.com'
  13969. }
  13970. };
  13971. /* eslint-disable spaced-comment */
  13972. H.defaultOptions.chart.styledMode = false;
  13973. '';
  13974. /**
  13975. * Global `Time` object with default options. Since v6.0.5, time settings can be
  13976. * applied individually for each chart. If no individual settings apply, this
  13977. * `Time` object is shared by all instances.
  13978. *
  13979. * @name Highcharts.time
  13980. * @type {Highcharts.Time}
  13981. */
  13982. H.time = new Time(merge(H.defaultOptions.global, H.defaultOptions.time));
  13983. /**
  13984. * Formats a JavaScript date timestamp (milliseconds since Jan 1st 1970) into a
  13985. * human readable date string. The format is a subset of the formats for PHP's
  13986. * [strftime](https://www.php.net/manual/en/function.strftime.php) function.
  13987. * Additional formats can be given in the {@link Highcharts.dateFormats} hook.
  13988. *
  13989. * Since v6.0.5, all internal dates are formatted through the
  13990. * {@link Highcharts.Chart#time} instance to respect chart-level time settings.
  13991. * The `Highcharts.dateFormat` function only reflects global time settings set
  13992. * with `setOptions`.
  13993. *
  13994. * Supported format keys:
  13995. * - `%a`: Short weekday, like 'Mon'
  13996. * - `%A`: Long weekday, like 'Monday'
  13997. * - `%d`: Two digit day of the month, 01 to 31
  13998. * - `%e`: Day of the month, 1 through 31
  13999. * - `%w`: Day of the week, 0 through 6
  14000. * - `%b`: Short month, like 'Jan'
  14001. * - `%B`: Long month, like 'January'
  14002. * - `%m`: Two digit month number, 01 through 12
  14003. * - `%y`: Two digits year, like 09 for 2009
  14004. * - `%Y`: Four digits year, like 2009
  14005. * - `%H`: Two digits hours in 24h format, 00 through 23
  14006. * - `%k`: Hours in 24h format, 0 through 23
  14007. * - `%I`: Two digits hours in 12h format, 00 through 11
  14008. * - `%l`: Hours in 12h format, 1 through 12
  14009. * - `%M`: Two digits minutes, 00 through 59
  14010. * - `%p`: Upper case AM or PM
  14011. * - `%P`: Lower case AM or PM
  14012. * - `%S`: Two digits seconds, 00 through 59
  14013. * - `%L`: Milliseconds (naming from Ruby)
  14014. *
  14015. * @function Highcharts.dateFormat
  14016. *
  14017. * @param {string} format
  14018. * The desired format where various time representations are prefixed
  14019. * with `%`.
  14020. *
  14021. * @param {number} timestamp
  14022. * The JavaScript timestamp.
  14023. *
  14024. * @param {boolean} [capitalize=false]
  14025. * Upper case first letter in the return.
  14026. *
  14027. * @return {string}
  14028. * The formatted date.
  14029. */
  14030. H.dateFormat = function (format, timestamp, capitalize) {
  14031. return H.time.dateFormat(format, timestamp, capitalize);
  14032. };
  14033. var optionsModule = {
  14034. dateFormat: H.dateFormat,
  14035. defaultOptions: H.defaultOptions,
  14036. time: H.time
  14037. };
  14038. return optionsModule;
  14039. });
  14040. _registerModule(_modules, 'Core/Axis/Tick.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
  14041. /* *
  14042. *
  14043. * (c) 2010-2021 Torstein Honsi
  14044. *
  14045. * License: www.highcharts.com/license
  14046. *
  14047. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  14048. *
  14049. * */
  14050. var deg2rad = H.deg2rad;
  14051. var clamp = U.clamp,
  14052. correctFloat = U.correctFloat,
  14053. defined = U.defined,
  14054. destroyObjectProperties = U.destroyObjectProperties,
  14055. extend = U.extend,
  14056. fireEvent = U.fireEvent,
  14057. isNumber = U.isNumber,
  14058. merge = U.merge,
  14059. objectEach = U.objectEach,
  14060. pick = U.pick;
  14061. /**
  14062. * Optional parameters for the tick.
  14063. * @private
  14064. * @interface Highcharts.TickParametersObject
  14065. */ /**
  14066. * Set category for the tick.
  14067. * @name Highcharts.TickParametersObject#category
  14068. * @type {string|undefined}
  14069. */ /**
  14070. * @name Highcharts.TickParametersObject#options
  14071. * @type {Highcharts.Dictionary<any>|undefined}
  14072. */ /**
  14073. * Set tickmarkOffset for the tick.
  14074. * @name Highcharts.TickParametersObject#tickmarkOffset
  14075. * @type {number|undefined}
  14076. */
  14077. /**
  14078. * Additonal time tick information.
  14079. *
  14080. * @interface Highcharts.TimeTicksInfoObject
  14081. * @extends Highcharts.TimeNormalizedObject
  14082. */ /**
  14083. * @name Highcharts.TimeTicksInfoObject#higherRanks
  14084. * @type {Array<string>}
  14085. */ /**
  14086. * @name Highcharts.TimeTicksInfoObject#totalRange
  14087. * @type {number}
  14088. */
  14089. ''; // detach doclets above
  14090. /* eslint-disable no-invalid-this, valid-jsdoc */
  14091. /**
  14092. * The Tick class.
  14093. *
  14094. * @class
  14095. * @name Highcharts.Tick
  14096. *
  14097. * @param {Highcharts.Axis} axis
  14098. * The axis of the tick.
  14099. *
  14100. * @param {number} pos
  14101. * The position of the tick on the axis in terms of axis values.
  14102. *
  14103. * @param {string} [type]
  14104. * The type of tick, either 'minor' or an empty string
  14105. *
  14106. * @param {boolean} [noLabel=false]
  14107. * Whether to disable the label or not. Defaults to false.
  14108. *
  14109. * @param {object} [parameters]
  14110. * Optional parameters for the tick.
  14111. */
  14112. var Tick = /** @class */ (function () {
  14113. /* *
  14114. *
  14115. * Constructors
  14116. *
  14117. * */
  14118. function Tick(axis, pos, type, noLabel, parameters) {
  14119. this.isNew = true;
  14120. this.isNewLabel = true;
  14121. /**
  14122. * The related axis of the tick.
  14123. * @name Highcharts.Tick#axis
  14124. * @type {Highcharts.Axis}
  14125. */
  14126. this.axis = axis;
  14127. /**
  14128. * The logical position of the tick on the axis in terms of axis values.
  14129. * @name Highcharts.Tick#pos
  14130. * @type {number}
  14131. */
  14132. this.pos = pos;
  14133. /**
  14134. * The tick type, which can be `"minor"`, or an empty string.
  14135. * @name Highcharts.Tick#type
  14136. * @type {string}
  14137. */
  14138. this.type = type || '';
  14139. this.parameters = parameters || {};
  14140. /**
  14141. * The mark offset of the tick on the axis. Usually `undefined`, numeric
  14142. * for grid axes.
  14143. * @name Highcharts.Tick#tickmarkOffset
  14144. * @type {number|undefined}
  14145. */
  14146. this.tickmarkOffset = this.parameters.tickmarkOffset;
  14147. this.options = this.parameters.options;
  14148. fireEvent(this, 'init');
  14149. if (!type && !noLabel) {
  14150. this.addLabel();
  14151. }
  14152. }
  14153. /* *
  14154. *
  14155. * Functions
  14156. *
  14157. * */
  14158. /**
  14159. * Write the tick label.
  14160. *
  14161. * @private
  14162. * @function Highcharts.Tick#addLabel
  14163. * @return {void}
  14164. */
  14165. Tick.prototype.addLabel = function () {
  14166. var tick = this,
  14167. axis = tick.axis,
  14168. options = axis.options,
  14169. chart = axis.chart,
  14170. categories = axis.categories,
  14171. log = axis.logarithmic,
  14172. names = axis.names,
  14173. pos = tick.pos,
  14174. labelOptions = pick(tick.options && tick.options.labels,
  14175. options.labels),
  14176. str,
  14177. tickPositions = axis.tickPositions,
  14178. isFirst = pos === tickPositions[0],
  14179. isLast = pos === tickPositions[tickPositions.length - 1],
  14180. value = this.parameters.category || (categories ?
  14181. pick(categories[pos],
  14182. names[pos],
  14183. pos) :
  14184. pos),
  14185. label = tick.label,
  14186. animateLabels = (!labelOptions.step || labelOptions.step === 1) &&
  14187. axis.tickInterval === 1,
  14188. tickPositionInfo = tickPositions.info,
  14189. dateTimeLabelFormat,
  14190. dateTimeLabelFormats,
  14191. i,
  14192. list;
  14193. // Set the datetime label format. If a higher rank is set for this
  14194. // position, use that. If not, use the general format.
  14195. if (axis.dateTime && tickPositionInfo) {
  14196. dateTimeLabelFormats = chart.time.resolveDTLFormat(options.dateTimeLabelFormats[(!options.grid &&
  14197. tickPositionInfo.higherRanks[pos]) ||
  14198. tickPositionInfo.unitName]);
  14199. dateTimeLabelFormat = dateTimeLabelFormats.main;
  14200. }
  14201. // set properties for access in render method
  14202. /**
  14203. * True if the tick is the first one on the axis.
  14204. * @name Highcharts.Tick#isFirst
  14205. * @readonly
  14206. * @type {boolean|undefined}
  14207. */
  14208. tick.isFirst = isFirst;
  14209. /**
  14210. * True if the tick is the last one on the axis.
  14211. * @name Highcharts.Tick#isLast
  14212. * @readonly
  14213. * @type {boolean|undefined}
  14214. */
  14215. tick.isLast = isLast;
  14216. // Get the string
  14217. tick.formatCtx = {
  14218. axis: axis,
  14219. chart: chart,
  14220. isFirst: isFirst,
  14221. isLast: isLast,
  14222. dateTimeLabelFormat: dateTimeLabelFormat,
  14223. tickPositionInfo: tickPositionInfo,
  14224. value: log ? correctFloat(log.lin2log(value)) : value,
  14225. pos: pos
  14226. };
  14227. str = axis.labelFormatter.call(tick.formatCtx, this.formatCtx);
  14228. // Set up conditional formatting based on the format list if existing.
  14229. list = dateTimeLabelFormats && dateTimeLabelFormats.list;
  14230. if (list) {
  14231. tick.shortenLabel = function () {
  14232. for (i = 0; i < list.length; i++) {
  14233. label.attr({
  14234. text: axis.labelFormatter.call(extend(tick.formatCtx, { dateTimeLabelFormat: list[i] }))
  14235. });
  14236. if (label.getBBox().width <
  14237. axis.getSlotWidth(tick) - 2 *
  14238. pick(labelOptions.padding, 5)) {
  14239. return;
  14240. }
  14241. }
  14242. label.attr({
  14243. text: ''
  14244. });
  14245. };
  14246. }
  14247. // Call only after first render
  14248. if (animateLabels && axis._addedPlotLB) {
  14249. tick.moveLabel(str, labelOptions);
  14250. }
  14251. // First call
  14252. if (!defined(label) && !tick.movedLabel) {
  14253. /**
  14254. * The rendered text label of the tick.
  14255. * @name Highcharts.Tick#label
  14256. * @type {Highcharts.SVGElement|undefined}
  14257. */
  14258. tick.label = label = tick.createLabel({ x: 0, y: 0 }, str, labelOptions);
  14259. // Base value to detect change for new calls to getBBox
  14260. tick.rotation = 0;
  14261. // update
  14262. }
  14263. else if (label && label.textStr !== str && !animateLabels) {
  14264. // When resetting text, also reset the width if dynamically set
  14265. // (#8809)
  14266. if (label.textWidth &&
  14267. !(labelOptions.style && labelOptions.style.width) &&
  14268. !label.styles.width) {
  14269. label.css({ width: null });
  14270. }
  14271. label.attr({ text: str });
  14272. label.textPxLength = label.getBBox().width;
  14273. }
  14274. };
  14275. /**
  14276. * Render and return the label of the tick.
  14277. *
  14278. * @private
  14279. * @function Highcharts.Tick#createLabel
  14280. * @param {Highcharts.PositionObject} xy
  14281. * @param {string} str
  14282. * @param {Highcharts.XAxisLabelsOptions} labelOptions
  14283. * @return {Highcharts.SVGElement|undefined}
  14284. */
  14285. Tick.prototype.createLabel = function (xy, str, labelOptions) {
  14286. var axis = this.axis,
  14287. chart = axis.chart,
  14288. label = defined(str) && labelOptions.enabled ?
  14289. chart.renderer
  14290. .text(str,
  14291. xy.x,
  14292. xy.y,
  14293. labelOptions.useHTML)
  14294. .add(axis.labelGroup) :
  14295. null;
  14296. // Un-rotated length
  14297. if (label) {
  14298. // Without position absolute, IE export sometimes is wrong
  14299. if (!chart.styledMode) {
  14300. label.css(merge(labelOptions.style));
  14301. }
  14302. label.textPxLength = label.getBBox().width;
  14303. }
  14304. return label;
  14305. };
  14306. /**
  14307. * Destructor for the tick prototype
  14308. *
  14309. * @private
  14310. * @function Highcharts.Tick#destroy
  14311. * @return {void}
  14312. */
  14313. Tick.prototype.destroy = function () {
  14314. destroyObjectProperties(this, this.axis);
  14315. };
  14316. /**
  14317. * Gets the x and y positions for ticks in terms of pixels.
  14318. *
  14319. * @private
  14320. * @function Highcharts.Tick#getPosition
  14321. *
  14322. * @param {boolean} horiz
  14323. * Whether the tick is on an horizontal axis or not.
  14324. *
  14325. * @param {number} tickPos
  14326. * Position of the tick.
  14327. *
  14328. * @param {number} tickmarkOffset
  14329. * Tickmark offset for all ticks.
  14330. *
  14331. * @param {boolean} [old]
  14332. * Whether the axis has changed or not.
  14333. *
  14334. * @return {Highcharts.PositionObject}
  14335. * The tick position.
  14336. *
  14337. * @fires Highcharts.Tick#event:afterGetPosition
  14338. */
  14339. Tick.prototype.getPosition = function (horiz, tickPos, tickmarkOffset, old) {
  14340. var axis = this.axis,
  14341. chart = axis.chart,
  14342. cHeight = (old && chart.oldChartHeight) || chart.chartHeight,
  14343. pos;
  14344. pos = {
  14345. x: horiz ?
  14346. correctFloat(axis.translate(tickPos + tickmarkOffset, null, null, old) +
  14347. axis.transB) :
  14348. (axis.left +
  14349. axis.offset +
  14350. (axis.opposite ?
  14351. (((old && chart.oldChartWidth) ||
  14352. chart.chartWidth) -
  14353. axis.right -
  14354. axis.left) :
  14355. 0)),
  14356. y: horiz ?
  14357. (cHeight -
  14358. axis.bottom +
  14359. axis.offset -
  14360. (axis.opposite ? axis.height : 0)) :
  14361. correctFloat(cHeight -
  14362. axis.translate(tickPos + tickmarkOffset, null, null, old) -
  14363. axis.transB)
  14364. };
  14365. // Chrome workaround for #10516
  14366. pos.y = clamp(pos.y, -1e5, 1e5);
  14367. fireEvent(this, 'afterGetPosition', { pos: pos });
  14368. return pos;
  14369. };
  14370. /**
  14371. * Get the x, y position of the tick label
  14372. *
  14373. * @private
  14374. * @return {Highcharts.PositionObject}
  14375. */
  14376. Tick.prototype.getLabelPosition = function (x, y, label, horiz, labelOptions, tickmarkOffset, index, step) {
  14377. var axis = this.axis,
  14378. transA = axis.transA,
  14379. reversed = ( // #7911
  14380. axis.isLinked && axis.linkedParent ?
  14381. axis.linkedParent.reversed :
  14382. axis.reversed),
  14383. staggerLines = axis.staggerLines,
  14384. rotCorr = axis.tickRotCorr || { x: 0,
  14385. y: 0 },
  14386. yOffset = labelOptions.y,
  14387. // Adjust for label alignment if we use reserveSpace: true (#5286)
  14388. labelOffsetCorrection = (!horiz && !axis.reserveSpaceDefault ?
  14389. -axis.labelOffset * (axis.labelAlign === 'center' ? 0.5 : 1) :
  14390. 0),
  14391. line,
  14392. pos = {};
  14393. if (!defined(yOffset)) {
  14394. if (axis.side === 0) {
  14395. yOffset = label.rotation ? -8 : -label.getBBox().height;
  14396. }
  14397. else if (axis.side === 2) {
  14398. yOffset = rotCorr.y + 8;
  14399. }
  14400. else {
  14401. // #3140, #3140
  14402. yOffset = Math.cos(label.rotation * deg2rad) *
  14403. (rotCorr.y - label.getBBox(false, 0).height / 2);
  14404. }
  14405. }
  14406. x = x +
  14407. labelOptions.x +
  14408. labelOffsetCorrection +
  14409. rotCorr.x -
  14410. (tickmarkOffset && horiz ?
  14411. tickmarkOffset * transA * (reversed ? -1 : 1) :
  14412. 0);
  14413. y = y + yOffset - (tickmarkOffset && !horiz ?
  14414. tickmarkOffset * transA * (reversed ? 1 : -1) : 0);
  14415. // Correct for staggered labels
  14416. if (staggerLines) {
  14417. line = (index / (step || 1) % staggerLines);
  14418. if (axis.opposite) {
  14419. line = staggerLines - line - 1;
  14420. }
  14421. y += line * (axis.labelOffset / staggerLines);
  14422. }
  14423. pos.x = x;
  14424. pos.y = Math.round(y);
  14425. fireEvent(this, 'afterGetLabelPosition', { pos: pos, tickmarkOffset: tickmarkOffset, index: index });
  14426. return pos;
  14427. };
  14428. /**
  14429. * Get the offset height or width of the label
  14430. *
  14431. * @private
  14432. * @function Highcharts.Tick#getLabelSize
  14433. * @return {number}
  14434. */
  14435. Tick.prototype.getLabelSize = function () {
  14436. return this.label ?
  14437. this.label.getBBox()[this.axis.horiz ? 'height' : 'width'] :
  14438. 0;
  14439. };
  14440. /**
  14441. * Extendible method to return the path of the marker
  14442. *
  14443. * @private
  14444. *
  14445. */
  14446. Tick.prototype.getMarkPath = function (x, y, tickLength, tickWidth, horiz, renderer) {
  14447. return renderer.crispLine([[
  14448. 'M',
  14449. x,
  14450. y
  14451. ], [
  14452. 'L',
  14453. x + (horiz ? 0 : -tickLength),
  14454. y + (horiz ? tickLength : 0)
  14455. ]], tickWidth);
  14456. };
  14457. /**
  14458. * Handle the label overflow by adjusting the labels to the left and right
  14459. * edge, or hide them if they collide into the neighbour label.
  14460. *
  14461. * @private
  14462. * @function Highcharts.Tick#handleOverflow
  14463. * @param {Highcharts.PositionObject} xy
  14464. * @return {void}
  14465. */
  14466. Tick.prototype.handleOverflow = function (xy) {
  14467. var tick = this,
  14468. axis = this.axis,
  14469. labelOptions = axis.options.labels,
  14470. pxPos = xy.x,
  14471. chartWidth = axis.chart.chartWidth,
  14472. spacing = axis.chart.spacing,
  14473. leftBound = pick(axis.labelLeft,
  14474. Math.min(axis.pos,
  14475. spacing[3])),
  14476. rightBound = pick(axis.labelRight,
  14477. Math.max(!axis.isRadial ? axis.pos + axis.len : 0,
  14478. chartWidth - spacing[1])),
  14479. label = this.label,
  14480. rotation = this.rotation,
  14481. factor = {
  14482. left: 0,
  14483. center: 0.5,
  14484. right: 1
  14485. }[axis.labelAlign || label.attr('align')],
  14486. labelWidth = label.getBBox().width,
  14487. slotWidth = axis.getSlotWidth(tick),
  14488. modifiedSlotWidth = slotWidth,
  14489. xCorrection = factor,
  14490. goRight = 1,
  14491. leftPos,
  14492. rightPos,
  14493. textWidth,
  14494. css = {};
  14495. // Check if the label overshoots the chart spacing box. If it does, move
  14496. // it. If it now overshoots the slotWidth, add ellipsis.
  14497. if (!rotation &&
  14498. pick(labelOptions.overflow, 'justify') === 'justify') {
  14499. leftPos = pxPos - factor * labelWidth;
  14500. rightPos = pxPos + (1 - factor) * labelWidth;
  14501. if (leftPos < leftBound) {
  14502. modifiedSlotWidth =
  14503. xy.x + modifiedSlotWidth * (1 - factor) - leftBound;
  14504. }
  14505. else if (rightPos > rightBound) {
  14506. modifiedSlotWidth =
  14507. rightBound - xy.x + modifiedSlotWidth * factor;
  14508. goRight = -1;
  14509. }
  14510. modifiedSlotWidth = Math.min(slotWidth, modifiedSlotWidth); // #4177
  14511. if (modifiedSlotWidth < slotWidth && axis.labelAlign === 'center') {
  14512. xy.x += (goRight *
  14513. (slotWidth -
  14514. modifiedSlotWidth -
  14515. xCorrection * (slotWidth - Math.min(labelWidth, modifiedSlotWidth))));
  14516. }
  14517. // If the label width exceeds the available space, set a text width
  14518. // to be picked up below. Also, if a width has been set before, we
  14519. // need to set a new one because the reported labelWidth will be
  14520. // limited by the box (#3938).
  14521. if (labelWidth > modifiedSlotWidth ||
  14522. (axis.autoRotation && (label.styles || {}).width)) {
  14523. textWidth = modifiedSlotWidth;
  14524. }
  14525. // Add ellipsis to prevent rotated labels to be clipped against the edge
  14526. // of the chart
  14527. }
  14528. else if (rotation < 0 &&
  14529. pxPos - factor * labelWidth < leftBound) {
  14530. textWidth = Math.round(pxPos / Math.cos(rotation * deg2rad) - leftBound);
  14531. }
  14532. else if (rotation > 0 &&
  14533. pxPos + factor * labelWidth > rightBound) {
  14534. textWidth = Math.round((chartWidth - pxPos) /
  14535. Math.cos(rotation * deg2rad));
  14536. }
  14537. if (textWidth) {
  14538. if (tick.shortenLabel) {
  14539. tick.shortenLabel();
  14540. }
  14541. else {
  14542. css.width = Math.floor(textWidth) + 'px';
  14543. if (!(labelOptions.style || {}).textOverflow) {
  14544. css.textOverflow = 'ellipsis';
  14545. }
  14546. label.css(css);
  14547. }
  14548. }
  14549. };
  14550. /**
  14551. * Try to replace the label if the same one already exists.
  14552. *
  14553. * @private
  14554. * @function Highcharts.Tick#moveLabel
  14555. * @param {string} str
  14556. * @param {Highcharts.XAxisLabelsOptions} labelOptions
  14557. *
  14558. * @return {void}
  14559. */
  14560. Tick.prototype.moveLabel = function (str, labelOptions) {
  14561. var tick = this,
  14562. label = tick.label,
  14563. moved = false,
  14564. axis = tick.axis,
  14565. labelPos,
  14566. reversed = axis.reversed,
  14567. xPos,
  14568. yPos;
  14569. if (label && label.textStr === str) {
  14570. tick.movedLabel = label;
  14571. moved = true;
  14572. delete tick.label;
  14573. }
  14574. else { // Find a label with the same string
  14575. objectEach(axis.ticks, function (currentTick) {
  14576. if (!moved &&
  14577. !currentTick.isNew &&
  14578. currentTick !== tick &&
  14579. currentTick.label &&
  14580. currentTick.label.textStr === str) {
  14581. tick.movedLabel = currentTick.label;
  14582. moved = true;
  14583. currentTick.labelPos = tick.movedLabel.xy;
  14584. delete currentTick.label;
  14585. }
  14586. });
  14587. }
  14588. // Create new label if the actual one is moved
  14589. if (!moved && (tick.labelPos || label)) {
  14590. labelPos = tick.labelPos || label.xy;
  14591. xPos = axis.horiz ?
  14592. (reversed ? 0 : axis.width + axis.left) : labelPos.x;
  14593. yPos = axis.horiz ?
  14594. labelPos.y : (reversed ? (axis.width + axis.left) : 0);
  14595. tick.movedLabel = tick.createLabel({ x: xPos, y: yPos }, str, labelOptions);
  14596. if (tick.movedLabel) {
  14597. tick.movedLabel.attr({ opacity: 0 });
  14598. }
  14599. }
  14600. };
  14601. /**
  14602. * Put everything in place
  14603. *
  14604. * @private
  14605. * @param {number} index
  14606. * @param {boolean} [old]
  14607. * Use old coordinates to prepare an animation into new position
  14608. * @param {number} [opacity]
  14609. * @return {voids}
  14610. */
  14611. Tick.prototype.render = function (index, old, opacity) {
  14612. var tick = this,
  14613. axis = tick.axis,
  14614. horiz = axis.horiz,
  14615. pos = tick.pos,
  14616. tickmarkOffset = pick(tick.tickmarkOffset,
  14617. axis.tickmarkOffset),
  14618. xy = tick.getPosition(horiz,
  14619. pos,
  14620. tickmarkOffset,
  14621. old),
  14622. x = xy.x,
  14623. y = xy.y,
  14624. reverseCrisp = ((horiz && x === axis.pos + axis.len) ||
  14625. (!horiz && y === axis.pos)) ? -1 : 1; // #1480, #1687
  14626. opacity = pick(opacity, 1);
  14627. this.isActive = true;
  14628. // Create the grid line
  14629. this.renderGridLine(old, opacity, reverseCrisp);
  14630. // create the tick mark
  14631. this.renderMark(xy, opacity, reverseCrisp);
  14632. // the label is created on init - now move it into place
  14633. this.renderLabel(xy, old, opacity, index);
  14634. tick.isNew = false;
  14635. fireEvent(this, 'afterRender');
  14636. };
  14637. /**
  14638. * Renders the gridLine.
  14639. *
  14640. * @private
  14641. * @param {boolean} old Whether or not the tick is old
  14642. * @param {number} opacity The opacity of the grid line
  14643. * @param {number} reverseCrisp Modifier for avoiding overlapping 1 or -1
  14644. * @return {void}
  14645. */
  14646. Tick.prototype.renderGridLine = function (old, opacity, reverseCrisp) {
  14647. var tick = this, axis = tick.axis, options = axis.options, gridLine = tick.gridLine, gridLinePath, attribs = {}, pos = tick.pos, type = tick.type, tickmarkOffset = pick(tick.tickmarkOffset, axis.tickmarkOffset), renderer = axis.chart.renderer, gridPrefix = type ? type + 'Grid' : 'grid', gridLineWidth = options[gridPrefix + 'LineWidth'], gridLineColor = options[gridPrefix + 'LineColor'], dashStyle = options[gridPrefix + 'LineDashStyle'];
  14648. if (!gridLine) {
  14649. if (!axis.chart.styledMode) {
  14650. attribs.stroke = gridLineColor;
  14651. attribs['stroke-width'] = gridLineWidth;
  14652. if (dashStyle) {
  14653. attribs.dashstyle = dashStyle;
  14654. }
  14655. }
  14656. if (!type) {
  14657. attribs.zIndex = 1;
  14658. }
  14659. if (old) {
  14660. opacity = 0;
  14661. }
  14662. /**
  14663. * The rendered grid line of the tick.
  14664. * @name Highcharts.Tick#gridLine
  14665. * @type {Highcharts.SVGElement|undefined}
  14666. */
  14667. tick.gridLine = gridLine = renderer.path()
  14668. .attr(attribs)
  14669. .addClass('highcharts-' + (type ? type + '-' : '') + 'grid-line')
  14670. .add(axis.gridGroup);
  14671. }
  14672. if (gridLine) {
  14673. gridLinePath = axis.getPlotLinePath({
  14674. value: pos + tickmarkOffset,
  14675. lineWidth: gridLine.strokeWidth() * reverseCrisp,
  14676. force: 'pass',
  14677. old: old
  14678. });
  14679. // If the parameter 'old' is set, the current call will be followed
  14680. // by another call, therefore do not do any animations this time
  14681. if (gridLinePath) {
  14682. gridLine[old || tick.isNew ? 'attr' : 'animate']({
  14683. d: gridLinePath,
  14684. opacity: opacity
  14685. });
  14686. }
  14687. }
  14688. };
  14689. /**
  14690. * Renders the tick mark.
  14691. *
  14692. * @private
  14693. * @param {Highcharts.PositionObject} xy The position vector of the mark
  14694. * @param {number} opacity The opacity of the mark
  14695. * @param {number} reverseCrisp Modifier for avoiding overlapping 1 or -1
  14696. * @return {void}
  14697. */
  14698. Tick.prototype.renderMark = function (xy, opacity, reverseCrisp) {
  14699. var tick = this, axis = tick.axis, options = axis.options, renderer = axis.chart.renderer, type = tick.type, tickPrefix = type ? type + 'Tick' : 'tick', tickSize = axis.tickSize(tickPrefix), mark = tick.mark, isNewMark = !mark, x = xy.x, y = xy.y, tickWidth = pick(options[tickPrefix + 'Width'], !type && axis.isXAxis ? 1 : 0), // X axis defaults to 1
  14700. tickColor = options[tickPrefix + 'Color'];
  14701. if (tickSize) {
  14702. // negate the length
  14703. if (axis.opposite) {
  14704. tickSize[0] = -tickSize[0];
  14705. }
  14706. // First time, create it
  14707. if (isNewMark) {
  14708. /**
  14709. * The rendered mark of the tick.
  14710. * @name Highcharts.Tick#mark
  14711. * @type {Highcharts.SVGElement|undefined}
  14712. */
  14713. tick.mark = mark = renderer.path()
  14714. .addClass('highcharts-' + (type ? type + '-' : '') + 'tick')
  14715. .add(axis.axisGroup);
  14716. if (!axis.chart.styledMode) {
  14717. mark.attr({
  14718. stroke: tickColor,
  14719. 'stroke-width': tickWidth
  14720. });
  14721. }
  14722. }
  14723. mark[isNewMark ? 'attr' : 'animate']({
  14724. d: tick.getMarkPath(x, y, tickSize[0], mark.strokeWidth() * reverseCrisp, axis.horiz, renderer),
  14725. opacity: opacity
  14726. });
  14727. }
  14728. };
  14729. /**
  14730. * Renders the tick label.
  14731. * Note: The label should already be created in init(), so it should only
  14732. * have to be moved into place.
  14733. *
  14734. * @private
  14735. * @param {Highcharts.PositionObject} xy The position vector of the label
  14736. * @param {boolean} old Whether or not the tick is old
  14737. * @param {number} opacity The opacity of the label
  14738. * @param {number} index The index of the tick
  14739. * @return {void}
  14740. */
  14741. Tick.prototype.renderLabel = function (xy, old, opacity, index) {
  14742. var tick = this,
  14743. axis = tick.axis,
  14744. horiz = axis.horiz,
  14745. options = axis.options,
  14746. label = tick.label,
  14747. labelOptions = options.labels,
  14748. step = labelOptions.step,
  14749. tickmarkOffset = pick(tick.tickmarkOffset,
  14750. axis.tickmarkOffset),
  14751. show = true,
  14752. x = xy.x,
  14753. y = xy.y;
  14754. if (label && isNumber(x)) {
  14755. label.xy = xy = tick.getLabelPosition(x, y, label, horiz, labelOptions, tickmarkOffset, index, step);
  14756. // Apply show first and show last. If the tick is both first and
  14757. // last, it is a single centered tick, in which case we show the
  14758. // label anyway (#2100).
  14759. if ((tick.isFirst &&
  14760. !tick.isLast &&
  14761. !pick(options.showFirstLabel, 1)) ||
  14762. (tick.isLast &&
  14763. !tick.isFirst &&
  14764. !pick(options.showLastLabel, 1))) {
  14765. show = false;
  14766. // Handle label overflow and show or hide accordingly
  14767. }
  14768. else if (horiz &&
  14769. !labelOptions.step &&
  14770. !labelOptions.rotation &&
  14771. !old &&
  14772. opacity !== 0) {
  14773. tick.handleOverflow(xy);
  14774. }
  14775. // apply step
  14776. if (step && index % step) {
  14777. // show those indices dividable by step
  14778. show = false;
  14779. }
  14780. // Set the new position, and show or hide
  14781. if (show && isNumber(xy.y)) {
  14782. xy.opacity = opacity;
  14783. label[tick.isNewLabel ? 'attr' : 'animate'](xy);
  14784. tick.isNewLabel = false;
  14785. }
  14786. else {
  14787. label.attr('y', -9999); // #1338
  14788. tick.isNewLabel = true;
  14789. }
  14790. }
  14791. };
  14792. /**
  14793. * Replace labels with the moved ones to perform animation. Additionally
  14794. * destroy unused labels.
  14795. *
  14796. * @private
  14797. * @function Highcharts.Tick#replaceMovedLabel
  14798. * @return {void}
  14799. */
  14800. Tick.prototype.replaceMovedLabel = function () {
  14801. var tick = this,
  14802. label = tick.label,
  14803. axis = tick.axis,
  14804. reversed = axis.reversed,
  14805. x,
  14806. y;
  14807. // Animate and destroy
  14808. if (label && !tick.isNew) {
  14809. x = axis.horiz ? (reversed ? axis.left : axis.width + axis.left) : label.xy.x;
  14810. y = axis.horiz ?
  14811. label.xy.y :
  14812. (reversed ? axis.width + axis.top : axis.top);
  14813. label.animate({ x: x, y: y, opacity: 0 }, void 0, label.destroy);
  14814. delete tick.label;
  14815. }
  14816. axis.isDirty = true;
  14817. tick.label = tick.movedLabel;
  14818. delete tick.movedLabel;
  14819. };
  14820. return Tick;
  14821. }());
  14822. H.Tick = Tick;
  14823. return H.Tick;
  14824. });
  14825. _registerModule(_modules, 'Core/Axis/Axis.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Core/Color/Palette.js'], _modules['Core/Options.js'], _modules['Core/Axis/Tick.js'], _modules['Core/Utilities.js']], function (A, Color, H, palette, O, Tick, U) {
  14826. /* *
  14827. *
  14828. * (c) 2010-2021 Torstein Honsi
  14829. *
  14830. * License: www.highcharts.com/license
  14831. *
  14832. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  14833. *
  14834. * */
  14835. var animObject = A.animObject;
  14836. var defaultOptions = O.defaultOptions;
  14837. var addEvent = U.addEvent,
  14838. arrayMax = U.arrayMax,
  14839. arrayMin = U.arrayMin,
  14840. clamp = U.clamp,
  14841. correctFloat = U.correctFloat,
  14842. defined = U.defined,
  14843. destroyObjectProperties = U.destroyObjectProperties,
  14844. erase = U.erase,
  14845. error = U.error,
  14846. extend = U.extend,
  14847. fireEvent = U.fireEvent,
  14848. format = U.format,
  14849. getMagnitude = U.getMagnitude,
  14850. isArray = U.isArray,
  14851. isFunction = U.isFunction,
  14852. isNumber = U.isNumber,
  14853. isString = U.isString,
  14854. merge = U.merge,
  14855. normalizeTickInterval = U.normalizeTickInterval,
  14856. objectEach = U.objectEach,
  14857. pick = U.pick,
  14858. relativeLength = U.relativeLength,
  14859. removeEvent = U.removeEvent,
  14860. splat = U.splat,
  14861. syncTimeout = U.syncTimeout;
  14862. /**
  14863. * Options for the path on the Axis to be calculated.
  14864. * @interface Highcharts.AxisPlotLinePathOptionsObject
  14865. */ /**
  14866. * Axis value.
  14867. * @name Highcharts.AxisPlotLinePathOptionsObject#value
  14868. * @type {number|undefined}
  14869. */ /**
  14870. * Line width used for calculation crisp line coordinates. Defaults to 1.
  14871. * @name Highcharts.AxisPlotLinePathOptionsObject#lineWidth
  14872. * @type {number|undefined}
  14873. */ /**
  14874. * If `false`, the function will return null when it falls outside the axis
  14875. * bounds. If `true`, the function will return a path aligned to the plot area
  14876. * sides if it falls outside. If `pass`, it will return a path outside.
  14877. * @name Highcharts.AxisPlotLinePathOptionsObject#force
  14878. * @type {string|boolean|undefined}
  14879. */ /**
  14880. * Used in Highstock. When `true`, plot paths (crosshair, plotLines, gridLines)
  14881. * will be rendered on all axes when defined on the first axis.
  14882. * @name Highcharts.AxisPlotLinePathOptionsObject#acrossPanes
  14883. * @type {boolean|undefined}
  14884. */ /**
  14885. * Use old coordinates (for resizing and rescaling).
  14886. * If not set, defaults to `false`.
  14887. * @name Highcharts.AxisPlotLinePathOptionsObject#old
  14888. * @type {boolean|undefined}
  14889. */ /**
  14890. * If given, return the plot line path of a pixel position on the axis.
  14891. * @name Highcharts.AxisPlotLinePathOptionsObject#translatedValue
  14892. * @type {number|undefined}
  14893. */ /**
  14894. * Used in Polar axes. Reverse the positions for concatenation of polygonal
  14895. * plot bands
  14896. * @name Highcharts.AxisPlotLinePathOptionsObject#reverse
  14897. * @type {boolean|undefined}
  14898. */
  14899. /**
  14900. * Options for crosshairs on axes.
  14901. *
  14902. * @product highstock
  14903. *
  14904. * @typedef {Highcharts.XAxisCrosshairOptions|Highcharts.YAxisCrosshairOptions} Highcharts.AxisCrosshairOptions
  14905. */
  14906. /**
  14907. * @typedef {"navigator"|"pan"|"rangeSelectorButton"|"rangeSelectorInput"|"scrollbar"|"traverseUpButton"|"zoom"} Highcharts.AxisExtremesTriggerValue
  14908. */
  14909. /**
  14910. * @callback Highcharts.AxisEventCallbackFunction
  14911. *
  14912. * @param {Highcharts.Axis} this
  14913. */
  14914. /**
  14915. * @callback Highcharts.AxisLabelsFormatterCallbackFunction
  14916. *
  14917. * @param {Highcharts.AxisLabelsFormatterContextObject<number>} this
  14918. *
  14919. * @param {Highcharts.AxisLabelsFormatterContextObject<string>} that
  14920. *
  14921. * @return {string}
  14922. */
  14923. /**
  14924. * @interface Highcharts.AxisLabelsFormatterContextObject<T>
  14925. */ /**
  14926. * @name Highcharts.AxisLabelsFormatterContextObject<T>#axis
  14927. * @type {Highcharts.Axis}
  14928. */ /**
  14929. * @name Highcharts.AxisLabelsFormatterContextObject<T>#chart
  14930. * @type {Highcharts.Chart}
  14931. */ /**
  14932. * @name Highcharts.AxisLabelsFormatterContextObject<T>#isFirst
  14933. * @type {boolean}
  14934. */ /**
  14935. * @name Highcharts.AxisLabelsFormatterContextObject<T>#isLast
  14936. * @type {boolean}
  14937. */ /**
  14938. * @name Highcharts.AxisLabelsFormatterContextObject<T>#pos
  14939. * @type {number}
  14940. */ /**
  14941. * This can be either a numeric value or a category string.
  14942. * @name Highcharts.AxisLabelsFormatterContextObject<T>#value
  14943. * @type {T}
  14944. */
  14945. /**
  14946. * Options for axes.
  14947. *
  14948. * @typedef {Highcharts.XAxisOptions|Highcharts.YAxisOptions|Highcharts.ZAxisOptions} Highcharts.AxisOptions
  14949. */
  14950. /**
  14951. * @callback Highcharts.AxisPointBreakEventCallbackFunction
  14952. *
  14953. * @param {Highcharts.Axis} this
  14954. *
  14955. * @param {Highcharts.AxisPointBreakEventObject} evt
  14956. */
  14957. /**
  14958. * @interface Highcharts.AxisPointBreakEventObject
  14959. */ /**
  14960. * @name Highcharts.AxisPointBreakEventObject#brk
  14961. * @type {Highcharts.Dictionary<number>}
  14962. */ /**
  14963. * @name Highcharts.AxisPointBreakEventObject#point
  14964. * @type {Highcharts.Point}
  14965. */ /**
  14966. * @name Highcharts.AxisPointBreakEventObject#preventDefault
  14967. * @type {Function}
  14968. */ /**
  14969. * @name Highcharts.AxisPointBreakEventObject#target
  14970. * @type {Highcharts.SVGElement}
  14971. */ /**
  14972. * @name Highcharts.AxisPointBreakEventObject#type
  14973. * @type {"pointBreak"|"pointInBreak"}
  14974. */
  14975. /**
  14976. * @callback Highcharts.AxisSetExtremesEventCallbackFunction
  14977. *
  14978. * @param {Highcharts.Axis} this
  14979. *
  14980. * @param {Highcharts.AxisSetExtremesEventObject} evt
  14981. */
  14982. /**
  14983. * @interface Highcharts.AxisSetExtremesEventObject
  14984. * @extends Highcharts.ExtremesObject
  14985. */ /**
  14986. * @name Highcharts.AxisSetExtremesEventObject#preventDefault
  14987. * @type {Function}
  14988. */ /**
  14989. * @name Highcharts.AxisSetExtremesEventObject#target
  14990. * @type {Highcharts.SVGElement}
  14991. */ /**
  14992. * @name Highcharts.AxisSetExtremesEventObject#trigger
  14993. * @type {Highcharts.AxisExtremesTriggerValue|string}
  14994. */ /**
  14995. * @name Highcharts.AxisSetExtremesEventObject#type
  14996. * @type {"setExtremes"}
  14997. */
  14998. /**
  14999. * @callback Highcharts.AxisTickPositionerCallbackFunction
  15000. *
  15001. * @param {Highcharts.Axis} this
  15002. *
  15003. * @return {Highcharts.AxisTickPositionsArray}
  15004. */
  15005. /**
  15006. * @interface Highcharts.AxisTickPositionsArray
  15007. * @augments Array<number>
  15008. */
  15009. /**
  15010. * @typedef {"high"|"low"|"middle"} Highcharts.AxisTitleAlignValue
  15011. */
  15012. /**
  15013. * @typedef {Highcharts.XAxisTitleOptions|Highcharts.YAxisTitleOptions|Highcharts.ZAxisTitleOptions} Highcharts.AxisTitleOptions
  15014. */
  15015. /**
  15016. * @typedef {"linear"|"logarithmic"|"datetime"|"category"|"treegrid"} Highcharts.AxisTypeValue
  15017. */
  15018. /**
  15019. * The returned object literal from the {@link Highcharts.Axis#getExtremes}
  15020. * function.
  15021. *
  15022. * @interface Highcharts.ExtremesObject
  15023. */ /**
  15024. * The maximum value of the axis' associated series.
  15025. * @name Highcharts.ExtremesObject#dataMax
  15026. * @type {number}
  15027. */ /**
  15028. * The minimum value of the axis' associated series.
  15029. * @name Highcharts.ExtremesObject#dataMin
  15030. * @type {number}
  15031. */ /**
  15032. * The maximum axis value, either automatic or set manually. If the `max` option
  15033. * is not set, `maxPadding` is 0 and `endOnTick` is false, this value will be
  15034. * the same as `dataMax`.
  15035. * @name Highcharts.ExtremesObject#max
  15036. * @type {number}
  15037. */ /**
  15038. * The minimum axis value, either automatic or set manually. If the `min` option
  15039. * is not set, `minPadding` is 0 and `startOnTick` is false, this value will be
  15040. * the same as `dataMin`.
  15041. * @name Highcharts.ExtremesObject#min
  15042. * @type {number}
  15043. */ /**
  15044. * The user defined maximum, either from the `max` option or from a zoom or
  15045. * `setExtremes` action.
  15046. * @name Highcharts.ExtremesObject#userMax
  15047. * @type {number}
  15048. */ /**
  15049. * The user defined minimum, either from the `min` option or from a zoom or
  15050. * `setExtremes` action.
  15051. * @name Highcharts.ExtremesObject#userMin
  15052. * @type {number}
  15053. */
  15054. /**
  15055. * Formatter function for the text of a crosshair label.
  15056. *
  15057. * @callback Highcharts.XAxisCrosshairLabelFormatterCallbackFunction
  15058. *
  15059. * @param {Highcharts.Axis} this
  15060. * Axis context
  15061. *
  15062. * @param {number} value
  15063. * Y value of the data point
  15064. *
  15065. * @return {string}
  15066. */
  15067. ''; // detach doclets above
  15068. var deg2rad = H.deg2rad;
  15069. /**
  15070. * Create a new axis object. Called internally when instanciating a new chart or
  15071. * adding axes by {@link Highcharts.Chart#addAxis}.
  15072. *
  15073. * A chart can have from 0 axes (pie chart) to multiples. In a normal, single
  15074. * series cartesian chart, there is one X axis and one Y axis.
  15075. *
  15076. * The X axis or axes are referenced by {@link Highcharts.Chart.xAxis}, which is
  15077. * an array of Axis objects. If there is only one axis, it can be referenced
  15078. * through `chart.xAxis[0]`, and multiple axes have increasing indices. The same
  15079. * pattern goes for Y axes.
  15080. *
  15081. * If you need to get the axes from a series object, use the `series.xAxis` and
  15082. * `series.yAxis` properties. These are not arrays, as one series can only be
  15083. * associated to one X and one Y axis.
  15084. *
  15085. * A third way to reference the axis programmatically is by `id`. Add an `id` in
  15086. * the axis configuration options, and get the axis by
  15087. * {@link Highcharts.Chart#get}.
  15088. *
  15089. * Configuration options for the axes are given in options.xAxis and
  15090. * options.yAxis.
  15091. *
  15092. * @class
  15093. * @name Highcharts.Axis
  15094. *
  15095. * @param {Highcharts.Chart} chart
  15096. * The Chart instance to apply the axis on.
  15097. *
  15098. * @param {Highcharts.AxisOptions} userOptions
  15099. * Axis options.
  15100. */
  15101. var Axis = /** @class */ (function () {
  15102. /* *
  15103. *
  15104. * Constructors
  15105. *
  15106. * */
  15107. function Axis(chart, userOptions) {
  15108. this.alternateBands = void 0;
  15109. this.bottom = void 0;
  15110. this.categories = void 0;
  15111. this.chart = void 0;
  15112. this.closestPointRange = void 0;
  15113. this.coll = void 0;
  15114. this.hasNames = void 0;
  15115. this.hasVisibleSeries = void 0;
  15116. this.height = void 0;
  15117. this.isLinked = void 0;
  15118. this.labelEdge = void 0; // @todo
  15119. this.labelFormatter = void 0;
  15120. this.left = void 0;
  15121. this.len = void 0;
  15122. this.max = void 0;
  15123. this.maxLabelLength = void 0;
  15124. this.min = void 0;
  15125. this.minorTickInterval = void 0;
  15126. this.minorTicks = void 0;
  15127. this.minPixelPadding = void 0;
  15128. this.names = void 0;
  15129. this.offset = void 0;
  15130. this.options = void 0;
  15131. this.overlap = void 0;
  15132. this.paddedTicks = void 0;
  15133. this.plotLinesAndBands = void 0;
  15134. this.plotLinesAndBandsGroups = void 0;
  15135. this.pointRange = void 0;
  15136. this.pointRangePadding = void 0;
  15137. this.pos = void 0;
  15138. this.positiveValuesOnly = void 0;
  15139. this.right = void 0;
  15140. this.series = void 0;
  15141. this.side = void 0;
  15142. this.tickAmount = void 0;
  15143. this.tickInterval = void 0;
  15144. this.tickmarkOffset = void 0;
  15145. this.tickPositions = void 0;
  15146. this.tickRotCorr = void 0;
  15147. this.ticks = void 0;
  15148. this.top = void 0;
  15149. this.transA = void 0;
  15150. this.transB = void 0;
  15151. this.translationSlope = void 0;
  15152. this.userOptions = void 0;
  15153. this.visible = void 0;
  15154. this.width = void 0;
  15155. this.zoomEnabled = void 0;
  15156. this.init(chart, userOptions);
  15157. }
  15158. /* *
  15159. *
  15160. * Functions
  15161. *
  15162. * */
  15163. /**
  15164. * Overrideable function to initialize the axis.
  15165. *
  15166. * @see {@link Axis}
  15167. *
  15168. * @function Highcharts.Axis#init
  15169. *
  15170. * @param {Highcharts.Chart} chart
  15171. * The Chart instance to apply the axis on.
  15172. *
  15173. * @param {Highcharts.AxisOptions} userOptions
  15174. * Axis options.
  15175. *
  15176. * @fires Highcharts.Axis#event:afterInit
  15177. * @fires Highcharts.Axis#event:init
  15178. */
  15179. Axis.prototype.init = function (chart, userOptions) {
  15180. var isXAxis = userOptions.isX,
  15181. axis = this;
  15182. /**
  15183. * The Chart that the axis belongs to.
  15184. *
  15185. * @name Highcharts.Axis#chart
  15186. * @type {Highcharts.Chart}
  15187. */
  15188. axis.chart = chart;
  15189. /**
  15190. * Whether the axis is horizontal.
  15191. *
  15192. * @name Highcharts.Axis#horiz
  15193. * @type {boolean|undefined}
  15194. */
  15195. axis.horiz = chart.inverted && !axis.isZAxis ? !isXAxis : isXAxis;
  15196. /**
  15197. * Whether the axis is the x-axis.
  15198. *
  15199. * @name Highcharts.Axis#isXAxis
  15200. * @type {boolean|undefined}
  15201. */
  15202. axis.isXAxis = isXAxis;
  15203. /**
  15204. * The collection where the axis belongs, for example `xAxis`, `yAxis`
  15205. * or `colorAxis`. Corresponds to properties on Chart, for example
  15206. * {@link Chart.xAxis}.
  15207. *
  15208. * @name Highcharts.Axis#coll
  15209. * @type {string}
  15210. */
  15211. axis.coll = axis.coll || (isXAxis ? 'xAxis' : 'yAxis');
  15212. fireEvent(this, 'init', { userOptions: userOptions });
  15213. axis.opposite = pick(userOptions.opposite, axis.opposite); // needed in setOptions
  15214. /**
  15215. * The side on which the axis is rendered. 0 is top, 1 is right, 2
  15216. * is bottom and 3 is left.
  15217. *
  15218. * @name Highcharts.Axis#side
  15219. * @type {number}
  15220. */
  15221. axis.side = pick(userOptions.side, axis.side, (axis.horiz ?
  15222. (axis.opposite ? 0 : 2) : // top : bottom
  15223. (axis.opposite ? 1 : 3)) // right : left
  15224. );
  15225. /**
  15226. * Current options for the axis after merge of defaults and user's
  15227. * options.
  15228. *
  15229. * @name Highcharts.Axis#options
  15230. * @type {Highcharts.AxisOptions}
  15231. */
  15232. axis.setOptions(userOptions);
  15233. var options = this.options,
  15234. type = options.type;
  15235. axis.labelFormatter = (options.labels.formatter ||
  15236. // can be overwritten by dynamic format
  15237. axis.defaultLabelFormatter);
  15238. /**
  15239. * User's options for this axis without defaults.
  15240. *
  15241. * @name Highcharts.Axis#userOptions
  15242. * @type {Highcharts.AxisOptions}
  15243. */
  15244. axis.userOptions = userOptions;
  15245. axis.minPixelPadding = 0;
  15246. /**
  15247. * Whether the axis is reversed. Based on the `axis.reversed`,
  15248. * option, but inverted charts have reversed xAxis by default.
  15249. *
  15250. * @name Highcharts.Axis#reversed
  15251. * @type {boolean}
  15252. */
  15253. axis.reversed = pick(options.reversed, axis.reversed);
  15254. axis.visible = options.visible !== false;
  15255. axis.zoomEnabled = options.zoomEnabled !== false;
  15256. // Initial categories
  15257. axis.hasNames =
  15258. type === 'category' || options.categories === true;
  15259. /**
  15260. * If categories are present for the axis, names are used instead of
  15261. * numbers for that axis.
  15262. *
  15263. * Since Highcharts 3.0, categories can also be extracted by giving each
  15264. * point a name and setting axis type to `category`. However, if you
  15265. * have multiple series, best practice remains defining the `categories`
  15266. * array.
  15267. *
  15268. * @see [xAxis.categories](/highcharts/xAxis.categories)
  15269. *
  15270. * @name Highcharts.Axis#categories
  15271. * @type {Array<string>}
  15272. * @readonly
  15273. */
  15274. axis.categories = options.categories || axis.hasNames;
  15275. if (!axis.names) { // Preserve on update (#3830)
  15276. axis.names = [];
  15277. axis.names.keys = {};
  15278. }
  15279. // Placeholder for plotlines and plotbands groups
  15280. axis.plotLinesAndBandsGroups = {};
  15281. // Shorthand types
  15282. axis.positiveValuesOnly = !!axis.logarithmic;
  15283. // Flag, if axis is linked to another axis
  15284. axis.isLinked = defined(options.linkedTo);
  15285. /**
  15286. * List of major ticks mapped by postition on axis.
  15287. *
  15288. * @see {@link Highcharts.Tick}
  15289. *
  15290. * @name Highcharts.Axis#ticks
  15291. * @type {Highcharts.Dictionary<Highcharts.Tick>}
  15292. */
  15293. axis.ticks = {};
  15294. axis.labelEdge = [];
  15295. /**
  15296. * List of minor ticks mapped by position on the axis.
  15297. *
  15298. * @see {@link Highcharts.Tick}
  15299. *
  15300. * @name Highcharts.Axis#minorTicks
  15301. * @type {Highcharts.Dictionary<Highcharts.Tick>}
  15302. */
  15303. axis.minorTicks = {};
  15304. // List of plotLines/Bands
  15305. axis.plotLinesAndBands = [];
  15306. // Alternate bands
  15307. axis.alternateBands = {};
  15308. // Axis metrics
  15309. axis.len = 0;
  15310. axis.minRange = axis.userMinRange = options.minRange || options.maxZoom;
  15311. axis.range = options.range;
  15312. axis.offset = options.offset || 0;
  15313. /**
  15314. * The maximum value of the axis. In a logarithmic axis, this is the
  15315. * logarithm of the real value, and the real value can be obtained from
  15316. * {@link Axis#getExtremes}.
  15317. *
  15318. * @name Highcharts.Axis#max
  15319. * @type {number|null}
  15320. */
  15321. axis.max = null;
  15322. /**
  15323. * The minimum value of the axis. In a logarithmic axis, this is the
  15324. * logarithm of the real value, and the real value can be obtained from
  15325. * {@link Axis#getExtremes}.
  15326. *
  15327. * @name Highcharts.Axis#min
  15328. * @type {number|null}
  15329. */
  15330. axis.min = null;
  15331. /**
  15332. * The processed crosshair options.
  15333. *
  15334. * @name Highcharts.Axis#crosshair
  15335. * @type {boolean|Highcharts.AxisCrosshairOptions}
  15336. */
  15337. axis.crosshair = pick(options.crosshair, splat(chart.options.tooltip.crosshairs)[isXAxis ? 0 : 1], false);
  15338. var events = axis.options.events;
  15339. // Register. Don't add it again on Axis.update().
  15340. if (chart.axes.indexOf(axis) === -1) { //
  15341. if (isXAxis) { // #2713
  15342. chart.axes.splice(chart.xAxis.length, 0, axis);
  15343. }
  15344. else {
  15345. chart.axes.push(axis);
  15346. }
  15347. chart[axis.coll].push(axis);
  15348. }
  15349. /**
  15350. * All series associated to the axis.
  15351. *
  15352. * @name Highcharts.Axis#series
  15353. * @type {Array<Highcharts.Series>}
  15354. */
  15355. axis.series = axis.series || []; // populated by Series
  15356. // Reversed axis
  15357. if (chart.inverted &&
  15358. !axis.isZAxis &&
  15359. isXAxis &&
  15360. typeof axis.reversed === 'undefined') {
  15361. axis.reversed = true;
  15362. }
  15363. axis.labelRotation = axis.options.labels.rotation;
  15364. // register event listeners
  15365. objectEach(events, function (event, eventType) {
  15366. if (isFunction(event)) {
  15367. addEvent(axis, eventType, event);
  15368. }
  15369. });
  15370. fireEvent(this, 'afterInit');
  15371. };
  15372. /**
  15373. * Merge and set options.
  15374. *
  15375. * @private
  15376. * @function Highcharts.Axis#setOptions
  15377. *
  15378. * @param {Highcharts.AxisOptions} userOptions
  15379. * Axis options.
  15380. *
  15381. * @fires Highcharts.Axis#event:afterSetOptions
  15382. */
  15383. Axis.prototype.setOptions = function (userOptions) {
  15384. this.options = merge(Axis.defaultOptions, (this.coll === 'yAxis') && Axis.defaultYAxisOptions, [
  15385. Axis.defaultTopAxisOptions,
  15386. Axis.defaultRightAxisOptions,
  15387. Axis.defaultBottomAxisOptions,
  15388. Axis.defaultLeftAxisOptions
  15389. ][this.side], merge(
  15390. // if set in setOptions (#1053):
  15391. defaultOptions[this.coll], userOptions));
  15392. fireEvent(this, 'afterSetOptions', { userOptions: userOptions });
  15393. };
  15394. /**
  15395. * The default label formatter. The context is a special config object for
  15396. * the label. In apps, use the
  15397. * [labels.formatter](https://api.highcharts.com/highcharts/xAxis.labels.formatter)
  15398. * instead, except when a modification is needed.
  15399. *
  15400. * @function Highcharts.Axis#defaultLabelFormatter
  15401. *
  15402. * @param {Highcharts.AxisLabelsFormatterContextObject<number>|Highcharts.AxisLabelsFormatterContextObject<string>} this
  15403. * Formatter context of axis label.
  15404. *
  15405. * @return {string}
  15406. * The formatted label content.
  15407. */
  15408. Axis.prototype.defaultLabelFormatter = function () {
  15409. var axis = this.axis,
  15410. value = isNumber(this.value) ? this.value : NaN,
  15411. time = axis.chart.time,
  15412. categories = axis.categories,
  15413. dateTimeLabelFormat = this.dateTimeLabelFormat,
  15414. lang = defaultOptions.lang,
  15415. numericSymbols = lang.numericSymbols,
  15416. numSymMagnitude = lang.numericSymbolMagnitude || 1000,
  15417. i = numericSymbols && numericSymbols.length,
  15418. multi,
  15419. ret,
  15420. formatOption = axis.options.labels.format,
  15421. // make sure the same symbol is added for all labels on a linear
  15422. // axis
  15423. numericSymbolDetector = axis.logarithmic ?
  15424. Math.abs(value) :
  15425. axis.tickInterval;
  15426. var chart = this.chart;
  15427. var numberFormatter = chart.numberFormatter;
  15428. if (formatOption) {
  15429. ret = format(formatOption, this, chart);
  15430. }
  15431. else if (categories) {
  15432. ret = "" + this.value;
  15433. }
  15434. else if (dateTimeLabelFormat) { // datetime axis
  15435. ret = time.dateFormat(dateTimeLabelFormat, value);
  15436. }
  15437. else if (i && numericSymbolDetector >= 1000) {
  15438. // Decide whether we should add a numeric symbol like k (thousands)
  15439. // or M (millions). If we are to enable this in tooltip or other
  15440. // places as well, we can move this logic to the numberFormatter and
  15441. // enable it by a parameter.
  15442. while (i-- && typeof ret === 'undefined') {
  15443. multi = Math.pow(numSymMagnitude, i + 1);
  15444. if (
  15445. // Only accept a numeric symbol when the distance is more
  15446. // than a full unit. So for example if the symbol is k, we
  15447. // don't accept numbers like 0.5k.
  15448. numericSymbolDetector >= multi &&
  15449. // Accept one decimal before the symbol. Accepts 0.5k but
  15450. // not 0.25k. How does this work with the previous?
  15451. (value * 10) % multi === 0 &&
  15452. numericSymbols[i] !== null &&
  15453. value !== 0) { // #5480
  15454. ret = numberFormatter(value / multi, -1) + numericSymbols[i];
  15455. }
  15456. }
  15457. }
  15458. if (typeof ret === 'undefined') {
  15459. if (Math.abs(value) >= 10000) { // add thousands separators
  15460. ret = numberFormatter(value, -1);
  15461. }
  15462. else { // small numbers
  15463. ret = numberFormatter(value, -1, void 0, ''); // #2466
  15464. }
  15465. }
  15466. return ret;
  15467. };
  15468. /**
  15469. * Get the minimum and maximum for the series of each axis. The function
  15470. * analyzes the axis series and updates `this.dataMin` and `this.dataMax`.
  15471. *
  15472. * @private
  15473. * @function Highcharts.Axis#getSeriesExtremes
  15474. *
  15475. * @fires Highcharts.Axis#event:afterGetSeriesExtremes
  15476. * @fires Highcharts.Axis#event:getSeriesExtremes
  15477. */
  15478. Axis.prototype.getSeriesExtremes = function () {
  15479. var axis = this,
  15480. chart = axis.chart,
  15481. xExtremes;
  15482. fireEvent(this, 'getSeriesExtremes', null, function () {
  15483. axis.hasVisibleSeries = false;
  15484. // Reset properties in case we're redrawing (#3353)
  15485. axis.dataMin = axis.dataMax = axis.threshold = null;
  15486. axis.softThreshold = !axis.isXAxis;
  15487. if (axis.stacking) {
  15488. axis.stacking.buildStacks();
  15489. }
  15490. // loop through this axis' series
  15491. axis.series.forEach(function (series) {
  15492. if (series.visible ||
  15493. !chart.options.chart.ignoreHiddenSeries) {
  15494. var seriesOptions = series.options,
  15495. xData,
  15496. threshold = seriesOptions.threshold,
  15497. seriesDataMin,
  15498. seriesDataMax;
  15499. axis.hasVisibleSeries = true;
  15500. // Validate threshold in logarithmic axes
  15501. if (axis.positiveValuesOnly && threshold <= 0) {
  15502. threshold = null;
  15503. }
  15504. // Get dataMin and dataMax for X axes
  15505. if (axis.isXAxis) {
  15506. xData = series.xData;
  15507. if (xData.length) {
  15508. var isPositive = function (number) { return number > 0; };
  15509. xData = axis.logarithmic ?
  15510. xData.filter(axis.validatePositiveValue) :
  15511. xData;
  15512. xExtremes = series.getXExtremes(xData);
  15513. // If xData contains values which is not numbers,
  15514. // then filter them out. To prevent performance hit,
  15515. // we only do this after we have already found
  15516. // seriesDataMin because in most cases all data is
  15517. // valid. #5234.
  15518. seriesDataMin = xExtremes.min;
  15519. seriesDataMax = xExtremes.max;
  15520. if (!isNumber(seriesDataMin) &&
  15521. // #5010:
  15522. !(seriesDataMin instanceof Date)) {
  15523. xData = xData.filter(isNumber);
  15524. xExtremes = series.getXExtremes(xData);
  15525. // Do it again with valid data
  15526. seriesDataMin = xExtremes.min;
  15527. seriesDataMax = xExtremes.max;
  15528. }
  15529. if (xData.length) {
  15530. axis.dataMin = Math.min(pick(axis.dataMin, seriesDataMin), seriesDataMin);
  15531. axis.dataMax = Math.max(pick(axis.dataMax, seriesDataMax), seriesDataMax);
  15532. }
  15533. }
  15534. // Get dataMin and dataMax for Y axes, as well as handle
  15535. // stacking and processed data
  15536. }
  15537. else {
  15538. // Get this particular series extremes
  15539. var dataExtremes = series.applyExtremes();
  15540. // Get the dataMin and dataMax so far. If percentage is
  15541. // used, the min and max are always 0 and 100. If
  15542. // seriesDataMin and seriesDataMax is null, then series
  15543. // doesn't have active y data, we continue with nulls
  15544. if (isNumber(dataExtremes.dataMin)) {
  15545. seriesDataMin = dataExtremes.dataMin;
  15546. axis.dataMin = Math.min(pick(axis.dataMin, seriesDataMin), seriesDataMin);
  15547. }
  15548. if (isNumber(dataExtremes.dataMax)) {
  15549. seriesDataMax = dataExtremes.dataMax;
  15550. axis.dataMax = Math.max(pick(axis.dataMax, seriesDataMax), seriesDataMax);
  15551. }
  15552. // Adjust to threshold
  15553. if (defined(threshold)) {
  15554. axis.threshold = threshold;
  15555. }
  15556. // If any series has a hard threshold, it takes
  15557. // precedence
  15558. if (!seriesOptions.softThreshold ||
  15559. axis.positiveValuesOnly) {
  15560. axis.softThreshold = false;
  15561. }
  15562. }
  15563. }
  15564. });
  15565. });
  15566. fireEvent(this, 'afterGetSeriesExtremes');
  15567. };
  15568. /**
  15569. * Translate from axis value to pixel position on the chart, or back. Use
  15570. * the `toPixels` and `toValue` functions in applications.
  15571. *
  15572. * @private
  15573. * @function Highcharts.Axis#translate
  15574. *
  15575. * @param {number} val
  15576. * TO-DO: parameter description
  15577. *
  15578. * @param {boolean|null} [backwards]
  15579. * TO-DO: parameter description
  15580. *
  15581. * @param {boolean|null} [cvsCoord]
  15582. * TO-DO: parameter description
  15583. *
  15584. * @param {boolean|null} [old]
  15585. * TO-DO: parameter description
  15586. *
  15587. * @param {boolean} [handleLog]
  15588. * TO-DO: parameter description
  15589. *
  15590. * @param {number} [pointPlacement]
  15591. * TO-DO: parameter description
  15592. *
  15593. * @return {number|undefined}
  15594. */
  15595. Axis.prototype.translate = function (val, backwards, cvsCoord, old, handleLog, pointPlacement) {
  15596. var axis = this.linkedParent || this, // #1417
  15597. sign = 1,
  15598. cvsOffset = 0,
  15599. localA = old && axis.old ? axis.old.transA : axis.transA,
  15600. localMin = old && axis.old ? axis.old.min : axis.min,
  15601. returnValue = 0,
  15602. minPixelPadding = axis.minPixelPadding,
  15603. doPostTranslate = (axis.isOrdinal ||
  15604. axis.brokenAxis && axis.brokenAxis.hasBreaks ||
  15605. (axis.logarithmic && handleLog)) && axis.lin2val;
  15606. if (!localA) {
  15607. localA = axis.transA;
  15608. }
  15609. // In vertical axes, the canvas coordinates start from 0 at the top like
  15610. // in SVG.
  15611. if (cvsCoord) {
  15612. sign *= -1; // canvas coordinates inverts the value
  15613. cvsOffset = axis.len;
  15614. }
  15615. // Handle reversed axis
  15616. if (axis.reversed) {
  15617. sign *= -1;
  15618. cvsOffset -= sign * (axis.sector || axis.len);
  15619. }
  15620. // From pixels to value
  15621. if (backwards) { // reverse translation
  15622. val = val * sign + cvsOffset;
  15623. val -= minPixelPadding;
  15624. // from chart pixel to value:
  15625. returnValue = val / localA + localMin;
  15626. if (doPostTranslate) { // log and ordinal axes
  15627. returnValue = axis.lin2val(returnValue);
  15628. }
  15629. // From value to pixels
  15630. }
  15631. else {
  15632. if (doPostTranslate) { // log and ordinal axes
  15633. val = axis.val2lin(val);
  15634. }
  15635. returnValue = isNumber(localMin) ?
  15636. (sign * (val - localMin) * localA +
  15637. cvsOffset +
  15638. (sign * minPixelPadding) +
  15639. (isNumber(pointPlacement) ?
  15640. localA * pointPlacement :
  15641. 0)) :
  15642. void 0;
  15643. }
  15644. return returnValue;
  15645. };
  15646. /**
  15647. * Translate a value in terms of axis units into pixels within the chart.
  15648. *
  15649. * @function Highcharts.Axis#toPixels
  15650. *
  15651. * @param {number} value
  15652. * A value in terms of axis units.
  15653. *
  15654. * @param {boolean} paneCoordinates
  15655. * Whether to return the pixel coordinate relative to the chart or just the
  15656. * axis/pane itself.
  15657. *
  15658. * @return {number}
  15659. * Pixel position of the value on the chart or axis.
  15660. */
  15661. Axis.prototype.toPixels = function (value, paneCoordinates) {
  15662. return this.translate(value, false, !this.horiz, null, true) +
  15663. (paneCoordinates ? 0 : this.pos);
  15664. };
  15665. /**
  15666. * Translate a pixel position along the axis to a value in terms of axis
  15667. * units.
  15668. *
  15669. * @function Highcharts.Axis#toValue
  15670. *
  15671. * @param {number} pixel
  15672. * The pixel value coordinate.
  15673. *
  15674. * @param {boolean} [paneCoordinates=false]
  15675. * Whether the input pixel is relative to the chart or just the axis/pane
  15676. * itself.
  15677. *
  15678. * @return {number}
  15679. * The axis value.
  15680. */
  15681. Axis.prototype.toValue = function (pixel, paneCoordinates) {
  15682. return this.translate(pixel - (paneCoordinates ? 0 : this.pos), true, !this.horiz, null, true);
  15683. };
  15684. /**
  15685. * Create the path for a plot line that goes from the given value on
  15686. * this axis, across the plot to the opposite side. Also used internally for
  15687. * grid lines and crosshairs.
  15688. *
  15689. * @function Highcharts.Axis#getPlotLinePath
  15690. *
  15691. * @param {Highcharts.AxisPlotLinePathOptionsObject} options
  15692. * Options for the path.
  15693. *
  15694. * @return {Highcharts.SVGPathArray|null}
  15695. * The SVG path definition for the plot line.
  15696. */
  15697. Axis.prototype.getPlotLinePath = function (options) {
  15698. var axis = this,
  15699. chart = axis.chart,
  15700. axisLeft = axis.left,
  15701. axisTop = axis.top,
  15702. old = options.old,
  15703. value = options.value,
  15704. translatedValue = options.translatedValue,
  15705. lineWidth = options.lineWidth,
  15706. force = options.force,
  15707. x1,
  15708. y1,
  15709. x2,
  15710. y2,
  15711. cHeight = (old && chart.oldChartHeight) || chart.chartHeight,
  15712. cWidth = (old && chart.oldChartWidth) || chart.chartWidth,
  15713. skip,
  15714. transB = axis.transB,
  15715. evt;
  15716. // eslint-disable-next-line valid-jsdoc
  15717. /**
  15718. * Check if x is between a and b. If not, either move to a/b
  15719. * or skip, depending on the force parameter.
  15720. * @private
  15721. */
  15722. function between(x, a, b) {
  15723. if (force !== 'pass' && x < a || x > b) {
  15724. if (force) {
  15725. x = clamp(x, a, b);
  15726. }
  15727. else {
  15728. skip = true;
  15729. }
  15730. }
  15731. return x;
  15732. }
  15733. evt = {
  15734. value: value,
  15735. lineWidth: lineWidth,
  15736. old: old,
  15737. force: force,
  15738. acrossPanes: options.acrossPanes,
  15739. translatedValue: translatedValue
  15740. };
  15741. fireEvent(this, 'getPlotLinePath', evt, function (e) {
  15742. translatedValue = pick(translatedValue, axis.translate(value, null, null, old));
  15743. // Keep the translated value within sane bounds, and avoid Infinity
  15744. // to fail the isNumber test (#7709).
  15745. translatedValue = clamp(translatedValue, -1e5, 1e5);
  15746. x1 = x2 = Math.round(translatedValue + transB);
  15747. y1 = y2 = Math.round(cHeight - translatedValue - transB);
  15748. if (!isNumber(translatedValue)) { // no min or max
  15749. skip = true;
  15750. force = false; // #7175, don't force it when path is invalid
  15751. }
  15752. else if (axis.horiz) {
  15753. y1 = axisTop;
  15754. y2 = cHeight - axis.bottom;
  15755. x1 = x2 = between(x1, axisLeft, axisLeft + axis.width);
  15756. }
  15757. else {
  15758. x1 = axisLeft;
  15759. x2 = cWidth - axis.right;
  15760. y1 = y2 = between(y1, axisTop, axisTop + axis.height);
  15761. }
  15762. e.path = skip && !force ?
  15763. null :
  15764. chart.renderer.crispLine([['M', x1, y1], ['L', x2, y2]], lineWidth || 1);
  15765. });
  15766. return evt.path;
  15767. };
  15768. /**
  15769. * Internal function to get the tick positions of a linear axis to round
  15770. * values like whole tens or every five.
  15771. *
  15772. * @function Highcharts.Axis#getLinearTickPositions
  15773. *
  15774. * @param {number} tickInterval
  15775. * The normalized tick interval.
  15776. *
  15777. * @param {number} min
  15778. * Axis minimum.
  15779. *
  15780. * @param {number} max
  15781. * Axis maximum.
  15782. *
  15783. * @return {Array<number>}
  15784. * An array of axis values where ticks should be placed.
  15785. */
  15786. Axis.prototype.getLinearTickPositions = function (tickInterval, min, max) {
  15787. var pos,
  15788. lastPos,
  15789. roundedMin = correctFloat(Math.floor(min / tickInterval) * tickInterval),
  15790. roundedMax = correctFloat(Math.ceil(max / tickInterval) * tickInterval),
  15791. tickPositions = [],
  15792. precision;
  15793. // When the precision is higher than what we filter out in
  15794. // correctFloat, skip it (#6183).
  15795. if (correctFloat(roundedMin + tickInterval) === roundedMin) {
  15796. precision = 20;
  15797. }
  15798. // For single points, add a tick regardless of the relative position
  15799. // (#2662, #6274)
  15800. if (this.single) {
  15801. return [min];
  15802. }
  15803. // Populate the intermediate values
  15804. pos = roundedMin;
  15805. while (pos <= roundedMax) {
  15806. // Place the tick on the rounded value
  15807. tickPositions.push(pos);
  15808. // Always add the raw tickInterval, not the corrected one.
  15809. pos = correctFloat(pos + tickInterval, precision);
  15810. // If the interval is not big enough in the current min - max range
  15811. // to actually increase the loop variable, we need to break out to
  15812. // prevent endless loop. Issue #619
  15813. if (pos === lastPos) {
  15814. break;
  15815. }
  15816. // Record the last value
  15817. lastPos = pos;
  15818. }
  15819. return tickPositions;
  15820. };
  15821. /**
  15822. * Resolve the new minorTicks/minorTickInterval options into the legacy
  15823. * loosely typed minorTickInterval option.
  15824. *
  15825. * @function Highcharts.Axis#getMinorTickInterval
  15826. *
  15827. * @return {number|"auto"|null}
  15828. */
  15829. Axis.prototype.getMinorTickInterval = function () {
  15830. var options = this.options;
  15831. if (options.minorTicks === true) {
  15832. return pick(options.minorTickInterval, 'auto');
  15833. }
  15834. if (options.minorTicks === false) {
  15835. return null;
  15836. }
  15837. return options.minorTickInterval;
  15838. };
  15839. /**
  15840. * Internal function to return the minor tick positions. For logarithmic
  15841. * axes, the same logic as for major ticks is reused.
  15842. *
  15843. * @function Highcharts.Axis#getMinorTickPositions
  15844. *
  15845. * @return {Array<number>}
  15846. * An array of axis values where ticks should be placed.
  15847. */
  15848. Axis.prototype.getMinorTickPositions = function () {
  15849. var axis = this,
  15850. options = axis.options,
  15851. tickPositions = axis.tickPositions,
  15852. minorTickInterval = axis.minorTickInterval,
  15853. minorTickPositions = [],
  15854. pos,
  15855. pointRangePadding = axis.pointRangePadding || 0,
  15856. min = axis.min - pointRangePadding, // #1498
  15857. max = axis.max + pointRangePadding, // #1498
  15858. range = max - min;
  15859. // If minor ticks get too dense, they are hard to read, and may cause
  15860. // long running script. So we don't draw them.
  15861. if (range && range / minorTickInterval < axis.len / 3) { // #3875
  15862. var logarithmic_1 = axis.logarithmic;
  15863. if (logarithmic_1) {
  15864. // For each interval in the major ticks, compute the minor ticks
  15865. // separately.
  15866. this.paddedTicks.forEach(function (_pos, i, paddedTicks) {
  15867. if (i) {
  15868. minorTickPositions.push.apply(minorTickPositions, logarithmic_1.getLogTickPositions(minorTickInterval, paddedTicks[i - 1], paddedTicks[i], true));
  15869. }
  15870. });
  15871. }
  15872. else if (axis.dateTime &&
  15873. this.getMinorTickInterval() === 'auto') { // #1314
  15874. minorTickPositions = minorTickPositions.concat(axis.getTimeTicks(axis.dateTime.normalizeTimeTickInterval(minorTickInterval), min, max, options.startOfWeek));
  15875. }
  15876. else {
  15877. for (pos = min + (tickPositions[0] - min) % minorTickInterval; pos <= max; pos += minorTickInterval) {
  15878. // Very, very, tight grid lines (#5771)
  15879. if (pos === minorTickPositions[0]) {
  15880. break;
  15881. }
  15882. minorTickPositions.push(pos);
  15883. }
  15884. }
  15885. }
  15886. if (minorTickPositions.length !== 0) {
  15887. axis.trimTicks(minorTickPositions); // #3652 #3743 #1498 #6330
  15888. }
  15889. return minorTickPositions;
  15890. };
  15891. /**
  15892. * Adjust the min and max for the minimum range. Keep in mind that the
  15893. * series data is not yet processed, so we don't have information on data
  15894. * cropping and grouping, or updated `axis.pointRange` or
  15895. * `series.pointRange`. The data can't be processed until we have finally
  15896. * established min and max.
  15897. *
  15898. * @private
  15899. * @function Highcharts.Axis#adjustForMinRange
  15900. */
  15901. Axis.prototype.adjustForMinRange = function () {
  15902. var axis = this,
  15903. options = axis.options,
  15904. min = axis.min,
  15905. max = axis.max,
  15906. log = axis.logarithmic,
  15907. zoomOffset,
  15908. spaceAvailable,
  15909. closestDataRange = 0,
  15910. i,
  15911. distance,
  15912. xData,
  15913. loopLength,
  15914. minArgs,
  15915. maxArgs,
  15916. minRange;
  15917. // Set the automatic minimum range based on the closest point distance
  15918. if (axis.isXAxis &&
  15919. typeof axis.minRange === 'undefined' &&
  15920. !log) {
  15921. if (defined(options.min) || defined(options.max)) {
  15922. axis.minRange = null; // don't do this again
  15923. }
  15924. else {
  15925. // Find the closest distance between raw data points, as opposed
  15926. // to closestPointRange that applies to processed points
  15927. // (cropped and grouped)
  15928. axis.series.forEach(function (series) {
  15929. xData = series.xData;
  15930. loopLength = series.xIncrement ? 1 : xData.length - 1;
  15931. if (xData.length > 1) {
  15932. for (i = loopLength; i > 0; i--) {
  15933. distance = xData[i] - xData[i - 1];
  15934. if (!closestDataRange || distance < closestDataRange) {
  15935. closestDataRange = distance;
  15936. }
  15937. }
  15938. }
  15939. });
  15940. axis.minRange = Math.min(closestDataRange * 5, axis.dataMax - axis.dataMin);
  15941. }
  15942. }
  15943. // if minRange is exceeded, adjust
  15944. if (max - min < axis.minRange) {
  15945. spaceAvailable =
  15946. axis.dataMax - axis.dataMin >=
  15947. axis.minRange;
  15948. minRange = axis.minRange;
  15949. zoomOffset = (minRange - max + min) / 2;
  15950. // if min and max options have been set, don't go beyond it
  15951. minArgs = [
  15952. min - zoomOffset,
  15953. pick(options.min, min - zoomOffset)
  15954. ];
  15955. // If space is available, stay within the data range
  15956. if (spaceAvailable) {
  15957. minArgs[2] = axis.logarithmic ?
  15958. axis.logarithmic.log2lin(axis.dataMin) :
  15959. axis.dataMin;
  15960. }
  15961. min = arrayMax(minArgs);
  15962. maxArgs = [
  15963. min + minRange,
  15964. pick(options.max, min + minRange)
  15965. ];
  15966. // If space is availabe, stay within the data range
  15967. if (spaceAvailable) {
  15968. maxArgs[2] = log ?
  15969. log.log2lin(axis.dataMax) :
  15970. axis.dataMax;
  15971. }
  15972. max = arrayMin(maxArgs);
  15973. // now if the max is adjusted, adjust the min back
  15974. if (max - min < minRange) {
  15975. minArgs[0] = max - minRange;
  15976. minArgs[1] = pick(options.min, max - minRange);
  15977. min = arrayMax(minArgs);
  15978. }
  15979. }
  15980. // Record modified extremes
  15981. axis.min = min;
  15982. axis.max = max;
  15983. };
  15984. // eslint-disable-next-line valid-jsdoc
  15985. /**
  15986. * Find the closestPointRange across all series.
  15987. *
  15988. * @private
  15989. * @function Highcharts.Axis#getClosest
  15990. */
  15991. Axis.prototype.getClosest = function () {
  15992. var ret;
  15993. if (this.categories) {
  15994. ret = 1;
  15995. }
  15996. else {
  15997. this.series.forEach(function (series) {
  15998. var seriesClosest = series.closestPointRange,
  15999. visible = series.visible ||
  16000. !series.chart.options.chart.ignoreHiddenSeries;
  16001. if (!series.noSharedTooltip &&
  16002. defined(seriesClosest) &&
  16003. visible) {
  16004. ret = defined(ret) ?
  16005. Math.min(ret, seriesClosest) :
  16006. seriesClosest;
  16007. }
  16008. });
  16009. }
  16010. return ret;
  16011. };
  16012. /**
  16013. * When a point name is given and no x, search for the name in the existing
  16014. * categories, or if categories aren't provided, search names or create a
  16015. * new category (#2522).
  16016. * @private
  16017. * @function Highcharts.Axis#nameToX
  16018. *
  16019. * @param {Highcharts.Point} point
  16020. * The point to inspect.
  16021. *
  16022. * @return {number}
  16023. * The X value that the point is given.
  16024. */
  16025. Axis.prototype.nameToX = function (point) {
  16026. var explicitCategories = isArray(this.categories),
  16027. names = explicitCategories ? this.categories : this.names,
  16028. nameX = point.options.x,
  16029. x;
  16030. point.series.requireSorting = false;
  16031. if (!defined(nameX)) {
  16032. nameX = this.options.uniqueNames === false ?
  16033. point.series.autoIncrement() :
  16034. (explicitCategories ?
  16035. names.indexOf(point.name) :
  16036. pick(names.keys[point.name], -1));
  16037. }
  16038. if (nameX === -1) { // Not found in currenct categories
  16039. if (!explicitCategories) {
  16040. x = names.length;
  16041. }
  16042. }
  16043. else {
  16044. x = nameX;
  16045. }
  16046. // Write the last point's name to the names array
  16047. if (typeof x !== 'undefined') {
  16048. this.names[x] = point.name;
  16049. // Backwards mapping is much faster than array searching (#7725)
  16050. this.names.keys[point.name] = x;
  16051. }
  16052. return x;
  16053. };
  16054. /**
  16055. * When changes have been done to series data, update the axis.names.
  16056. *
  16057. * @private
  16058. * @function Highcharts.Axis#updateNames
  16059. */
  16060. Axis.prototype.updateNames = function () {
  16061. var axis = this,
  16062. names = this.names,
  16063. i = names.length;
  16064. if (i > 0) {
  16065. Object.keys(names.keys).forEach(function (key) {
  16066. delete (names.keys)[key];
  16067. });
  16068. names.length = 0;
  16069. this.minRange = this.userMinRange; // Reset
  16070. (this.series || []).forEach(function (series) {
  16071. // Reset incrementer (#5928)
  16072. series.xIncrement = null;
  16073. // When adding a series, points are not yet generated
  16074. if (!series.points || series.isDirtyData) {
  16075. // When we're updating the series with data that is longer
  16076. // than it was, and cropThreshold is passed, we need to make
  16077. // sure that the axis.max is increased _before_ running the
  16078. // premature processData. Otherwise this early iteration of
  16079. // processData will crop the points to axis.max, and the
  16080. // names array will be too short (#5857).
  16081. axis.max = Math.max(axis.max, series.xData.length - 1);
  16082. series.processData();
  16083. series.generatePoints();
  16084. }
  16085. series.data.forEach(function (point, i) {
  16086. var x;
  16087. if (point &&
  16088. point.options &&
  16089. typeof point.name !== 'undefined' // #9562
  16090. ) {
  16091. x = axis.nameToX(point);
  16092. if (typeof x !== 'undefined' && x !== point.x) {
  16093. point.x = x;
  16094. series.xData[i] = x;
  16095. }
  16096. }
  16097. });
  16098. });
  16099. }
  16100. };
  16101. /**
  16102. * Update translation information.
  16103. *
  16104. * @private
  16105. * @function Highcharts.Axis#setAxisTranslation
  16106. *
  16107. * @fires Highcharts.Axis#event:afterSetAxisTranslation
  16108. */
  16109. Axis.prototype.setAxisTranslation = function () {
  16110. var axis = this,
  16111. range = axis.max - axis.min,
  16112. pointRange = axis.axisPointRange || 0,
  16113. closestPointRange,
  16114. minPointOffset = 0,
  16115. pointRangePadding = 0,
  16116. linkedParent = axis.linkedParent,
  16117. ordinalCorrection,
  16118. hasCategories = !!axis.categories,
  16119. transA = axis.transA,
  16120. isXAxis = axis.isXAxis;
  16121. // Adjust translation for padding. Y axis with categories need to go
  16122. // through the same (#1784).
  16123. if (isXAxis || hasCategories || pointRange) {
  16124. // Get the closest points
  16125. closestPointRange = axis.getClosest();
  16126. if (linkedParent) {
  16127. minPointOffset = linkedParent.minPointOffset;
  16128. pointRangePadding = linkedParent.pointRangePadding;
  16129. }
  16130. else {
  16131. axis.series.forEach(function (series) {
  16132. var seriesPointRange = hasCategories ?
  16133. 1 :
  16134. (isXAxis ?
  16135. pick(series.options.pointRange,
  16136. closestPointRange, 0) :
  16137. (axis.axisPointRange || 0)), // #2806
  16138. pointPlacement = series.options.pointPlacement;
  16139. pointRange = Math.max(pointRange, seriesPointRange);
  16140. if (!axis.single || hasCategories) {
  16141. // TODO: series should internally set x- and y-
  16142. // pointPlacement to simplify this logic.
  16143. var isPointPlacementAxis = series.is('xrange') ? !isXAxis : isXAxis;
  16144. // minPointOffset is the value padding to the left of
  16145. // the axis in order to make room for points with a
  16146. // pointRange, typically columns. When the
  16147. // pointPlacement option is 'between' or 'on', this
  16148. // padding does not apply.
  16149. minPointOffset = Math.max(minPointOffset, isPointPlacementAxis && isString(pointPlacement) ?
  16150. 0 :
  16151. seriesPointRange / 2);
  16152. // Determine the total padding needed to the length of
  16153. // the axis to make room for the pointRange. If the
  16154. // series' pointPlacement is 'on', no padding is added.
  16155. pointRangePadding = Math.max(pointRangePadding, isPointPlacementAxis && pointPlacement === 'on' ?
  16156. 0 :
  16157. seriesPointRange);
  16158. }
  16159. });
  16160. }
  16161. // Record minPointOffset and pointRangePadding
  16162. ordinalCorrection = axis.ordinal && axis.ordinal.slope && closestPointRange ?
  16163. axis.ordinal.slope / closestPointRange :
  16164. 1; // #988, #1853
  16165. axis.minPointOffset = minPointOffset =
  16166. minPointOffset * ordinalCorrection;
  16167. axis.pointRangePadding =
  16168. pointRangePadding = pointRangePadding * ordinalCorrection;
  16169. // pointRange means the width reserved for each point, like in a
  16170. // column chart
  16171. axis.pointRange = Math.min(pointRange, axis.single && hasCategories ? 1 : range);
  16172. // closestPointRange means the closest distance between points. In
  16173. // columns it is mostly equal to pointRange, but in lines pointRange
  16174. // is 0 while closestPointRange is some other value
  16175. if (isXAxis) {
  16176. axis.closestPointRange = closestPointRange;
  16177. }
  16178. }
  16179. // Secondary values
  16180. axis.translationSlope = axis.transA = transA =
  16181. axis.staticScale ||
  16182. axis.len / ((range + pointRangePadding) || 1);
  16183. // Translation addend
  16184. axis.transB = axis.horiz ? axis.left : axis.bottom;
  16185. axis.minPixelPadding = transA * minPointOffset;
  16186. fireEvent(this, 'afterSetAxisTranslation');
  16187. };
  16188. /**
  16189. * @private
  16190. * @function Highcharts.Axis#minFromRange
  16191. *
  16192. * @return {number}
  16193. */
  16194. Axis.prototype.minFromRange = function () {
  16195. var axis = this;
  16196. return axis.max - axis.range;
  16197. };
  16198. /**
  16199. * Set the tick positions to round values and optionally extend the extremes
  16200. * to the nearest tick.
  16201. *
  16202. * @private
  16203. * @function Highcharts.Axis#setTickInterval
  16204. *
  16205. * @param {boolean} secondPass
  16206. * TO-DO: parameter description
  16207. *
  16208. * @fires Highcharts.Axis#event:foundExtremes
  16209. */
  16210. Axis.prototype.setTickInterval = function (secondPass) {
  16211. var axis = this,
  16212. chart = axis.chart,
  16213. log = axis.logarithmic,
  16214. options = axis.options,
  16215. isXAxis = axis.isXAxis,
  16216. isLinked = axis.isLinked,
  16217. maxPadding = options.maxPadding,
  16218. minPadding = options.minPadding,
  16219. length,
  16220. linkedParentExtremes,
  16221. tickIntervalOption = options.tickInterval,
  16222. minTickInterval,
  16223. tickPixelIntervalOption = options.tickPixelInterval,
  16224. categories = axis.categories,
  16225. threshold = isNumber(axis.threshold) ? axis.threshold : null,
  16226. softThreshold = axis.softThreshold,
  16227. thresholdMin,
  16228. thresholdMax,
  16229. hardMin,
  16230. hardMax;
  16231. if (!axis.dateTime && !categories && !isLinked) {
  16232. this.getTickAmount();
  16233. }
  16234. // Min or max set either by zooming/setExtremes or initial options
  16235. hardMin = pick(axis.userMin, options.min);
  16236. hardMax = pick(axis.userMax, options.max);
  16237. // Linked axis gets the extremes from the parent axis
  16238. if (isLinked) {
  16239. axis.linkedParent = chart[axis.coll][options.linkedTo];
  16240. linkedParentExtremes = axis.linkedParent.getExtremes();
  16241. axis.min = pick(linkedParentExtremes.min, linkedParentExtremes.dataMin);
  16242. axis.max = pick(linkedParentExtremes.max, linkedParentExtremes.dataMax);
  16243. if (options.type !== axis.linkedParent.options.type) {
  16244. // Can't link axes of different type
  16245. error(11, 1, chart);
  16246. }
  16247. // Initial min and max from the extreme data values
  16248. }
  16249. else {
  16250. // Adjust to hard threshold
  16251. if (softThreshold && defined(threshold)) {
  16252. if (axis.dataMin >= threshold) {
  16253. thresholdMin = threshold;
  16254. minPadding = 0;
  16255. }
  16256. else if (axis.dataMax <= threshold) {
  16257. thresholdMax = threshold;
  16258. maxPadding = 0;
  16259. }
  16260. }
  16261. axis.min = pick(hardMin, thresholdMin, axis.dataMin);
  16262. axis.max = pick(hardMax, thresholdMax, axis.dataMax);
  16263. }
  16264. if (log) {
  16265. if (axis.positiveValuesOnly &&
  16266. !secondPass &&
  16267. Math.min(axis.min, pick(axis.dataMin, axis.min)) <= 0) { // #978
  16268. // Can't plot negative values on log axis
  16269. error(10, 1, chart);
  16270. }
  16271. // The correctFloat cures #934, float errors on full tens. But it
  16272. // was too aggressive for #4360 because of conversion back to lin,
  16273. // therefore use precision 15.
  16274. axis.min = correctFloat(log.log2lin(axis.min), 16);
  16275. axis.max = correctFloat(log.log2lin(axis.max), 16);
  16276. }
  16277. // handle zoomed range
  16278. if (axis.range && defined(axis.max)) {
  16279. // #618, #6773:
  16280. axis.userMin = axis.min = hardMin =
  16281. Math.max(axis.dataMin, axis.minFromRange());
  16282. axis.userMax = hardMax = axis.max;
  16283. axis.range = null; // don't use it when running setExtremes
  16284. }
  16285. // Hook for Highstock Scroller. Consider combining with beforePadding.
  16286. fireEvent(axis, 'foundExtremes');
  16287. // Hook for adjusting this.min and this.max. Used by bubble series.
  16288. if (axis.beforePadding) {
  16289. axis.beforePadding();
  16290. }
  16291. // adjust min and max for the minimum range
  16292. axis.adjustForMinRange();
  16293. // Pad the values to get clear of the chart's edges. To avoid
  16294. // tickInterval taking the padding into account, we do this after
  16295. // computing tick interval (#1337).
  16296. if (!categories &&
  16297. !axis.axisPointRange &&
  16298. !(axis.stacking && axis.stacking.usePercentage) &&
  16299. !isLinked &&
  16300. defined(axis.min) &&
  16301. defined(axis.max)) {
  16302. length = axis.max - axis.min;
  16303. if (length) {
  16304. if (!defined(hardMin) && minPadding) {
  16305. axis.min -= length * minPadding;
  16306. }
  16307. if (!defined(hardMax) && maxPadding) {
  16308. axis.max += length * maxPadding;
  16309. }
  16310. }
  16311. }
  16312. // Handle options for floor, ceiling, softMin and softMax (#6359)
  16313. if (!isNumber(axis.userMin)) {
  16314. if (isNumber(options.softMin) && options.softMin < axis.min) {
  16315. axis.min = hardMin = options.softMin; // #6894
  16316. }
  16317. if (isNumber(options.floor)) {
  16318. axis.min = Math.max(axis.min, options.floor);
  16319. }
  16320. }
  16321. if (!isNumber(axis.userMax)) {
  16322. if (isNumber(options.softMax) && options.softMax > axis.max) {
  16323. axis.max = hardMax = options.softMax; // #6894
  16324. }
  16325. if (isNumber(options.ceiling)) {
  16326. axis.max = Math.min(axis.max, options.ceiling);
  16327. }
  16328. }
  16329. // When the threshold is soft, adjust the extreme value only if the data
  16330. // extreme and the padded extreme land on either side of the threshold.
  16331. // For example, a series of [0, 1, 2, 3] would make the yAxis add a tick
  16332. // for -1 because of the default minPadding and startOnTick options.
  16333. // This is prevented by the softThreshold option.
  16334. if (softThreshold && defined(axis.dataMin)) {
  16335. threshold = threshold || 0;
  16336. if (!defined(hardMin) &&
  16337. axis.min < threshold &&
  16338. axis.dataMin >= threshold) {
  16339. axis.min = axis.options.minRange ?
  16340. Math.min(threshold, axis.max -
  16341. axis.minRange) :
  16342. threshold;
  16343. }
  16344. else if (!defined(hardMax) &&
  16345. axis.max > threshold &&
  16346. axis.dataMax <= threshold) {
  16347. axis.max = axis.options.minRange ?
  16348. Math.max(threshold, axis.min +
  16349. axis.minRange) :
  16350. threshold;
  16351. }
  16352. }
  16353. // If min is bigger than highest, or if max less than lowest value, the
  16354. // chart should not render points. (#14417)
  16355. if (isNumber(axis.min) &&
  16356. isNumber(axis.max) &&
  16357. !this.chart.polar &&
  16358. (axis.min > axis.max)) {
  16359. if (defined(axis.options.min)) {
  16360. axis.max = axis.min;
  16361. }
  16362. else if (defined(axis.options.max)) {
  16363. axis.min = axis.max;
  16364. }
  16365. }
  16366. // get tickInterval
  16367. if (axis.min === axis.max ||
  16368. typeof axis.min === 'undefined' ||
  16369. typeof axis.max === 'undefined') {
  16370. axis.tickInterval = 1;
  16371. }
  16372. else if (isLinked &&
  16373. !tickIntervalOption &&
  16374. tickPixelIntervalOption ===
  16375. axis.linkedParent.options.tickPixelInterval) {
  16376. axis.tickInterval = tickIntervalOption =
  16377. axis.linkedParent.tickInterval;
  16378. }
  16379. else {
  16380. axis.tickInterval = pick(tickIntervalOption, this.tickAmount ?
  16381. ((axis.max - axis.min) /
  16382. Math.max(this.tickAmount - 1, 1)) :
  16383. void 0,
  16384. // For categoried axis, 1 is default, for linear axis use
  16385. // tickPix
  16386. categories ?
  16387. 1 :
  16388. // don't let it be more than the data range
  16389. (axis.max - axis.min) *
  16390. tickPixelIntervalOption /
  16391. Math.max(axis.len, tickPixelIntervalOption));
  16392. }
  16393. // Now we're finished detecting min and max, crop and group series data.
  16394. // This is in turn needed in order to find tick positions in ordinal
  16395. // axes.
  16396. if (isXAxis && !secondPass) {
  16397. axis.series.forEach(function (series) {
  16398. var _a,
  16399. _b;
  16400. series.processData(axis.min !== ((_a = axis.old) === null || _a === void 0 ? void 0 : _a.min) || axis.max !== ((_b = axis.old) === null || _b === void 0 ? void 0 : _b.max));
  16401. });
  16402. }
  16403. // set the translation factor used in translate function
  16404. axis.setAxisTranslation();
  16405. // hook for ordinal axes and radial axes
  16406. fireEvent(this, 'initialAxisTranslation');
  16407. // In column-like charts, don't cramp in more ticks than there are
  16408. // points (#1943, #4184)
  16409. if (axis.pointRange && !tickIntervalOption) {
  16410. axis.tickInterval = Math.max(axis.pointRange, axis.tickInterval);
  16411. }
  16412. // Before normalizing the tick interval, handle minimum tick interval.
  16413. // This applies only if tickInterval is not defined.
  16414. minTickInterval = pick(options.minTickInterval,
  16415. // In datetime axes, don't go below the data interval, except when
  16416. // there are scatter-like series involved (#13369).
  16417. axis.dateTime &&
  16418. !axis.series.some(function (s) { return s.noSharedTooltip; }) ?
  16419. axis.closestPointRange : 0);
  16420. if (!tickIntervalOption && axis.tickInterval < minTickInterval) {
  16421. axis.tickInterval = minTickInterval;
  16422. }
  16423. // for linear axes, get magnitude and normalize the interval
  16424. if (!axis.dateTime && !axis.logarithmic && !tickIntervalOption) {
  16425. axis.tickInterval = normalizeTickInterval(axis.tickInterval, void 0, getMagnitude(axis.tickInterval), pick(options.allowDecimals,
  16426. // If the tick interval is greather than 0.5, avoid
  16427. // decimals, as linear axes are often used to render
  16428. // discrete values. #3363. If a tick amount is set, allow
  16429. // decimals by default, as it increases the chances for a
  16430. // good fit.
  16431. axis.tickInterval < 0.5 || this.tickAmount !== void 0), !!this.tickAmount);
  16432. }
  16433. // Prevent ticks from getting so close that we can't draw the labels
  16434. if (!this.tickAmount) {
  16435. axis.tickInterval = axis.unsquish();
  16436. }
  16437. this.setTickPositions();
  16438. };
  16439. /**
  16440. * Now we have computed the normalized tickInterval, get the tick positions.
  16441. *
  16442. * @private
  16443. * @function Highcharts.Axis#setTickPositions
  16444. *
  16445. * @fires Highcharts.Axis#event:afterSetTickPositions
  16446. */
  16447. Axis.prototype.setTickPositions = function () {
  16448. var axis = this,
  16449. options = this.options,
  16450. tickPositions,
  16451. tickPositionsOption = options.tickPositions,
  16452. minorTickIntervalOption = this.getMinorTickInterval(),
  16453. tickPositioner = options.tickPositioner,
  16454. hasVerticalPanning = this.hasVerticalPanning(),
  16455. isColorAxis = this.coll === 'colorAxis',
  16456. startOnTick = (isColorAxis || !hasVerticalPanning) && options.startOnTick,
  16457. endOnTick = (isColorAxis || !hasVerticalPanning) && options.endOnTick;
  16458. // Set the tickmarkOffset
  16459. this.tickmarkOffset = (this.categories &&
  16460. options.tickmarkPlacement === 'between' &&
  16461. this.tickInterval === 1) ? 0.5 : 0; // #3202
  16462. // get minorTickInterval
  16463. this.minorTickInterval =
  16464. minorTickIntervalOption === 'auto' &&
  16465. this.tickInterval ?
  16466. this.tickInterval / 5 :
  16467. minorTickIntervalOption;
  16468. // When there is only one point, or all points have the same value on
  16469. // this axis, then min and max are equal and tickPositions.length is 0
  16470. // or 1. In this case, add some padding in order to center the point,
  16471. // but leave it with one tick. #1337.
  16472. this.single =
  16473. this.min === this.max &&
  16474. defined(this.min) &&
  16475. !this.tickAmount &&
  16476. (
  16477. // Data is on integer (#6563)
  16478. parseInt(this.min, 10) === this.min ||
  16479. // Between integers and decimals are not allowed (#6274)
  16480. options.allowDecimals !== false);
  16481. /**
  16482. * Contains the current positions that are laid out on the axis. The
  16483. * positions are numbers in terms of axis values. In a category axis
  16484. * they are integers, in a datetime axis they are also integers, but
  16485. * designating milliseconds.
  16486. *
  16487. * This property is read only - for modifying the tick positions, use
  16488. * the `tickPositioner` callback or [axis.tickPositions(
  16489. * https://api.highcharts.com/highcharts/xAxis.tickPositions) option
  16490. * instead.
  16491. *
  16492. * @name Highcharts.Axis#tickPositions
  16493. * @type {Highcharts.AxisTickPositionsArray|undefined}
  16494. */
  16495. this.tickPositions =
  16496. // Find the tick positions. Work on a copy (#1565)
  16497. tickPositions =
  16498. (tickPositionsOption && tickPositionsOption.slice());
  16499. if (!tickPositions) {
  16500. // Too many ticks (#6405). Create a friendly warning and provide two
  16501. // ticks so at least we can show the data series.
  16502. if ((!axis.ordinal || !axis.ordinal.positions) &&
  16503. ((this.max - this.min) /
  16504. this.tickInterval >
  16505. Math.max(2 * this.len, 200))) {
  16506. tickPositions = [this.min, this.max];
  16507. error(19, false, this.chart);
  16508. }
  16509. else if (axis.dateTime) {
  16510. tickPositions = axis.getTimeTicks(axis.dateTime.normalizeTimeTickInterval(this.tickInterval, options.units), this.min, this.max, options.startOfWeek, axis.ordinal && axis.ordinal.positions, this.closestPointRange, true);
  16511. }
  16512. else if (axis.logarithmic) {
  16513. tickPositions = axis.logarithmic.getLogTickPositions(this.tickInterval, this.min, this.max);
  16514. }
  16515. else {
  16516. tickPositions = this.getLinearTickPositions(this.tickInterval, this.min, this.max);
  16517. }
  16518. // Too dense ticks, keep only the first and last (#4477)
  16519. if (tickPositions.length > this.len) {
  16520. tickPositions = [tickPositions[0], tickPositions.pop()];
  16521. // Reduce doubled value (#7339)
  16522. if (tickPositions[0] === tickPositions[1]) {
  16523. tickPositions.length = 1;
  16524. }
  16525. }
  16526. this.tickPositions = tickPositions;
  16527. // Run the tick positioner callback, that allows modifying auto tick
  16528. // positions.
  16529. if (tickPositioner) {
  16530. tickPositioner = tickPositioner.apply(axis, [this.min, this.max]);
  16531. if (tickPositioner) {
  16532. this.tickPositions = tickPositions = tickPositioner;
  16533. }
  16534. }
  16535. }
  16536. // Reset min/max or remove extremes based on start/end on tick
  16537. this.paddedTicks = tickPositions.slice(0); // Used for logarithmic minor
  16538. this.trimTicks(tickPositions, startOnTick, endOnTick);
  16539. if (!this.isLinked) {
  16540. // Substract half a unit (#2619, #2846, #2515, #3390),
  16541. // but not in case of multiple ticks (#6897)
  16542. if (this.single &&
  16543. tickPositions.length < 2 &&
  16544. !this.categories &&
  16545. !this.series.some(function (s) {
  16546. return (s.is('heatmap') && s.options.pointPlacement === 'between');
  16547. })) {
  16548. this.min -= 0.5;
  16549. this.max += 0.5;
  16550. }
  16551. if (!tickPositionsOption && !tickPositioner) {
  16552. this.adjustTickAmount();
  16553. }
  16554. }
  16555. fireEvent(this, 'afterSetTickPositions');
  16556. };
  16557. /**
  16558. * Handle startOnTick and endOnTick by either adapting to padding min/max or
  16559. * rounded min/max. Also handle single data points.
  16560. *
  16561. * @private
  16562. * @function Highcharts.Axis#trimTicks
  16563. *
  16564. * @param {Array<number>} tickPositions
  16565. * TO-DO: parameter description
  16566. *
  16567. * @param {boolean} [startOnTick]
  16568. * TO-DO: parameter description
  16569. *
  16570. * @param {boolean} [endOnTick]
  16571. * TO-DO: parameter description
  16572. */
  16573. Axis.prototype.trimTicks = function (tickPositions, startOnTick, endOnTick) {
  16574. var roundedMin = tickPositions[0],
  16575. roundedMax = tickPositions[tickPositions.length - 1],
  16576. minPointOffset = (!this.isOrdinal && this.minPointOffset) || 0; // (#12716)
  16577. fireEvent(this, 'trimTicks');
  16578. if (!this.isLinked) {
  16579. if (startOnTick && roundedMin !== -Infinity) { // #6502
  16580. this.min = roundedMin;
  16581. }
  16582. else {
  16583. while (this.min - minPointOffset > tickPositions[0]) {
  16584. tickPositions.shift();
  16585. }
  16586. }
  16587. if (endOnTick) {
  16588. this.max = roundedMax;
  16589. }
  16590. else {
  16591. while (this.max + minPointOffset <
  16592. tickPositions[tickPositions.length - 1]) {
  16593. tickPositions.pop();
  16594. }
  16595. }
  16596. // If no tick are left, set one tick in the middle (#3195)
  16597. if (tickPositions.length === 0 &&
  16598. defined(roundedMin) &&
  16599. !this.options.tickPositions) {
  16600. tickPositions.push((roundedMax + roundedMin) / 2);
  16601. }
  16602. }
  16603. };
  16604. /**
  16605. * Check if there are multiple axes in the same pane.
  16606. *
  16607. * @private
  16608. * @function Highcharts.Axis#alignToOthers
  16609. *
  16610. * @return {boolean|undefined}
  16611. * True if there are other axes.
  16612. */
  16613. Axis.prototype.alignToOthers = function () {
  16614. var axis = this,
  16615. others = // Whether there is another axis to pair with this one
  16616. {},
  16617. hasOther,
  16618. options = axis.options;
  16619. if (
  16620. // Only if alignTicks is true
  16621. this.chart.options.chart.alignTicks !== false &&
  16622. options.alignTicks !== false &&
  16623. // Disabled when startOnTick or endOnTick are false (#7604)
  16624. options.startOnTick !== false &&
  16625. options.endOnTick !== false &&
  16626. // Don't try to align ticks on a log axis, they are not evenly
  16627. // spaced (#6021)
  16628. !axis.logarithmic) {
  16629. this.chart[this.coll].forEach(function (axis) {
  16630. var otherOptions = axis.options, horiz = axis.horiz, key = [
  16631. horiz ? otherOptions.left : otherOptions.top,
  16632. otherOptions.width,
  16633. otherOptions.height,
  16634. otherOptions.pane
  16635. ].join(',');
  16636. if (axis.series.length) { // #4442
  16637. if (others[key]) {
  16638. hasOther = true; // #4201
  16639. }
  16640. else {
  16641. others[key] = 1;
  16642. }
  16643. }
  16644. });
  16645. }
  16646. return hasOther;
  16647. };
  16648. /**
  16649. * Find the max ticks of either the x and y axis collection, and record it
  16650. * in `this.tickAmount`.
  16651. *
  16652. * @private
  16653. * @function Highcharts.Axis#getTickAmount
  16654. */
  16655. Axis.prototype.getTickAmount = function () {
  16656. var axis = this,
  16657. options = this.options,
  16658. tickAmount = options.tickAmount,
  16659. tickPixelInterval = options.tickPixelInterval;
  16660. if (!defined(options.tickInterval) &&
  16661. !tickAmount &&
  16662. this.len < tickPixelInterval &&
  16663. !this.isRadial &&
  16664. !axis.logarithmic &&
  16665. options.startOnTick &&
  16666. options.endOnTick) {
  16667. tickAmount = 2;
  16668. }
  16669. if (!tickAmount && this.alignToOthers()) {
  16670. // Add 1 because 4 tick intervals require 5 ticks (including first
  16671. // and last)
  16672. tickAmount = Math.ceil(this.len / tickPixelInterval) + 1;
  16673. }
  16674. // For tick amounts of 2 and 3, compute five ticks and remove the
  16675. // intermediate ones. This prevents the axis from adding ticks that are
  16676. // too far away from the data extremes.
  16677. if (tickAmount < 4) {
  16678. this.finalTickAmt = tickAmount;
  16679. tickAmount = 5;
  16680. }
  16681. this.tickAmount = tickAmount;
  16682. };
  16683. /**
  16684. * When using multiple axes, adjust the number of ticks to match the highest
  16685. * number of ticks in that group.
  16686. *
  16687. * @private
  16688. * @function Highcharts.Axis#adjustTickAmount
  16689. */
  16690. Axis.prototype.adjustTickAmount = function () {
  16691. var axis = this,
  16692. axisOptions = axis.options,
  16693. tickInterval = axis.tickInterval,
  16694. tickPositions = axis.tickPositions,
  16695. tickAmount = axis.tickAmount,
  16696. finalTickAmt = axis.finalTickAmt,
  16697. currentTickAmount = tickPositions && tickPositions.length,
  16698. threshold = pick(axis.threshold,
  16699. axis.softThreshold ? 0 : null),
  16700. len,
  16701. i;
  16702. if (axis.hasData() && isNumber(axis.min) && isNumber(axis.max)) { // #14769
  16703. if (currentTickAmount < tickAmount) {
  16704. while (tickPositions.length < tickAmount) {
  16705. // Extend evenly for both sides unless we're on the
  16706. // threshold (#3965)
  16707. if (tickPositions.length % 2 ||
  16708. axis.min === threshold) {
  16709. // to the end
  16710. tickPositions.push(correctFloat(tickPositions[tickPositions.length - 1] +
  16711. tickInterval));
  16712. }
  16713. else {
  16714. // to the start
  16715. tickPositions.unshift(correctFloat(tickPositions[0] - tickInterval));
  16716. }
  16717. }
  16718. axis.transA *= (currentTickAmount - 1) / (tickAmount - 1);
  16719. // Do not crop when ticks are not extremes (#9841)
  16720. axis.min = axisOptions.startOnTick ?
  16721. tickPositions[0] :
  16722. Math.min(axis.min, tickPositions[0]);
  16723. axis.max = axisOptions.endOnTick ?
  16724. tickPositions[tickPositions.length - 1] :
  16725. Math.max(axis.max, tickPositions[tickPositions.length - 1]);
  16726. // We have too many ticks, run second pass to try to reduce ticks
  16727. }
  16728. else if (currentTickAmount > tickAmount) {
  16729. axis.tickInterval *= 2;
  16730. axis.setTickPositions();
  16731. }
  16732. // The finalTickAmt property is set in getTickAmount
  16733. if (defined(finalTickAmt)) {
  16734. i = len = tickPositions.length;
  16735. while (i--) {
  16736. if (
  16737. // Remove every other tick
  16738. (finalTickAmt === 3 && i % 2 === 1) ||
  16739. // Remove all but first and last
  16740. (finalTickAmt <= 2 && i > 0 && i < len - 1)) {
  16741. tickPositions.splice(i, 1);
  16742. }
  16743. }
  16744. axis.finalTickAmt = void 0;
  16745. }
  16746. }
  16747. };
  16748. /**
  16749. * Set the scale based on data min and max, user set min and max or options.
  16750. *
  16751. * @private
  16752. * @function Highcharts.Axis#setScale
  16753. *
  16754. * @fires Highcharts.Axis#event:afterSetScale
  16755. */
  16756. Axis.prototype.setScale = function () {
  16757. var _a,
  16758. _b,
  16759. _c,
  16760. _d,
  16761. _e;
  16762. var axis = this,
  16763. isDirtyAxisLength,
  16764. isDirtyData = false,
  16765. isXAxisDirty = false;
  16766. axis.series.forEach(function (series) {
  16767. var _a;
  16768. isDirtyData = isDirtyData || series.isDirtyData || series.isDirty;
  16769. // When x axis is dirty, we need new data extremes for y as
  16770. // well:
  16771. isXAxisDirty = isXAxisDirty || ((_a = series.xAxis) === null || _a === void 0 ? void 0 : _a.isDirty) || false;
  16772. });
  16773. // set the new axisLength
  16774. axis.setAxisSize();
  16775. isDirtyAxisLength = axis.len !== ((_a = axis.old) === null || _a === void 0 ? void 0 : _a.len);
  16776. // do we really need to go through all this?
  16777. if (isDirtyAxisLength ||
  16778. isDirtyData ||
  16779. isXAxisDirty ||
  16780. axis.isLinked ||
  16781. axis.forceRedraw ||
  16782. axis.userMin !== ((_b = axis.old) === null || _b === void 0 ? void 0 : _b.userMin) ||
  16783. axis.userMax !== ((_c = axis.old) === null || _c === void 0 ? void 0 : _c.userMax) ||
  16784. axis.alignToOthers()) {
  16785. if (axis.stacking) {
  16786. axis.stacking.resetStacks();
  16787. }
  16788. axis.forceRedraw = false;
  16789. // get data extremes if needed
  16790. axis.getSeriesExtremes();
  16791. // get fixed positions based on tickInterval
  16792. axis.setTickInterval();
  16793. // Mark as dirty if it is not already set to dirty and extremes have
  16794. // changed. #595.
  16795. if (!axis.isDirty) {
  16796. axis.isDirty =
  16797. isDirtyAxisLength ||
  16798. axis.min !== ((_d = axis.old) === null || _d === void 0 ? void 0 : _d.min) ||
  16799. axis.max !== ((_e = axis.old) === null || _e === void 0 ? void 0 : _e.max);
  16800. }
  16801. }
  16802. else if (axis.stacking) {
  16803. axis.stacking.cleanStacks();
  16804. }
  16805. // Recalculate panning state object, when the data
  16806. // has changed. It is required when vertical panning is enabled.
  16807. if (isDirtyData && axis.panningState) {
  16808. axis.panningState.isDirty = true;
  16809. }
  16810. fireEvent(this, 'afterSetScale');
  16811. };
  16812. /**
  16813. * Set the minimum and maximum of the axes after render time. If the
  16814. * `startOnTick` and `endOnTick` options are true, the minimum and maximum
  16815. * values are rounded off to the nearest tick. To prevent this, these
  16816. * options can be set to false before calling setExtremes. Also, setExtremes
  16817. * will not allow a range lower than the `minRange` option, which by default
  16818. * is the range of five points.
  16819. *
  16820. * @sample highcharts/members/axis-setextremes/
  16821. * Set extremes from a button
  16822. * @sample highcharts/members/axis-setextremes-datetime/
  16823. * Set extremes on a datetime axis
  16824. * @sample highcharts/members/axis-setextremes-off-ticks/
  16825. * Set extremes off ticks
  16826. * @sample stock/members/axis-setextremes/
  16827. * Set extremes in Highstock
  16828. * @sample maps/members/axis-setextremes/
  16829. * Set extremes in Highmaps
  16830. *
  16831. * @function Highcharts.Axis#setExtremes
  16832. *
  16833. * @param {number} [newMin]
  16834. * The new minimum value.
  16835. *
  16836. * @param {number} [newMax]
  16837. * The new maximum value.
  16838. *
  16839. * @param {boolean} [redraw=true]
  16840. * Whether to redraw the chart or wait for an explicit call to
  16841. * {@link Highcharts.Chart#redraw}
  16842. *
  16843. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=true]
  16844. * Enable or modify animations.
  16845. *
  16846. * @param {*} [eventArguments]
  16847. * Arguments to be accessed in event handler.
  16848. *
  16849. * @fires Highcharts.Axis#event:setExtremes
  16850. */
  16851. Axis.prototype.setExtremes = function (newMin, newMax, redraw, animation, eventArguments) {
  16852. var axis = this,
  16853. chart = axis.chart;
  16854. redraw = pick(redraw, true); // defaults to true
  16855. axis.series.forEach(function (serie) {
  16856. delete serie.kdTree;
  16857. });
  16858. // Extend the arguments with min and max
  16859. eventArguments = extend(eventArguments, {
  16860. min: newMin,
  16861. max: newMax
  16862. });
  16863. // Fire the event
  16864. fireEvent(axis, 'setExtremes', eventArguments, function () {
  16865. axis.userMin = newMin;
  16866. axis.userMax = newMax;
  16867. axis.eventArgs = eventArguments;
  16868. if (redraw) {
  16869. chart.redraw(animation);
  16870. }
  16871. });
  16872. };
  16873. /**
  16874. * Overridable method for zooming chart. Pulled out in a separate method to
  16875. * allow overriding in stock charts.
  16876. * @private
  16877. * @function Highcharts.Axis#zoom
  16878. *
  16879. * @param {number} newMin
  16880. * TO-DO: parameter description
  16881. *
  16882. * @param {number} newMax
  16883. * TO-DO: parameter description
  16884. *
  16885. * @return {boolean}
  16886. */
  16887. Axis.prototype.zoom = function (newMin, newMax) {
  16888. var axis = this,
  16889. dataMin = this.dataMin,
  16890. dataMax = this.dataMax,
  16891. options = this.options,
  16892. min = Math.min(dataMin,
  16893. pick(options.min,
  16894. dataMin)),
  16895. max = Math.max(dataMax,
  16896. pick(options.max,
  16897. dataMax)),
  16898. evt = {
  16899. newMin: newMin,
  16900. newMax: newMax
  16901. };
  16902. fireEvent(this, 'zoom', evt, function (e) {
  16903. // Use e.newMin and e.newMax - event handlers may have altered them
  16904. var newMin = e.newMin,
  16905. newMax = e.newMax;
  16906. if (newMin !== axis.min || newMax !== axis.max) { // #5790
  16907. // Prevent pinch zooming out of range. Check for defined is for
  16908. // #1946. #1734.
  16909. if (!axis.allowZoomOutside) {
  16910. // #6014, sometimes newMax will be smaller than min (or
  16911. // newMin will be larger than max).
  16912. if (defined(dataMin)) {
  16913. if (newMin < min) {
  16914. newMin = min;
  16915. }
  16916. if (newMin > max) {
  16917. newMin = max;
  16918. }
  16919. }
  16920. if (defined(dataMax)) {
  16921. if (newMax < min) {
  16922. newMax = min;
  16923. }
  16924. if (newMax > max) {
  16925. newMax = max;
  16926. }
  16927. }
  16928. }
  16929. // In full view, displaying the reset zoom button is not
  16930. // required
  16931. axis.displayBtn = (typeof newMin !== 'undefined' ||
  16932. typeof newMax !== 'undefined');
  16933. // Do it
  16934. axis.setExtremes(newMin, newMax, false, void 0, { trigger: 'zoom' });
  16935. }
  16936. e.zoomed = true;
  16937. });
  16938. return evt.zoomed;
  16939. };
  16940. /**
  16941. * Update the axis metrics.
  16942. *
  16943. * @private
  16944. * @function Highcharts.Axis#setAxisSize
  16945. */
  16946. Axis.prototype.setAxisSize = function () {
  16947. var chart = this.chart,
  16948. options = this.options,
  16949. // [top, right, bottom, left]
  16950. offsets = options.offsets || [0, 0, 0, 0],
  16951. horiz = this.horiz,
  16952. // Check for percentage based input values. Rounding fixes problems
  16953. // with column overflow and plot line filtering (#4898, #4899)
  16954. width = this.width = Math.round(relativeLength(pick(options.width,
  16955. chart.plotWidth - offsets[3] + offsets[1]),
  16956. chart.plotWidth)),
  16957. height = this.height = Math.round(relativeLength(pick(options.height,
  16958. chart.plotHeight - offsets[0] + offsets[2]),
  16959. chart.plotHeight)),
  16960. top = this.top = Math.round(relativeLength(pick(options.top,
  16961. chart.plotTop + offsets[0]),
  16962. chart.plotHeight,
  16963. chart.plotTop)),
  16964. left = this.left = Math.round(relativeLength(pick(options.left,
  16965. chart.plotLeft + offsets[3]),
  16966. chart.plotWidth,
  16967. chart.plotLeft));
  16968. // Expose basic values to use in Series object and navigator
  16969. this.bottom = chart.chartHeight - height - top;
  16970. this.right = chart.chartWidth - width - left;
  16971. // Direction agnostic properties
  16972. this.len = Math.max(horiz ? width : height, 0); // Math.max fixes #905
  16973. this.pos = horiz ? left : top; // distance from SVG origin
  16974. };
  16975. /**
  16976. * Get the current extremes for the axis.
  16977. *
  16978. * @sample highcharts/members/axis-getextremes/
  16979. * Report extremes by click on a button
  16980. * @sample maps/members/axis-getextremes/
  16981. * Get extremes in Highmaps
  16982. *
  16983. * @function Highcharts.Axis#getExtremes
  16984. *
  16985. * @return {Highcharts.ExtremesObject}
  16986. * An object containing extremes information.
  16987. */
  16988. Axis.prototype.getExtremes = function () {
  16989. var axis = this;
  16990. var log = axis.logarithmic;
  16991. return {
  16992. min: log ?
  16993. correctFloat(log.lin2log(axis.min)) :
  16994. axis.min,
  16995. max: log ?
  16996. correctFloat(log.lin2log(axis.max)) :
  16997. axis.max,
  16998. dataMin: axis.dataMin,
  16999. dataMax: axis.dataMax,
  17000. userMin: axis.userMin,
  17001. userMax: axis.userMax
  17002. };
  17003. };
  17004. /**
  17005. * Get the zero plane either based on zero or on the min or max value.
  17006. * Used in bar and area plots.
  17007. *
  17008. * @function Highcharts.Axis#getThreshold
  17009. *
  17010. * @param {number} threshold
  17011. * The threshold in axis values.
  17012. *
  17013. * @return {number|undefined}
  17014. * The translated threshold position in terms of pixels, and corrected to
  17015. * stay within the axis bounds.
  17016. */
  17017. Axis.prototype.getThreshold = function (threshold) {
  17018. var axis = this,
  17019. log = axis.logarithmic,
  17020. realMin = log ? log.lin2log(axis.min) : axis.min,
  17021. realMax = log ? log.lin2log(axis.max) : axis.max;
  17022. if (threshold === null || threshold === -Infinity) {
  17023. threshold = realMin;
  17024. }
  17025. else if (threshold === Infinity) {
  17026. threshold = realMax;
  17027. }
  17028. else if (realMin > threshold) {
  17029. threshold = realMin;
  17030. }
  17031. else if (realMax < threshold) {
  17032. threshold = realMax;
  17033. }
  17034. return axis.translate(threshold, 0, 1, 0, 1);
  17035. };
  17036. /**
  17037. * Compute auto alignment for the axis label based on which side the axis is
  17038. * on and the given rotation for the label.
  17039. *
  17040. * @private
  17041. * @function Highcharts.Axis#autoLabelAlign
  17042. *
  17043. * @param {number} rotation
  17044. * The rotation in degrees as set by either the `rotation` or `autoRotation`
  17045. * options.
  17046. *
  17047. * @return {Highcharts.AlignValue}
  17048. * Can be `"center"`, `"left"` or `"right"`.
  17049. */
  17050. Axis.prototype.autoLabelAlign = function (rotation) {
  17051. var angle = (pick(rotation, 0) - (this.side * 90) + 720) % 360,
  17052. evt = { align: 'center' };
  17053. fireEvent(this, 'autoLabelAlign', evt, function (e) {
  17054. if (angle > 15 && angle < 165) {
  17055. e.align = 'right';
  17056. }
  17057. else if (angle > 195 && angle < 345) {
  17058. e.align = 'left';
  17059. }
  17060. });
  17061. return evt.align;
  17062. };
  17063. /**
  17064. * Get the tick length and width for the axis based on axis options.
  17065. * @private
  17066. * @function Highcharts.Axis#tickSize
  17067. *
  17068. * @param {string} [prefix]
  17069. * 'tick' or 'minorTick'
  17070. *
  17071. * @return {Array<number,number>|undefined}
  17072. * An array of tickLength and tickWidth
  17073. */
  17074. Axis.prototype.tickSize = function (prefix) {
  17075. var options = this.options, tickLength = options[prefix === 'tick' ? 'tickLength' : 'minorTickLength'], tickWidth = pick(options[prefix === 'tick' ? 'tickWidth' : 'minorTickWidth'],
  17076. // Default to 1 on linear and datetime X axes
  17077. prefix === 'tick' && this.isXAxis && !this.categories ? 1 : 0), e, tickSize;
  17078. if (tickWidth && tickLength) {
  17079. // Negate the length
  17080. if (options[prefix + 'Position'] === 'inside') {
  17081. tickLength = -tickLength;
  17082. }
  17083. tickSize = [tickLength, tickWidth];
  17084. }
  17085. e = { tickSize: tickSize };
  17086. fireEvent(this, 'afterTickSize', e);
  17087. return e.tickSize;
  17088. };
  17089. /**
  17090. * Return the size of the labels.
  17091. *
  17092. * @private
  17093. * @function Highcharts.Axis#labelMetrics
  17094. *
  17095. * @return {Highcharts.FontMetricsObject}
  17096. */
  17097. Axis.prototype.labelMetrics = function () {
  17098. var index = this.tickPositions && this.tickPositions[0] || 0;
  17099. return this.chart.renderer.fontMetrics(this.options.labels.style &&
  17100. this.options.labels.style.fontSize, this.ticks[index] && this.ticks[index].label);
  17101. };
  17102. /**
  17103. * Prevent the ticks from getting so close we can't draw the labels. On a
  17104. * horizontal axis, this is handled by rotating the labels, removing ticks
  17105. * and adding ellipsis. On a vertical axis remove ticks and add ellipsis.
  17106. *
  17107. * @private
  17108. * @function Highcharts.Axis#unsquish
  17109. *
  17110. * @return {number}
  17111. */
  17112. Axis.prototype.unsquish = function () {
  17113. var labelOptions = this.options.labels,
  17114. horiz = this.horiz,
  17115. tickInterval = this.tickInterval,
  17116. newTickInterval = tickInterval,
  17117. slotSize = this.len / (((this.categories ? 1 : 0) +
  17118. this.max -
  17119. this.min) /
  17120. tickInterval),
  17121. rotation,
  17122. rotationOption = labelOptions.rotation,
  17123. labelMetrics = this.labelMetrics(),
  17124. step,
  17125. bestScore = Number.MAX_VALUE,
  17126. autoRotation,
  17127. range = Math.max(this.max - this.min, 0),
  17128. // Return the multiple of tickInterval that is needed to avoid
  17129. // collision
  17130. getStep = function (spaceNeeded) {
  17131. var step = spaceNeeded / (slotSize || 1);
  17132. step = step > 1 ? Math.ceil(step) : 1;
  17133. // Guard for very small or negative angles (#9835)
  17134. if (step * tickInterval > range &&
  17135. spaceNeeded !== Infinity &&
  17136. slotSize !== Infinity &&
  17137. range) {
  17138. step = Math.ceil(range / tickInterval);
  17139. }
  17140. return correctFloat(step * tickInterval);
  17141. };
  17142. if (horiz) {
  17143. autoRotation = !labelOptions.staggerLines &&
  17144. !labelOptions.step &&
  17145. ( // #3971
  17146. defined(rotationOption) ?
  17147. [rotationOption] :
  17148. slotSize < pick(labelOptions.autoRotationLimit, 80) && labelOptions.autoRotation);
  17149. if (autoRotation) {
  17150. // Loop over the given autoRotation options, and determine
  17151. // which gives the best score. The best score is that with
  17152. // the lowest number of steps and a rotation closest
  17153. // to horizontal.
  17154. autoRotation.forEach(function (rot) {
  17155. var score;
  17156. if (rot === rotationOption ||
  17157. (rot && rot >= -90 && rot <= 90)) { // #3891
  17158. step = getStep(Math.abs(labelMetrics.h / Math.sin(deg2rad * rot)));
  17159. score = step + Math.abs(rot / 360);
  17160. if (score < bestScore) {
  17161. bestScore = score;
  17162. rotation = rot;
  17163. newTickInterval = step;
  17164. }
  17165. }
  17166. });
  17167. }
  17168. }
  17169. else if (!labelOptions.step) { // #4411
  17170. newTickInterval = getStep(labelMetrics.h);
  17171. }
  17172. this.autoRotation = autoRotation;
  17173. this.labelRotation = pick(rotation, rotationOption);
  17174. return newTickInterval;
  17175. };
  17176. /**
  17177. * Get the general slot width for labels/categories on this axis. This may
  17178. * change between the pre-render (from Axis.getOffset) and the final tick
  17179. * rendering and placement.
  17180. *
  17181. * @private
  17182. * @function Highcharts.Axis#getSlotWidth
  17183. *
  17184. * @param {Highcharts.Tick} [tick] Optionally, calculate the slot width
  17185. * basing on tick label. It is used in highcharts-3d module, where the slots
  17186. * has different widths depending on perspective angles.
  17187. *
  17188. * @return {number}
  17189. * The pixel width allocated to each axis label.
  17190. */
  17191. Axis.prototype.getSlotWidth = function (tick) {
  17192. var _a;
  17193. // #5086, #1580, #1931
  17194. var chart = this.chart,
  17195. horiz = this.horiz,
  17196. labelOptions = this.options.labels,
  17197. slotCount = Math.max(this.tickPositions.length - (this.categories ? 0 : 1), 1),
  17198. marginLeft = chart.margin[3];
  17199. // Used by grid axis
  17200. if (tick && isNumber(tick.slotWidth)) { // #13221, can be 0
  17201. return tick.slotWidth;
  17202. }
  17203. if (horiz &&
  17204. labelOptions &&
  17205. (labelOptions.step || 0) < 2) {
  17206. if (labelOptions.rotation) { // #4415
  17207. return 0;
  17208. }
  17209. return ((this.staggerLines || 1) * this.len) / slotCount;
  17210. }
  17211. if (!horiz) {
  17212. // #7028
  17213. var cssWidth = (_a = labelOptions === null || labelOptions === void 0 ? void 0 : labelOptions.style) === null || _a === void 0 ? void 0 : _a.width;
  17214. if (cssWidth !== void 0) {
  17215. return parseInt(cssWidth, 10);
  17216. }
  17217. if (marginLeft) {
  17218. return marginLeft - chart.spacing[3];
  17219. }
  17220. }
  17221. // Last resort, a fraction of the available size
  17222. return chart.chartWidth * 0.33;
  17223. };
  17224. /**
  17225. * Render the axis labels and determine whether ellipsis or rotation need to
  17226. * be applied.
  17227. *
  17228. * @private
  17229. * @function Highcharts.Axis#renderUnsquish
  17230. */
  17231. Axis.prototype.renderUnsquish = function () {
  17232. var chart = this.chart,
  17233. renderer = chart.renderer,
  17234. tickPositions = this.tickPositions,
  17235. ticks = this.ticks,
  17236. labelOptions = this.options.labels,
  17237. labelStyleOptions = (labelOptions && labelOptions.style || {}),
  17238. horiz = this.horiz,
  17239. slotWidth = this.getSlotWidth(),
  17240. innerWidth = Math.max(1,
  17241. Math.round(slotWidth - 2 * (labelOptions.padding || 5))),
  17242. attr = {},
  17243. labelMetrics = this.labelMetrics(),
  17244. textOverflowOption = (labelOptions.style &&
  17245. labelOptions.style.textOverflow),
  17246. commonWidth,
  17247. commonTextOverflow,
  17248. maxLabelLength = 0,
  17249. label,
  17250. i,
  17251. pos;
  17252. // Set rotation option unless it is "auto", like in gauges
  17253. if (!isString(labelOptions.rotation)) {
  17254. // #4443:
  17255. attr.rotation = labelOptions.rotation || 0;
  17256. }
  17257. // Get the longest label length
  17258. tickPositions.forEach(function (tick) {
  17259. tick = ticks[tick];
  17260. // Replace label - sorting animation
  17261. if (tick.movedLabel) {
  17262. tick.replaceMovedLabel();
  17263. }
  17264. if (tick &&
  17265. tick.label &&
  17266. tick.label.textPxLength > maxLabelLength) {
  17267. maxLabelLength = tick.label.textPxLength;
  17268. }
  17269. });
  17270. this.maxLabelLength = maxLabelLength;
  17271. // Handle auto rotation on horizontal axis
  17272. if (this.autoRotation) {
  17273. // Apply rotation only if the label is too wide for the slot, and
  17274. // the label is wider than its height.
  17275. if (maxLabelLength > innerWidth &&
  17276. maxLabelLength > labelMetrics.h) {
  17277. attr.rotation = this.labelRotation;
  17278. }
  17279. else {
  17280. this.labelRotation = 0;
  17281. }
  17282. // Handle word-wrap or ellipsis on vertical axis
  17283. }
  17284. else if (slotWidth) {
  17285. // For word-wrap or ellipsis
  17286. commonWidth = innerWidth;
  17287. if (!textOverflowOption) {
  17288. commonTextOverflow = 'clip';
  17289. // On vertical axis, only allow word wrap if there is room
  17290. // for more lines.
  17291. i = tickPositions.length;
  17292. while (!horiz && i--) {
  17293. pos = tickPositions[i];
  17294. label = ticks[pos].label;
  17295. if (label) {
  17296. // Reset ellipsis in order to get the correct
  17297. // bounding box (#4070)
  17298. if (label.styles &&
  17299. label.styles.textOverflow === 'ellipsis') {
  17300. label.css({ textOverflow: 'clip' });
  17301. // Set the correct width in order to read
  17302. // the bounding box height (#4678, #5034)
  17303. }
  17304. else if (label.textPxLength > slotWidth) {
  17305. label.css({ width: slotWidth + 'px' });
  17306. }
  17307. if (label.getBBox().height > (this.len / tickPositions.length -
  17308. (labelMetrics.h - labelMetrics.f))) {
  17309. label.specificTextOverflow = 'ellipsis';
  17310. }
  17311. }
  17312. }
  17313. }
  17314. }
  17315. // Add ellipsis if the label length is significantly longer than ideal
  17316. if (attr.rotation) {
  17317. commonWidth = (maxLabelLength > chart.chartHeight * 0.5 ?
  17318. chart.chartHeight * 0.33 :
  17319. maxLabelLength);
  17320. if (!textOverflowOption) {
  17321. commonTextOverflow = 'ellipsis';
  17322. }
  17323. }
  17324. // Set the explicit or automatic label alignment
  17325. this.labelAlign = labelOptions.align ||
  17326. this.autoLabelAlign(this.labelRotation);
  17327. if (this.labelAlign) {
  17328. attr.align = this.labelAlign;
  17329. }
  17330. // Apply general and specific CSS
  17331. tickPositions.forEach(function (pos) {
  17332. var tick = ticks[pos],
  17333. label = tick && tick.label,
  17334. widthOption = labelStyleOptions.width,
  17335. css = {};
  17336. if (label) {
  17337. // This needs to go before the CSS in old IE (#4502)
  17338. label.attr(attr);
  17339. if (tick.shortenLabel) {
  17340. tick.shortenLabel();
  17341. }
  17342. else if (commonWidth &&
  17343. !widthOption &&
  17344. // Setting width in this case messes with the bounding box
  17345. // (#7975)
  17346. labelStyleOptions.whiteSpace !== 'nowrap' &&
  17347. (
  17348. // Speed optimizing, #7656
  17349. commonWidth < label.textPxLength ||
  17350. // Resetting CSS, #4928
  17351. label.element.tagName === 'SPAN')) {
  17352. css.width = commonWidth + 'px';
  17353. if (!textOverflowOption) {
  17354. css.textOverflow = (label.specificTextOverflow ||
  17355. commonTextOverflow);
  17356. }
  17357. label.css(css);
  17358. // Reset previously shortened label (#8210)
  17359. }
  17360. else if (label.styles &&
  17361. label.styles.width &&
  17362. !css.width &&
  17363. !widthOption) {
  17364. label.css({ width: null });
  17365. }
  17366. delete label.specificTextOverflow;
  17367. tick.rotation = attr.rotation;
  17368. }
  17369. }, this);
  17370. // Note: Why is this not part of getLabelPosition?
  17371. this.tickRotCorr = renderer.rotCorr(labelMetrics.b, this.labelRotation || 0, this.side !== 0);
  17372. };
  17373. /**
  17374. * Return true if the axis has associated data.
  17375. *
  17376. * @function Highcharts.Axis#hasData
  17377. *
  17378. * @return {boolean}
  17379. * True if the axis has associated visible series and those series have
  17380. * either valid data points or explicit `min` and `max` settings.
  17381. */
  17382. Axis.prototype.hasData = function () {
  17383. return this.series.some(function (s) {
  17384. return s.hasData();
  17385. }) ||
  17386. (this.options.showEmpty &&
  17387. defined(this.min) &&
  17388. defined(this.max));
  17389. };
  17390. /**
  17391. * Adds the title defined in axis.options.title.
  17392. *
  17393. * @function Highcharts.Axis#addTitle
  17394. *
  17395. * @param {boolean} [display]
  17396. * Whether or not to display the title.
  17397. */
  17398. Axis.prototype.addTitle = function (display) {
  17399. var axis = this,
  17400. renderer = axis.chart.renderer,
  17401. horiz = axis.horiz,
  17402. opposite = axis.opposite,
  17403. options = axis.options,
  17404. axisTitleOptions = options.title,
  17405. textAlign,
  17406. styledMode = axis.chart.styledMode;
  17407. if (!axis.axisTitle) {
  17408. textAlign = axisTitleOptions.textAlign;
  17409. if (!textAlign) {
  17410. textAlign = (horiz ? {
  17411. low: 'left',
  17412. middle: 'center',
  17413. high: 'right'
  17414. } : {
  17415. low: opposite ? 'right' : 'left',
  17416. middle: 'center',
  17417. high: opposite ? 'left' : 'right'
  17418. })[axisTitleOptions.align];
  17419. }
  17420. axis.axisTitle = renderer
  17421. .text(axisTitleOptions.text, 0, 0, axisTitleOptions.useHTML)
  17422. .attr({
  17423. zIndex: 7,
  17424. rotation: axisTitleOptions.rotation || 0,
  17425. align: textAlign
  17426. })
  17427. .addClass('highcharts-axis-title');
  17428. // #7814, don't mutate style option
  17429. if (!styledMode) {
  17430. axis.axisTitle.css(merge(axisTitleOptions.style));
  17431. }
  17432. axis.axisTitle.add(axis.axisGroup);
  17433. axis.axisTitle.isNew = true;
  17434. }
  17435. // Max width defaults to the length of the axis
  17436. if (!styledMode &&
  17437. !axisTitleOptions.style.width &&
  17438. !axis.isRadial) {
  17439. axis.axisTitle.css({
  17440. width: axis.len + 'px'
  17441. });
  17442. }
  17443. // hide or show the title depending on whether showEmpty is set
  17444. axis.axisTitle[display ? 'show' : 'hide'](display);
  17445. };
  17446. /**
  17447. * Generates a tick for initial positioning.
  17448. *
  17449. * @private
  17450. * @function Highcharts.Axis#generateTick
  17451. *
  17452. * @param {number} pos
  17453. * The tick position in axis values.
  17454. *
  17455. * @param {number} [i]
  17456. * The index of the tick in {@link Axis.tickPositions}.
  17457. */
  17458. Axis.prototype.generateTick = function (pos) {
  17459. var axis = this;
  17460. var ticks = axis.ticks;
  17461. if (!ticks[pos]) {
  17462. ticks[pos] = new Tick(axis, pos);
  17463. }
  17464. else {
  17465. ticks[pos].addLabel(); // update labels depending on tick interval
  17466. }
  17467. };
  17468. /**
  17469. * Render the tick labels to a preliminary position to get their sizes
  17470. *
  17471. * @private
  17472. * @function Highcharts.Axis#getOffset
  17473. *
  17474. * @fires Highcharts.Axis#event:afterGetOffset
  17475. */
  17476. Axis.prototype.getOffset = function () {
  17477. var _this = this;
  17478. var axis = this,
  17479. chart = axis.chart,
  17480. renderer = chart.renderer,
  17481. options = axis.options,
  17482. tickPositions = axis.tickPositions,
  17483. ticks = axis.ticks,
  17484. horiz = axis.horiz,
  17485. side = axis.side,
  17486. invertedSide = chart.inverted &&
  17487. !axis.isZAxis ? [1, 0, 3, 2][side] : side,
  17488. hasData,
  17489. showAxis,
  17490. titleOffset = 0,
  17491. titleOffsetOption,
  17492. titleMargin = 0,
  17493. axisTitleOptions = options.title,
  17494. labelOptions = options.labels,
  17495. labelOffset = 0, // reset
  17496. labelOffsetPadded,
  17497. axisOffset = chart.axisOffset,
  17498. clipOffset = chart.clipOffset,
  17499. clip,
  17500. directionFactor = [-1, 1, 1, -1][side],
  17501. className = options.className,
  17502. axisParent = axis.axisParent, // Used in color axis
  17503. lineHeightCorrection;
  17504. // For reuse in Axis.render
  17505. hasData = axis.hasData();
  17506. axis.showAxis = showAxis = hasData || pick(options.showEmpty, true);
  17507. // Set/reset staggerLines
  17508. axis.staggerLines = axis.horiz && labelOptions.staggerLines;
  17509. // Create the axisGroup and gridGroup elements on first iteration
  17510. if (!axis.axisGroup) {
  17511. var createGroup = function (name,
  17512. suffix,
  17513. zIndex) { return renderer.g(name)
  17514. .attr({ zIndex: zIndex })
  17515. .addClass("highcharts-" + _this.coll.toLowerCase() + suffix + " " +
  17516. (_this.isRadial ? "highcharts-radial-axis" + suffix + " " : '') +
  17517. (className || ''))
  17518. .add(axisParent); };
  17519. axis.gridGroup = createGroup('grid', '-grid', options.gridZIndex || 1);
  17520. axis.axisGroup = createGroup('axis', '', options.zIndex || 2);
  17521. axis.labelGroup = createGroup('axis-labels', '-labels', labelOptions.zIndex || 7);
  17522. }
  17523. if (hasData || axis.isLinked) {
  17524. // Generate ticks
  17525. tickPositions.forEach(function (pos, i) {
  17526. // i is not used here, but may be used in overrides
  17527. axis.generateTick(pos, i);
  17528. });
  17529. axis.renderUnsquish();
  17530. // Left side must be align: right and right side must
  17531. // have align: left for labels
  17532. axis.reserveSpaceDefault = (side === 0 ||
  17533. side === 2 ||
  17534. { 1: 'left', 3: 'right' }[side] === axis.labelAlign);
  17535. if (pick(labelOptions.reserveSpace, axis.labelAlign === 'center' ? true : null, axis.reserveSpaceDefault)) {
  17536. tickPositions.forEach(function (pos) {
  17537. // get the highest offset
  17538. labelOffset = Math.max(ticks[pos].getLabelSize(), labelOffset);
  17539. });
  17540. }
  17541. if (axis.staggerLines) {
  17542. labelOffset *= axis.staggerLines;
  17543. }
  17544. axis.labelOffset = labelOffset * (axis.opposite ? -1 : 1);
  17545. }
  17546. else { // doesn't have data
  17547. objectEach(ticks, function (tick, n) {
  17548. tick.destroy();
  17549. delete ticks[n];
  17550. });
  17551. }
  17552. if (axisTitleOptions &&
  17553. axisTitleOptions.text &&
  17554. axisTitleOptions.enabled !== false) {
  17555. axis.addTitle(showAxis);
  17556. if (showAxis && axisTitleOptions.reserveSpace !== false) {
  17557. axis.titleOffset = titleOffset =
  17558. axis.axisTitle.getBBox()[horiz ? 'height' : 'width'];
  17559. titleOffsetOption = axisTitleOptions.offset;
  17560. titleMargin = defined(titleOffsetOption) ?
  17561. 0 :
  17562. pick(axisTitleOptions.margin, horiz ? 5 : 10);
  17563. }
  17564. }
  17565. // Render the axis line
  17566. axis.renderLine();
  17567. // handle automatic or user set offset
  17568. axis.offset = directionFactor * pick(options.offset, axisOffset[side] ? axisOffset[side] + (options.margin || 0) : 0);
  17569. axis.tickRotCorr = axis.tickRotCorr || { x: 0, y: 0 }; // polar
  17570. if (side === 0) {
  17571. lineHeightCorrection = -axis.labelMetrics().h;
  17572. }
  17573. else if (side === 2) {
  17574. lineHeightCorrection = axis.tickRotCorr.y;
  17575. }
  17576. else {
  17577. lineHeightCorrection = 0;
  17578. }
  17579. // Find the padded label offset
  17580. labelOffsetPadded = Math.abs(labelOffset) + titleMargin;
  17581. if (labelOffset) {
  17582. labelOffsetPadded -= lineHeightCorrection;
  17583. labelOffsetPadded += directionFactor * (horiz ?
  17584. pick(labelOptions.y, axis.tickRotCorr.y + directionFactor * 8) :
  17585. labelOptions.x);
  17586. }
  17587. axis.axisTitleMargin = pick(titleOffsetOption, labelOffsetPadded);
  17588. if (axis.getMaxLabelDimensions) {
  17589. axis.maxLabelDimensions = axis.getMaxLabelDimensions(ticks, tickPositions);
  17590. }
  17591. // Due to GridAxis.tickSize, tickSize should be calculated after ticks
  17592. // has rendered.
  17593. var tickSize = this.tickSize('tick');
  17594. axisOffset[side] = Math.max(axisOffset[side], axis.axisTitleMargin + titleOffset +
  17595. directionFactor * axis.offset, labelOffsetPadded, // #3027
  17596. tickPositions && tickPositions.length && tickSize ?
  17597. tickSize[0] + directionFactor * axis.offset :
  17598. 0 // #4866
  17599. );
  17600. // Decide the clipping needed to keep the graph inside
  17601. // the plot area and axis lines
  17602. clip = options.offset ?
  17603. 0 :
  17604. // #4308, #4371:
  17605. Math.floor(axis.axisLine.strokeWidth() / 2) * 2;
  17606. clipOffset[invertedSide] =
  17607. Math.max(clipOffset[invertedSide], clip);
  17608. fireEvent(this, 'afterGetOffset');
  17609. };
  17610. /**
  17611. * Internal function to get the path for the axis line. Extended for polar
  17612. * charts.
  17613. *
  17614. * @function Highcharts.Axis#getLinePath
  17615. *
  17616. * @param {number} lineWidth
  17617. * The line width in pixels.
  17618. *
  17619. * @return {Highcharts.SVGPathArray}
  17620. * The SVG path definition in array form.
  17621. */
  17622. Axis.prototype.getLinePath = function (lineWidth) {
  17623. var chart = this.chart,
  17624. opposite = this.opposite,
  17625. offset = this.offset,
  17626. horiz = this.horiz,
  17627. lineLeft = this.left + (opposite ? this.width : 0) + offset,
  17628. lineTop = chart.chartHeight - this.bottom -
  17629. (opposite ? this.height : 0) + offset;
  17630. if (opposite) {
  17631. lineWidth *= -1; // crispify the other way - #1480, #1687
  17632. }
  17633. return chart.renderer
  17634. .crispLine([
  17635. [
  17636. 'M',
  17637. horiz ?
  17638. this.left :
  17639. lineLeft,
  17640. horiz ?
  17641. lineTop :
  17642. this.top
  17643. ],
  17644. [
  17645. 'L',
  17646. horiz ?
  17647. chart.chartWidth - this.right :
  17648. lineLeft,
  17649. horiz ?
  17650. lineTop :
  17651. chart.chartHeight - this.bottom
  17652. ]
  17653. ], lineWidth);
  17654. };
  17655. /**
  17656. * Render the axis line. Called internally when rendering and redrawing the
  17657. * axis.
  17658. *
  17659. * @function Highcharts.Axis#renderLine
  17660. */
  17661. Axis.prototype.renderLine = function () {
  17662. if (!this.axisLine) {
  17663. this.axisLine = this.chart.renderer.path()
  17664. .addClass('highcharts-axis-line')
  17665. .add(this.axisGroup);
  17666. if (!this.chart.styledMode) {
  17667. this.axisLine.attr({
  17668. stroke: this.options.lineColor,
  17669. 'stroke-width': this.options.lineWidth,
  17670. zIndex: 7
  17671. });
  17672. }
  17673. }
  17674. };
  17675. /**
  17676. * Position the axis title.
  17677. *
  17678. * @private
  17679. * @function Highcharts.Axis#getTitlePosition
  17680. *
  17681. * @return {Highcharts.PositionObject}
  17682. * X and Y positions for the title.
  17683. */
  17684. Axis.prototype.getTitlePosition = function () {
  17685. // compute anchor points for each of the title align options
  17686. var horiz = this.horiz,
  17687. axisLeft = this.left,
  17688. axisTop = this.top,
  17689. axisLength = this.len,
  17690. axisTitleOptions = this.options.title,
  17691. margin = horiz ? axisLeft : axisTop,
  17692. opposite = this.opposite,
  17693. offset = this.offset,
  17694. xOption = axisTitleOptions.x || 0,
  17695. yOption = axisTitleOptions.y || 0,
  17696. axisTitle = this.axisTitle,
  17697. fontMetrics = this.chart.renderer.fontMetrics(axisTitleOptions.style &&
  17698. axisTitleOptions.style.fontSize,
  17699. axisTitle),
  17700. // The part of a multiline text that is below the baseline of the
  17701. // first line. Subtract 1 to preserve pixel-perfectness from the
  17702. // old behaviour (v5.0.12), where only one line was allowed.
  17703. textHeightOvershoot = Math.max(axisTitle.getBBox(null, 0).height - fontMetrics.h - 1, 0),
  17704. // the position in the length direction of the axis
  17705. alongAxis = {
  17706. low: margin + (horiz ? 0 : axisLength),
  17707. middle: margin + axisLength / 2,
  17708. high: margin + (horiz ? axisLength : 0)
  17709. }[axisTitleOptions.align],
  17710. // the position in the perpendicular direction of the axis
  17711. offAxis = (horiz ? axisTop + this.height : axisLeft) +
  17712. (horiz ? 1 : -1) * // horizontal axis reverses the margin
  17713. (opposite ? -1 : 1) * // so does opposite axes
  17714. this.axisTitleMargin +
  17715. [
  17716. -textHeightOvershoot,
  17717. textHeightOvershoot,
  17718. fontMetrics.f,
  17719. -textHeightOvershoot // left
  17720. ][this.side],
  17721. titlePosition = {
  17722. x: horiz ?
  17723. alongAxis + xOption :
  17724. offAxis + (opposite ? this.width : 0) + offset + xOption,
  17725. y: horiz ?
  17726. offAxis + yOption - (opposite ? this.height : 0) + offset :
  17727. alongAxis + yOption
  17728. };
  17729. fireEvent(this, 'afterGetTitlePosition', { titlePosition: titlePosition });
  17730. return titlePosition;
  17731. };
  17732. /**
  17733. * Render a minor tick into the given position. If a minor tick already
  17734. * exists in this position, move it.
  17735. *
  17736. * @function Highcharts.Axis#renderMinorTick
  17737. *
  17738. * @param {number} pos
  17739. * The position in axis values.
  17740. */
  17741. Axis.prototype.renderMinorTick = function (pos) {
  17742. var axis = this;
  17743. var slideInTicks = axis.chart.hasRendered && axis.old;
  17744. var minorTicks = axis.minorTicks;
  17745. if (!minorTicks[pos]) {
  17746. minorTicks[pos] = new Tick(axis, pos, 'minor');
  17747. }
  17748. // Render new ticks in old position
  17749. if (slideInTicks && minorTicks[pos].isNew) {
  17750. minorTicks[pos].render(null, true);
  17751. }
  17752. minorTicks[pos].render(null, false, 1);
  17753. };
  17754. /**
  17755. * Render a major tick into the given position. If a tick already exists
  17756. * in this position, move it.
  17757. *
  17758. * @function Highcharts.Axis#renderTick
  17759. *
  17760. * @param {number} pos
  17761. * The position in axis values.
  17762. *
  17763. * @param {number} i
  17764. * The tick index.
  17765. */
  17766. Axis.prototype.renderTick = function (pos, i) {
  17767. var _a;
  17768. var axis = this;
  17769. var isLinked = axis.isLinked;
  17770. var ticks = axis.ticks;
  17771. var slideInTicks = axis.chart.hasRendered && axis.old;
  17772. // Linked axes need an extra check to find out if
  17773. if (!isLinked ||
  17774. (pos >= axis.min && pos <= axis.max) || ((_a = axis.grid) === null || _a === void 0 ? void 0 : _a.isColumn)) {
  17775. if (!ticks[pos]) {
  17776. ticks[pos] = new Tick(axis, pos);
  17777. }
  17778. // NOTE this seems like overkill. Could be handled in tick.render by
  17779. // setting old position in attr, then set new position in animate.
  17780. // render new ticks in old position
  17781. if (slideInTicks && ticks[pos].isNew) {
  17782. // Start with negative opacity so that it is visible from
  17783. // halfway into the animation
  17784. ticks[pos].render(i, true, -1);
  17785. }
  17786. ticks[pos].render(i);
  17787. }
  17788. };
  17789. /**
  17790. * Render the axis.
  17791. *
  17792. * @private
  17793. * @function Highcharts.Axis#render
  17794. *
  17795. * @fires Highcharts.Axis#event:afterRender
  17796. */
  17797. Axis.prototype.render = function () {
  17798. var axis = this,
  17799. chart = axis.chart,
  17800. log = axis.logarithmic,
  17801. renderer = chart.renderer,
  17802. options = axis.options,
  17803. isLinked = axis.isLinked,
  17804. tickPositions = axis.tickPositions,
  17805. axisTitle = axis.axisTitle,
  17806. ticks = axis.ticks,
  17807. minorTicks = axis.minorTicks,
  17808. alternateBands = axis.alternateBands,
  17809. stackLabelOptions = options.stackLabels,
  17810. alternateGridColor = options.alternateGridColor,
  17811. tickmarkOffset = axis.tickmarkOffset,
  17812. axisLine = axis.axisLine,
  17813. showAxis = axis.showAxis,
  17814. animation = animObject(renderer.globalAnimation),
  17815. from,
  17816. to;
  17817. // Reset
  17818. axis.labelEdge.length = 0;
  17819. axis.overlap = false;
  17820. // Mark all elements inActive before we go over and mark the active ones
  17821. [ticks, minorTicks, alternateBands].forEach(function (coll) {
  17822. objectEach(coll, function (tick) {
  17823. tick.isActive = false;
  17824. });
  17825. });
  17826. // If the series has data draw the ticks. Else only the line and title
  17827. if (axis.hasData() || isLinked) {
  17828. // minor ticks
  17829. if (axis.minorTickInterval && !axis.categories) {
  17830. axis.getMinorTickPositions().forEach(function (pos) {
  17831. axis.renderMinorTick(pos);
  17832. });
  17833. }
  17834. // Major ticks. Pull out the first item and render it last so that
  17835. // we can get the position of the neighbour label. #808.
  17836. if (tickPositions.length) { // #1300
  17837. tickPositions.forEach(function (pos, i) {
  17838. axis.renderTick(pos, i);
  17839. });
  17840. // In a categorized axis, the tick marks are displayed
  17841. // between labels. So we need to add a tick mark and
  17842. // grid line at the left edge of the X axis.
  17843. if (tickmarkOffset && (axis.min === 0 || axis.single)) {
  17844. if (!ticks[-1]) {
  17845. ticks[-1] = new Tick(axis, -1, null, true);
  17846. }
  17847. ticks[-1].render(-1);
  17848. }
  17849. }
  17850. // alternate grid color
  17851. if (alternateGridColor) {
  17852. tickPositions.forEach(function (pos, i) {
  17853. to = typeof tickPositions[i + 1] !== 'undefined' ?
  17854. tickPositions[i + 1] + tickmarkOffset :
  17855. axis.max - tickmarkOffset;
  17856. if (i % 2 === 0 &&
  17857. pos < axis.max &&
  17858. to <= axis.max + (chart.polar ?
  17859. -tickmarkOffset :
  17860. tickmarkOffset)) { // #2248, #4660
  17861. if (!alternateBands[pos]) {
  17862. // Should be imported from PlotLineOrBand.js, but
  17863. // the dependency cycle with axis is a problem
  17864. alternateBands[pos] = new H.PlotLineOrBand(axis);
  17865. }
  17866. from = pos + tickmarkOffset; // #949
  17867. alternateBands[pos].options = {
  17868. from: log ? log.lin2log(from) : from,
  17869. to: log ? log.lin2log(to) : to,
  17870. color: alternateGridColor,
  17871. className: 'highcharts-alternate-grid'
  17872. };
  17873. alternateBands[pos].render();
  17874. alternateBands[pos].isActive = true;
  17875. }
  17876. });
  17877. }
  17878. // custom plot lines and bands
  17879. if (!axis._addedPlotLB) { // only first time
  17880. axis._addedPlotLB = true;
  17881. (options.plotLines || [])
  17882. .concat(options.plotBands || [])
  17883. .forEach(function (plotLineOptions) {
  17884. axis.addPlotBandOrLine(plotLineOptions);
  17885. });
  17886. }
  17887. } // end if hasData
  17888. // Remove inactive ticks
  17889. [ticks, minorTicks, alternateBands].forEach(function (coll) {
  17890. var i,
  17891. forDestruction = [],
  17892. delay = animation.duration,
  17893. destroyInactiveItems = function () {
  17894. i = forDestruction.length;
  17895. while (i--) {
  17896. // When resizing rapidly, the same items
  17897. // may be destroyed in different timeouts,
  17898. // or the may be reactivated
  17899. if (coll[forDestruction[i]] &&
  17900. !coll[forDestruction[i]].isActive) {
  17901. coll[forDestruction[i]].destroy();
  17902. delete coll[forDestruction[i]];
  17903. }
  17904. }
  17905. };
  17906. objectEach(coll, function (tick, pos) {
  17907. if (!tick.isActive) {
  17908. // Render to zero opacity
  17909. tick.render(pos, false, 0);
  17910. tick.isActive = false;
  17911. forDestruction.push(pos);
  17912. }
  17913. });
  17914. // When the objects are finished fading out, destroy them
  17915. syncTimeout(destroyInactiveItems, coll === alternateBands ||
  17916. !chart.hasRendered ||
  17917. !delay ?
  17918. 0 :
  17919. delay);
  17920. });
  17921. // Set the axis line path
  17922. if (axisLine) {
  17923. axisLine[axisLine.isPlaced ? 'animate' : 'attr']({
  17924. d: this.getLinePath(axisLine.strokeWidth())
  17925. });
  17926. axisLine.isPlaced = true;
  17927. // Show or hide the line depending on options.showEmpty
  17928. axisLine[showAxis ? 'show' : 'hide'](showAxis);
  17929. }
  17930. if (axisTitle && showAxis) {
  17931. var titleXy = axis.getTitlePosition();
  17932. if (isNumber(titleXy.y)) {
  17933. axisTitle[axisTitle.isNew ? 'attr' : 'animate'](titleXy);
  17934. axisTitle.isNew = false;
  17935. }
  17936. else {
  17937. axisTitle.attr('y', -9999);
  17938. axisTitle.isNew = true;
  17939. }
  17940. }
  17941. // Stacked totals:
  17942. if (stackLabelOptions && stackLabelOptions.enabled && axis.stacking) {
  17943. axis.stacking.renderStackTotals();
  17944. }
  17945. // End stacked totals
  17946. // Record old scaling for updating/animation
  17947. axis.old = {
  17948. len: axis.len,
  17949. max: axis.max,
  17950. min: axis.min,
  17951. transA: axis.transA,
  17952. userMax: axis.userMax,
  17953. userMin: axis.userMin
  17954. };
  17955. axis.isDirty = false;
  17956. fireEvent(this, 'afterRender');
  17957. };
  17958. /**
  17959. * Redraw the axis to reflect changes in the data or axis extremes. Called
  17960. * internally from Highcharts.Chart#redraw.
  17961. *
  17962. * @private
  17963. * @function Highcharts.Axis#redraw
  17964. */
  17965. Axis.prototype.redraw = function () {
  17966. if (this.visible) {
  17967. // render the axis
  17968. this.render();
  17969. // move plot lines and bands
  17970. this.plotLinesAndBands.forEach(function (plotLine) {
  17971. plotLine.render();
  17972. });
  17973. }
  17974. // mark associated series as dirty and ready for redraw
  17975. this.series.forEach(function (series) {
  17976. series.isDirty = true;
  17977. });
  17978. };
  17979. /**
  17980. * Returns an array of axis properties, that should be untouched during
  17981. * reinitialization.
  17982. *
  17983. * @private
  17984. * @function Highcharts.Axis#getKeepProps
  17985. *
  17986. * @return {Array<string>}
  17987. */
  17988. Axis.prototype.getKeepProps = function () {
  17989. return (this.keepProps || Axis.keepProps);
  17990. };
  17991. /**
  17992. * Destroys an Axis instance. See {@link Axis#remove} for the API endpoint
  17993. * to fully remove the axis.
  17994. *
  17995. * @private
  17996. * @function Highcharts.Axis#destroy
  17997. *
  17998. * @param {boolean} [keepEvents]
  17999. * Whether to preserve events, used internally in Axis.update.
  18000. */
  18001. Axis.prototype.destroy = function (keepEvents) {
  18002. var axis = this,
  18003. plotLinesAndBands = axis.plotLinesAndBands,
  18004. plotGroup,
  18005. i;
  18006. fireEvent(this, 'destroy', { keepEvents: keepEvents });
  18007. // Remove the events
  18008. if (!keepEvents) {
  18009. removeEvent(axis);
  18010. }
  18011. // Destroy collections
  18012. [axis.ticks, axis.minorTicks, axis.alternateBands].forEach(function (coll) {
  18013. destroyObjectProperties(coll);
  18014. });
  18015. if (plotLinesAndBands) {
  18016. i = plotLinesAndBands.length;
  18017. while (i--) { // #1975
  18018. plotLinesAndBands[i].destroy();
  18019. }
  18020. }
  18021. // Destroy elements
  18022. ['axisLine', 'axisTitle', 'axisGroup',
  18023. 'gridGroup', 'labelGroup', 'cross', 'scrollbar'].forEach(function (prop) {
  18024. if (axis[prop]) {
  18025. axis[prop] = axis[prop].destroy();
  18026. }
  18027. });
  18028. // Destroy each generated group for plotlines and plotbands
  18029. for (plotGroup in axis.plotLinesAndBandsGroups) { // eslint-disable-line guard-for-in
  18030. axis.plotLinesAndBandsGroups[plotGroup] =
  18031. axis.plotLinesAndBandsGroups[plotGroup].destroy();
  18032. }
  18033. // Delete all properties and fall back to the prototype.
  18034. objectEach(axis, function (val, key) {
  18035. if (axis.getKeepProps().indexOf(key) === -1) {
  18036. delete axis[key];
  18037. }
  18038. });
  18039. };
  18040. /**
  18041. * Internal function to draw a crosshair.
  18042. *
  18043. * @function Highcharts.Axis#drawCrosshair
  18044. *
  18045. * @param {Highcharts.PointerEventObject} [e]
  18046. * The event arguments from the modified pointer event, extended with
  18047. * `chartX` and `chartY`
  18048. *
  18049. * @param {Highcharts.Point} [point]
  18050. * The Point object if the crosshair snaps to points.
  18051. *
  18052. * @fires Highcharts.Axis#event:afterDrawCrosshair
  18053. * @fires Highcharts.Axis#event:drawCrosshair
  18054. */
  18055. Axis.prototype.drawCrosshair = function (e, point) {
  18056. var path,
  18057. options = this.crosshair,
  18058. snap = pick(options.snap,
  18059. true),
  18060. pos,
  18061. categorized,
  18062. graphic = this.cross,
  18063. crossOptions,
  18064. chart = this.chart;
  18065. fireEvent(this, 'drawCrosshair', { e: e, point: point });
  18066. // Use last available event when updating non-snapped crosshairs without
  18067. // mouse interaction (#5287)
  18068. if (!e) {
  18069. e = this.cross && this.cross.e;
  18070. }
  18071. if (
  18072. // Disabled in options
  18073. !this.crosshair ||
  18074. // Snap
  18075. ((defined(point) || !snap) === false)) {
  18076. this.hideCrosshair();
  18077. }
  18078. else {
  18079. // Get the path
  18080. if (!snap) {
  18081. pos = e &&
  18082. (this.horiz ?
  18083. e.chartX - this.pos :
  18084. this.len - e.chartY + this.pos);
  18085. }
  18086. else if (defined(point)) {
  18087. // #3834
  18088. pos = pick(this.coll !== 'colorAxis' ?
  18089. point.crosshairPos : // 3D axis extension
  18090. null, this.isXAxis ?
  18091. point.plotX :
  18092. this.len - point.plotY);
  18093. }
  18094. if (defined(pos)) {
  18095. crossOptions = {
  18096. // value, only used on radial
  18097. value: point && (this.isXAxis ?
  18098. point.x :
  18099. pick(point.stackY, point.y)),
  18100. translatedValue: pos
  18101. };
  18102. if (chart.polar) {
  18103. // Additional information required for crosshairs in
  18104. // polar chart
  18105. extend(crossOptions, {
  18106. isCrosshair: true,
  18107. chartX: e && e.chartX,
  18108. chartY: e && e.chartY,
  18109. point: point
  18110. });
  18111. }
  18112. path = this.getPlotLinePath(crossOptions) ||
  18113. null; // #3189
  18114. }
  18115. if (!defined(path)) {
  18116. this.hideCrosshair();
  18117. return;
  18118. }
  18119. categorized = this.categories && !this.isRadial;
  18120. // Draw the cross
  18121. if (!graphic) {
  18122. this.cross = graphic = chart.renderer
  18123. .path()
  18124. .addClass('highcharts-crosshair highcharts-crosshair-' +
  18125. (categorized ? 'category ' : 'thin ') +
  18126. options.className)
  18127. .attr({
  18128. zIndex: pick(options.zIndex, 2)
  18129. })
  18130. .add();
  18131. // Presentational attributes
  18132. if (!chart.styledMode) {
  18133. graphic.attr({
  18134. stroke: options.color ||
  18135. (categorized ?
  18136. Color
  18137. .parse(palette.highlightColor20)
  18138. .setOpacity(0.25)
  18139. .get() :
  18140. palette.neutralColor20),
  18141. 'stroke-width': pick(options.width, 1)
  18142. }).css({
  18143. 'pointer-events': 'none'
  18144. });
  18145. if (options.dashStyle) {
  18146. graphic.attr({
  18147. dashstyle: options.dashStyle
  18148. });
  18149. }
  18150. }
  18151. }
  18152. graphic.show().attr({
  18153. d: path
  18154. });
  18155. if (categorized && !options.width) {
  18156. graphic.attr({
  18157. 'stroke-width': this.transA
  18158. });
  18159. }
  18160. this.cross.e = e;
  18161. }
  18162. fireEvent(this, 'afterDrawCrosshair', { e: e, point: point });
  18163. };
  18164. /**
  18165. * Hide the crosshair if visible.
  18166. *
  18167. * @function Highcharts.Axis#hideCrosshair
  18168. */
  18169. Axis.prototype.hideCrosshair = function () {
  18170. if (this.cross) {
  18171. this.cross.hide();
  18172. }
  18173. fireEvent(this, 'afterHideCrosshair');
  18174. };
  18175. /**
  18176. * Check whether the chart has vertical panning ('y' or 'xy' type).
  18177. *
  18178. * @private
  18179. * @function Highcharts.Axis#hasVerticalPanning
  18180. * @return {boolean}
  18181. *
  18182. */
  18183. Axis.prototype.hasVerticalPanning = function () {
  18184. var _a;
  18185. var panningOptions = (_a = this.chart.options.chart) === null || _a === void 0 ? void 0 : _a.panning;
  18186. return Boolean(panningOptions &&
  18187. panningOptions.enabled && // #14624
  18188. /y/.test(panningOptions.type));
  18189. };
  18190. /**
  18191. * Check whether the given value is a positive valid axis value.
  18192. *
  18193. * @private
  18194. * @function Highcharts.Axis#validatePositiveValue
  18195. *
  18196. * @param {unknown} value
  18197. * The axis value
  18198. *
  18199. * @return {boolean}
  18200. */
  18201. Axis.prototype.validatePositiveValue = function (value) {
  18202. return isNumber(value) && value > 0;
  18203. };
  18204. /**
  18205. * Update an axis object with a new set of options. The options are merged
  18206. * with the existing options, so only new or altered options need to be
  18207. * specified.
  18208. *
  18209. * @sample highcharts/members/axis-update/
  18210. * Axis update demo
  18211. *
  18212. * @function Highcharts.Axis#update
  18213. *
  18214. * @param {Highcharts.AxisOptions} options
  18215. * The new options that will be merged in with existing options on
  18216. * the axis.
  18217. *
  18218. * @param {boolean} [redraw=true]
  18219. * Whether to redraw the chart after the axis is altered. If doing
  18220. * more operations on the chart, it is a good idea to set redraw to
  18221. * false and call {@link Chart#redraw} after.
  18222. */
  18223. Axis.prototype.update = function (options, redraw) {
  18224. var chart = this.chart,
  18225. newEvents = ((options && options.events) || {});
  18226. options = merge(this.userOptions, options);
  18227. // Color Axis is not an array,
  18228. // This change is applied in the ColorAxis wrapper
  18229. if (chart.options[this.coll].indexOf) {
  18230. // Don't use this.options.index,
  18231. // StockChart has Axes in navigator too
  18232. chart.options[this.coll][chart.options[this.coll].indexOf(this.userOptions)] = options;
  18233. }
  18234. // Remove old events, if no new exist (#8161)
  18235. objectEach(chart.options[this.coll].events, function (fn, ev) {
  18236. if (typeof newEvents[ev] === 'undefined') {
  18237. newEvents[ev] = void 0;
  18238. }
  18239. });
  18240. this.destroy(true);
  18241. this.init(chart, extend(options, { events: newEvents }));
  18242. chart.isDirtyBox = true;
  18243. if (pick(redraw, true)) {
  18244. chart.redraw();
  18245. }
  18246. };
  18247. /**
  18248. * Remove the axis from the chart.
  18249. *
  18250. * @sample highcharts/members/chart-addaxis/
  18251. * Add and remove axes
  18252. *
  18253. * @function Highcharts.Axis#remove
  18254. *
  18255. * @param {boolean} [redraw=true]
  18256. * Whether to redraw the chart following the remove.
  18257. */
  18258. Axis.prototype.remove = function (redraw) {
  18259. var chart = this.chart,
  18260. key = this.coll, // xAxis or yAxis
  18261. axisSeries = this.series,
  18262. i = axisSeries.length;
  18263. // Remove associated series (#2687)
  18264. while (i--) {
  18265. if (axisSeries[i]) {
  18266. axisSeries[i].remove(false);
  18267. }
  18268. }
  18269. // Remove the axis
  18270. erase(chart.axes, this);
  18271. erase(chart[key], this);
  18272. if (isArray(chart.options[key])) {
  18273. chart.options[key].splice(this.options.index, 1);
  18274. }
  18275. else { // color axis, #6488
  18276. delete chart.options[key];
  18277. }
  18278. chart[key].forEach(function (axis, i) {
  18279. // Re-index, #1706, #8075
  18280. axis.options.index = axis.userOptions.index = i;
  18281. });
  18282. this.destroy();
  18283. chart.isDirtyBox = true;
  18284. if (pick(redraw, true)) {
  18285. chart.redraw();
  18286. }
  18287. };
  18288. /**
  18289. * Update the axis title by options after render time.
  18290. *
  18291. * @sample highcharts/members/axis-settitle/
  18292. * Set a new Y axis title
  18293. *
  18294. * @function Highcharts.Axis#setTitle
  18295. *
  18296. * @param {Highcharts.AxisTitleOptions} titleOptions
  18297. * The additional title options.
  18298. *
  18299. * @param {boolean} [redraw=true]
  18300. * Whether to redraw the chart after setting the title.
  18301. *
  18302. * @return {void}
  18303. */
  18304. Axis.prototype.setTitle = function (titleOptions, redraw) {
  18305. this.update({ title: titleOptions }, redraw);
  18306. };
  18307. /**
  18308. * Set new axis categories and optionally redraw.
  18309. *
  18310. * @sample highcharts/members/axis-setcategories/
  18311. * Set categories by click on a button
  18312. *
  18313. * @function Highcharts.Axis#setCategories
  18314. *
  18315. * @param {Array<string>} categories
  18316. * The new categories.
  18317. *
  18318. * @param {boolean} [redraw=true]
  18319. * Whether to redraw the chart.
  18320. */
  18321. Axis.prototype.setCategories = function (categories, redraw) {
  18322. this.update({ categories: categories }, redraw);
  18323. };
  18324. /* *
  18325. *
  18326. * Static Properties
  18327. *
  18328. * */
  18329. /**
  18330. * The X axis or category axis. Normally this is the horizontal axis,
  18331. * though if the chart is inverted this is the vertical axis. In case of
  18332. * multiple axes, the xAxis node is an array of configuration objects.
  18333. *
  18334. * See the [Axis class](/class-reference/Highcharts.Axis) for programmatic
  18335. * access to the axis.
  18336. *
  18337. * @productdesc {highmaps}
  18338. * In Highmaps, the axis is hidden, but it is used behind the scenes to
  18339. * control features like zooming and panning. Zooming is in effect the same
  18340. * as setting the extremes of one of the exes.
  18341. *
  18342. * @type {*|Array<*>}
  18343. * @optionparent xAxis
  18344. *
  18345. * @private
  18346. */
  18347. Axis.defaultOptions = {
  18348. /**
  18349. * When using multiple axis, the ticks of two or more opposite axes
  18350. * will automatically be aligned by adding ticks to the axis or axes
  18351. * with the least ticks, as if `tickAmount` were specified.
  18352. *
  18353. * This can be prevented by setting `alignTicks` to false. If the grid
  18354. * lines look messy, it's a good idea to hide them for the secondary
  18355. * axis by setting `gridLineWidth` to 0.
  18356. *
  18357. * If `startOnTick` or `endOnTick` in an Axis options are set to false,
  18358. * then the `alignTicks ` will be disabled for the Axis.
  18359. *
  18360. * Disabled for logarithmic axes.
  18361. *
  18362. * @type {boolean}
  18363. * @default true
  18364. * @product highcharts highstock gantt
  18365. * @apioption xAxis.alignTicks
  18366. */
  18367. /**
  18368. * Whether to allow decimals in this axis' ticks. When counting
  18369. * integers, like persons or hits on a web page, decimals should
  18370. * be avoided in the labels.
  18371. *
  18372. * @see [minTickInterval](#xAxis.minTickInterval)
  18373. *
  18374. * @sample {highcharts|highstock} highcharts/yaxis/allowdecimals-true/
  18375. * True by default
  18376. * @sample {highcharts|highstock} highcharts/yaxis/allowdecimals-false/
  18377. * False
  18378. *
  18379. * @type {boolean}
  18380. * @default true
  18381. * @since 2.0
  18382. * @apioption xAxis.allowDecimals
  18383. */
  18384. /**
  18385. * When using an alternate grid color, a band is painted across the
  18386. * plot area between every other grid line.
  18387. *
  18388. * @sample {highcharts} highcharts/yaxis/alternategridcolor/
  18389. * Alternate grid color on the Y axis
  18390. * @sample {highstock} stock/xaxis/alternategridcolor/
  18391. * Alternate grid color on the Y axis
  18392. *
  18393. * @type {Highcharts.ColorType}
  18394. * @apioption xAxis.alternateGridColor
  18395. */
  18396. /**
  18397. * An array defining breaks in the axis, the sections defined will be
  18398. * left out and all the points shifted closer to each other.
  18399. *
  18400. * @productdesc {highcharts}
  18401. * Requires that the broken-axis.js module is loaded.
  18402. *
  18403. * @sample {highcharts} highcharts/axisbreak/break-simple/
  18404. * Simple break
  18405. * @sample {highcharts|highstock} highcharts/axisbreak/break-visualized/
  18406. * Advanced with callback
  18407. * @sample {highstock} stock/demo/intraday-breaks/
  18408. * Break on nights and weekends
  18409. *
  18410. * @type {Array<*>}
  18411. * @since 4.1.0
  18412. * @product highcharts highstock gantt
  18413. * @apioption xAxis.breaks
  18414. */
  18415. /**
  18416. * A number indicating how much space should be left between the start
  18417. * and the end of the break. The break size is given in axis units,
  18418. * so for instance on a `datetime` axis, a break size of 3600000 would
  18419. * indicate the equivalent of an hour.
  18420. *
  18421. * @type {number}
  18422. * @default 0
  18423. * @since 4.1.0
  18424. * @product highcharts highstock gantt
  18425. * @apioption xAxis.breaks.breakSize
  18426. */
  18427. /**
  18428. * The point where the break starts.
  18429. *
  18430. * @type {number}
  18431. * @since 4.1.0
  18432. * @product highcharts highstock gantt
  18433. * @apioption xAxis.breaks.from
  18434. */
  18435. /**
  18436. * Defines an interval after which the break appears again. By default
  18437. * the breaks do not repeat.
  18438. *
  18439. * @type {number}
  18440. * @default 0
  18441. * @since 4.1.0
  18442. * @product highcharts highstock gantt
  18443. * @apioption xAxis.breaks.repeat
  18444. */
  18445. /**
  18446. * The point where the break ends.
  18447. *
  18448. * @type {number}
  18449. * @since 4.1.0
  18450. * @product highcharts highstock gantt
  18451. * @apioption xAxis.breaks.to
  18452. */
  18453. /**
  18454. * If categories are present for the xAxis, names are used instead of
  18455. * numbers for that axis.
  18456. *
  18457. * Since Highcharts 3.0, categories can also
  18458. * be extracted by giving each point a [name](#series.data) and setting
  18459. * axis [type](#xAxis.type) to `category`. However, if you have multiple
  18460. * series, best practice remains defining the `categories` array.
  18461. *
  18462. * Example: `categories: ['Apples', 'Bananas', 'Oranges']`
  18463. *
  18464. * @sample {highcharts} highcharts/demo/line-labels/
  18465. * With
  18466. * @sample {highcharts} highcharts/xaxis/categories/
  18467. * Without
  18468. *
  18469. * @type {Array<string>}
  18470. * @product highcharts gantt
  18471. * @apioption xAxis.categories
  18472. */
  18473. /**
  18474. * The highest allowed value for automatically computed axis extremes.
  18475. *
  18476. * @see [floor](#xAxis.floor)
  18477. *
  18478. * @sample {highcharts|highstock} highcharts/yaxis/floor-ceiling/
  18479. * Floor and ceiling
  18480. *
  18481. * @type {number}
  18482. * @since 4.0
  18483. * @product highcharts highstock gantt
  18484. * @apioption xAxis.ceiling
  18485. */
  18486. /**
  18487. * A class name that opens for styling the axis by CSS, especially in
  18488. * Highcharts styled mode. The class name is applied to group elements
  18489. * for the grid, axis elements and labels.
  18490. *
  18491. * @sample {highcharts|highstock|highmaps} highcharts/css/axis/
  18492. * Multiple axes with separate styling
  18493. *
  18494. * @type {string}
  18495. * @since 5.0.0
  18496. * @apioption xAxis.className
  18497. */
  18498. /**
  18499. * Configure a crosshair that follows either the mouse pointer or the
  18500. * hovered point.
  18501. *
  18502. * In styled mode, the crosshairs are styled in the
  18503. * `.highcharts-crosshair`, `.highcharts-crosshair-thin` or
  18504. * `.highcharts-xaxis-category` classes.
  18505. *
  18506. * @productdesc {highstock}
  18507. * In Highstock, by default, the crosshair is enabled on the X axis and
  18508. * disabled on the Y axis.
  18509. *
  18510. * @sample {highcharts} highcharts/xaxis/crosshair-both/
  18511. * Crosshair on both axes
  18512. * @sample {highstock} stock/xaxis/crosshairs-xy/
  18513. * Crosshair on both axes
  18514. * @sample {highmaps} highcharts/xaxis/crosshair-both/
  18515. * Crosshair on both axes
  18516. *
  18517. * @declare Highcharts.AxisCrosshairOptions
  18518. * @type {boolean|*}
  18519. * @default false
  18520. * @since 4.1
  18521. * @apioption xAxis.crosshair
  18522. */
  18523. /**
  18524. * A class name for the crosshair, especially as a hook for styling.
  18525. *
  18526. * @type {string}
  18527. * @since 5.0.0
  18528. * @apioption xAxis.crosshair.className
  18529. */
  18530. /**
  18531. * The color of the crosshair. Defaults to `#cccccc` for numeric and
  18532. * datetime axes, and `rgba(204,214,235,0.25)` for category axes, where
  18533. * the crosshair by default highlights the whole category.
  18534. *
  18535. * @sample {highcharts|highstock|highmaps} highcharts/xaxis/crosshair-customized/
  18536. * Customized crosshairs
  18537. *
  18538. * @type {Highcharts.ColorType}
  18539. * @default #cccccc
  18540. * @since 4.1
  18541. * @apioption xAxis.crosshair.color
  18542. */
  18543. /**
  18544. * The dash style for the crosshair. See
  18545. * [plotOptions.series.dashStyle](#plotOptions.series.dashStyle)
  18546. * for possible values.
  18547. *
  18548. * @sample {highcharts|highmaps} highcharts/xaxis/crosshair-dotted/
  18549. * Dotted crosshair
  18550. * @sample {highstock} stock/xaxis/crosshair-dashed/
  18551. * Dashed X axis crosshair
  18552. *
  18553. * @type {Highcharts.DashStyleValue}
  18554. * @default Solid
  18555. * @since 4.1
  18556. * @apioption xAxis.crosshair.dashStyle
  18557. */
  18558. /**
  18559. * A label on the axis next to the crosshair.
  18560. *
  18561. * In styled mode, the label is styled with the
  18562. * `.highcharts-crosshair-label` class.
  18563. *
  18564. * @sample {highstock} stock/xaxis/crosshair-label/
  18565. * Crosshair labels
  18566. * @sample {highstock} highcharts/css/crosshair-label/
  18567. * Style mode
  18568. *
  18569. * @declare Highcharts.AxisCrosshairLabelOptions
  18570. * @since 2.1
  18571. * @product highstock
  18572. * @apioption xAxis.crosshair.label
  18573. */
  18574. /**
  18575. * Alignment of the label compared to the axis. Defaults to `"left"` for
  18576. * right-side axes, `"right"` for left-side axes and `"center"` for
  18577. * horizontal axes.
  18578. *
  18579. * @type {Highcharts.AlignValue}
  18580. * @since 2.1
  18581. * @product highstock
  18582. * @apioption xAxis.crosshair.label.align
  18583. */
  18584. /**
  18585. * The background color for the label. Defaults to the related series
  18586. * color, or `#666666` if that is not available.
  18587. *
  18588. * @type {Highcharts.ColorType}
  18589. * @since 2.1
  18590. * @product highstock
  18591. * @apioption xAxis.crosshair.label.backgroundColor
  18592. */
  18593. /**
  18594. * The border color for the crosshair label
  18595. *
  18596. * @type {Highcharts.ColorType}
  18597. * @since 2.1
  18598. * @product highstock
  18599. * @apioption xAxis.crosshair.label.borderColor
  18600. */
  18601. /**
  18602. * The border corner radius of the crosshair label.
  18603. *
  18604. * @type {number}
  18605. * @default 3
  18606. * @since 2.1.10
  18607. * @product highstock
  18608. * @apioption xAxis.crosshair.label.borderRadius
  18609. */
  18610. /**
  18611. * The border width for the crosshair label.
  18612. *
  18613. * @type {number}
  18614. * @default 0
  18615. * @since 2.1
  18616. * @product highstock
  18617. * @apioption xAxis.crosshair.label.borderWidth
  18618. */
  18619. /**
  18620. * Flag to enable crosshair's label.
  18621. *
  18622. * @sample {highstock} stock/xaxis/crosshairs-xy/
  18623. * Enabled label for yAxis' crosshair
  18624. *
  18625. * @type {boolean}
  18626. * @default false
  18627. * @since 2.1
  18628. * @product highstock
  18629. * @apioption xAxis.crosshair.label.enabled
  18630. */
  18631. /**
  18632. * A format string for the crosshair label. Defaults to `{value}` for
  18633. * numeric axes and `{value:%b %d, %Y}` for datetime axes.
  18634. *
  18635. * @type {string}
  18636. * @since 2.1
  18637. * @product highstock
  18638. * @apioption xAxis.crosshair.label.format
  18639. */
  18640. /**
  18641. * Formatter function for the label text.
  18642. *
  18643. * @type {Highcharts.XAxisCrosshairLabelFormatterCallbackFunction}
  18644. * @since 2.1
  18645. * @product highstock
  18646. * @apioption xAxis.crosshair.label.formatter
  18647. */
  18648. /**
  18649. * Padding inside the crosshair label.
  18650. *
  18651. * @type {number}
  18652. * @default 8
  18653. * @since 2.1
  18654. * @product highstock
  18655. * @apioption xAxis.crosshair.label.padding
  18656. */
  18657. /**
  18658. * The shape to use for the label box.
  18659. *
  18660. * @type {string}
  18661. * @default callout
  18662. * @since 2.1
  18663. * @product highstock
  18664. * @apioption xAxis.crosshair.label.shape
  18665. */
  18666. /**
  18667. * Text styles for the crosshair label.
  18668. *
  18669. * @type {Highcharts.CSSObject}
  18670. * @default {"color": "white", "fontWeight": "normal", "fontSize": "11px", "textAlign": "center"}
  18671. * @since 2.1
  18672. * @product highstock
  18673. * @apioption xAxis.crosshair.label.style
  18674. */
  18675. /**
  18676. * Whether the crosshair should snap to the point or follow the pointer
  18677. * independent of points.
  18678. *
  18679. * @sample {highcharts|highstock} highcharts/xaxis/crosshair-snap-false/
  18680. * True by default
  18681. * @sample {highmaps} maps/demo/latlon-advanced/
  18682. * Snap is false
  18683. *
  18684. * @type {boolean}
  18685. * @default true
  18686. * @since 4.1
  18687. * @apioption xAxis.crosshair.snap
  18688. */
  18689. /**
  18690. * The pixel width of the crosshair. Defaults to 1 for numeric or
  18691. * datetime axes, and for one category width for category axes.
  18692. *
  18693. * @sample {highcharts} highcharts/xaxis/crosshair-customized/
  18694. * Customized crosshairs
  18695. * @sample {highstock} highcharts/xaxis/crosshair-customized/
  18696. * Customized crosshairs
  18697. * @sample {highmaps} highcharts/xaxis/crosshair-customized/
  18698. * Customized crosshairs
  18699. *
  18700. * @type {number}
  18701. * @default 1
  18702. * @since 4.1
  18703. * @apioption xAxis.crosshair.width
  18704. */
  18705. /**
  18706. * The Z index of the crosshair. Higher Z indices allow drawing the
  18707. * crosshair on top of the series or behind the grid lines.
  18708. *
  18709. * @type {number}
  18710. * @default 2
  18711. * @since 4.1
  18712. * @apioption xAxis.crosshair.zIndex
  18713. */
  18714. /**
  18715. * Whether to zoom axis. If `chart.zoomType` is set, the option allows
  18716. * to disable zooming on an individual axis.
  18717. *
  18718. * @sample {highcharts} highcharts/xaxis/zoomenabled/
  18719. * Zoom enabled is false
  18720. *
  18721. *
  18722. * @type {boolean}
  18723. * @default enabled
  18724. * @apioption xAxis.zoomEnabled
  18725. */
  18726. /**
  18727. * For a datetime axis, the scale will automatically adjust to the
  18728. * appropriate unit. This member gives the default string
  18729. * representations used for each unit. For intermediate values,
  18730. * different units may be used, for example the `day` unit can be used
  18731. * on midnight and `hour` unit be used for intermediate values on the
  18732. * same axis.
  18733. *
  18734. * For an overview of the replacement codes, see
  18735. * [dateFormat](/class-reference/Highcharts#dateFormat).
  18736. *
  18737. * Defaults to:
  18738. * ```js
  18739. * {
  18740. * millisecond: '%H:%M:%S.%L',
  18741. * second: '%H:%M:%S',
  18742. * minute: '%H:%M',
  18743. * hour: '%H:%M',
  18744. * day: '%e. %b',
  18745. * week: '%e. %b',
  18746. * month: '%b \'%y',
  18747. * year: '%Y'
  18748. * }
  18749. * ```
  18750. *
  18751. * @sample {highcharts} highcharts/xaxis/datetimelabelformats/
  18752. * Different day format on X axis
  18753. * @sample {highstock} stock/xaxis/datetimelabelformats/
  18754. * More information in x axis labels
  18755. *
  18756. * @declare Highcharts.AxisDateTimeLabelFormatsOptions
  18757. * @product highcharts highstock gantt
  18758. */
  18759. dateTimeLabelFormats: {
  18760. /**
  18761. * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
  18762. * @type {string|*}
  18763. */
  18764. millisecond: {
  18765. main: '%H:%M:%S.%L',
  18766. range: false
  18767. },
  18768. /**
  18769. * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
  18770. * @type {string|*}
  18771. */
  18772. second: {
  18773. main: '%H:%M:%S',
  18774. range: false
  18775. },
  18776. /**
  18777. * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
  18778. * @type {string|*}
  18779. */
  18780. minute: {
  18781. main: '%H:%M',
  18782. range: false
  18783. },
  18784. /**
  18785. * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
  18786. * @type {string|*}
  18787. */
  18788. hour: {
  18789. main: '%H:%M',
  18790. range: false
  18791. },
  18792. /**
  18793. * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
  18794. * @type {string|*}
  18795. */
  18796. day: {
  18797. main: '%e. %b'
  18798. },
  18799. /**
  18800. * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
  18801. * @type {string|*}
  18802. */
  18803. week: {
  18804. main: '%e. %b'
  18805. },
  18806. /**
  18807. * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
  18808. * @type {string|*}
  18809. */
  18810. month: {
  18811. main: '%b \'%y'
  18812. },
  18813. /**
  18814. * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
  18815. * @type {string|*}
  18816. */
  18817. year: {
  18818. main: '%Y'
  18819. }
  18820. },
  18821. /**
  18822. * Whether to force the axis to end on a tick. Use this option with
  18823. * the `maxPadding` option to control the axis end.
  18824. *
  18825. * @productdesc {highstock}
  18826. * In Highstock, `endOnTick` is always `false` when the navigator
  18827. * is enabled, to prevent jumpy scrolling.
  18828. *
  18829. * @sample {highcharts} highcharts/chart/reflow-true/
  18830. * True by default
  18831. * @sample {highcharts} highcharts/yaxis/endontick/
  18832. * False
  18833. * @sample {highstock} stock/demo/basic-line/
  18834. * True by default
  18835. * @sample {highstock} stock/xaxis/endontick/
  18836. * False
  18837. *
  18838. * @since 1.2.0
  18839. */
  18840. endOnTick: false,
  18841. /**
  18842. * Event handlers for the axis.
  18843. *
  18844. * @type {*}
  18845. * @apioption xAxis.events
  18846. */
  18847. /**
  18848. * An event fired after the breaks have rendered.
  18849. *
  18850. * @see [breaks](#xAxis.breaks)
  18851. *
  18852. * @sample {highcharts} highcharts/axisbreak/break-event/
  18853. * AfterBreak Event
  18854. *
  18855. * @type {Highcharts.AxisEventCallbackFunction}
  18856. * @since 4.1.0
  18857. * @product highcharts gantt
  18858. * @apioption xAxis.events.afterBreaks
  18859. */
  18860. /**
  18861. * As opposed to the `setExtremes` event, this event fires after the
  18862. * final min and max values are computed and corrected for `minRange`.
  18863. *
  18864. * Fires when the minimum and maximum is set for the axis, either by
  18865. * calling the `.setExtremes()` method or by selecting an area in the
  18866. * chart. One parameter, `event`, is passed to the function, containing
  18867. * common event information.
  18868. *
  18869. * The new user set minimum and maximum values can be found by
  18870. * `event.min` and `event.max`. These reflect the axis minimum and
  18871. * maximum in axis values. The actual data extremes are found in
  18872. * `event.dataMin` and `event.dataMax`.
  18873. *
  18874. * @type {Highcharts.AxisSetExtremesEventCallbackFunction}
  18875. * @since 2.3
  18876. * @context Highcharts.Axis
  18877. * @apioption xAxis.events.afterSetExtremes
  18878. */
  18879. /**
  18880. * An event fired when a break from this axis occurs on a point.
  18881. *
  18882. * @see [breaks](#xAxis.breaks)
  18883. *
  18884. * @sample {highcharts} highcharts/axisbreak/break-visualized/
  18885. * Visualization of a Break
  18886. *
  18887. * @type {Highcharts.AxisPointBreakEventCallbackFunction}
  18888. * @since 4.1.0
  18889. * @product highcharts gantt
  18890. * @context Highcharts.Axis
  18891. * @apioption xAxis.events.pointBreak
  18892. */
  18893. /**
  18894. * An event fired when a point falls inside a break from this axis.
  18895. *
  18896. * @type {Highcharts.AxisPointBreakEventCallbackFunction}
  18897. * @product highcharts highstock gantt
  18898. * @context Highcharts.Axis
  18899. * @apioption xAxis.events.pointInBreak
  18900. */
  18901. /**
  18902. * Fires when the minimum and maximum is set for the axis, either by
  18903. * calling the `.setExtremes()` method or by selecting an area in the
  18904. * chart. One parameter, `event`, is passed to the function,
  18905. * containing common event information.
  18906. *
  18907. * The new user set minimum and maximum values can be found by
  18908. * `event.min` and `event.max`. These reflect the axis minimum and
  18909. * maximum in data values. When an axis is zoomed all the way out from
  18910. * the "Reset zoom" button, `event.min` and `event.max` are null, and
  18911. * the new extremes are set based on `this.dataMin` and `this.dataMax`.
  18912. *
  18913. * @sample {highstock} stock/xaxis/events-setextremes/
  18914. * Log new extremes on x axis
  18915. *
  18916. * @type {Highcharts.AxisSetExtremesEventCallbackFunction}
  18917. * @since 1.2.0
  18918. * @context Highcharts.Axis
  18919. * @apioption xAxis.events.setExtremes
  18920. */
  18921. /**
  18922. * The lowest allowed value for automatically computed axis extremes.
  18923. *
  18924. * @see [ceiling](#yAxis.ceiling)
  18925. *
  18926. * @sample {highcharts} highcharts/yaxis/floor-ceiling/
  18927. * Floor and ceiling
  18928. * @sample {highstock} stock/demo/lazy-loading/
  18929. * Prevent negative stock price on Y axis
  18930. *
  18931. * @type {number}
  18932. * @since 4.0
  18933. * @product highcharts highstock gantt
  18934. * @apioption xAxis.floor
  18935. */
  18936. /**
  18937. * The dash or dot style of the grid lines. For possible values, see
  18938. * [this demonstration](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/series-dashstyle-all/).
  18939. *
  18940. * @sample {highcharts} highcharts/yaxis/gridlinedashstyle/
  18941. * Long dashes
  18942. * @sample {highstock} stock/xaxis/gridlinedashstyle/
  18943. * Long dashes
  18944. *
  18945. * @type {Highcharts.DashStyleValue}
  18946. * @default Solid
  18947. * @since 1.2
  18948. * @apioption xAxis.gridLineDashStyle
  18949. */
  18950. /**
  18951. * The Z index of the grid lines.
  18952. *
  18953. * @sample {highcharts|highstock} highcharts/xaxis/gridzindex/
  18954. * A Z index of 4 renders the grid above the graph
  18955. *
  18956. * @type {number}
  18957. * @default 1
  18958. * @product highcharts highstock gantt
  18959. * @apioption xAxis.gridZIndex
  18960. */
  18961. /**
  18962. * An id for the axis. This can be used after render time to get
  18963. * a pointer to the axis object through `chart.get()`.
  18964. *
  18965. * @sample {highcharts} highcharts/xaxis/id/
  18966. * Get the object
  18967. * @sample {highstock} stock/xaxis/id/
  18968. * Get the object
  18969. *
  18970. * @type {string}
  18971. * @since 1.2.0
  18972. * @apioption xAxis.id
  18973. */
  18974. /**
  18975. * The axis labels show the number or category for each tick.
  18976. *
  18977. * Since v8.0.0: Labels are animated in categorized x-axis with
  18978. * updating data if `tickInterval` and `step` is set to 1.
  18979. *
  18980. * @productdesc {highmaps}
  18981. * X and Y axis labels are by default disabled in Highmaps, but the
  18982. * functionality is inherited from Highcharts and used on `colorAxis`,
  18983. * and can be enabled on X and Y axes too.
  18984. */
  18985. labels: {
  18986. /**
  18987. * What part of the string the given position is anchored to.
  18988. * If `left`, the left side of the string is at the axis position.
  18989. * Can be one of `"left"`, `"center"` or `"right"`. Defaults to
  18990. * an intelligent guess based on which side of the chart the axis
  18991. * is on and the rotation of the label.
  18992. *
  18993. * @see [reserveSpace](#xAxis.labels.reserveSpace)
  18994. *
  18995. * @sample {highcharts} highcharts/xaxis/labels-align-left/
  18996. * Left
  18997. * @sample {highcharts} highcharts/xaxis/labels-align-right/
  18998. * Right
  18999. * @sample {highcharts} highcharts/xaxis/labels-reservespace-true/
  19000. * Left-aligned labels on a vertical category axis
  19001. *
  19002. * @type {Highcharts.AlignValue}
  19003. * @apioption xAxis.labels.align
  19004. */
  19005. /**
  19006. * For horizontal axes, the allowed degrees of label rotation
  19007. * to prevent overlapping labels. If there is enough space,
  19008. * labels are not rotated. As the chart gets narrower, it
  19009. * will start rotating the labels -45 degrees, then remove
  19010. * every second label and try again with rotations 0 and -45 etc.
  19011. * Set it to `false` to disable rotation, which will
  19012. * cause the labels to word-wrap if possible.
  19013. *
  19014. * @sample {highcharts|highstock} highcharts/xaxis/labels-autorotation-default/
  19015. * Default auto rotation of 0 or -45
  19016. * @sample {highcharts|highstock} highcharts/xaxis/labels-autorotation-0-90/
  19017. * Custom graded auto rotation
  19018. *
  19019. * @type {Array<number>|false}
  19020. * @default [-45]
  19021. * @since 4.1.0
  19022. * @product highcharts highstock gantt
  19023. * @apioption xAxis.labels.autoRotation
  19024. */
  19025. /**
  19026. * When each category width is more than this many pixels, we don't
  19027. * apply auto rotation. Instead, we lay out the axis label with word
  19028. * wrap. A lower limit makes sense when the label contains multiple
  19029. * short words that don't extend the available horizontal space for
  19030. * each label.
  19031. *
  19032. * @sample {highcharts} highcharts/xaxis/labels-autorotationlimit/
  19033. * Lower limit
  19034. *
  19035. * @type {number}
  19036. * @default 80
  19037. * @since 4.1.5
  19038. * @product highcharts gantt
  19039. * @apioption xAxis.labels.autoRotationLimit
  19040. */
  19041. /**
  19042. * Polar charts only. The label's pixel distance from the perimeter
  19043. * of the plot area.
  19044. *
  19045. * @type {number}
  19046. * @default 15
  19047. * @product highcharts gantt
  19048. * @apioption xAxis.labels.distance
  19049. */
  19050. /**
  19051. * Enable or disable the axis labels.
  19052. *
  19053. * @sample {highcharts} highcharts/xaxis/labels-enabled/
  19054. * X axis labels disabled
  19055. * @sample {highstock} stock/xaxis/labels-enabled/
  19056. * X axis labels disabled
  19057. *
  19058. * @default {highcharts|highstock|gantt} true
  19059. * @default {highmaps} false
  19060. */
  19061. enabled: true,
  19062. /**
  19063. * A format string for the axis label. See
  19064. * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
  19065. * for example usage.
  19066. *
  19067. * Note: The default value is not specified due to the dynamic
  19068. * nature of the default implementation.
  19069. *
  19070. * @sample {highcharts|highstock} highcharts/yaxis/labels-format/
  19071. * Add units to Y axis label
  19072. *
  19073. * @type {string}
  19074. * @since 3.0
  19075. * @apioption xAxis.labels.format
  19076. */
  19077. /**
  19078. * Callback JavaScript function to format the label. The value
  19079. * is given by `this.value`. Additional properties for `this` are
  19080. * `axis`, `chart`, `isFirst` and `isLast`. The value of the default
  19081. * label formatter can be retrieved by calling
  19082. * `this.axis.defaultLabelFormatter.call(this)` within the function.
  19083. *
  19084. * Defaults to:
  19085. * ```js
  19086. * function() {
  19087. * return this.value;
  19088. * }
  19089. * ```
  19090. *
  19091. * @sample {highcharts} highcharts/xaxis/labels-formatter-linked/
  19092. * Linked category names
  19093. * @sample {highcharts} highcharts/xaxis/labels-formatter-extended/
  19094. * Modified numeric labels
  19095. * @sample {highstock} stock/xaxis/labels-formatter/
  19096. * Added units on Y axis
  19097. *
  19098. * @type {Highcharts.AxisLabelsFormatterCallbackFunction}
  19099. * @apioption xAxis.labels.formatter
  19100. */
  19101. /**
  19102. * The number of pixels to indent the labels per level in a treegrid
  19103. * axis.
  19104. *
  19105. * @sample gantt/treegrid-axis/demo
  19106. * Indentation 10px by default.
  19107. * @sample gantt/treegrid-axis/indentation-0px
  19108. * Indentation set to 0px.
  19109. *
  19110. * @product gantt
  19111. */
  19112. indentation: 10,
  19113. /**
  19114. * Horizontal axis only. When `staggerLines` is not set,
  19115. * `maxStaggerLines` defines how many lines the axis is allowed to
  19116. * add to automatically avoid overlapping X labels. Set to `1` to
  19117. * disable overlap detection.
  19118. *
  19119. * @deprecated
  19120. * @type {number}
  19121. * @default 5
  19122. * @since 1.3.3
  19123. * @apioption xAxis.labels.maxStaggerLines
  19124. */
  19125. /**
  19126. * How to handle overflowing labels on horizontal axis. If set to
  19127. * `"allow"`, it will not be aligned at all. By default it
  19128. * `"justify"` labels inside the chart area. If there is room to
  19129. * move it, it will be aligned to the edge, else it will be removed.
  19130. *
  19131. * @type {string}
  19132. * @default justify
  19133. * @since 2.2.5
  19134. * @validvalue ["allow", "justify"]
  19135. * @apioption xAxis.labels.overflow
  19136. */
  19137. /**
  19138. * The pixel padding for axis labels, to ensure white space between
  19139. * them.
  19140. *
  19141. * @type {number}
  19142. * @default 5
  19143. * @product highcharts gantt
  19144. * @apioption xAxis.labels.padding
  19145. */
  19146. /**
  19147. * Whether to reserve space for the labels. By default, space is
  19148. * reserved for the labels in these cases:
  19149. *
  19150. * * On all horizontal axes.
  19151. * * On vertical axes if `label.align` is `right` on a left-side
  19152. * axis or `left` on a right-side axis.
  19153. * * On vertical axes if `label.align` is `center`.
  19154. *
  19155. * This can be turned off when for example the labels are rendered
  19156. * inside the plot area instead of outside.
  19157. *
  19158. * @see [labels.align](#xAxis.labels.align)
  19159. *
  19160. * @sample {highcharts} highcharts/xaxis/labels-reservespace/
  19161. * No reserved space, labels inside plot
  19162. * @sample {highcharts} highcharts/xaxis/labels-reservespace-true/
  19163. * Left-aligned labels on a vertical category axis
  19164. *
  19165. * @type {boolean}
  19166. * @since 4.1.10
  19167. * @product highcharts gantt
  19168. * @apioption xAxis.labels.reserveSpace
  19169. */
  19170. /**
  19171. * Rotation of the labels in degrees.
  19172. *
  19173. * @sample {highcharts} highcharts/xaxis/labels-rotation/
  19174. * X axis labels rotated 90°
  19175. *
  19176. * @type {number}
  19177. * @default 0
  19178. * @apioption xAxis.labels.rotation
  19179. */
  19180. /**
  19181. * Horizontal axes only. The number of lines to spread the labels
  19182. * over to make room or tighter labels.
  19183. *
  19184. * @sample {highcharts} highcharts/xaxis/labels-staggerlines/
  19185. * Show labels over two lines
  19186. * @sample {highstock} stock/xaxis/labels-staggerlines/
  19187. * Show labels over two lines
  19188. *
  19189. * @type {number}
  19190. * @since 2.1
  19191. * @apioption xAxis.labels.staggerLines
  19192. */
  19193. /**
  19194. * To show only every _n_'th label on the axis, set the step to _n_.
  19195. * Setting the step to 2 shows every other label.
  19196. *
  19197. * By default, the step is calculated automatically to avoid
  19198. * overlap. To prevent this, set it to 1\. This usually only
  19199. * happens on a category axis, and is often a sign that you have
  19200. * chosen the wrong axis type.
  19201. *
  19202. * Read more at
  19203. * [Axis docs](https://www.highcharts.com/docs/chart-concepts/axes)
  19204. * => What axis should I use?
  19205. *
  19206. * @sample {highcharts} highcharts/xaxis/labels-step/
  19207. * Showing only every other axis label on a categorized
  19208. * x-axis
  19209. * @sample {highcharts} highcharts/xaxis/labels-step-auto/
  19210. * Auto steps on a category axis
  19211. *
  19212. * @type {number}
  19213. * @since 2.1
  19214. * @apioption xAxis.labels.step
  19215. */
  19216. /**
  19217. * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  19218. * to render the labels.
  19219. *
  19220. * @type {boolean}
  19221. * @default false
  19222. * @apioption xAxis.labels.useHTML
  19223. */
  19224. /**
  19225. * The x position offset of all labels relative to the tick
  19226. * positions on the axis.
  19227. *
  19228. * @sample {highcharts} highcharts/xaxis/labels-x/
  19229. * Y axis labels placed on grid lines
  19230. */
  19231. x: 0,
  19232. /**
  19233. * The y position offset of all labels relative to the tick
  19234. * positions on the axis. The default makes it adapt to the font
  19235. * size of the bottom axis.
  19236. *
  19237. * @sample {highcharts} highcharts/xaxis/labels-x/
  19238. * Y axis labels placed on grid lines
  19239. *
  19240. * @type {number}
  19241. * @apioption xAxis.labels.y
  19242. */
  19243. /**
  19244. * The Z index for the axis labels.
  19245. *
  19246. * @type {number}
  19247. * @default 7
  19248. * @apioption xAxis.labels.zIndex
  19249. */
  19250. /**
  19251. * CSS styles for the label. Use `whiteSpace: 'nowrap'` to prevent
  19252. * wrapping of category labels. Use `textOverflow: 'none'` to
  19253. * prevent ellipsis (dots).
  19254. *
  19255. * In styled mode, the labels are styled with the
  19256. * `.highcharts-axis-labels` class.
  19257. *
  19258. * @sample {highcharts} highcharts/xaxis/labels-style/
  19259. * Red X axis labels
  19260. *
  19261. * @type {Highcharts.CSSObject}
  19262. */
  19263. style: {
  19264. /** @internal */
  19265. color: palette.neutralColor60,
  19266. /** @internal */
  19267. cursor: 'default',
  19268. /** @internal */
  19269. fontSize: '11px'
  19270. }
  19271. },
  19272. /**
  19273. * The left position as the horizontal axis. If it's a number, it is
  19274. * interpreted as pixel position relative to the chart.
  19275. *
  19276. * Since Highcharts v5.0.13: If it's a percentage string, it is
  19277. * interpreted as percentages of the plot width, offset from plot area
  19278. * left.
  19279. *
  19280. * @type {number|string}
  19281. * @product highcharts highstock
  19282. * @apioption xAxis.left
  19283. */
  19284. /**
  19285. * The top position as the vertical axis. If it's a number, it is
  19286. * interpreted as pixel position relative to the chart.
  19287. *
  19288. * Since Highcharts 2: If it's a percentage string, it is interpreted
  19289. * as percentages of the plot height, offset from plot area top.
  19290. *
  19291. * @type {number|string}
  19292. * @product highcharts highstock
  19293. * @apioption xAxis.top
  19294. */
  19295. /**
  19296. * Index of another axis that this axis is linked to. When an axis is
  19297. * linked to a master axis, it will take the same extremes as
  19298. * the master, but as assigned by min or max or by setExtremes.
  19299. * It can be used to show additional info, or to ease reading the
  19300. * chart by duplicating the scales.
  19301. *
  19302. * @sample {highcharts} highcharts/xaxis/linkedto/
  19303. * Different string formats of the same date
  19304. * @sample {highcharts} highcharts/yaxis/linkedto/
  19305. * Y values on both sides
  19306. *
  19307. * @type {number}
  19308. * @since 2.0.2
  19309. * @product highcharts highstock gantt
  19310. * @apioption xAxis.linkedTo
  19311. */
  19312. /**
  19313. * The maximum value of the axis. If `null`, the max value is
  19314. * automatically calculated.
  19315. *
  19316. * If the [endOnTick](#yAxis.endOnTick) option is true, the `max` value
  19317. * might be rounded up.
  19318. *
  19319. * If a [tickAmount](#yAxis.tickAmount) is set, the axis may be extended
  19320. * beyond the set max in order to reach the given number of ticks. The
  19321. * same may happen in a chart with multiple axes, determined by [chart.
  19322. * alignTicks](#chart), where a `tickAmount` is applied internally.
  19323. *
  19324. * @sample {highcharts} highcharts/yaxis/max-200/
  19325. * Y axis max of 200
  19326. * @sample {highcharts} highcharts/yaxis/max-logarithmic/
  19327. * Y axis max on logarithmic axis
  19328. * @sample {highstock} stock/xaxis/min-max/
  19329. * Fixed min and max on X axis
  19330. * @sample {highmaps} maps/axis/min-max/
  19331. * Pre-zoomed to a specific area
  19332. *
  19333. * @type {number|null}
  19334. * @apioption xAxis.max
  19335. */
  19336. /**
  19337. * Padding of the max value relative to the length of the axis. A
  19338. * padding of 0.05 will make a 100px axis 5px longer. This is useful
  19339. * when you don't want the highest data value to appear on the edge
  19340. * of the plot area. When the axis' `max` option is set or a max extreme
  19341. * is set using `axis.setExtremes()`, the maxPadding will be ignored.
  19342. *
  19343. * @sample {highcharts} highcharts/yaxis/maxpadding/
  19344. * Max padding of 0.25 on y axis
  19345. * @sample {highstock} stock/xaxis/minpadding-maxpadding/
  19346. * Greater min- and maxPadding
  19347. * @sample {highmaps} maps/chart/plotbackgroundcolor-gradient/
  19348. * Add some padding
  19349. *
  19350. * @default {highcharts} 0.01
  19351. * @default {highstock|highmaps} 0
  19352. * @since 1.2.0
  19353. */
  19354. maxPadding: 0.01,
  19355. /**
  19356. * Deprecated. Use `minRange` instead.
  19357. *
  19358. * @deprecated
  19359. * @type {number}
  19360. * @product highcharts highstock
  19361. * @apioption xAxis.maxZoom
  19362. */
  19363. /**
  19364. * The minimum value of the axis. If `null` the min value is
  19365. * automatically calculated.
  19366. *
  19367. * If the [startOnTick](#yAxis.startOnTick) option is true (default),
  19368. * the `min` value might be rounded down.
  19369. *
  19370. * The automatically calculated minimum value is also affected by
  19371. * [floor](#yAxis.floor), [softMin](#yAxis.softMin),
  19372. * [minPadding](#yAxis.minPadding), [minRange](#yAxis.minRange)
  19373. * as well as [series.threshold](#plotOptions.series.threshold)
  19374. * and [series.softThreshold](#plotOptions.series.softThreshold).
  19375. *
  19376. * @sample {highcharts} highcharts/yaxis/min-startontick-false/
  19377. * -50 with startOnTick to false
  19378. * @sample {highcharts} highcharts/yaxis/min-startontick-true/
  19379. * -50 with startOnTick true by default
  19380. * @sample {highstock} stock/xaxis/min-max/
  19381. * Set min and max on X axis
  19382. * @sample {highmaps} maps/axis/min-max/
  19383. * Pre-zoomed to a specific area
  19384. *
  19385. * @type {number|null}
  19386. * @apioption xAxis.min
  19387. */
  19388. /**
  19389. * The dash or dot style of the minor grid lines. For possible values,
  19390. * see [this demonstration](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/series-dashstyle-all/).
  19391. *
  19392. * @sample {highcharts} highcharts/yaxis/minorgridlinedashstyle/
  19393. * Long dashes on minor grid lines
  19394. * @sample {highstock} stock/xaxis/minorgridlinedashstyle/
  19395. * Long dashes on minor grid lines
  19396. *
  19397. * @type {Highcharts.DashStyleValue}
  19398. * @default Solid
  19399. * @since 1.2
  19400. * @apioption xAxis.minorGridLineDashStyle
  19401. */
  19402. /**
  19403. * Specific tick interval in axis units for the minor ticks. On a linear
  19404. * axis, if `"auto"`, the minor tick interval is calculated as a fifth
  19405. * of the tickInterval. If `null` or `undefined`, minor ticks are not
  19406. * shown.
  19407. *
  19408. * On logarithmic axes, the unit is the power of the value. For example,
  19409. * setting the minorTickInterval to 1 puts one tick on each of 0.1, 1,
  19410. * 10, 100 etc. Setting the minorTickInterval to 0.1 produces 9 ticks
  19411. * between 1 and 10, 10 and 100 etc.
  19412. *
  19413. * If user settings dictate minor ticks to become too dense, they don't
  19414. * make sense, and will be ignored to prevent performance problems.
  19415. *
  19416. * @sample {highcharts} highcharts/yaxis/minortickinterval-null/
  19417. * Null by default
  19418. * @sample {highcharts} highcharts/yaxis/minortickinterval-5/
  19419. * 5 units
  19420. * @sample {highcharts} highcharts/yaxis/minortickinterval-log-auto/
  19421. * "auto"
  19422. * @sample {highcharts} highcharts/yaxis/minortickinterval-log/
  19423. * 0.1
  19424. * @sample {highstock} stock/demo/basic-line/
  19425. * Null by default
  19426. * @sample {highstock} stock/xaxis/minortickinterval-auto/
  19427. * "auto"
  19428. *
  19429. * @type {number|string|null}
  19430. * @apioption xAxis.minorTickInterval
  19431. */
  19432. /**
  19433. * The pixel length of the minor tick marks.
  19434. *
  19435. * @sample {highcharts} highcharts/yaxis/minorticklength/
  19436. * 10px on Y axis
  19437. * @sample {highstock} stock/xaxis/minorticks/
  19438. * 10px on Y axis
  19439. */
  19440. minorTickLength: 2,
  19441. /**
  19442. * The position of the minor tick marks relative to the axis line.
  19443. * Can be one of `inside` and `outside`.
  19444. *
  19445. * @sample {highcharts} highcharts/yaxis/minortickposition-outside/
  19446. * Outside by default
  19447. * @sample {highcharts} highcharts/yaxis/minortickposition-inside/
  19448. * Inside
  19449. * @sample {highstock} stock/xaxis/minorticks/
  19450. * Inside
  19451. *
  19452. * @validvalue ["inside", "outside"]
  19453. */
  19454. minorTickPosition: 'outside',
  19455. /**
  19456. * Enable or disable minor ticks. Unless
  19457. * [minorTickInterval](#xAxis.minorTickInterval) is set, the tick
  19458. * interval is calculated as a fifth of the `tickInterval`.
  19459. *
  19460. * On a logarithmic axis, minor ticks are laid out based on a best
  19461. * guess, attempting to enter approximately 5 minor ticks between
  19462. * each major tick.
  19463. *
  19464. * Prior to v6.0.0, ticks were unabled in auto layout by setting
  19465. * `minorTickInterval` to `"auto"`.
  19466. *
  19467. * @productdesc {highcharts}
  19468. * On axes using [categories](#xAxis.categories), minor ticks are not
  19469. * supported.
  19470. *
  19471. * @sample {highcharts} highcharts/yaxis/minorticks-true/
  19472. * Enabled on linear Y axis
  19473. *
  19474. * @type {boolean}
  19475. * @default false
  19476. * @since 6.0.0
  19477. * @apioption xAxis.minorTicks
  19478. */
  19479. /**
  19480. * The pixel width of the minor tick mark.
  19481. *
  19482. * @sample {highcharts} highcharts/yaxis/minortickwidth/
  19483. * 3px width
  19484. * @sample {highstock} stock/xaxis/minorticks/
  19485. * 1px width
  19486. *
  19487. * @type {number}
  19488. * @default 0
  19489. * @apioption xAxis.minorTickWidth
  19490. */
  19491. /**
  19492. * Padding of the min value relative to the length of the axis. A
  19493. * padding of 0.05 will make a 100px axis 5px longer. This is useful
  19494. * when you don't want the lowest data value to appear on the edge
  19495. * of the plot area. When the axis' `min` option is set or a min extreme
  19496. * is set using `axis.setExtremes()`, the minPadding will be ignored.
  19497. *
  19498. * @sample {highcharts} highcharts/yaxis/minpadding/
  19499. * Min padding of 0.2
  19500. * @sample {highstock} stock/xaxis/minpadding-maxpadding/
  19501. * Greater min- and maxPadding
  19502. * @sample {highmaps} maps/chart/plotbackgroundcolor-gradient/
  19503. * Add some padding
  19504. *
  19505. * @default {highcharts} 0.01
  19506. * @default {highstock|highmaps} 0
  19507. * @since 1.2.0
  19508. * @product highcharts highstock gantt
  19509. */
  19510. minPadding: 0.01,
  19511. /**
  19512. * The minimum range to display on this axis. The entire axis will not
  19513. * be allowed to span over a smaller interval than this. For example,
  19514. * for a datetime axis the main unit is milliseconds. If minRange is
  19515. * set to 3600000, you can't zoom in more than to one hour.
  19516. *
  19517. * The default minRange for the x axis is five times the smallest
  19518. * interval between any of the data points.
  19519. *
  19520. * On a logarithmic axis, the unit for the minimum range is the power.
  19521. * So a minRange of 1 means that the axis can be zoomed to 10-100,
  19522. * 100-1000, 1000-10000 etc.
  19523. *
  19524. * **Note**: The `minPadding`, `maxPadding`, `startOnTick` and
  19525. * `endOnTick` settings also affect how the extremes of the axis
  19526. * are computed.
  19527. *
  19528. * @sample {highcharts} highcharts/xaxis/minrange/
  19529. * Minimum range of 5
  19530. * @sample {highstock} stock/xaxis/minrange/
  19531. * Max zoom of 6 months overrides user selections
  19532. * @sample {highmaps} maps/axis/minrange/
  19533. * Minimum range of 1000
  19534. *
  19535. * @type {number}
  19536. * @apioption xAxis.minRange
  19537. */
  19538. /**
  19539. * The minimum tick interval allowed in axis values. For example on
  19540. * zooming in on an axis with daily data, this can be used to prevent
  19541. * the axis from showing hours. Defaults to the closest distance between
  19542. * two points on the axis.
  19543. *
  19544. * @type {number}
  19545. * @since 2.3.0
  19546. * @apioption xAxis.minTickInterval
  19547. */
  19548. /**
  19549. * The distance in pixels from the plot area to the axis line.
  19550. * A positive offset moves the axis with it's line, labels and ticks
  19551. * away from the plot area. This is typically used when two or more
  19552. * axes are displayed on the same side of the plot. With multiple
  19553. * axes the offset is dynamically adjusted to avoid collision, this
  19554. * can be overridden by setting offset explicitly.
  19555. *
  19556. * @sample {highcharts} highcharts/yaxis/offset/
  19557. * Y axis offset of 70
  19558. * @sample {highcharts} highcharts/yaxis/offset-centered/
  19559. * Axes positioned in the center of the plot
  19560. * @sample {highstock} stock/xaxis/offset/
  19561. * Y axis offset by 70 px
  19562. *
  19563. * @type {number}
  19564. * @default 0
  19565. * @apioption xAxis.offset
  19566. */
  19567. /**
  19568. * Whether to display the axis on the opposite side of the normal. The
  19569. * normal is on the left side for vertical axes and bottom for
  19570. * horizontal, so the opposite sides will be right and top respectively.
  19571. * This is typically used with dual or multiple axes.
  19572. *
  19573. * @sample {highcharts} highcharts/yaxis/opposite/
  19574. * Secondary Y axis opposite
  19575. * @sample {highstock} stock/xaxis/opposite/
  19576. * Y axis on left side
  19577. *
  19578. * @type {boolean}
  19579. * @default {highcharts|highstock|highmaps} false
  19580. * @default {gantt} true
  19581. * @apioption xAxis.opposite
  19582. */
  19583. /**
  19584. * In an ordinal axis, the points are equally spaced in the chart
  19585. * regardless of the actual time or x distance between them. This means
  19586. * that missing data periods (e.g. nights or weekends for a stock chart)
  19587. * will not take up space in the chart.
  19588. * Having `ordinal: false` will show any gaps created by the `gapSize`
  19589. * setting proportionate to their duration.
  19590. *
  19591. * In stock charts the X axis is ordinal by default, unless
  19592. * the boost module is used and at least one of the series' data length
  19593. * exceeds the [boostThreshold](#series.line.boostThreshold).
  19594. *
  19595. * @sample {highstock} stock/xaxis/ordinal-true/
  19596. * True by default
  19597. * @sample {highstock} stock/xaxis/ordinal-false/
  19598. * False
  19599. *
  19600. * @type {boolean}
  19601. * @default true
  19602. * @since 1.1
  19603. * @product highstock
  19604. * @apioption xAxis.ordinal
  19605. */
  19606. /**
  19607. * Additional range on the right side of the xAxis. Works similar to
  19608. * `xAxis.maxPadding`, but value is set in milliseconds. Can be set for
  19609. * both main `xAxis` and the navigator's `xAxis`.
  19610. *
  19611. * @sample {highstock} stock/xaxis/overscroll/
  19612. * One minute overscroll with live data
  19613. *
  19614. * @type {number}
  19615. * @default 0
  19616. * @since 6.0.0
  19617. * @product highstock
  19618. * @apioption xAxis.overscroll
  19619. */
  19620. /**
  19621. * Refers to the index in the [panes](#panes) array. Used for circular
  19622. * gauges and polar charts. When the option is not set then first pane
  19623. * will be used.
  19624. *
  19625. * @sample highcharts/demo/gauge-vu-meter
  19626. * Two gauges with different center
  19627. *
  19628. * @type {number}
  19629. * @product highcharts
  19630. * @apioption xAxis.pane
  19631. */
  19632. /**
  19633. * The zoomed range to display when only defining one or none of `min`
  19634. * or `max`. For example, to show the latest month, a range of one month
  19635. * can be set.
  19636. *
  19637. * @sample {highstock} stock/xaxis/range/
  19638. * Setting a zoomed range when the rangeSelector is disabled
  19639. *
  19640. * @type {number}
  19641. * @product highstock
  19642. * @apioption xAxis.range
  19643. */
  19644. /**
  19645. * Whether to reverse the axis so that the highest number is closest
  19646. * to the origin. If the chart is inverted, the x axis is reversed by
  19647. * default.
  19648. *
  19649. * @sample {highcharts} highcharts/yaxis/reversed/
  19650. * Reversed Y axis
  19651. * @sample {highstock} stock/xaxis/reversed/
  19652. * Reversed Y axis
  19653. *
  19654. * @type {boolean}
  19655. * @default false
  19656. * @apioption xAxis.reversed
  19657. */
  19658. // reversed: false,
  19659. /**
  19660. * This option determines how stacks should be ordered within a group.
  19661. * For example reversed xAxis also reverses stacks, so first series
  19662. * comes last in a group. To keep order like for non-reversed xAxis
  19663. * enable this option.
  19664. *
  19665. * @sample {highcharts} highcharts/xaxis/reversedstacks/
  19666. * Reversed stacks comparison
  19667. * @sample {highstock} highcharts/xaxis/reversedstacks/
  19668. * Reversed stacks comparison
  19669. *
  19670. * @type {boolean}
  19671. * @default false
  19672. * @since 6.1.1
  19673. * @product highcharts highstock
  19674. * @apioption xAxis.reversedStacks
  19675. */
  19676. /**
  19677. * An optional scrollbar to display on the X axis in response to
  19678. * limiting the minimum and maximum of the axis values.
  19679. *
  19680. * In styled mode, all the presentational options for the scrollbar are
  19681. * replaced by the classes `.highcharts-scrollbar-thumb`,
  19682. * `.highcharts-scrollbar-arrow`, `.highcharts-scrollbar-button`,
  19683. * `.highcharts-scrollbar-rifles` and `.highcharts-scrollbar-track`.
  19684. *
  19685. * @sample {highstock} stock/yaxis/heatmap-scrollbars/
  19686. * Heatmap with both scrollbars
  19687. *
  19688. * @extends scrollbar
  19689. * @since 4.2.6
  19690. * @product highstock
  19691. * @apioption xAxis.scrollbar
  19692. */
  19693. /**
  19694. * Whether to show the axis line and title when the axis has no data.
  19695. *
  19696. * @sample {highcharts} highcharts/yaxis/showempty/
  19697. * When clicking the legend to hide series, one axis preserves
  19698. * line and title, the other doesn't
  19699. * @sample {highstock} highcharts/yaxis/showempty/
  19700. * When clicking the legend to hide series, one axis preserves
  19701. * line and title, the other doesn't
  19702. *
  19703. * @since 1.1
  19704. */
  19705. showEmpty: true,
  19706. /**
  19707. * Whether to show the first tick label.
  19708. *
  19709. * @sample {highcharts} highcharts/xaxis/showfirstlabel-false/
  19710. * Set to false on X axis
  19711. * @sample {highstock} stock/xaxis/showfirstlabel/
  19712. * Labels below plot lines on Y axis
  19713. *
  19714. * @type {boolean}
  19715. * @default true
  19716. * @apioption xAxis.showFirstLabel
  19717. */
  19718. /**
  19719. * Whether to show the last tick label. Defaults to `true` on cartesian
  19720. * charts, and `false` on polar charts.
  19721. *
  19722. * @sample {highcharts} highcharts/xaxis/showlastlabel-true/
  19723. * Set to true on X axis
  19724. * @sample {highstock} stock/xaxis/showfirstlabel/
  19725. * Labels below plot lines on Y axis
  19726. *
  19727. * @type {boolean}
  19728. * @default true
  19729. * @product highcharts highstock gantt
  19730. * @apioption xAxis.showLastLabel
  19731. */
  19732. /**
  19733. * A soft maximum for the axis. If the series data maximum is less than
  19734. * this, the axis will stay at this maximum, but if the series data
  19735. * maximum is higher, the axis will flex to show all data.
  19736. *
  19737. * @sample highcharts/yaxis/softmin-softmax/
  19738. * Soft min and max
  19739. *
  19740. * @type {number}
  19741. * @since 5.0.1
  19742. * @product highcharts highstock gantt
  19743. * @apioption xAxis.softMax
  19744. */
  19745. /**
  19746. * A soft minimum for the axis. If the series data minimum is greater
  19747. * than this, the axis will stay at this minimum, but if the series
  19748. * data minimum is lower, the axis will flex to show all data.
  19749. *
  19750. * @sample highcharts/yaxis/softmin-softmax/
  19751. * Soft min and max
  19752. *
  19753. * @type {number}
  19754. * @since 5.0.1
  19755. * @product highcharts highstock gantt
  19756. * @apioption xAxis.softMin
  19757. */
  19758. /**
  19759. * For datetime axes, this decides where to put the tick between weeks.
  19760. * 0 = Sunday, 1 = Monday.
  19761. *
  19762. * @sample {highcharts} highcharts/xaxis/startofweek-monday/
  19763. * Monday by default
  19764. * @sample {highcharts} highcharts/xaxis/startofweek-sunday/
  19765. * Sunday
  19766. * @sample {highstock} stock/xaxis/startofweek-1
  19767. * Monday by default
  19768. * @sample {highstock} stock/xaxis/startofweek-0
  19769. * Sunday
  19770. *
  19771. * @product highcharts highstock gantt
  19772. */
  19773. startOfWeek: 1,
  19774. /**
  19775. * Whether to force the axis to start on a tick. Use this option with
  19776. * the `minPadding` option to control the axis start.
  19777. *
  19778. * @productdesc {highstock}
  19779. * In Highstock, `startOnTick` is always `false` when the navigator
  19780. * is enabled, to prevent jumpy scrolling.
  19781. *
  19782. * @sample {highcharts} highcharts/xaxis/startontick-false/
  19783. * False by default
  19784. * @sample {highcharts} highcharts/xaxis/startontick-true/
  19785. * True
  19786. *
  19787. * @since 1.2.0
  19788. */
  19789. startOnTick: false,
  19790. /**
  19791. * The amount of ticks to draw on the axis. This opens up for aligning
  19792. * the ticks of multiple charts or panes within a chart. This option
  19793. * overrides the `tickPixelInterval` option.
  19794. *
  19795. * This option only has an effect on linear axes. Datetime, logarithmic
  19796. * or category axes are not affected.
  19797. *
  19798. * @sample {highcharts} highcharts/yaxis/tickamount/
  19799. * 8 ticks on Y axis
  19800. * @sample {highstock} highcharts/yaxis/tickamount/
  19801. * 8 ticks on Y axis
  19802. *
  19803. * @type {number}
  19804. * @since 4.1.0
  19805. * @product highcharts highstock gantt
  19806. * @apioption xAxis.tickAmount
  19807. */
  19808. /**
  19809. * The interval of the tick marks in axis units. When `undefined`, the
  19810. * tick interval is computed to approximately follow the
  19811. * [tickPixelInterval](#xAxis.tickPixelInterval) on linear and datetime
  19812. * axes. On categorized axes, a `undefined` tickInterval will default to
  19813. * 1, one category. Note that datetime axes are based on milliseconds,
  19814. * so for example an interval of one day is expressed as
  19815. * `24 * 3600 * 1000`.
  19816. *
  19817. * On logarithmic axes, the tickInterval is based on powers, so a
  19818. * tickInterval of 1 means one tick on each of 0.1, 1, 10, 100 etc. A
  19819. * tickInterval of 2 means a tick of 0.1, 10, 1000 etc. A tickInterval
  19820. * of 0.2 puts a tick on 0.1, 0.2, 0.4, 0.6, 0.8, 1, 2, 4, 6, 8, 10, 20,
  19821. * 40 etc.
  19822. *
  19823. *
  19824. * If the tickInterval is too dense for labels to be drawn, Highcharts
  19825. * may remove ticks.
  19826. *
  19827. * If the chart has multiple axes, the [alignTicks](#chart.alignTicks)
  19828. * option may interfere with the `tickInterval` setting.
  19829. *
  19830. * @see [tickPixelInterval](#xAxis.tickPixelInterval)
  19831. * @see [tickPositions](#xAxis.tickPositions)
  19832. * @see [tickPositioner](#xAxis.tickPositioner)
  19833. *
  19834. * @sample {highcharts} highcharts/xaxis/tickinterval-5/
  19835. * Tick interval of 5 on a linear axis
  19836. * @sample {highstock} stock/xaxis/tickinterval/
  19837. * Tick interval of 0.01 on Y axis
  19838. *
  19839. * @type {number}
  19840. * @apioption xAxis.tickInterval
  19841. */
  19842. /**
  19843. * The pixel length of the main tick marks.
  19844. *
  19845. * @sample {highcharts} highcharts/xaxis/ticklength/
  19846. * 20 px tick length on the X axis
  19847. * @sample {highstock} stock/xaxis/ticks/
  19848. * Formatted ticks on X axis
  19849. */
  19850. tickLength: 10,
  19851. /**
  19852. * If tickInterval is `null` this option sets the approximate pixel
  19853. * interval of the tick marks. Not applicable to categorized axis.
  19854. *
  19855. * The tick interval is also influenced by the [minTickInterval](
  19856. * #xAxis.minTickInterval) option, that, by default prevents ticks from
  19857. * being denser than the data points.
  19858. *
  19859. * @see [tickInterval](#xAxis.tickInterval)
  19860. * @see [tickPositioner](#xAxis.tickPositioner)
  19861. * @see [tickPositions](#xAxis.tickPositions)
  19862. *
  19863. * @sample {highcharts} highcharts/xaxis/tickpixelinterval-50/
  19864. * 50 px on X axis
  19865. * @sample {highstock} stock/xaxis/tickpixelinterval/
  19866. * 200 px on X axis
  19867. */
  19868. tickPixelInterval: 100,
  19869. /**
  19870. * For categorized axes only. If `on` the tick mark is placed in the
  19871. * center of the category, if `between` the tick mark is placed between
  19872. * categories. The default is `between` if the `tickInterval` is 1, else
  19873. * `on`.
  19874. *
  19875. * @sample {highcharts} highcharts/xaxis/tickmarkplacement-between/
  19876. * "between" by default
  19877. * @sample {highcharts} highcharts/xaxis/tickmarkplacement-on/
  19878. * "on"
  19879. *
  19880. * @product highcharts gantt
  19881. * @validvalue ["on", "between"]
  19882. */
  19883. tickmarkPlacement: 'between',
  19884. /**
  19885. * The position of the major tick marks relative to the axis line.
  19886. * Can be one of `inside` and `outside`.
  19887. *
  19888. * @sample {highcharts} highcharts/xaxis/tickposition-outside/
  19889. * "outside" by default
  19890. * @sample {highcharts} highcharts/xaxis/tickposition-inside/
  19891. * "inside"
  19892. * @sample {highstock} stock/xaxis/ticks/
  19893. * Formatted ticks on X axis
  19894. *
  19895. * @validvalue ["inside", "outside"]
  19896. */
  19897. tickPosition: 'outside',
  19898. /**
  19899. * A callback function returning array defining where the ticks are
  19900. * laid out on the axis. This overrides the default behaviour of
  19901. * [tickPixelInterval](#xAxis.tickPixelInterval) and [tickInterval](
  19902. * #xAxis.tickInterval). The automatic tick positions are accessible
  19903. * through `this.tickPositions` and can be modified by the callback.
  19904. *
  19905. * @see [tickPositions](#xAxis.tickPositions)
  19906. *
  19907. * @sample {highcharts} highcharts/xaxis/tickpositions-tickpositioner/
  19908. * Demo of tickPositions and tickPositioner
  19909. * @sample {highstock} highcharts/xaxis/tickpositions-tickpositioner/
  19910. * Demo of tickPositions and tickPositioner
  19911. *
  19912. * @type {Highcharts.AxisTickPositionerCallbackFunction}
  19913. * @apioption xAxis.tickPositioner
  19914. */
  19915. /**
  19916. * An array defining where the ticks are laid out on the axis. This
  19917. * overrides the default behaviour of [tickPixelInterval](
  19918. * #xAxis.tickPixelInterval) and [tickInterval](#xAxis.tickInterval).
  19919. *
  19920. * @see [tickPositioner](#xAxis.tickPositioner)
  19921. *
  19922. * @sample {highcharts} highcharts/xaxis/tickpositions-tickpositioner/
  19923. * Demo of tickPositions and tickPositioner
  19924. * @sample {highstock} highcharts/xaxis/tickpositions-tickpositioner/
  19925. * Demo of tickPositions and tickPositioner
  19926. *
  19927. * @type {Array<number>}
  19928. * @apioption xAxis.tickPositions
  19929. */
  19930. /**
  19931. * The pixel width of the major tick marks. Defaults to 0 on category
  19932. * axes, otherwise 1.
  19933. *
  19934. * In styled mode, the stroke width is given in the `.highcharts-tick`
  19935. * class, but in order for the element to be generated on category axes,
  19936. * the option must be explicitly set to 1.
  19937. *
  19938. * @sample {highcharts} highcharts/xaxis/tickwidth/
  19939. * 10 px width
  19940. * @sample {highcharts} highcharts/css/axis-grid/
  19941. * Styled mode
  19942. * @sample {highstock} stock/xaxis/ticks/
  19943. * Formatted ticks on X axis
  19944. * @sample {highstock} highcharts/css/axis-grid/
  19945. * Styled mode
  19946. *
  19947. * @type {undefined|number}
  19948. * @default {highstock} 1
  19949. * @default {highmaps} 0
  19950. * @apioption xAxis.tickWidth
  19951. */
  19952. /**
  19953. * The axis title, showing next to the axis line.
  19954. *
  19955. * @productdesc {highmaps}
  19956. * In Highmaps, the axis is hidden by default, but adding an axis title
  19957. * is still possible. X axis and Y axis titles will appear at the bottom
  19958. * and left by default.
  19959. */
  19960. title: {
  19961. /**
  19962. * Deprecated. Set the `text` to `null` to disable the title.
  19963. *
  19964. * @deprecated
  19965. * @type {boolean}
  19966. * @product highcharts
  19967. * @apioption xAxis.title.enabled
  19968. */
  19969. /**
  19970. * The pixel distance between the axis labels or line and the title.
  19971. * Defaults to 0 for horizontal axes, 10 for vertical
  19972. *
  19973. * @sample {highcharts} highcharts/xaxis/title-margin/
  19974. * Y axis title margin of 60
  19975. *
  19976. * @type {number}
  19977. * @apioption xAxis.title.margin
  19978. */
  19979. /**
  19980. * The distance of the axis title from the axis line. By default,
  19981. * this distance is computed from the offset width of the labels,
  19982. * the labels' distance from the axis and the title's margin.
  19983. * However when the offset option is set, it overrides all this.
  19984. *
  19985. * @sample {highcharts} highcharts/yaxis/title-offset/
  19986. * Place the axis title on top of the axis
  19987. * @sample {highstock} highcharts/yaxis/title-offset/
  19988. * Place the axis title on top of the Y axis
  19989. *
  19990. * @type {number}
  19991. * @since 2.2.0
  19992. * @apioption xAxis.title.offset
  19993. */
  19994. /**
  19995. * Whether to reserve space for the title when laying out the axis.
  19996. *
  19997. * @type {boolean}
  19998. * @default true
  19999. * @since 5.0.11
  20000. * @product highcharts highstock gantt
  20001. * @apioption xAxis.title.reserveSpace
  20002. */
  20003. /**
  20004. * The rotation of the text in degrees. 0 is horizontal, 270 is
  20005. * vertical reading from bottom to top.
  20006. *
  20007. * @sample {highcharts} highcharts/yaxis/title-offset/
  20008. * Horizontal
  20009. *
  20010. * @type {number}
  20011. * @default 0
  20012. * @apioption xAxis.title.rotation
  20013. */
  20014. /**
  20015. * The actual text of the axis title. It can contain basic HTML tags
  20016. * like `b`, `i` and `span` with style.
  20017. *
  20018. * @sample {highcharts} highcharts/xaxis/title-text/
  20019. * Custom HTML
  20020. * @sample {highstock} stock/xaxis/title-text/
  20021. * Titles for both axes
  20022. *
  20023. * @type {string|null}
  20024. * @apioption xAxis.title.text
  20025. */
  20026. /**
  20027. * Alignment of the text, can be `"left"`, `"right"` or `"center"`.
  20028. * Default alignment depends on the
  20029. * [title.align](xAxis.title.align):
  20030. *
  20031. * Horizontal axes:
  20032. * - for `align` = `"low"`, `textAlign` is set to `left`
  20033. * - for `align` = `"middle"`, `textAlign` is set to `center`
  20034. * - for `align` = `"high"`, `textAlign` is set to `right`
  20035. *
  20036. * Vertical axes:
  20037. * - for `align` = `"low"` and `opposite` = `true`, `textAlign` is
  20038. * set to `right`
  20039. * - for `align` = `"low"` and `opposite` = `false`, `textAlign` is
  20040. * set to `left`
  20041. * - for `align` = `"middle"`, `textAlign` is set to `center`
  20042. * - for `align` = `"high"` and `opposite` = `true` `textAlign` is
  20043. * set to `left`
  20044. * - for `align` = `"high"` and `opposite` = `false` `textAlign` is
  20045. * set to `right`
  20046. *
  20047. * @type {Highcharts.AlignValue}
  20048. * @apioption xAxis.title.textAlign
  20049. */
  20050. /**
  20051. * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  20052. * to render the axis title.
  20053. *
  20054. * @type {boolean}
  20055. * @default false
  20056. * @product highcharts highstock gantt
  20057. * @apioption xAxis.title.useHTML
  20058. */
  20059. /**
  20060. * Horizontal pixel offset of the title position.
  20061. *
  20062. * @type {number}
  20063. * @default 0
  20064. * @since 4.1.6
  20065. * @product highcharts highstock gantt
  20066. * @apioption xAxis.title.x
  20067. */
  20068. /**
  20069. * Vertical pixel offset of the title position.
  20070. *
  20071. * @type {number}
  20072. * @product highcharts highstock gantt
  20073. * @apioption xAxis.title.y
  20074. */
  20075. /**
  20076. * Alignment of the title relative to the axis values. Possible
  20077. * values are "low", "middle" or "high".
  20078. *
  20079. * @sample {highcharts} highcharts/xaxis/title-align-low/
  20080. * "low"
  20081. * @sample {highcharts} highcharts/xaxis/title-align-center/
  20082. * "middle" by default
  20083. * @sample {highcharts} highcharts/xaxis/title-align-high/
  20084. * "high"
  20085. * @sample {highcharts} highcharts/yaxis/title-offset/
  20086. * Place the Y axis title on top of the axis
  20087. * @sample {highstock} stock/xaxis/title-align/
  20088. * Aligned to "high" value
  20089. *
  20090. * @type {Highcharts.AxisTitleAlignValue}
  20091. */
  20092. align: 'middle',
  20093. /**
  20094. * CSS styles for the title. If the title text is longer than the
  20095. * axis length, it will wrap to multiple lines by default. This can
  20096. * be customized by setting `textOverflow: 'ellipsis'`, by
  20097. * setting a specific `width` or by setting `whiteSpace: 'nowrap'`.
  20098. *
  20099. * In styled mode, the stroke width is given in the
  20100. * `.highcharts-axis-title` class.
  20101. *
  20102. * @sample {highcharts} highcharts/xaxis/title-style/
  20103. * Red
  20104. * @sample {highcharts} highcharts/css/axis/
  20105. * Styled mode
  20106. *
  20107. * @type {Highcharts.CSSObject}
  20108. */
  20109. style: {
  20110. /** @internal */
  20111. color: palette.neutralColor60
  20112. }
  20113. },
  20114. /**
  20115. * The type of axis. Can be one of `linear`, `logarithmic`, `datetime`
  20116. * or `category`. In a datetime axis, the numbers are given in
  20117. * milliseconds, and tick marks are placed on appropriate values like
  20118. * full hours or days. In a category axis, the
  20119. * [point names](#series.line.data.name) of the chart's series are used
  20120. * for categories, if not a [categories](#xAxis.categories) array is
  20121. * defined.
  20122. *
  20123. * @sample {highcharts} highcharts/xaxis/type-linear/
  20124. * Linear
  20125. * @sample {highcharts} highcharts/yaxis/type-log/
  20126. * Logarithmic
  20127. * @sample {highcharts} highcharts/yaxis/type-log-minorgrid/
  20128. * Logarithmic with minor grid lines
  20129. * @sample {highcharts} highcharts/xaxis/type-log-both/
  20130. * Logarithmic on two axes
  20131. * @sample {highcharts} highcharts/yaxis/type-log-negative/
  20132. * Logarithmic with extension to emulate negative values
  20133. *
  20134. * @type {Highcharts.AxisTypeValue}
  20135. * @product highcharts gantt
  20136. */
  20137. type: 'linear',
  20138. /**
  20139. * If there are multiple axes on the same side of the chart, the pixel
  20140. * margin between the axes. Defaults to 0 on vertical axes, 15 on
  20141. * horizontal axes.
  20142. *
  20143. * @type {number}
  20144. * @since 7.0.3
  20145. * @apioption xAxis.margin
  20146. */
  20147. /**
  20148. * Applies only when the axis `type` is `category`. When `uniqueNames`
  20149. * is true, points are placed on the X axis according to their names.
  20150. * If the same point name is repeated in the same or another series,
  20151. * the point is placed on the same X position as other points of the
  20152. * same name. When `uniqueNames` is false, the points are laid out in
  20153. * increasing X positions regardless of their names, and the X axis
  20154. * category will take the name of the last point in each position.
  20155. *
  20156. * @sample {highcharts} highcharts/xaxis/uniquenames-true/
  20157. * True by default
  20158. * @sample {highcharts} highcharts/xaxis/uniquenames-false/
  20159. * False
  20160. *
  20161. * @type {boolean}
  20162. * @default true
  20163. * @since 4.2.7
  20164. * @product highcharts gantt
  20165. * @apioption xAxis.uniqueNames
  20166. */
  20167. /**
  20168. * Datetime axis only. An array determining what time intervals the
  20169. * ticks are allowed to fall on. Each array item is an array where the
  20170. * first value is the time unit and the second value another array of
  20171. * allowed multiples.
  20172. *
  20173. * Defaults to:
  20174. * ```js
  20175. * units: [[
  20176. * 'millisecond', // unit name
  20177. * [1, 2, 5, 10, 20, 25, 50, 100, 200, 500] // allowed multiples
  20178. * ], [
  20179. * 'second',
  20180. * [1, 2, 5, 10, 15, 30]
  20181. * ], [
  20182. * 'minute',
  20183. * [1, 2, 5, 10, 15, 30]
  20184. * ], [
  20185. * 'hour',
  20186. * [1, 2, 3, 4, 6, 8, 12]
  20187. * ], [
  20188. * 'day',
  20189. * [1]
  20190. * ], [
  20191. * 'week',
  20192. * [1]
  20193. * ], [
  20194. * 'month',
  20195. * [1, 3, 6]
  20196. * ], [
  20197. * 'year',
  20198. * null
  20199. * ]]
  20200. * ```
  20201. *
  20202. * @type {Array<Array<string,(Array<number>|null)>>}
  20203. * @product highcharts highstock gantt
  20204. * @apioption xAxis.units
  20205. */
  20206. /**
  20207. * Whether axis, including axis title, line, ticks and labels, should
  20208. * be visible.
  20209. *
  20210. * @type {boolean}
  20211. * @default true
  20212. * @since 4.1.9
  20213. * @product highcharts highstock gantt
  20214. * @apioption xAxis.visible
  20215. */
  20216. /**
  20217. * Color of the minor, secondary grid lines.
  20218. *
  20219. * In styled mode, the stroke width is given in the
  20220. * `.highcharts-minor-grid-line` class.
  20221. *
  20222. * @sample {highcharts} highcharts/yaxis/minorgridlinecolor/
  20223. * Bright grey lines from Y axis
  20224. * @sample {highcharts|highstock} highcharts/css/axis-grid/
  20225. * Styled mode
  20226. * @sample {highstock} stock/xaxis/minorgridlinecolor/
  20227. * Bright grey lines from Y axis
  20228. *
  20229. * @type {Highcharts.ColorType}
  20230. * @default #f2f2f2
  20231. */
  20232. minorGridLineColor: palette.neutralColor5,
  20233. /**
  20234. * Width of the minor, secondary grid lines.
  20235. *
  20236. * In styled mode, the stroke width is given in the
  20237. * `.highcharts-grid-line` class.
  20238. *
  20239. * @sample {highcharts} highcharts/yaxis/minorgridlinewidth/
  20240. * 2px lines from Y axis
  20241. * @sample {highcharts|highstock} highcharts/css/axis-grid/
  20242. * Styled mode
  20243. * @sample {highstock} stock/xaxis/minorgridlinewidth/
  20244. * 2px lines from Y axis
  20245. */
  20246. minorGridLineWidth: 1,
  20247. /**
  20248. * Color for the minor tick marks.
  20249. *
  20250. * @sample {highcharts} highcharts/yaxis/minortickcolor/
  20251. * Black tick marks on Y axis
  20252. * @sample {highstock} stock/xaxis/minorticks/
  20253. * Black tick marks on Y axis
  20254. *
  20255. * @type {Highcharts.ColorType}
  20256. * @default #999999
  20257. */
  20258. minorTickColor: palette.neutralColor40,
  20259. /**
  20260. * The color of the line marking the axis itself.
  20261. *
  20262. * In styled mode, the line stroke is given in the
  20263. * `.highcharts-axis-line` or `.highcharts-xaxis-line` class.
  20264. *
  20265. * @productdesc {highmaps}
  20266. * In Highmaps, the axis line is hidden by default, because the axis is
  20267. * not visible by default.
  20268. *
  20269. * @sample {highcharts} highcharts/yaxis/linecolor/
  20270. * A red line on Y axis
  20271. * @sample {highcharts|highstock} highcharts/css/axis/
  20272. * Axes in styled mode
  20273. * @sample {highstock} stock/xaxis/linecolor/
  20274. * A red line on X axis
  20275. *
  20276. * @type {Highcharts.ColorType}
  20277. * @default #ccd6eb
  20278. */
  20279. lineColor: palette.highlightColor20,
  20280. /**
  20281. * The width of the line marking the axis itself.
  20282. *
  20283. * In styled mode, the stroke width is given in the
  20284. * `.highcharts-axis-line` or `.highcharts-xaxis-line` class.
  20285. *
  20286. * @sample {highcharts} highcharts/yaxis/linecolor/
  20287. * A 1px line on Y axis
  20288. * @sample {highcharts|highstock} highcharts/css/axis/
  20289. * Axes in styled mode
  20290. * @sample {highstock} stock/xaxis/linewidth/
  20291. * A 2px line on X axis
  20292. *
  20293. * @default {highcharts|highstock} 1
  20294. * @default {highmaps} 0
  20295. */
  20296. lineWidth: 1,
  20297. /**
  20298. * Color of the grid lines extending the ticks across the plot area.
  20299. *
  20300. * In styled mode, the stroke is given in the `.highcharts-grid-line`
  20301. * class.
  20302. *
  20303. * @productdesc {highmaps}
  20304. * In Highmaps, the grid lines are hidden by default.
  20305. *
  20306. * @sample {highcharts} highcharts/yaxis/gridlinecolor/
  20307. * Green lines
  20308. * @sample {highcharts|highstock} highcharts/css/axis-grid/
  20309. * Styled mode
  20310. * @sample {highstock} stock/xaxis/gridlinecolor/
  20311. * Green lines
  20312. *
  20313. * @type {Highcharts.ColorType}
  20314. * @default #e6e6e6
  20315. */
  20316. gridLineColor: palette.neutralColor10,
  20317. // gridLineDashStyle: 'solid',
  20318. /**
  20319. * The width of the grid lines extending the ticks across the plot area.
  20320. *
  20321. * In styled mode, the stroke width is given in the
  20322. * `.highcharts-grid-line` class.
  20323. *
  20324. * @sample {highcharts} highcharts/yaxis/gridlinewidth/
  20325. * 2px lines
  20326. * @sample {highcharts|highstock} highcharts/css/axis-grid/
  20327. * Styled mode
  20328. * @sample {highstock} stock/xaxis/gridlinewidth/
  20329. * 2px lines
  20330. *
  20331. * @type {number}
  20332. * @default 0
  20333. * @apioption xAxis.gridLineWidth
  20334. */
  20335. // gridLineWidth: 0,
  20336. /**
  20337. * The height as the vertical axis. If it's a number, it is
  20338. * interpreted as pixels.
  20339. *
  20340. * Since Highcharts 2: If it's a percentage string, it is interpreted
  20341. * as percentages of the total plot height.
  20342. *
  20343. * @type {number|string}
  20344. * @product highcharts highstock
  20345. * @apioption xAxis.height
  20346. */
  20347. /**
  20348. * The width as the horizontal axis. If it's a number, it is interpreted
  20349. * as pixels.
  20350. *
  20351. * Since Highcharts v5.0.13: If it's a percentage string, it is
  20352. * interpreted as percentages of the total plot width.
  20353. *
  20354. * @type {number|string}
  20355. * @product highcharts highstock
  20356. * @apioption xAxis.width
  20357. */
  20358. /**
  20359. * Color for the main tick marks.
  20360. *
  20361. * In styled mode, the stroke is given in the `.highcharts-tick`
  20362. * class.
  20363. *
  20364. * @sample {highcharts} highcharts/xaxis/tickcolor/
  20365. * Red ticks on X axis
  20366. * @sample {highcharts|highstock} highcharts/css/axis-grid/
  20367. * Styled mode
  20368. * @sample {highstock} stock/xaxis/ticks/
  20369. * Formatted ticks on X axis
  20370. *
  20371. * @type {Highcharts.ColorType}
  20372. * @default #ccd6eb
  20373. */
  20374. tickColor: palette.highlightColor20
  20375. // tickWidth: 1
  20376. };
  20377. /**
  20378. * The Y axis or value axis. Normally this is the vertical axis,
  20379. * though if the chart is inverted this is the horizontal axis.
  20380. * In case of multiple axes, the yAxis node is an array of
  20381. * configuration objects.
  20382. *
  20383. * See [the Axis object](/class-reference/Highcharts.Axis) for programmatic
  20384. * access to the axis.
  20385. *
  20386. * @type {*|Array<*>}
  20387. * @extends xAxis
  20388. * @excluding currentDateIndicator,ordinal,overscroll
  20389. * @optionparent yAxis
  20390. *
  20391. * @private
  20392. */
  20393. Axis.defaultYAxisOptions = {
  20394. /**
  20395. * The type of axis. Can be one of `linear`, `logarithmic`, `datetime`,
  20396. * `category` or `treegrid`. Defaults to `treegrid` for Gantt charts,
  20397. * `linear` for other chart types.
  20398. *
  20399. * In a datetime axis, the numbers are given in milliseconds, and tick
  20400. * marks are placed on appropriate values, like full hours or days. In a
  20401. * category or treegrid axis, the [point names](#series.line.data.name)
  20402. * of the chart's series are used for categories, if a
  20403. * [categories](#xAxis.categories) array is not defined.
  20404. *
  20405. * @sample {highcharts} highcharts/yaxis/type-log-minorgrid/
  20406. * Logarithmic with minor grid lines
  20407. * @sample {highcharts} highcharts/yaxis/type-log-negative/
  20408. * Logarithmic with extension to emulate negative values
  20409. * @sample {gantt} gantt/treegrid-axis/demo
  20410. * Treegrid axis
  20411. *
  20412. * @type {Highcharts.AxisTypeValue}
  20413. * @default {highcharts} linear
  20414. * @default {gantt} treegrid
  20415. * @product highcharts gantt
  20416. * @apioption yAxis.type
  20417. */
  20418. /**
  20419. * The height of the Y axis. If it's a number, it is interpreted as
  20420. * pixels.
  20421. *
  20422. * Since Highcharts 2: If it's a percentage string, it is interpreted as
  20423. * percentages of the total plot height.
  20424. *
  20425. * @see [yAxis.top](#yAxis.top)
  20426. *
  20427. * @sample {highstock} stock/demo/candlestick-and-volume/
  20428. * Percentage height panes
  20429. *
  20430. * @type {number|string}
  20431. * @product highcharts highstock
  20432. * @apioption yAxis.height
  20433. */
  20434. /**
  20435. * Solid gauge only. Unless [stops](#yAxis.stops) are set, the color
  20436. * to represent the maximum value of the Y axis.
  20437. *
  20438. * @sample {highcharts} highcharts/yaxis/mincolor-maxcolor/
  20439. * Min and max colors
  20440. *
  20441. * @type {Highcharts.ColorType}
  20442. * @default #003399
  20443. * @since 4.0
  20444. * @product highcharts
  20445. * @apioption yAxis.maxColor
  20446. */
  20447. /**
  20448. * Solid gauge only. Unless [stops](#yAxis.stops) are set, the color
  20449. * to represent the minimum value of the Y axis.
  20450. *
  20451. * @sample {highcharts} highcharts/yaxis/mincolor-maxcolor/
  20452. * Min and max color
  20453. *
  20454. * @type {Highcharts.ColorType}
  20455. * @default #e6ebf5
  20456. * @since 4.0
  20457. * @product highcharts
  20458. * @apioption yAxis.minColor
  20459. */
  20460. /**
  20461. * Whether to reverse the axis so that the highest number is closest
  20462. * to the origin.
  20463. *
  20464. * @sample {highcharts} highcharts/yaxis/reversed/
  20465. * Reversed Y axis
  20466. * @sample {highstock} stock/xaxis/reversed/
  20467. * Reversed Y axis
  20468. *
  20469. * @type {boolean}
  20470. * @default {highcharts} false
  20471. * @default {highstock} false
  20472. * @default {highmaps} true
  20473. * @default {gantt} true
  20474. * @apioption yAxis.reversed
  20475. */
  20476. /**
  20477. * If `true`, the first series in a stack will be drawn on top in a
  20478. * positive, non-reversed Y axis. If `false`, the first series is in
  20479. * the base of the stack.
  20480. *
  20481. * @sample {highcharts} highcharts/yaxis/reversedstacks-false/
  20482. * Non-reversed stacks
  20483. * @sample {highstock} highcharts/yaxis/reversedstacks-false/
  20484. * Non-reversed stacks
  20485. *
  20486. * @type {boolean}
  20487. * @default true
  20488. * @since 3.0.10
  20489. * @product highcharts highstock
  20490. * @apioption yAxis.reversedStacks
  20491. */
  20492. /**
  20493. * Solid gauge series only. Color stops for the solid gauge. Use this
  20494. * in cases where a linear gradient between a `minColor` and `maxColor`
  20495. * is not sufficient. The stops is an array of tuples, where the first
  20496. * item is a float between 0 and 1 assigning the relative position in
  20497. * the gradient, and the second item is the color.
  20498. *
  20499. * For solid gauges, the Y axis also inherits the concept of
  20500. * [data classes](https://api.highcharts.com/highmaps#colorAxis.dataClasses)
  20501. * from the Highmaps color axis.
  20502. *
  20503. * @see [minColor](#yAxis.minColor)
  20504. * @see [maxColor](#yAxis.maxColor)
  20505. *
  20506. * @sample {highcharts} highcharts/demo/gauge-solid/
  20507. * True by default
  20508. *
  20509. * @type {Array<Array<number,Highcharts.ColorType>>}
  20510. * @since 4.0
  20511. * @product highcharts
  20512. * @apioption yAxis.stops
  20513. */
  20514. /**
  20515. * The pixel width of the major tick marks.
  20516. *
  20517. * @sample {highcharts} highcharts/xaxis/tickwidth/ 10 px width
  20518. * @sample {highstock} stock/xaxis/ticks/ Formatted ticks on X axis
  20519. *
  20520. * @type {number}
  20521. * @default 0
  20522. * @product highcharts highstock gantt
  20523. * @apioption yAxis.tickWidth
  20524. */
  20525. /**
  20526. * Whether to force the axis to end on a tick. Use this option with
  20527. * the `maxPadding` option to control the axis end.
  20528. *
  20529. * This option is always disabled, when panning type is
  20530. * either `y` or `xy`.
  20531. *
  20532. * @see [type](#chart.panning.type)
  20533. *
  20534. *
  20535. * @sample {highcharts} highcharts/chart/reflow-true/
  20536. * True by default
  20537. * @sample {highcharts} highcharts/yaxis/endontick/
  20538. * False
  20539. * @sample {highstock} stock/demo/basic-line/
  20540. * True by default
  20541. * @sample {highstock} stock/xaxis/endontick/
  20542. * False for Y axis
  20543. *
  20544. * @since 1.2.0
  20545. */
  20546. endOnTick: true,
  20547. /**
  20548. * Padding of the max value relative to the length of the axis. A
  20549. * padding of 0.05 will make a 100px axis 5px longer. This is useful
  20550. * when you don't want the highest data value to appear on the edge
  20551. * of the plot area. When the axis' `max` option is set or a max extreme
  20552. * is set using `axis.setExtremes()`, the maxPadding will be ignored.
  20553. *
  20554. * Also the `softThreshold` option takes precedence over `maxPadding`,
  20555. * so if the data is tangent to the threshold, `maxPadding` may not
  20556. * apply unless `softThreshold` is set to false.
  20557. *
  20558. * @sample {highcharts} highcharts/yaxis/maxpadding-02/
  20559. * Max padding of 0.2
  20560. * @sample {highstock} stock/xaxis/minpadding-maxpadding/
  20561. * Greater min- and maxPadding
  20562. *
  20563. * @since 1.2.0
  20564. * @product highcharts highstock gantt
  20565. */
  20566. maxPadding: 0.05,
  20567. /**
  20568. * Padding of the min value relative to the length of the axis. A
  20569. * padding of 0.05 will make a 100px axis 5px longer. This is useful
  20570. * when you don't want the lowest data value to appear on the edge
  20571. * of the plot area. When the axis' `min` option is set or a max extreme
  20572. * is set using `axis.setExtremes()`, the maxPadding will be ignored.
  20573. *
  20574. * Also the `softThreshold` option takes precedence over `minPadding`,
  20575. * so if the data is tangent to the threshold, `minPadding` may not
  20576. * apply unless `softThreshold` is set to false.
  20577. *
  20578. * @sample {highcharts} highcharts/yaxis/minpadding/
  20579. * Min padding of 0.2
  20580. * @sample {highstock} stock/xaxis/minpadding-maxpadding/
  20581. * Greater min- and maxPadding
  20582. *
  20583. * @since 1.2.0
  20584. * @product highcharts highstock gantt
  20585. */
  20586. minPadding: 0.05,
  20587. /**
  20588. * @productdesc {highstock}
  20589. * In Highstock 1.x, the Y axis was placed on the left side by default.
  20590. *
  20591. * @sample {highcharts} highcharts/yaxis/opposite/
  20592. * Secondary Y axis opposite
  20593. * @sample {highstock} stock/xaxis/opposite/
  20594. * Y axis on left side
  20595. *
  20596. * @type {boolean}
  20597. * @default {highstock} true
  20598. * @default {highcharts} false
  20599. * @product highstock highcharts gantt
  20600. * @apioption yAxis.opposite
  20601. */
  20602. /**
  20603. * @see [tickInterval](#xAxis.tickInterval)
  20604. * @see [tickPositioner](#xAxis.tickPositioner)
  20605. * @see [tickPositions](#xAxis.tickPositions)
  20606. */
  20607. tickPixelInterval: 72,
  20608. showLastLabel: true,
  20609. /**
  20610. * @extends xAxis.labels
  20611. */
  20612. labels: {
  20613. /**
  20614. * Angular gauges and solid gauges only.
  20615. * The label's pixel distance from the perimeter of the plot area.
  20616. *
  20617. * Since v7.1.2: If it's a percentage string, it is interpreted the
  20618. * same as [series.radius](#plotOptions.gauge.radius), so label can be
  20619. * aligned under the gauge's shape.
  20620. *
  20621. * @sample {highcharts} highcharts/yaxis/labels-distance/
  20622. * Labels centered under the arc
  20623. *
  20624. * @type {number|string}
  20625. * @default -25
  20626. * @product highcharts
  20627. * @apioption yAxis.labels.distance
  20628. */
  20629. /**
  20630. * The y position offset of all labels relative to the tick
  20631. * positions on the axis. For polar and radial axis consider the use
  20632. * of the [distance](#yAxis.labels.distance) option.
  20633. *
  20634. * @sample {highcharts} highcharts/xaxis/labels-x/
  20635. * Y axis labels placed on grid lines
  20636. *
  20637. * @type {number}
  20638. * @default {highcharts} 3
  20639. * @default {highstock} -2
  20640. * @default {highmaps} 3
  20641. * @apioption yAxis.labels.y
  20642. */
  20643. /**
  20644. * What part of the string the given position is anchored to. Can
  20645. * be one of `"left"`, `"center"` or `"right"`. The exact position
  20646. * also depends on the `labels.x` setting.
  20647. *
  20648. * Angular gauges and solid gauges defaults to `"center"`.
  20649. * Solid gauges with two labels have additional option `"auto"`
  20650. * for automatic horizontal and vertical alignment.
  20651. *
  20652. * @see [yAxis.labels.distance](#yAxis.labels.distance)
  20653. *
  20654. * @sample {highcharts} highcharts/yaxis/labels-align-left/
  20655. * Left
  20656. * @sample {highcharts} highcharts/series-solidgauge/labels-auto-aligned/
  20657. * Solid gauge labels auto aligned
  20658. *
  20659. * @type {Highcharts.AlignValue}
  20660. * @default {highcharts|highmaps} right
  20661. * @default {highstock} left
  20662. * @apioption yAxis.labels.align
  20663. */
  20664. /**
  20665. * The x position offset of all labels relative to the tick
  20666. * positions on the axis. Defaults to -15 for left axis, 15 for
  20667. * right axis.
  20668. *
  20669. * @sample {highcharts} highcharts/xaxis/labels-x/
  20670. * Y axis labels placed on grid lines
  20671. */
  20672. x: -8
  20673. },
  20674. /**
  20675. * @productdesc {highmaps}
  20676. * In Highmaps, the axis line is hidden by default, because the axis is
  20677. * not visible by default.
  20678. *
  20679. * @type {Highcharts.ColorType}
  20680. * @apioption yAxis.lineColor
  20681. */
  20682. /**
  20683. * @sample {highcharts} highcharts/yaxis/max-200/
  20684. * Y axis max of 200
  20685. * @sample {highcharts} highcharts/yaxis/max-logarithmic/
  20686. * Y axis max on logarithmic axis
  20687. * @sample {highstock} stock/yaxis/min-max/
  20688. * Fixed min and max on Y axis
  20689. * @sample {highmaps} maps/axis/min-max/
  20690. * Pre-zoomed to a specific area
  20691. *
  20692. * @apioption yAxis.max
  20693. */
  20694. /**
  20695. * @sample {highcharts} highcharts/yaxis/min-startontick-false/
  20696. * -50 with startOnTick to false
  20697. * @sample {highcharts} highcharts/yaxis/min-startontick-true/
  20698. * -50 with startOnTick true by default
  20699. * @sample {highstock} stock/yaxis/min-max/
  20700. * Fixed min and max on Y axis
  20701. * @sample {highmaps} maps/axis/min-max/
  20702. * Pre-zoomed to a specific area
  20703. *
  20704. * @apioption yAxis.min
  20705. */
  20706. /**
  20707. * An optional scrollbar to display on the Y axis in response to
  20708. * limiting the minimum an maximum of the axis values.
  20709. *
  20710. * In styled mode, all the presentational options for the scrollbar
  20711. * are replaced by the classes `.highcharts-scrollbar-thumb`,
  20712. * `.highcharts-scrollbar-arrow`, `.highcharts-scrollbar-button`,
  20713. * `.highcharts-scrollbar-rifles` and `.highcharts-scrollbar-track`.
  20714. *
  20715. * @sample {highstock} stock/yaxis/scrollbar/
  20716. * Scrollbar on the Y axis
  20717. *
  20718. * @extends scrollbar
  20719. * @since 4.2.6
  20720. * @product highstock
  20721. * @excluding height
  20722. * @apioption yAxis.scrollbar
  20723. */
  20724. /**
  20725. * Enable the scrollbar on the Y axis.
  20726. *
  20727. * @sample {highstock} stock/yaxis/scrollbar/
  20728. * Enabled on Y axis
  20729. *
  20730. * @type {boolean}
  20731. * @default false
  20732. * @since 4.2.6
  20733. * @product highstock
  20734. * @apioption yAxis.scrollbar.enabled
  20735. */
  20736. /**
  20737. * Pixel margin between the scrollbar and the axis elements.
  20738. *
  20739. * @type {number}
  20740. * @default 10
  20741. * @since 4.2.6
  20742. * @product highstock
  20743. * @apioption yAxis.scrollbar.margin
  20744. */
  20745. /**
  20746. * Whether to show the scrollbar when it is fully zoomed out at max
  20747. * range. Setting it to `false` on the Y axis makes the scrollbar stay
  20748. * hidden until the user zooms in, like common in browsers.
  20749. *
  20750. * @type {boolean}
  20751. * @default true
  20752. * @since 4.2.6
  20753. * @product highstock
  20754. * @apioption yAxis.scrollbar.showFull
  20755. */
  20756. /**
  20757. * The width of a vertical scrollbar or height of a horizontal
  20758. * scrollbar. Defaults to 20 on touch devices.
  20759. *
  20760. * @type {number}
  20761. * @default 14
  20762. * @since 4.2.6
  20763. * @product highstock
  20764. * @apioption yAxis.scrollbar.size
  20765. */
  20766. /**
  20767. * Z index of the scrollbar elements.
  20768. *
  20769. * @type {number}
  20770. * @default 3
  20771. * @since 4.2.6
  20772. * @product highstock
  20773. * @apioption yAxis.scrollbar.zIndex
  20774. */
  20775. /**
  20776. * A soft maximum for the axis. If the series data maximum is less
  20777. * than this, the axis will stay at this maximum, but if the series
  20778. * data maximum is higher, the axis will flex to show all data.
  20779. *
  20780. * **Note**: The [series.softThreshold](
  20781. * #plotOptions.series.softThreshold) option takes precedence over this
  20782. * option.
  20783. *
  20784. * @sample highcharts/yaxis/softmin-softmax/
  20785. * Soft min and max
  20786. *
  20787. * @type {number}
  20788. * @since 5.0.1
  20789. * @product highcharts highstock gantt
  20790. * @apioption yAxis.softMax
  20791. */
  20792. /**
  20793. * A soft minimum for the axis. If the series data minimum is greater
  20794. * than this, the axis will stay at this minimum, but if the series
  20795. * data minimum is lower, the axis will flex to show all data.
  20796. *
  20797. * **Note**: The [series.softThreshold](
  20798. * #plotOptions.series.softThreshold) option takes precedence over this
  20799. * option.
  20800. *
  20801. * @sample highcharts/yaxis/softmin-softmax/
  20802. * Soft min and max
  20803. *
  20804. * @type {number}
  20805. * @since 5.0.1
  20806. * @product highcharts highstock gantt
  20807. * @apioption yAxis.softMin
  20808. */
  20809. /**
  20810. * Defines the horizontal alignment of the stack total label. Can be one
  20811. * of `"left"`, `"center"` or `"right"`. The default value is calculated
  20812. * at runtime and depends on orientation and whether the stack is
  20813. * positive or negative.
  20814. *
  20815. * @sample {highcharts} highcharts/yaxis/stacklabels-align-left/
  20816. * Aligned to the left
  20817. * @sample {highcharts} highcharts/yaxis/stacklabels-align-center/
  20818. * Aligned in center
  20819. * @sample {highcharts} highcharts/yaxis/stacklabels-align-right/
  20820. * Aligned to the right
  20821. *
  20822. * @type {Highcharts.AlignValue}
  20823. * @since 2.1.5
  20824. * @product highcharts
  20825. * @apioption yAxis.stackLabels.align
  20826. */
  20827. /**
  20828. * A format string for the data label. Available variables are the same
  20829. * as for `formatter`.
  20830. *
  20831. * @type {string}
  20832. * @default {total}
  20833. * @since 3.0.2
  20834. * @product highcharts highstock
  20835. * @apioption yAxis.stackLabels.format
  20836. */
  20837. /**
  20838. * Rotation of the labels in degrees.
  20839. *
  20840. * @sample {highcharts} highcharts/yaxis/stacklabels-rotation/
  20841. * Labels rotated 45°
  20842. *
  20843. * @type {number}
  20844. * @default 0
  20845. * @since 2.1.5
  20846. * @product highcharts
  20847. * @apioption yAxis.stackLabels.rotation
  20848. */
  20849. /**
  20850. * The text alignment for the label. While `align` determines where the
  20851. * texts anchor point is placed with regards to the stack, `textAlign`
  20852. * determines how the text is aligned against its anchor point. Possible
  20853. * values are `"left"`, `"center"` and `"right"`. The default value is
  20854. * calculated at runtime and depends on orientation and whether the
  20855. * stack is positive or negative.
  20856. *
  20857. * @sample {highcharts} highcharts/yaxis/stacklabels-textalign-left/
  20858. * Label in center position but text-aligned left
  20859. *
  20860. * @type {Highcharts.AlignValue}
  20861. * @since 2.1.5
  20862. * @product highcharts
  20863. * @apioption yAxis.stackLabels.textAlign
  20864. */
  20865. /**
  20866. * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  20867. * to render the labels.
  20868. *
  20869. * @type {boolean}
  20870. * @default false
  20871. * @since 3.0
  20872. * @product highcharts highstock
  20873. * @apioption yAxis.stackLabels.useHTML
  20874. */
  20875. /**
  20876. * Defines the vertical alignment of the stack total label. Can be one
  20877. * of `"top"`, `"middle"` or `"bottom"`. The default value is calculated
  20878. * at runtime and depends on orientation and whether the stack is
  20879. * positive or negative.
  20880. *
  20881. * @sample {highcharts} highcharts/yaxis/stacklabels-verticalalign-top/
  20882. * Vertically aligned top
  20883. * @sample {highcharts} highcharts/yaxis/stacklabels-verticalalign-middle/
  20884. * Vertically aligned middle
  20885. * @sample {highcharts} highcharts/yaxis/stacklabels-verticalalign-bottom/
  20886. * Vertically aligned bottom
  20887. *
  20888. * @type {Highcharts.VerticalAlignValue}
  20889. * @since 2.1.5
  20890. * @product highcharts
  20891. * @apioption yAxis.stackLabels.verticalAlign
  20892. */
  20893. /**
  20894. * The x position offset of the label relative to the left of the
  20895. * stacked bar. The default value is calculated at runtime and depends
  20896. * on orientation and whether the stack is positive or negative.
  20897. *
  20898. * @sample {highcharts} highcharts/yaxis/stacklabels-x/
  20899. * Stack total labels with x offset
  20900. *
  20901. * @type {number}
  20902. * @since 2.1.5
  20903. * @product highcharts
  20904. * @apioption yAxis.stackLabels.x
  20905. */
  20906. /**
  20907. * The y position offset of the label relative to the tick position
  20908. * on the axis. The default value is calculated at runtime and depends
  20909. * on orientation and whether the stack is positive or negative.
  20910. *
  20911. * @sample {highcharts} highcharts/yaxis/stacklabels-y/
  20912. * Stack total labels with y offset
  20913. *
  20914. * @type {number}
  20915. * @since 2.1.5
  20916. * @product highcharts
  20917. * @apioption yAxis.stackLabels.y
  20918. */
  20919. /**
  20920. * Whether to force the axis to start on a tick. Use this option with
  20921. * the `maxPadding` option to control the axis start.
  20922. *
  20923. * This option is always disabled, when panning type is
  20924. * either `y` or `xy`.
  20925. *
  20926. * @see [type](#chart.panning.type)
  20927. *
  20928. * @sample {highcharts} highcharts/xaxis/startontick-false/
  20929. * False by default
  20930. * @sample {highcharts} highcharts/xaxis/startontick-true/
  20931. * True
  20932. * @sample {highstock} stock/xaxis/endontick/
  20933. * False for Y axis
  20934. *
  20935. * @since 1.2.0
  20936. * @product highcharts highstock gantt
  20937. */
  20938. startOnTick: true,
  20939. title: {
  20940. /**
  20941. * The pixel distance between the axis labels and the title.
  20942. * Positive values are outside the axis line, negative are inside.
  20943. *
  20944. * @sample {highcharts} highcharts/xaxis/title-margin/
  20945. * Y axis title margin of 60
  20946. *
  20947. * @type {number}
  20948. * @default 40
  20949. * @apioption yAxis.title.margin
  20950. */
  20951. /**
  20952. * The rotation of the text in degrees. 0 is horizontal, 270 is
  20953. * vertical reading from bottom to top.
  20954. *
  20955. * @sample {highcharts} highcharts/yaxis/title-offset/
  20956. * Horizontal
  20957. */
  20958. rotation: 270,
  20959. /**
  20960. * The actual text of the axis title. Horizontal texts can contain
  20961. * HTML, but rotated texts are painted using vector techniques and
  20962. * must be clean text. The Y axis title is disabled by setting the
  20963. * `text` option to `undefined`.
  20964. *
  20965. * @sample {highcharts} highcharts/xaxis/title-text/
  20966. * Custom HTML
  20967. *
  20968. * @type {string|null}
  20969. * @default {highcharts} Values
  20970. * @default {highstock} undefined
  20971. * @product highcharts highstock gantt
  20972. */
  20973. text: 'Values'
  20974. },
  20975. /**
  20976. * The top position of the Y axis. If it's a number, it is interpreted
  20977. * as pixel position relative to the chart.
  20978. *
  20979. * Since Highcharts 2: If it's a percentage string, it is interpreted as
  20980. * percentages of the plot height, offset from plot area top.
  20981. *
  20982. * @see [yAxis.height](#yAxis.height)
  20983. *
  20984. * @sample {highstock} stock/demo/candlestick-and-volume/
  20985. * Percentage height panes
  20986. *
  20987. * @type {number|string}
  20988. * @product highcharts highstock
  20989. * @apioption yAxis.top
  20990. */
  20991. /**
  20992. * The stack labels show the total value for each bar in a stacked
  20993. * column or bar chart. The label will be placed on top of positive
  20994. * columns and below negative columns. In case of an inverted column
  20995. * chart or a bar chart the label is placed to the right of positive
  20996. * bars and to the left of negative bars.
  20997. *
  20998. * @product highcharts
  20999. */
  21000. stackLabels: {
  21001. /**
  21002. * Enable or disable the initial animation when a series is
  21003. * displayed for the `stackLabels`. The animation can also be set as
  21004. * a configuration object. Please note that this option only
  21005. * applies to the initial animation.
  21006. * For other animations, see [chart.animation](#chart.animation)
  21007. * and the animation parameter under the API methods.
  21008. * The following properties are supported:
  21009. *
  21010. * - `defer`: The animation delay time in milliseconds.
  21011. *
  21012. * @sample {highcharts} highcharts/plotoptions/animation-defer/
  21013. * Animation defer settings
  21014. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  21015. * @since 8.2.0
  21016. * @apioption yAxis.stackLabels.animation
  21017. */
  21018. animation: {},
  21019. /**
  21020. * The animation delay time in milliseconds.
  21021. * Set to `0` renders stackLabel immediately.
  21022. * As `undefined` inherits defer time from the [series.animation.defer](#plotOptions.series.animation.defer).
  21023. *
  21024. * @type {number}
  21025. * @since 8.2.0
  21026. * @apioption yAxis.stackLabels.animation.defer
  21027. */
  21028. /**
  21029. * Allow the stack labels to overlap.
  21030. *
  21031. * @sample {highcharts} highcharts/yaxis/stacklabels-allowoverlap-false/
  21032. * Default false
  21033. *
  21034. * @since 5.0.13
  21035. * @product highcharts
  21036. */
  21037. allowOverlap: false,
  21038. /**
  21039. * The background color or gradient for the stack label.
  21040. *
  21041. * @sample {highcharts} highcharts/yaxis/stacklabels-box/
  21042. * Stack labels box options
  21043. * @type {Highcharts.ColorType}
  21044. * @since 8.1.0
  21045. * @apioption yAxis.stackLabels.backgroundColor
  21046. */
  21047. /**
  21048. * The border color for the stack label. Defaults to `undefined`.
  21049. *
  21050. * @sample {highcharts} highcharts/yaxis/stacklabels-box/
  21051. * Stack labels box options
  21052. * @type {Highcharts.ColorType}
  21053. * @since 8.1.0
  21054. * @apioption yAxis.stackLabels.borderColor
  21055. */
  21056. /**
  21057. * The border radius in pixels for the stack label.
  21058. *
  21059. * @sample {highcharts} highcharts/yaxis/stacklabels-box/
  21060. * Stack labels box options
  21061. * @type {number}
  21062. * @default 0
  21063. * @since 8.1.0
  21064. * @apioption yAxis.stackLabels.borderRadius
  21065. */
  21066. /**
  21067. * The border width in pixels for the stack label.
  21068. *
  21069. * @sample {highcharts} highcharts/yaxis/stacklabels-box/
  21070. * Stack labels box options
  21071. * @type {number}
  21072. * @default 0
  21073. * @since 8.1.0
  21074. * @apioption yAxis.stackLabels.borderWidth
  21075. */
  21076. /**
  21077. * Enable or disable the stack total labels.
  21078. *
  21079. * @sample {highcharts} highcharts/yaxis/stacklabels-enabled/
  21080. * Enabled stack total labels
  21081. * @sample {highcharts} highcharts/yaxis/stacklabels-enabled-waterfall/
  21082. * Enabled stack labels in waterfall chart
  21083. *
  21084. * @since 2.1.5
  21085. * @product highcharts
  21086. */
  21087. enabled: false,
  21088. /**
  21089. * Whether to hide stack labels that are outside the plot area.
  21090. * By default, the stack label is moved
  21091. * inside the plot area according to the
  21092. * [overflow](/highcharts/#yAxis/stackLabels/overflow)
  21093. * option.
  21094. *
  21095. * @type {boolean}
  21096. * @since 7.1.3
  21097. */
  21098. crop: true,
  21099. /**
  21100. * How to handle stack total labels that flow outside the plot area.
  21101. * The default is set to `"justify"`,
  21102. * which aligns them inside the plot area.
  21103. * For columns and bars, this means it will be moved inside the bar.
  21104. * To display stack labels outside the plot area,
  21105. * set `crop` to `false` and `overflow` to `"allow"`.
  21106. *
  21107. * @sample highcharts/yaxis/stacklabels-overflow/
  21108. * Stack labels flows outside the plot area.
  21109. *
  21110. * @type {Highcharts.DataLabelsOverflowValue}
  21111. * @since 7.1.3
  21112. */
  21113. overflow: 'justify',
  21114. /* eslint-disable valid-jsdoc */
  21115. /**
  21116. * Callback JavaScript function to format the label. The value is
  21117. * given by `this.total`.
  21118. *
  21119. * @sample {highcharts} highcharts/yaxis/stacklabels-formatter/
  21120. * Added units to stack total value
  21121. *
  21122. * @type {Highcharts.FormatterCallbackFunction<Highcharts.StackItemObject>}
  21123. * @since 2.1.5
  21124. * @product highcharts
  21125. */
  21126. formatter: function () {
  21127. var numberFormatter = this.axis.chart.numberFormatter;
  21128. /* eslint-enable valid-jsdoc */
  21129. return numberFormatter(this.total, -1);
  21130. },
  21131. /**
  21132. * CSS styles for the label.
  21133. *
  21134. * In styled mode, the styles are set in the
  21135. * `.highcharts-stack-label` class.
  21136. *
  21137. * @sample {highcharts} highcharts/yaxis/stacklabels-style/
  21138. * Red stack total labels
  21139. *
  21140. * @type {Highcharts.CSSObject}
  21141. * @since 2.1.5
  21142. * @product highcharts
  21143. */
  21144. style: {
  21145. /** @internal */
  21146. color: palette.neutralColor100,
  21147. /** @internal */
  21148. fontSize: '11px',
  21149. /** @internal */
  21150. fontWeight: 'bold',
  21151. /** @internal */
  21152. textOutline: '1px contrast'
  21153. }
  21154. },
  21155. gridLineWidth: 1,
  21156. lineWidth: 0
  21157. // tickWidth: 0
  21158. };
  21159. /**
  21160. * The Z axis or depth axis for 3D plots.
  21161. *
  21162. * See the [Axis class](/class-reference/Highcharts.Axis) for programmatic
  21163. * access to the axis.
  21164. *
  21165. * @sample {highcharts} highcharts/3d/scatter-zaxis-categories/
  21166. * Z-Axis with Categories
  21167. * @sample {highcharts} highcharts/3d/scatter-zaxis-grid/
  21168. * Z-Axis with styling
  21169. *
  21170. * @type {*|Array<*>}
  21171. * @extends xAxis
  21172. * @since 5.0.0
  21173. * @product highcharts
  21174. * @excluding breaks, crosshair, height, left, lineColor, lineWidth,
  21175. * nameToX, showEmpty, top, width
  21176. * @apioption zAxis
  21177. *
  21178. * @private
  21179. */
  21180. // This variable extends the defaultOptions for left axes.
  21181. Axis.defaultLeftAxisOptions = {
  21182. labels: {
  21183. x: -15
  21184. },
  21185. title: {
  21186. rotation: 270
  21187. }
  21188. };
  21189. // This variable extends the defaultOptions for right axes.
  21190. Axis.defaultRightAxisOptions = {
  21191. labels: {
  21192. x: 15
  21193. },
  21194. title: {
  21195. rotation: 90
  21196. }
  21197. };
  21198. // This variable extends the defaultOptions for bottom axes.
  21199. Axis.defaultBottomAxisOptions = {
  21200. labels: {
  21201. autoRotation: [-45],
  21202. x: 0
  21203. // overflow: undefined,
  21204. // staggerLines: null
  21205. },
  21206. margin: 15,
  21207. title: {
  21208. rotation: 0
  21209. }
  21210. };
  21211. // This variable extends the defaultOptions for top axes.
  21212. Axis.defaultTopAxisOptions = {
  21213. labels: {
  21214. autoRotation: [-45],
  21215. x: 0
  21216. // overflow: undefined
  21217. // staggerLines: null
  21218. },
  21219. margin: 15,
  21220. title: {
  21221. rotation: 0
  21222. }
  21223. };
  21224. // Properties to survive after destroy, needed for Axis.update (#4317,
  21225. // #5773, #5881).
  21226. Axis.keepProps = ['extKey', 'hcEvents', 'names', 'series', 'userMax', 'userMin'];
  21227. return Axis;
  21228. }());
  21229. H.Axis = Axis;
  21230. return H.Axis;
  21231. });
  21232. _registerModule(_modules, 'Core/Axis/DateTimeAxis.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Utilities.js']], function (Axis, U) {
  21233. /* *
  21234. *
  21235. * (c) 2010-2021 Torstein Honsi
  21236. *
  21237. * License: www.highcharts.com/license
  21238. *
  21239. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  21240. *
  21241. * */
  21242. var addEvent = U.addEvent,
  21243. getMagnitude = U.getMagnitude,
  21244. normalizeTickInterval = U.normalizeTickInterval,
  21245. timeUnits = U.timeUnits;
  21246. /* eslint-disable valid-jsdoc */
  21247. var DateTimeAxisAdditions = /** @class */ (function () {
  21248. /* *
  21249. *
  21250. * Constructors
  21251. *
  21252. * */
  21253. function DateTimeAxisAdditions(axis) {
  21254. this.axis = axis;
  21255. }
  21256. /* *
  21257. *
  21258. * Functions
  21259. *
  21260. * */
  21261. /**
  21262. * Get a normalized tick interval for dates. Returns a configuration object
  21263. * with unit range (interval), count and name. Used to prepare data for
  21264. * `getTimeTicks`. Previously this logic was part of getTimeTicks, but as
  21265. * `getTimeTicks` now runs of segments in stock charts, the normalizing
  21266. * logic was extracted in order to prevent it for running over again for
  21267. * each segment having the same interval. #662, #697.
  21268. * @private
  21269. */
  21270. /**
  21271. * Get a normalized tick interval for dates. Returns a configuration object
  21272. * with unit range (interval), count and name. Used to prepare data for
  21273. * `getTimeTicks`. Previously this logic was part of getTimeTicks, but as
  21274. * `getTimeTicks` now runs of segments in stock charts, the normalizing
  21275. * logic was extracted in order to prevent it for running over again for
  21276. * each segment having the same interval. #662, #697.
  21277. * @private
  21278. */
  21279. DateTimeAxisAdditions.prototype.normalizeTimeTickInterval = function (tickInterval, unitsOption) {
  21280. var units = unitsOption || [[
  21281. 'millisecond',
  21282. [1, 2, 5, 10, 20, 25, 50, 100, 200, 500] // allowed multiples
  21283. ],
  21284. [
  21285. 'second',
  21286. [1, 2, 5, 10, 15, 30]
  21287. ],
  21288. [
  21289. 'minute',
  21290. [1, 2, 5, 10, 15, 30]
  21291. ],
  21292. [
  21293. 'hour',
  21294. [1, 2, 3, 4, 6, 8, 12]
  21295. ],
  21296. [
  21297. 'day',
  21298. [1, 2]
  21299. ],
  21300. [
  21301. 'week',
  21302. [1, 2]
  21303. ],
  21304. [
  21305. 'month',
  21306. [1, 2, 3, 4, 6]
  21307. ],
  21308. [
  21309. 'year',
  21310. null
  21311. ]],
  21312. unit = units[units.length - 1], // default unit is years
  21313. interval = timeUnits[unit[0]],
  21314. multiples = unit[1],
  21315. count,
  21316. i;
  21317. // loop through the units to find the one that best fits the
  21318. // tickInterval
  21319. for (i = 0; i < units.length; i++) {
  21320. unit = units[i];
  21321. interval = timeUnits[unit[0]];
  21322. multiples = unit[1];
  21323. if (units[i + 1]) {
  21324. // lessThan is in the middle between the highest multiple and
  21325. // the next unit.
  21326. var lessThan = (interval *
  21327. multiples[multiples.length - 1] +
  21328. timeUnits[units[i + 1][0]]) / 2;
  21329. // break and keep the current unit
  21330. if (tickInterval <= lessThan) {
  21331. break;
  21332. }
  21333. }
  21334. }
  21335. // prevent 2.5 years intervals, though 25, 250 etc. are allowed
  21336. if (interval === timeUnits.year && tickInterval < 5 * interval) {
  21337. multiples = [1, 2, 5];
  21338. }
  21339. // get the count
  21340. count = normalizeTickInterval(tickInterval / interval, multiples, unit[0] === 'year' ? // #1913, #2360
  21341. Math.max(getMagnitude(tickInterval / interval), 1) :
  21342. 1);
  21343. return {
  21344. unitRange: interval,
  21345. count: count,
  21346. unitName: unit[0]
  21347. };
  21348. };
  21349. return DateTimeAxisAdditions;
  21350. }());
  21351. /**
  21352. * Date and time support for axes.
  21353. *
  21354. * @private
  21355. * @class
  21356. */
  21357. var DateTimeAxis = /** @class */ (function () {
  21358. function DateTimeAxis() {
  21359. }
  21360. /* *
  21361. *
  21362. * Static Functions
  21363. *
  21364. * */
  21365. /**
  21366. * Extends axis class with date and time support.
  21367. * @private
  21368. */
  21369. DateTimeAxis.compose = function (AxisClass) {
  21370. AxisClass.keepProps.push('dateTime');
  21371. var axisProto = AxisClass.prototype;
  21372. /**
  21373. * Set the tick positions to a time unit that makes sense, for example
  21374. * on the first of each month or on every Monday. Return an array with
  21375. * the time positions. Used in datetime axes as well as for grouping
  21376. * data on a datetime axis.
  21377. *
  21378. * @private
  21379. * @function Highcharts.Axis#getTimeTicks
  21380. *
  21381. * @param {Highcharts.TimeNormalizeObject} normalizedInterval
  21382. * The interval in axis values (ms) and thecount.
  21383. *
  21384. * @param {number} min
  21385. * The minimum in axis values.
  21386. *
  21387. * @param {number} max
  21388. * The maximum in axis values.
  21389. *
  21390. * @param {number} startOfWeek
  21391. *
  21392. * @return {Highcharts.AxisTickPositionsArray}
  21393. */
  21394. axisProto.getTimeTicks = function () {
  21395. return this.chart.time.getTimeTicks.apply(this.chart.time, arguments);
  21396. };
  21397. /* eslint-disable no-invalid-this */
  21398. addEvent(AxisClass, 'init', function (e) {
  21399. var axis = this;
  21400. var options = e.userOptions;
  21401. if (options.type !== 'datetime') {
  21402. axis.dateTime = void 0;
  21403. return;
  21404. }
  21405. if (!axis.dateTime) {
  21406. axis.dateTime = new DateTimeAxisAdditions(axis);
  21407. }
  21408. });
  21409. /* eslint-enable no-invalid-this */
  21410. };
  21411. /* *
  21412. *
  21413. * Static Properties
  21414. *
  21415. * */
  21416. DateTimeAxis.AdditionsClass = DateTimeAxisAdditions;
  21417. return DateTimeAxis;
  21418. }());
  21419. DateTimeAxis.compose(Axis);
  21420. return DateTimeAxis;
  21421. });
  21422. _registerModule(_modules, 'Core/Axis/LogarithmicAxis.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Utilities.js']], function (Axis, U) {
  21423. /* *
  21424. *
  21425. * (c) 2010-2021 Torstein Honsi
  21426. *
  21427. * License: www.highcharts.com/license
  21428. *
  21429. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  21430. *
  21431. * */
  21432. var addEvent = U.addEvent,
  21433. getMagnitude = U.getMagnitude,
  21434. normalizeTickInterval = U.normalizeTickInterval,
  21435. pick = U.pick;
  21436. /* eslint-disable valid-jsdoc */
  21437. /**
  21438. * Provides logarithmic support for axes.
  21439. *
  21440. * @private
  21441. * @class
  21442. */
  21443. var LogarithmicAxisAdditions = /** @class */ (function () {
  21444. /* *
  21445. *
  21446. * Constructors
  21447. *
  21448. * */
  21449. function LogarithmicAxisAdditions(axis) {
  21450. this.axis = axis;
  21451. }
  21452. /* *
  21453. *
  21454. * Functions
  21455. *
  21456. * */
  21457. /**
  21458. * Set the tick positions of a logarithmic axis.
  21459. */
  21460. LogarithmicAxisAdditions.prototype.getLogTickPositions = function (interval, min, max, minor) {
  21461. var log = this;
  21462. var axis = log.axis;
  21463. var axisLength = axis.len;
  21464. var options = axis.options;
  21465. // Since we use this method for both major and minor ticks,
  21466. // use a local variable and return the result
  21467. var positions = [];
  21468. // Reset
  21469. if (!minor) {
  21470. log.minorAutoInterval = void 0;
  21471. }
  21472. // First case: All ticks fall on whole logarithms: 1, 10, 100 etc.
  21473. if (interval >= 0.5) {
  21474. interval = Math.round(interval);
  21475. positions = axis.getLinearTickPositions(interval, min, max);
  21476. // Second case: We need intermediary ticks. For example
  21477. // 1, 2, 4, 6, 8, 10, 20, 40 etc.
  21478. }
  21479. else if (interval >= 0.08) {
  21480. var roundedMin = Math.floor(min),
  21481. intermediate,
  21482. i,
  21483. j,
  21484. len,
  21485. pos,
  21486. lastPos,
  21487. break2;
  21488. if (interval > 0.3) {
  21489. intermediate = [1, 2, 4];
  21490. // 0.2 equals five minor ticks per 1, 10, 100 etc
  21491. }
  21492. else if (interval > 0.15) {
  21493. intermediate = [1, 2, 4, 6, 8];
  21494. }
  21495. else { // 0.1 equals ten minor ticks per 1, 10, 100 etc
  21496. intermediate = [1, 2, 3, 4, 5, 6, 7, 8, 9];
  21497. }
  21498. for (i = roundedMin; i < max + 1 && !break2; i++) {
  21499. len = intermediate.length;
  21500. for (j = 0; j < len && !break2; j++) {
  21501. pos = log.log2lin(log.lin2log(i) * intermediate[j]);
  21502. // #1670, lastPos is #3113
  21503. if (pos > min &&
  21504. (!minor || lastPos <= max) &&
  21505. typeof lastPos !== 'undefined') {
  21506. positions.push(lastPos);
  21507. }
  21508. if (lastPos > max) {
  21509. break2 = true;
  21510. }
  21511. lastPos = pos;
  21512. }
  21513. }
  21514. // Third case: We are so deep in between whole logarithmic values that
  21515. // we might as well handle the tick positions like a linear axis. For
  21516. // example 1.01, 1.02, 1.03, 1.04.
  21517. }
  21518. else {
  21519. var realMin = log.lin2log(min),
  21520. realMax = log.lin2log(max),
  21521. tickIntervalOption = minor ?
  21522. axis.getMinorTickInterval() :
  21523. options.tickInterval,
  21524. filteredTickIntervalOption = tickIntervalOption === 'auto' ?
  21525. null :
  21526. tickIntervalOption,
  21527. tickPixelIntervalOption = options.tickPixelInterval / (minor ? 5 : 1),
  21528. totalPixelLength = minor ?
  21529. axisLength / axis.tickPositions.length :
  21530. axisLength;
  21531. interval = pick(filteredTickIntervalOption, log.minorAutoInterval, (realMax - realMin) *
  21532. tickPixelIntervalOption / (totalPixelLength || 1));
  21533. interval = normalizeTickInterval(interval, void 0, getMagnitude(interval));
  21534. positions = axis.getLinearTickPositions(interval, realMin, realMax).map(log.log2lin);
  21535. if (!minor) {
  21536. log.minorAutoInterval = interval / 5;
  21537. }
  21538. }
  21539. // Set the axis-level tickInterval variable
  21540. if (!minor) {
  21541. axis.tickInterval = interval;
  21542. }
  21543. return positions;
  21544. };
  21545. LogarithmicAxisAdditions.prototype.lin2log = function (num) {
  21546. return Math.pow(10, num);
  21547. };
  21548. LogarithmicAxisAdditions.prototype.log2lin = function (num) {
  21549. return Math.log(num) / Math.LN10;
  21550. };
  21551. return LogarithmicAxisAdditions;
  21552. }());
  21553. var LogarithmicAxis = /** @class */ (function () {
  21554. function LogarithmicAxis() {
  21555. }
  21556. /**
  21557. * Provides logarithmic support for axes.
  21558. *
  21559. * @private
  21560. */
  21561. LogarithmicAxis.compose = function (AxisClass) {
  21562. AxisClass.keepProps.push('logarithmic');
  21563. /* eslint-disable no-invalid-this */
  21564. addEvent(AxisClass, 'init', function (e) {
  21565. var axis = this;
  21566. var options = e.userOptions;
  21567. var logarithmic = axis.logarithmic;
  21568. if (options.type !== 'logarithmic') {
  21569. axis.logarithmic = void 0;
  21570. }
  21571. else {
  21572. if (!logarithmic) {
  21573. logarithmic = axis.logarithmic = new LogarithmicAxisAdditions(axis);
  21574. }
  21575. }
  21576. });
  21577. addEvent(AxisClass, 'afterInit', function () {
  21578. var axis = this;
  21579. var log = axis.logarithmic;
  21580. // extend logarithmic axis
  21581. if (log) {
  21582. axis.lin2val = function (num) {
  21583. return log.lin2log(num);
  21584. };
  21585. axis.val2lin = function (num) {
  21586. return log.log2lin(num);
  21587. };
  21588. }
  21589. });
  21590. };
  21591. return LogarithmicAxis;
  21592. }());
  21593. LogarithmicAxis.compose(Axis); // @todo move to factory functions
  21594. return LogarithmicAxis;
  21595. });
  21596. _registerModule(_modules, 'Core/Axis/PlotLineOrBand.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Globals.js'], _modules['Core/Color/Palette.js'], _modules['Core/Utilities.js']], function (Axis, H, palette, U) {
  21597. /* *
  21598. *
  21599. * (c) 2010-2021 Torstein Honsi
  21600. *
  21601. * License: www.highcharts.com/license
  21602. *
  21603. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  21604. *
  21605. * */
  21606. /**
  21607. * Options for plot bands on axes.
  21608. *
  21609. * @typedef {Highcharts.XAxisPlotBandsOptions|Highcharts.YAxisPlotBandsOptions|Highcharts.ZAxisPlotBandsOptions} Highcharts.AxisPlotBandsOptions
  21610. */
  21611. /**
  21612. * Options for plot band labels on axes.
  21613. *
  21614. * @typedef {Highcharts.XAxisPlotBandsLabelOptions|Highcharts.YAxisPlotBandsLabelOptions|Highcharts.ZAxisPlotBandsLabelOptions} Highcharts.AxisPlotBandsLabelOptions
  21615. */
  21616. /**
  21617. * Options for plot lines on axes.
  21618. *
  21619. * @typedef {Highcharts.XAxisPlotLinesOptions|Highcharts.YAxisPlotLinesOptions|Highcharts.ZAxisPlotLinesOptions} Highcharts.AxisPlotLinesOptions
  21620. */
  21621. /**
  21622. * Options for plot line labels on axes.
  21623. *
  21624. * @typedef {Highcharts.XAxisPlotLinesLabelOptions|Highcharts.YAxisPlotLinesLabelOptions|Highcharts.ZAxisPlotLinesLabelOptions} Highcharts.AxisPlotLinesLabelOptions
  21625. */
  21626. var arrayMax = U.arrayMax,
  21627. arrayMin = U.arrayMin,
  21628. defined = U.defined,
  21629. destroyObjectProperties = U.destroyObjectProperties,
  21630. erase = U.erase,
  21631. extend = U.extend,
  21632. fireEvent = U.fireEvent,
  21633. merge = U.merge,
  21634. objectEach = U.objectEach,
  21635. pick = U.pick;
  21636. /* eslint-disable no-invalid-this, valid-jsdoc */
  21637. /**
  21638. * The object wrapper for plot lines and plot bands
  21639. *
  21640. * @class
  21641. * @name Highcharts.PlotLineOrBand
  21642. *
  21643. * @param {Highcharts.Axis} axis
  21644. *
  21645. * @param {Highcharts.AxisPlotLinesOptions|Highcharts.AxisPlotBandsOptions} [options]
  21646. */
  21647. var PlotLineOrBand = /** @class */ (function () {
  21648. function PlotLineOrBand(axis, options) {
  21649. this.axis = axis;
  21650. if (options) {
  21651. this.options = options;
  21652. this.id = options.id;
  21653. }
  21654. }
  21655. /**
  21656. * Render the plot line or plot band. If it is already existing,
  21657. * move it.
  21658. *
  21659. * @private
  21660. * @function Highcharts.PlotLineOrBand#render
  21661. * @return {Highcharts.PlotLineOrBand|undefined}
  21662. */
  21663. PlotLineOrBand.prototype.render = function () {
  21664. fireEvent(this, 'render');
  21665. var plotLine = this,
  21666. axis = plotLine.axis,
  21667. horiz = axis.horiz,
  21668. log = axis.logarithmic,
  21669. options = plotLine.options,
  21670. optionsLabel = options.label,
  21671. label = plotLine.label,
  21672. to = options.to,
  21673. from = options.from,
  21674. value = options.value,
  21675. isBand = defined(from) && defined(to),
  21676. isLine = defined(value),
  21677. svgElem = plotLine.svgElem,
  21678. isNew = !svgElem,
  21679. path = [],
  21680. color = options.color,
  21681. zIndex = pick(options.zIndex, 0),
  21682. events = options.events,
  21683. attribs = {
  21684. 'class': 'highcharts-plot-' + (isBand ? 'band ' : 'line ') +
  21685. (options.className || '')
  21686. },
  21687. groupAttribs = {},
  21688. renderer = axis.chart.renderer,
  21689. groupName = isBand ? 'bands' : 'lines',
  21690. group;
  21691. // logarithmic conversion
  21692. if (log) {
  21693. from = log.log2lin(from);
  21694. to = log.log2lin(to);
  21695. value = log.log2lin(value);
  21696. }
  21697. // Set the presentational attributes
  21698. if (!axis.chart.styledMode) {
  21699. if (isLine) {
  21700. attribs.stroke = color || palette.neutralColor40;
  21701. attribs['stroke-width'] = pick(options.width, 1);
  21702. if (options.dashStyle) {
  21703. attribs.dashstyle =
  21704. options.dashStyle;
  21705. }
  21706. }
  21707. else if (isBand) { // plot band
  21708. attribs.fill = color || palette.highlightColor10;
  21709. if (options.borderWidth) {
  21710. attribs.stroke = options.borderColor;
  21711. attribs['stroke-width'] = options.borderWidth;
  21712. }
  21713. }
  21714. }
  21715. // Grouping and zIndex
  21716. groupAttribs.zIndex = zIndex;
  21717. groupName += '-' + zIndex;
  21718. group = axis.plotLinesAndBandsGroups[groupName];
  21719. if (!group) {
  21720. axis.plotLinesAndBandsGroups[groupName] = group =
  21721. renderer.g('plot-' + groupName)
  21722. .attr(groupAttribs).add();
  21723. }
  21724. // Create the path
  21725. if (isNew) {
  21726. /**
  21727. * SVG element of the plot line or band.
  21728. *
  21729. * @name Highcharts.PlotLineOrBand#svgElement
  21730. * @type {Highcharts.SVGElement}
  21731. */
  21732. plotLine.svgElem = svgElem = renderer
  21733. .path()
  21734. .attr(attribs)
  21735. .add(group);
  21736. }
  21737. // Set the path or return
  21738. if (isLine) {
  21739. path = axis.getPlotLinePath({
  21740. value: value,
  21741. lineWidth: svgElem.strokeWidth(),
  21742. acrossPanes: options.acrossPanes
  21743. });
  21744. }
  21745. else if (isBand) { // plot band
  21746. path = axis.getPlotBandPath(from, to, options);
  21747. }
  21748. else {
  21749. return;
  21750. }
  21751. // common for lines and bands
  21752. // Add events only if they were not added before.
  21753. if (!plotLine.eventsAdded && events) {
  21754. objectEach(events, function (event, eventType) {
  21755. svgElem.on(eventType, function (e) {
  21756. events[eventType].apply(plotLine, [e]);
  21757. });
  21758. });
  21759. plotLine.eventsAdded = true;
  21760. }
  21761. if ((isNew || !svgElem.d) && path && path.length) {
  21762. svgElem.attr({ d: path });
  21763. }
  21764. else if (svgElem) {
  21765. if (path) {
  21766. svgElem.show(true);
  21767. svgElem.animate({ d: path });
  21768. }
  21769. else if (svgElem.d) {
  21770. svgElem.hide();
  21771. if (label) {
  21772. plotLine.label = label = label.destroy();
  21773. }
  21774. }
  21775. }
  21776. // the plot band/line label
  21777. if (optionsLabel &&
  21778. (defined(optionsLabel.text) || defined(optionsLabel.formatter)) &&
  21779. path &&
  21780. path.length &&
  21781. axis.width > 0 &&
  21782. axis.height > 0 &&
  21783. !path.isFlat) {
  21784. // apply defaults
  21785. optionsLabel = merge({
  21786. align: horiz && isBand && 'center',
  21787. x: horiz ? !isBand && 4 : 10,
  21788. verticalAlign: !horiz && isBand && 'middle',
  21789. y: horiz ? isBand ? 16 : 10 : isBand ? 6 : -4,
  21790. rotation: horiz && !isBand && 90
  21791. }, optionsLabel);
  21792. this.renderLabel(optionsLabel, path, isBand, zIndex);
  21793. }
  21794. else if (label) { // move out of sight
  21795. label.hide();
  21796. }
  21797. // chainable
  21798. return plotLine;
  21799. };
  21800. /**
  21801. * Render and align label for plot line or band.
  21802. *
  21803. * @private
  21804. * @function Highcharts.PlotLineOrBand#renderLabel
  21805. * @param {Highcharts.AxisPlotLinesLabelOptions|Highcharts.AxisPlotBandsLabelOptions} optionsLabel
  21806. * @param {Highcharts.SVGPathArray} path
  21807. * @param {boolean} [isBand]
  21808. * @param {number} [zIndex]
  21809. * @return {void}
  21810. */
  21811. PlotLineOrBand.prototype.renderLabel = function (optionsLabel, path, isBand, zIndex) {
  21812. var plotLine = this,
  21813. label = plotLine.label,
  21814. renderer = plotLine.axis.chart.renderer,
  21815. attribs,
  21816. xBounds,
  21817. yBounds,
  21818. x,
  21819. y,
  21820. labelText;
  21821. // add the SVG element
  21822. if (!label) {
  21823. attribs = {
  21824. align: optionsLabel.textAlign || optionsLabel.align,
  21825. rotation: optionsLabel.rotation,
  21826. 'class': 'highcharts-plot-' + (isBand ? 'band' : 'line') +
  21827. '-label ' + (optionsLabel.className || '')
  21828. };
  21829. attribs.zIndex = zIndex;
  21830. labelText = this.getLabelText(optionsLabel);
  21831. /**
  21832. * SVG element of the label.
  21833. *
  21834. * @name Highcharts.PlotLineOrBand#label
  21835. * @type {Highcharts.SVGElement}
  21836. */
  21837. plotLine.label = label = renderer
  21838. .text(labelText, 0, 0, optionsLabel.useHTML)
  21839. .attr(attribs)
  21840. .add();
  21841. if (!this.axis.chart.styledMode) {
  21842. label.css(optionsLabel.style);
  21843. }
  21844. }
  21845. // get the bounding box and align the label
  21846. // #3000 changed to better handle choice between plotband or plotline
  21847. xBounds = path.xBounds ||
  21848. [path[0][1], path[1][1], (isBand ? path[2][1] : path[0][1])];
  21849. yBounds = path.yBounds ||
  21850. [path[0][2], path[1][2], (isBand ? path[2][2] : path[0][2])];
  21851. x = arrayMin(xBounds);
  21852. y = arrayMin(yBounds);
  21853. label.align(optionsLabel, false, {
  21854. x: x,
  21855. y: y,
  21856. width: arrayMax(xBounds) - x,
  21857. height: arrayMax(yBounds) - y
  21858. });
  21859. label.show(true);
  21860. };
  21861. /**
  21862. * Get label's text content.
  21863. *
  21864. * @private
  21865. * @function Highcharts.PlotLineOrBand#getLabelText
  21866. * @param {Highcharts.AxisPlotLinesLabelOptions|Highcharts.AxisPlotBandsLabelOptions} optionsLabel
  21867. * @return {string}
  21868. */
  21869. PlotLineOrBand.prototype.getLabelText = function (optionsLabel) {
  21870. return defined(optionsLabel.formatter) ?
  21871. optionsLabel.formatter
  21872. .call(this) :
  21873. optionsLabel.text;
  21874. };
  21875. /**
  21876. * Remove the plot line or band.
  21877. *
  21878. * @function Highcharts.PlotLineOrBand#destroy
  21879. * @return {void}
  21880. */
  21881. PlotLineOrBand.prototype.destroy = function () {
  21882. // remove it from the lookup
  21883. erase(this.axis.plotLinesAndBands, this);
  21884. delete this.axis;
  21885. destroyObjectProperties(this);
  21886. };
  21887. return PlotLineOrBand;
  21888. }());
  21889. /* eslint-enable no-invalid-this, valid-jsdoc */
  21890. // Object with members for extending the Axis prototype
  21891. extend(Axis.prototype, /** @lends Highcharts.Axis.prototype */ {
  21892. /**
  21893. * An array of colored bands stretching across the plot area marking an
  21894. * interval on the axis.
  21895. *
  21896. * In styled mode, the plot bands are styled by the `.highcharts-plot-band`
  21897. * class in addition to the `className` option.
  21898. *
  21899. * @productdesc {highcharts}
  21900. * In a gauge, a plot band on the Y axis (value axis) will stretch along the
  21901. * perimeter of the gauge.
  21902. *
  21903. * @type {Array<*>}
  21904. * @product highcharts highstock gantt
  21905. * @apioption xAxis.plotBands
  21906. */
  21907. /**
  21908. * Flag to decide if plotBand should be rendered across all panes.
  21909. *
  21910. * @since 7.1.2
  21911. * @product highstock
  21912. * @type {boolean}
  21913. * @default true
  21914. * @apioption xAxis.plotBands.acrossPanes
  21915. */
  21916. /**
  21917. * Border color for the plot band. Also requires `borderWidth` to be set.
  21918. *
  21919. * @type {Highcharts.ColorString}
  21920. * @apioption xAxis.plotBands.borderColor
  21921. */
  21922. /**
  21923. * Border width for the plot band. Also requires `borderColor` to be set.
  21924. *
  21925. * @type {number}
  21926. * @default 0
  21927. * @apioption xAxis.plotBands.borderWidth
  21928. */
  21929. /**
  21930. * A custom class name, in addition to the default `highcharts-plot-band`,
  21931. * to apply to each individual band.
  21932. *
  21933. * @type {string}
  21934. * @since 5.0.0
  21935. * @apioption xAxis.plotBands.className
  21936. */
  21937. /**
  21938. * The color of the plot band.
  21939. *
  21940. * @sample {highcharts} highcharts/xaxis/plotbands-color/
  21941. * Color band
  21942. * @sample {highstock} stock/xaxis/plotbands/
  21943. * Plot band on Y axis
  21944. *
  21945. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  21946. * @default ${palette.highlightColor10}
  21947. * @apioption xAxis.plotBands.color
  21948. */
  21949. /**
  21950. * An object defining mouse events for the plot band. Supported properties
  21951. * are `click`, `mouseover`, `mouseout`, `mousemove`.
  21952. *
  21953. * @sample {highcharts} highcharts/xaxis/plotbands-events/
  21954. * Mouse events demonstrated
  21955. *
  21956. * @since 1.2
  21957. * @apioption xAxis.plotBands.events
  21958. */
  21959. /**
  21960. * Click event on a plot band.
  21961. *
  21962. * @type {Highcharts.EventCallbackFunction<Highcharts.PlotLineOrBand>}
  21963. * @apioption xAxis.plotBands.events.click
  21964. */
  21965. /**
  21966. * Mouse move event on a plot band.
  21967. *
  21968. * @type {Highcharts.EventCallbackFunction<Highcharts.PlotLineOrBand>}
  21969. * @apioption xAxis.plotBands.events.mousemove
  21970. */
  21971. /**
  21972. * Mouse out event on the corner of a plot band.
  21973. *
  21974. * @type {Highcharts.EventCallbackFunction<Highcharts.PlotLineOrBand>}
  21975. * @apioption xAxis.plotBands.events.mouseout
  21976. */
  21977. /**
  21978. * Mouse over event on a plot band.
  21979. *
  21980. * @type {Highcharts.EventCallbackFunction<Highcharts.PlotLineOrBand>}
  21981. * @apioption xAxis.plotBands.events.mouseover
  21982. */
  21983. /**
  21984. * The start position of the plot band in axis units.
  21985. *
  21986. * @sample {highcharts} highcharts/xaxis/plotbands-color/
  21987. * Datetime axis
  21988. * @sample {highcharts} highcharts/xaxis/plotbands-from/
  21989. * Categorized axis
  21990. * @sample {highstock} stock/xaxis/plotbands/
  21991. * Plot band on Y axis
  21992. *
  21993. * @type {number}
  21994. * @apioption xAxis.plotBands.from
  21995. */
  21996. /**
  21997. * An id used for identifying the plot band in Axis.removePlotBand.
  21998. *
  21999. * @sample {highcharts} highcharts/xaxis/plotbands-id/
  22000. * Remove plot band by id
  22001. * @sample {highstock} highcharts/xaxis/plotbands-id/
  22002. * Remove plot band by id
  22003. *
  22004. * @type {string}
  22005. * @apioption xAxis.plotBands.id
  22006. */
  22007. /**
  22008. * The end position of the plot band in axis units.
  22009. *
  22010. * @sample {highcharts} highcharts/xaxis/plotbands-color/
  22011. * Datetime axis
  22012. * @sample {highcharts} highcharts/xaxis/plotbands-from/
  22013. * Categorized axis
  22014. * @sample {highstock} stock/xaxis/plotbands/
  22015. * Plot band on Y axis
  22016. *
  22017. * @type {number}
  22018. * @apioption xAxis.plotBands.to
  22019. */
  22020. /**
  22021. * The z index of the plot band within the chart, relative to other
  22022. * elements. Using the same z index as another element may give
  22023. * unpredictable results, as the last rendered element will be on top.
  22024. * Values from 0 to 20 make sense.
  22025. *
  22026. * @sample {highcharts} highcharts/xaxis/plotbands-color/
  22027. * Behind plot lines by default
  22028. * @sample {highcharts} highcharts/xaxis/plotbands-zindex/
  22029. * Above plot lines
  22030. * @sample {highcharts} highcharts/xaxis/plotbands-zindex-above-series/
  22031. * Above plot lines and series
  22032. *
  22033. * @type {number}
  22034. * @since 1.2
  22035. * @apioption xAxis.plotBands.zIndex
  22036. */
  22037. /**
  22038. * Text labels for the plot bands
  22039. *
  22040. * @product highcharts highstock gantt
  22041. * @apioption xAxis.plotBands.label
  22042. */
  22043. /**
  22044. * Horizontal alignment of the label. Can be one of "left", "center" or
  22045. * "right".
  22046. *
  22047. * @sample {highcharts} highcharts/xaxis/plotbands-label-align/
  22048. * Aligned to the right
  22049. * @sample {highstock} stock/xaxis/plotbands-label/
  22050. * Plot band with labels
  22051. *
  22052. * @type {Highcharts.AlignValue}
  22053. * @default center
  22054. * @since 2.1
  22055. * @apioption xAxis.plotBands.label.align
  22056. */
  22057. /**
  22058. * Rotation of the text label in degrees .
  22059. *
  22060. * @sample {highcharts} highcharts/xaxis/plotbands-label-rotation/
  22061. * Vertical text
  22062. *
  22063. * @type {number}
  22064. * @default 0
  22065. * @since 2.1
  22066. * @apioption xAxis.plotBands.label.rotation
  22067. */
  22068. /**
  22069. * CSS styles for the text label.
  22070. *
  22071. * In styled mode, the labels are styled by the
  22072. * `.highcharts-plot-band-label` class.
  22073. *
  22074. * @sample {highcharts} highcharts/xaxis/plotbands-label-style/
  22075. * Blue and bold label
  22076. *
  22077. * @type {Highcharts.CSSObject}
  22078. * @since 2.1
  22079. * @apioption xAxis.plotBands.label.style
  22080. */
  22081. /**
  22082. * The string text itself. A subset of HTML is supported.
  22083. *
  22084. * @type {string}
  22085. * @since 2.1
  22086. * @apioption xAxis.plotBands.label.text
  22087. */
  22088. /**
  22089. * The text alignment for the label. While `align` determines where the
  22090. * texts anchor point is placed within the plot band, `textAlign` determines
  22091. * how the text is aligned against its anchor point. Possible values are
  22092. * "left", "center" and "right". Defaults to the same as the `align` option.
  22093. *
  22094. * @sample {highcharts} highcharts/xaxis/plotbands-label-rotation/
  22095. * Vertical text in center position but text-aligned left
  22096. *
  22097. * @type {Highcharts.AlignValue}
  22098. * @since 2.1
  22099. * @apioption xAxis.plotBands.label.textAlign
  22100. */
  22101. /**
  22102. * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  22103. * to render the labels.
  22104. *
  22105. * @type {boolean}
  22106. * @default false
  22107. * @since 3.0.3
  22108. * @apioption xAxis.plotBands.label.useHTML
  22109. */
  22110. /**
  22111. * Vertical alignment of the label relative to the plot band. Can be one of
  22112. * "top", "middle" or "bottom".
  22113. *
  22114. * @sample {highcharts} highcharts/xaxis/plotbands-label-verticalalign/
  22115. * Vertically centered label
  22116. * @sample {highstock} stock/xaxis/plotbands-label/
  22117. * Plot band with labels
  22118. *
  22119. * @type {Highcharts.VerticalAlignValue}
  22120. * @default top
  22121. * @since 2.1
  22122. * @apioption xAxis.plotBands.label.verticalAlign
  22123. */
  22124. /**
  22125. * Horizontal position relative the alignment. Default varies by
  22126. * orientation.
  22127. *
  22128. * @sample {highcharts} highcharts/xaxis/plotbands-label-align/
  22129. * Aligned 10px from the right edge
  22130. * @sample {highstock} stock/xaxis/plotbands-label/
  22131. * Plot band with labels
  22132. *
  22133. * @type {number}
  22134. * @since 2.1
  22135. * @apioption xAxis.plotBands.label.x
  22136. */
  22137. /**
  22138. * Vertical position of the text baseline relative to the alignment. Default
  22139. * varies by orientation.
  22140. *
  22141. * @sample {highcharts} highcharts/xaxis/plotbands-label-y/
  22142. * Label on x axis
  22143. * @sample {highstock} stock/xaxis/plotbands-label/
  22144. * Plot band with labels
  22145. *
  22146. * @type {number}
  22147. * @since 2.1
  22148. * @apioption xAxis.plotBands.label.y
  22149. */
  22150. /**
  22151. * An array of lines stretching across the plot area, marking a specific
  22152. * value on one of the axes.
  22153. *
  22154. * In styled mode, the plot lines are styled by the
  22155. * `.highcharts-plot-line` class in addition to the `className` option.
  22156. *
  22157. * @type {Array<*>}
  22158. * @product highcharts highstock gantt
  22159. * @sample {highcharts} highcharts/xaxis/plotlines-color/
  22160. * Basic plot line
  22161. * @sample {highcharts} highcharts/series-solidgauge/labels-auto-aligned/
  22162. * Solid gauge plot line
  22163. * @apioption xAxis.plotLines
  22164. */
  22165. /**
  22166. * Flag to decide if plotLine should be rendered across all panes.
  22167. *
  22168. * @sample {highstock} stock/xaxis/plotlines-acrosspanes/
  22169. * Plot lines on different panes
  22170. *
  22171. * @since 7.1.2
  22172. * @product highstock
  22173. * @type {boolean}
  22174. * @default true
  22175. * @apioption xAxis.plotLines.acrossPanes
  22176. */
  22177. /**
  22178. * A custom class name, in addition to the default `highcharts-plot-line`,
  22179. * to apply to each individual line.
  22180. *
  22181. * @type {string}
  22182. * @since 5.0.0
  22183. * @apioption xAxis.plotLines.className
  22184. */
  22185. /**
  22186. * The color of the line.
  22187. *
  22188. * @sample {highcharts} highcharts/xaxis/plotlines-color/
  22189. * A red line from X axis
  22190. * @sample {highstock} stock/xaxis/plotlines/
  22191. * Plot line on Y axis
  22192. *
  22193. * @type {Highcharts.ColorString}
  22194. * @default ${palette.neutralColor40}
  22195. * @apioption xAxis.plotLines.color
  22196. */
  22197. /**
  22198. * The dashing or dot style for the plot line. For possible values see
  22199. * [this overview](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/series-dashstyle-all/).
  22200. *
  22201. * @sample {highcharts} highcharts/xaxis/plotlines-dashstyle/
  22202. * Dash and dot pattern
  22203. * @sample {highstock} stock/xaxis/plotlines/
  22204. * Plot line on Y axis
  22205. *
  22206. * @type {Highcharts.DashStyleValue}
  22207. * @default Solid
  22208. * @since 1.2
  22209. * @apioption xAxis.plotLines.dashStyle
  22210. */
  22211. /**
  22212. * An object defining mouse events for the plot line. Supported
  22213. * properties are `click`, `mouseover`, `mouseout`, `mousemove`.
  22214. *
  22215. * @sample {highcharts} highcharts/xaxis/plotlines-events/
  22216. * Mouse events demonstrated
  22217. *
  22218. * @since 1.2
  22219. * @apioption xAxis.plotLines.events
  22220. */
  22221. /**
  22222. * Click event on a plot band.
  22223. *
  22224. * @type {Highcharts.EventCallbackFunction<Highcharts.PlotLineOrBand>}
  22225. * @apioption xAxis.plotLines.events.click
  22226. */
  22227. /**
  22228. * Mouse move event on a plot band.
  22229. *
  22230. * @type {Highcharts.EventCallbackFunction<Highcharts.PlotLineOrBand>}
  22231. * @apioption xAxis.plotLines.events.mousemove
  22232. */
  22233. /**
  22234. * Mouse out event on the corner of a plot band.
  22235. *
  22236. * @type {Highcharts.EventCallbackFunction<Highcharts.PlotLineOrBand>}
  22237. * @apioption xAxis.plotLines.events.mouseout
  22238. */
  22239. /**
  22240. * Mouse over event on a plot band.
  22241. *
  22242. * @type {Highcharts.EventCallbackFunction<Highcharts.PlotLineOrBand>}
  22243. * @apioption xAxis.plotLines.events.mouseover
  22244. */
  22245. /**
  22246. * An id used for identifying the plot line in Axis.removePlotLine.
  22247. *
  22248. * @sample {highcharts} highcharts/xaxis/plotlines-id/
  22249. * Remove plot line by id
  22250. *
  22251. * @type {string}
  22252. * @apioption xAxis.plotLines.id
  22253. */
  22254. /**
  22255. * The position of the line in axis units.
  22256. *
  22257. * @sample {highcharts} highcharts/xaxis/plotlines-color/
  22258. * Between two categories on X axis
  22259. * @sample {highstock} stock/xaxis/plotlines/
  22260. * Plot line on Y axis
  22261. *
  22262. * @type {number}
  22263. * @apioption xAxis.plotLines.value
  22264. */
  22265. /**
  22266. * The width or thickness of the plot line.
  22267. *
  22268. * @sample {highcharts} highcharts/xaxis/plotlines-color/
  22269. * 2px wide line from X axis
  22270. * @sample {highstock} stock/xaxis/plotlines/
  22271. * Plot line on Y axis
  22272. *
  22273. * @type {number}
  22274. * @default 2
  22275. * @apioption xAxis.plotLines.width
  22276. */
  22277. /**
  22278. * The z index of the plot line within the chart.
  22279. *
  22280. * @sample {highcharts} highcharts/xaxis/plotlines-zindex-behind/
  22281. * Behind plot lines by default
  22282. * @sample {highcharts} highcharts/xaxis/plotlines-zindex-above/
  22283. * Above plot lines
  22284. * @sample {highcharts} highcharts/xaxis/plotlines-zindex-above-all/
  22285. * Above plot lines and series
  22286. *
  22287. * @type {number}
  22288. * @since 1.2
  22289. * @apioption xAxis.plotLines.zIndex
  22290. */
  22291. /**
  22292. * Text labels for the plot bands
  22293. *
  22294. * @apioption xAxis.plotLines.label
  22295. */
  22296. /**
  22297. * Horizontal alignment of the label. Can be one of "left", "center" or
  22298. * "right".
  22299. *
  22300. * @sample {highcharts} highcharts/xaxis/plotlines-label-align-right/
  22301. * Aligned to the right
  22302. * @sample {highstock} stock/xaxis/plotlines/
  22303. * Plot line on Y axis
  22304. *
  22305. * @type {Highcharts.AlignValue}
  22306. * @default left
  22307. * @since 2.1
  22308. * @apioption xAxis.plotLines.label.align
  22309. */
  22310. /**
  22311. * Callback JavaScript function to format the label. Useful properties like
  22312. * the value of plot line or the range of plot band (`from` & `to`
  22313. * properties) can be found in `this.options` object.
  22314. *
  22315. * @sample {highcharts} highcharts/xaxis/plotlines-plotbands-label-formatter
  22316. * Label formatters for plot line and plot band.
  22317. * @type {Highcharts.FormatterCallbackFunction<Highcharts.PlotLineOrBand>}
  22318. * @apioption xAxis.plotLines.label.formatter
  22319. */
  22320. /**
  22321. * Rotation of the text label in degrees. Defaults to 0 for horizontal plot
  22322. * lines and 90 for vertical lines.
  22323. *
  22324. * @sample {highcharts} highcharts/xaxis/plotlines-label-verticalalign-middle/
  22325. * Slanted text
  22326. *
  22327. * @type {number}
  22328. * @since 2.1
  22329. * @apioption xAxis.plotLines.label.rotation
  22330. */
  22331. /**
  22332. * CSS styles for the text label.
  22333. *
  22334. * In styled mode, the labels are styled by the
  22335. * `.highcharts-plot-line-label` class.
  22336. *
  22337. * @sample {highcharts} highcharts/xaxis/plotlines-label-style/
  22338. * Blue and bold label
  22339. *
  22340. * @type {Highcharts.CSSObject}
  22341. * @since 2.1
  22342. * @apioption xAxis.plotLines.label.style
  22343. */
  22344. /**
  22345. * The text itself. A subset of HTML is supported.
  22346. *
  22347. * @type {string}
  22348. * @since 2.1
  22349. * @apioption xAxis.plotLines.label.text
  22350. */
  22351. /**
  22352. * The text alignment for the label. While `align` determines where the
  22353. * texts anchor point is placed within the plot band, `textAlign` determines
  22354. * how the text is aligned against its anchor point. Possible values are
  22355. * "left", "center" and "right". Defaults to the same as the `align` option.
  22356. *
  22357. * @sample {highcharts} highcharts/xaxis/plotlines-label-textalign/
  22358. * Text label in bottom position
  22359. *
  22360. * @type {Highcharts.AlignValue}
  22361. * @since 2.1
  22362. * @apioption xAxis.plotLines.label.textAlign
  22363. */
  22364. /**
  22365. * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  22366. * to render the labels.
  22367. *
  22368. * @type {boolean}
  22369. * @default false
  22370. * @since 3.0.3
  22371. * @apioption xAxis.plotLines.label.useHTML
  22372. */
  22373. /**
  22374. * Vertical alignment of the label relative to the plot line. Can be
  22375. * one of "top", "middle" or "bottom".
  22376. *
  22377. * @sample {highcharts} highcharts/xaxis/plotlines-label-verticalalign-middle/
  22378. * Vertically centered label
  22379. *
  22380. * @type {Highcharts.VerticalAlignValue}
  22381. * @default {highcharts} top
  22382. * @default {highstock} top
  22383. * @since 2.1
  22384. * @apioption xAxis.plotLines.label.verticalAlign
  22385. */
  22386. /**
  22387. * Horizontal position relative the alignment. Default varies by
  22388. * orientation.
  22389. *
  22390. * @sample {highcharts} highcharts/xaxis/plotlines-label-align-right/
  22391. * Aligned 10px from the right edge
  22392. * @sample {highstock} stock/xaxis/plotlines/
  22393. * Plot line on Y axis
  22394. *
  22395. * @type {number}
  22396. * @since 2.1
  22397. * @apioption xAxis.plotLines.label.x
  22398. */
  22399. /**
  22400. * Vertical position of the text baseline relative to the alignment. Default
  22401. * varies by orientation.
  22402. *
  22403. * @sample {highcharts} highcharts/xaxis/plotlines-label-y/
  22404. * Label below the plot line
  22405. * @sample {highstock} stock/xaxis/plotlines/
  22406. * Plot line on Y axis
  22407. *
  22408. * @type {number}
  22409. * @since 2.1
  22410. * @apioption xAxis.plotLines.label.y
  22411. */
  22412. /**
  22413. *
  22414. * @type {Array<*>}
  22415. * @extends xAxis.plotBands
  22416. * @apioption yAxis.plotBands
  22417. */
  22418. /**
  22419. * In a gauge chart, this option determines the inner radius of the
  22420. * plot band that stretches along the perimeter. It can be given as
  22421. * a percentage string, like `"100%"`, or as a pixel number, like `100`.
  22422. * By default, the inner radius is controlled by the [thickness](
  22423. * #yAxis.plotBands.thickness) option.
  22424. *
  22425. * @sample {highcharts} highcharts/xaxis/plotbands-gauge
  22426. * Gauge plot band
  22427. *
  22428. * @type {number|string}
  22429. * @since 2.3
  22430. * @product highcharts
  22431. * @apioption yAxis.plotBands.innerRadius
  22432. */
  22433. /**
  22434. * In a gauge chart, this option determines the outer radius of the
  22435. * plot band that stretches along the perimeter. It can be given as
  22436. * a percentage string, like `"100%"`, or as a pixel number, like `100`.
  22437. *
  22438. * @sample {highcharts} highcharts/xaxis/plotbands-gauge
  22439. * Gauge plot band
  22440. *
  22441. * @type {number|string}
  22442. * @default 100%
  22443. * @since 2.3
  22444. * @product highcharts
  22445. * @apioption yAxis.plotBands.outerRadius
  22446. */
  22447. /**
  22448. * In a gauge chart, this option sets the width of the plot band
  22449. * stretching along the perimeter. It can be given as a percentage
  22450. * string, like `"10%"`, or as a pixel number, like `10`. The default
  22451. * value 10 is the same as the default [tickLength](#yAxis.tickLength),
  22452. * thus making the plot band act as a background for the tick markers.
  22453. *
  22454. * @sample {highcharts} highcharts/xaxis/plotbands-gauge
  22455. * Gauge plot band
  22456. *
  22457. * @type {number|string}
  22458. * @default 10
  22459. * @since 2.3
  22460. * @product highcharts
  22461. * @apioption yAxis.plotBands.thickness
  22462. */
  22463. /**
  22464. * @type {Array<*>}
  22465. * @extends xAxis.plotLines
  22466. * @apioption yAxis.plotLines
  22467. */
  22468. /* eslint-disable no-invalid-this, valid-jsdoc */
  22469. /**
  22470. * Internal function to create the SVG path definition for a plot band.
  22471. *
  22472. * @function Highcharts.Axis#getPlotBandPath
  22473. *
  22474. * @param {number} from
  22475. * The axis value to start from.
  22476. *
  22477. * @param {number} to
  22478. * The axis value to end on.
  22479. *
  22480. * @param {Highcharts.AxisPlotBandsOptions|Highcharts.AxisPlotLinesOptions} options
  22481. * The plotBand or plotLine configuration object.
  22482. *
  22483. * @return {Highcharts.SVGPathArray}
  22484. * The SVG path definition in array form.
  22485. */
  22486. getPlotBandPath: function (from, to, options) {
  22487. if (options === void 0) { options = this.options; }
  22488. var toPath = this.getPlotLinePath({
  22489. value: to,
  22490. force: true,
  22491. acrossPanes: options.acrossPanes
  22492. }),
  22493. path = this.getPlotLinePath({
  22494. value: from,
  22495. force: true,
  22496. acrossPanes: options.acrossPanes
  22497. }),
  22498. result = [],
  22499. i,
  22500. // #4964 check if chart is inverted or plotband is on yAxis
  22501. horiz = this.horiz,
  22502. plus = 1,
  22503. isFlat,
  22504. outside = (from < this.min && to < this.min) ||
  22505. (from > this.max && to > this.max);
  22506. if (path && toPath) {
  22507. // Flat paths don't need labels (#3836)
  22508. if (outside) {
  22509. isFlat = path.toString() === toPath.toString();
  22510. plus = 0;
  22511. }
  22512. // Go over each subpath - for panes in Highstock
  22513. for (i = 0; i < path.length; i += 2) {
  22514. var pathStart = path[i],
  22515. pathEnd = path[i + 1],
  22516. toPathStart = toPath[i],
  22517. toPathEnd = toPath[i + 1];
  22518. // Type checking all affected path segments. Consider something
  22519. // smarter.
  22520. if ((pathStart[0] === 'M' || pathStart[0] === 'L') &&
  22521. (pathEnd[0] === 'M' || pathEnd[0] === 'L') &&
  22522. (toPathStart[0] === 'M' || toPathStart[0] === 'L') &&
  22523. (toPathEnd[0] === 'M' || toPathEnd[0] === 'L')) {
  22524. // Add 1 pixel when coordinates are the same
  22525. if (horiz && toPathStart[1] === pathStart[1]) {
  22526. toPathStart[1] += plus;
  22527. toPathEnd[1] += plus;
  22528. }
  22529. else if (!horiz && toPathStart[2] === pathStart[2]) {
  22530. toPathStart[2] += plus;
  22531. toPathEnd[2] += plus;
  22532. }
  22533. result.push(['M', pathStart[1], pathStart[2]], ['L', pathEnd[1], pathEnd[2]], ['L', toPathEnd[1], toPathEnd[2]], ['L', toPathStart[1], toPathStart[2]], ['Z']);
  22534. }
  22535. result.isFlat = isFlat;
  22536. }
  22537. }
  22538. else { // outside the axis area
  22539. path = null;
  22540. }
  22541. return result;
  22542. },
  22543. /**
  22544. * Add a plot band after render time.
  22545. *
  22546. * @sample highcharts/members/axis-addplotband/
  22547. * Toggle the plot band from a button
  22548. *
  22549. * @function Highcharts.Axis#addPlotBand
  22550. *
  22551. * @param {Highcharts.AxisPlotBandsOptions} options
  22552. * A configuration object for the plot band, as defined in
  22553. * [xAxis.plotBands](https://api.highcharts.com/highcharts/xAxis.plotBands).
  22554. *
  22555. * @return {Highcharts.PlotLineOrBand|undefined}
  22556. * The added plot band.
  22557. */
  22558. addPlotBand: function (options) {
  22559. return this.addPlotBandOrLine(options, 'plotBands');
  22560. },
  22561. /**
  22562. * Add a plot line after render time.
  22563. *
  22564. * @sample highcharts/members/axis-addplotline/
  22565. * Toggle the plot line from a button
  22566. *
  22567. * @function Highcharts.Axis#addPlotLine
  22568. *
  22569. * @param {Highcharts.AxisPlotLinesOptions} options
  22570. * A configuration object for the plot line, as defined in
  22571. * [xAxis.plotLines](https://api.highcharts.com/highcharts/xAxis.plotLines).
  22572. *
  22573. * @return {Highcharts.PlotLineOrBand|undefined}
  22574. * The added plot line.
  22575. */
  22576. addPlotLine: function (options) {
  22577. return this.addPlotBandOrLine(options, 'plotLines');
  22578. },
  22579. /**
  22580. * Add a plot band or plot line after render time. Called from addPlotBand
  22581. * and addPlotLine internally.
  22582. *
  22583. * @private
  22584. * @function Highcharts.Axis#addPlotBandOrLine
  22585. *
  22586. * @param {Highcharts.AxisPlotBandsOptions|Highcharts.AxisPlotLinesOptions} options
  22587. * The plotBand or plotLine configuration object.
  22588. *
  22589. * @param {"plotBands"|"plotLines"} [coll]
  22590. *
  22591. * @return {Highcharts.PlotLineOrBand|undefined}
  22592. */
  22593. addPlotBandOrLine: function (options, coll) {
  22594. var _this = this;
  22595. var obj = new H.PlotLineOrBand(this,
  22596. options),
  22597. userOptions = this.userOptions;
  22598. if (this.visible) {
  22599. obj = obj.render();
  22600. }
  22601. if (obj) { // #2189
  22602. if (!this._addedPlotLB) {
  22603. this._addedPlotLB = true;
  22604. (userOptions.plotLines || [])
  22605. .concat(userOptions.plotBands || [])
  22606. .forEach(function (plotLineOptions) {
  22607. _this.addPlotBandOrLine(plotLineOptions);
  22608. });
  22609. }
  22610. // Add it to the user options for exporting and Axis.update
  22611. if (coll) {
  22612. // Workaround Microsoft/TypeScript issue #32693
  22613. var updatedOptions = (userOptions[coll] || []);
  22614. updatedOptions.push(options);
  22615. userOptions[coll] = updatedOptions;
  22616. }
  22617. this.plotLinesAndBands.push(obj);
  22618. }
  22619. return obj;
  22620. },
  22621. /**
  22622. * Remove a plot band or plot line from the chart by id. Called internally
  22623. * from `removePlotBand` and `removePlotLine`.
  22624. *
  22625. * @private
  22626. * @function Highcharts.Axis#removePlotBandOrLine
  22627. * @param {string} id
  22628. * @return {void}
  22629. */
  22630. removePlotBandOrLine: function (id) {
  22631. var plotLinesAndBands = this.plotLinesAndBands,
  22632. options = this.options,
  22633. userOptions = this.userOptions,
  22634. i = plotLinesAndBands.length;
  22635. while (i--) {
  22636. if (plotLinesAndBands[i].id === id) {
  22637. plotLinesAndBands[i].destroy();
  22638. }
  22639. }
  22640. ([
  22641. options.plotLines || [],
  22642. userOptions.plotLines || [],
  22643. options.plotBands || [],
  22644. userOptions.plotBands || []
  22645. ]).forEach(function (arr) {
  22646. i = arr.length;
  22647. while (i--) {
  22648. if ((arr[i] || {}).id === id) {
  22649. erase(arr, arr[i]);
  22650. }
  22651. }
  22652. });
  22653. },
  22654. /**
  22655. * Remove a plot band by its id.
  22656. *
  22657. * @sample highcharts/members/axis-removeplotband/
  22658. * Remove plot band by id
  22659. * @sample highcharts/members/axis-addplotband/
  22660. * Toggle the plot band from a button
  22661. *
  22662. * @function Highcharts.Axis#removePlotBand
  22663. *
  22664. * @param {string} id
  22665. * The plot band's `id` as given in the original configuration
  22666. * object or in the `addPlotBand` option.
  22667. *
  22668. * @return {void}
  22669. */
  22670. removePlotBand: function (id) {
  22671. this.removePlotBandOrLine(id);
  22672. },
  22673. /**
  22674. * Remove a plot line by its id.
  22675. *
  22676. * @sample highcharts/xaxis/plotlines-id/
  22677. * Remove plot line by id
  22678. * @sample highcharts/members/axis-addplotline/
  22679. * Toggle the plot line from a button
  22680. *
  22681. * @function Highcharts.Axis#removePlotLine
  22682. *
  22683. * @param {string} id
  22684. * The plot line's `id` as given in the original configuration
  22685. * object or in the `addPlotLine` option.
  22686. */
  22687. removePlotLine: function (id) {
  22688. this.removePlotBandOrLine(id);
  22689. }
  22690. });
  22691. H.PlotLineOrBand = PlotLineOrBand;
  22692. return H.PlotLineOrBand;
  22693. });
  22694. _registerModule(_modules, 'Core/Tooltip.js', [_modules['Core/Globals.js'], _modules['Core/Color/Palette.js'], _modules['Core/Utilities.js']], function (H, palette, U) {
  22695. /* *
  22696. *
  22697. * (c) 2010-2021 Torstein Honsi
  22698. *
  22699. * License: www.highcharts.com/license
  22700. *
  22701. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  22702. *
  22703. * */
  22704. var doc = H.doc;
  22705. var clamp = U.clamp,
  22706. css = U.css,
  22707. defined = U.defined,
  22708. discardElement = U.discardElement,
  22709. extend = U.extend,
  22710. fireEvent = U.fireEvent,
  22711. format = U.format,
  22712. isNumber = U.isNumber,
  22713. isString = U.isString,
  22714. merge = U.merge,
  22715. pick = U.pick,
  22716. splat = U.splat,
  22717. syncTimeout = U.syncTimeout,
  22718. timeUnits = U.timeUnits;
  22719. /**
  22720. * Callback function to format the text of the tooltip from scratch.
  22721. *
  22722. * In case of single or shared tooltips, a string should be be returned. In case
  22723. * of splitted tooltips, it should return an array where the first item is the
  22724. * header, and subsequent items are mapped to the points. Return `false` to
  22725. * disable tooltip for a specific point on series.
  22726. *
  22727. * @callback Highcharts.TooltipFormatterCallbackFunction
  22728. *
  22729. * @param {Highcharts.TooltipFormatterContextObject} this
  22730. * Context to format
  22731. *
  22732. * @param {Highcharts.Tooltip} tooltip
  22733. * The tooltip instance
  22734. *
  22735. * @return {false|string|Array<(string|null|undefined)>|null|undefined}
  22736. * Formatted text or false
  22737. */
  22738. /**
  22739. * @interface Highcharts.TooltipFormatterContextObject
  22740. */ /**
  22741. * @name Highcharts.TooltipFormatterContextObject#color
  22742. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  22743. */ /**
  22744. * @name Highcharts.TooltipFormatterContextObject#colorIndex
  22745. * @type {number|undefined}
  22746. */ /**
  22747. * @name Highcharts.TooltipFormatterContextObject#key
  22748. * @type {number}
  22749. */ /**
  22750. * @name Highcharts.TooltipFormatterContextObject#percentage
  22751. * @type {number|undefined}
  22752. */ /**
  22753. * @name Highcharts.TooltipFormatterContextObject#point
  22754. * @type {Highcharts.Point}
  22755. */ /**
  22756. * @name Highcharts.TooltipFormatterContextObject#points
  22757. * @type {Array<Highcharts.TooltipFormatterContextObject>|undefined}
  22758. */ /**
  22759. * @name Highcharts.TooltipFormatterContextObject#series
  22760. * @type {Highcharts.Series}
  22761. */ /**
  22762. * @name Highcharts.TooltipFormatterContextObject#total
  22763. * @type {number|undefined}
  22764. */ /**
  22765. * @name Highcharts.TooltipFormatterContextObject#x
  22766. * @type {number}
  22767. */ /**
  22768. * @name Highcharts.TooltipFormatterContextObject#y
  22769. * @type {number}
  22770. */
  22771. /**
  22772. * A callback function to place the tooltip in a specific position.
  22773. *
  22774. * @callback Highcharts.TooltipPositionerCallbackFunction
  22775. *
  22776. * @param {Highcharts.Tooltip} this
  22777. * Tooltip context of the callback.
  22778. *
  22779. * @param {number} labelWidth
  22780. * Width of the tooltip.
  22781. *
  22782. * @param {number} labelHeight
  22783. * Height of the tooltip.
  22784. *
  22785. * @param {Highcharts.TooltipPositionerPointObject} point
  22786. * Point information for positioning a tooltip.
  22787. *
  22788. * @return {Highcharts.PositionObject}
  22789. * New position for the tooltip.
  22790. */
  22791. /**
  22792. * Point information for positioning a tooltip.
  22793. *
  22794. * @interface Highcharts.TooltipPositionerPointObject
  22795. * @extends Highcharts.Point
  22796. */ /**
  22797. * If `tooltip.split` option is enabled and positioner is called for each of the
  22798. * boxes separately, this property indicates the call on the xAxis header, which
  22799. * is not a point itself.
  22800. * @name Highcharts.TooltipPositionerPointObject#isHeader
  22801. * @type {boolean}
  22802. */ /**
  22803. * The reference point relative to the plot area. Add chart.plotLeft to get the
  22804. * full coordinates.
  22805. * @name Highcharts.TooltipPositionerPointObject#plotX
  22806. * @type {number}
  22807. */ /**
  22808. * The reference point relative to the plot area. Add chart.plotTop to get the
  22809. * full coordinates.
  22810. * @name Highcharts.TooltipPositionerPointObject#plotY
  22811. * @type {number}
  22812. */
  22813. /**
  22814. * @typedef {"callout"|"circle"|"square"} Highcharts.TooltipShapeValue
  22815. */
  22816. ''; // separates doclets above from variables below
  22817. /* eslint-disable no-invalid-this, valid-jsdoc */
  22818. /**
  22819. * Tooltip of a chart.
  22820. *
  22821. * @class
  22822. * @name Highcharts.Tooltip
  22823. *
  22824. * @param {Highcharts.Chart} chart
  22825. * The chart instance.
  22826. *
  22827. * @param {Highcharts.TooltipOptions} options
  22828. * Tooltip options.
  22829. */
  22830. var Tooltip = /** @class */ (function () {
  22831. /* *
  22832. *
  22833. * Constructors
  22834. *
  22835. * */
  22836. function Tooltip(chart, options) {
  22837. this.container = void 0;
  22838. this.crosshairs = [];
  22839. this.distance = 0;
  22840. this.isHidden = true;
  22841. this.isSticky = false;
  22842. this.now = {};
  22843. this.options = {};
  22844. this.outside = false;
  22845. this.chart = chart;
  22846. this.init(chart, options);
  22847. }
  22848. /* *
  22849. *
  22850. * Functions
  22851. *
  22852. * */
  22853. /**
  22854. * In styled mode, apply the default filter for the tooltip drop-shadow. It
  22855. * needs to have an id specific to the chart, otherwise there will be issues
  22856. * when one tooltip adopts the filter of a different chart, specifically one
  22857. * where the container is hidden.
  22858. *
  22859. * @private
  22860. * @function Highcharts.Tooltip#applyFilter
  22861. */
  22862. Tooltip.prototype.applyFilter = function () {
  22863. var chart = this.chart;
  22864. chart.renderer.definition({
  22865. tagName: 'filter',
  22866. attributes: {
  22867. id: 'drop-shadow-' + chart.index,
  22868. opacity: 0.5
  22869. },
  22870. children: [{
  22871. tagName: 'feGaussianBlur',
  22872. attributes: {
  22873. 'in': 'SourceAlpha',
  22874. stdDeviation: 1
  22875. }
  22876. }, {
  22877. tagName: 'feOffset',
  22878. attributes: {
  22879. dx: 1,
  22880. dy: 1
  22881. }
  22882. }, {
  22883. tagName: 'feComponentTransfer',
  22884. children: [{
  22885. tagName: 'feFuncA',
  22886. attributes: {
  22887. type: 'linear',
  22888. slope: 0.3
  22889. }
  22890. }]
  22891. }, {
  22892. tagName: 'feMerge',
  22893. children: [{
  22894. tagName: 'feMergeNode'
  22895. }, {
  22896. tagName: 'feMergeNode',
  22897. attributes: {
  22898. 'in': 'SourceGraphic'
  22899. }
  22900. }]
  22901. }]
  22902. });
  22903. chart.renderer.definition({
  22904. tagName: 'style',
  22905. textContent: '.highcharts-tooltip-' + chart.index + '{' +
  22906. 'filter:url(#drop-shadow-' + chart.index + ')' +
  22907. '}'
  22908. });
  22909. };
  22910. /**
  22911. * Build the body (lines) of the tooltip by iterating over the items and
  22912. * returning one entry for each item, abstracting this functionality allows
  22913. * to easily overwrite and extend it.
  22914. *
  22915. * @private
  22916. * @function Highcharts.Tooltip#bodyFormatter
  22917. * @param {Array<(Highcharts.Point|Highcharts.Series)>} items
  22918. * @return {Array<string>}
  22919. */
  22920. Tooltip.prototype.bodyFormatter = function (items) {
  22921. return items.map(function (item) {
  22922. var tooltipOptions = item.series.tooltipOptions;
  22923. return (tooltipOptions[(item.point.formatPrefix || 'point') + 'Formatter'] ||
  22924. item.point.tooltipFormatter).call(item.point, tooltipOptions[(item.point.formatPrefix || 'point') + 'Format'] || '');
  22925. });
  22926. };
  22927. /**
  22928. * Destroy the single tooltips in a split tooltip.
  22929. * If the tooltip is active then it is not destroyed, unless forced to.
  22930. *
  22931. * @private
  22932. * @function Highcharts.Tooltip#cleanSplit
  22933. *
  22934. * @param {boolean} [force]
  22935. * Force destroy all tooltips.
  22936. */
  22937. Tooltip.prototype.cleanSplit = function (force) {
  22938. this.chart.series.forEach(function (series) {
  22939. var tt = series && series.tt;
  22940. if (tt) {
  22941. if (!tt.isActive || force) {
  22942. series.tt = tt.destroy();
  22943. }
  22944. else {
  22945. tt.isActive = false;
  22946. }
  22947. }
  22948. });
  22949. };
  22950. /**
  22951. * In case no user defined formatter is given, this will be used. Note that
  22952. * the context here is an object holding point, series, x, y etc.
  22953. *
  22954. * @function Highcharts.Tooltip#defaultFormatter
  22955. *
  22956. * @param {Highcharts.Tooltip} tooltip
  22957. *
  22958. * @return {Array<string>}
  22959. */
  22960. Tooltip.prototype.defaultFormatter = function (tooltip) {
  22961. var items = this.points || splat(this),
  22962. s;
  22963. // Build the header
  22964. s = [tooltip.tooltipFooterHeaderFormatter(items[0])];
  22965. // build the values
  22966. s = s.concat(tooltip.bodyFormatter(items));
  22967. // footer
  22968. s.push(tooltip.tooltipFooterHeaderFormatter(items[0], true));
  22969. return s;
  22970. };
  22971. /**
  22972. * Removes and destroys the tooltip and its elements.
  22973. *
  22974. * @function Highcharts.Tooltip#destroy
  22975. */
  22976. Tooltip.prototype.destroy = function () {
  22977. // Destroy and clear local variables
  22978. if (this.label) {
  22979. this.label = this.label.destroy();
  22980. }
  22981. if (this.split && this.tt) {
  22982. this.cleanSplit(this.chart, true);
  22983. this.tt = this.tt.destroy();
  22984. }
  22985. if (this.renderer) {
  22986. this.renderer = this.renderer.destroy();
  22987. discardElement(this.container);
  22988. }
  22989. U.clearTimeout(this.hideTimer);
  22990. U.clearTimeout(this.tooltipTimeout);
  22991. };
  22992. /**
  22993. * Extendable method to get the anchor position of the tooltip
  22994. * from a point or set of points
  22995. *
  22996. * @private
  22997. * @function Highcharts.Tooltip#getAnchor
  22998. *
  22999. * @param {Highcharts.Point|Array<Highcharts.Point>} points
  23000. *
  23001. * @param {Highcharts.PointerEventObject} [mouseEvent]
  23002. *
  23003. * @return {Array<number>}
  23004. */
  23005. Tooltip.prototype.getAnchor = function (points, mouseEvent) {
  23006. var ret,
  23007. chart = this.chart,
  23008. pointer = chart.pointer,
  23009. inverted = chart.inverted,
  23010. plotTop = chart.plotTop,
  23011. plotLeft = chart.plotLeft,
  23012. plotX = 0,
  23013. plotY = 0,
  23014. yAxis,
  23015. xAxis;
  23016. points = splat(points);
  23017. // When tooltip follows mouse, relate the position to the mouse
  23018. if (this.followPointer && mouseEvent) {
  23019. if (typeof mouseEvent.chartX === 'undefined') {
  23020. mouseEvent = pointer.normalize(mouseEvent);
  23021. }
  23022. ret = [
  23023. mouseEvent.chartX - plotLeft,
  23024. mouseEvent.chartY - plotTop
  23025. ];
  23026. // Some series types use a specificly calculated tooltip position for
  23027. // each point
  23028. }
  23029. else if (points[0].tooltipPos) {
  23030. ret = points[0].tooltipPos;
  23031. // Calculate the average position and adjust for axis positions
  23032. }
  23033. else {
  23034. points.forEach(function (point) {
  23035. yAxis = point.series.yAxis;
  23036. xAxis = point.series.xAxis;
  23037. plotX += point.plotX || 0;
  23038. plotY += (point.plotLow ?
  23039. (point.plotLow + (point.plotHigh || 0)) / 2 :
  23040. (point.plotY || 0));
  23041. // Adjust position for positioned axes (top/left settings)
  23042. if (xAxis && yAxis) {
  23043. if (!inverted) { // #1151
  23044. plotX += xAxis.pos - plotLeft;
  23045. plotY += yAxis.pos - plotTop;
  23046. }
  23047. else { // #14771
  23048. plotX += plotTop + chart.plotHeight - xAxis.len - xAxis.pos;
  23049. plotY += plotLeft + chart.plotWidth - yAxis.len - yAxis.pos;
  23050. }
  23051. }
  23052. });
  23053. plotX /= points.length;
  23054. plotY /= points.length;
  23055. // Use the average position for multiple points
  23056. ret = [
  23057. inverted ? chart.plotWidth - plotY : plotX,
  23058. inverted ? chart.plotHeight - plotX : plotY
  23059. ];
  23060. // When shared, place the tooltip next to the mouse (#424)
  23061. if (this.shared && points.length > 1 && mouseEvent) {
  23062. if (inverted) {
  23063. ret[0] = mouseEvent.chartX - plotLeft;
  23064. }
  23065. else {
  23066. ret[1] = mouseEvent.chartY - plotTop;
  23067. }
  23068. }
  23069. }
  23070. return ret.map(Math.round);
  23071. };
  23072. /**
  23073. * Get the optimal date format for a point, based on a range.
  23074. *
  23075. * @private
  23076. * @function Highcharts.Tooltip#getDateFormat
  23077. *
  23078. * @param {number} range
  23079. * The time range
  23080. *
  23081. * @param {number} date
  23082. * The date of the point in question
  23083. *
  23084. * @param {number} startOfWeek
  23085. * An integer representing the first day of the week, where 0 is
  23086. * Sunday.
  23087. *
  23088. * @param {Highcharts.Dictionary<string>} dateTimeLabelFormats
  23089. * A map of time units to formats.
  23090. *
  23091. * @return {string}
  23092. * The optimal date format for a point.
  23093. */
  23094. Tooltip.prototype.getDateFormat = function (range, date, startOfWeek, dateTimeLabelFormats) {
  23095. var time = this.chart.time, dateStr = time.dateFormat('%m-%d %H:%M:%S.%L', date), format, n, blank = '01-01 00:00:00.000', strpos = {
  23096. millisecond: 15,
  23097. second: 12,
  23098. minute: 9,
  23099. hour: 6,
  23100. day: 3
  23101. }, lastN = 'millisecond'; // for sub-millisecond data, #4223
  23102. for (n in timeUnits) { // eslint-disable-line guard-for-in
  23103. // If the range is exactly one week and we're looking at a
  23104. // Sunday/Monday, go for the week format
  23105. if (range === timeUnits.week &&
  23106. +time.dateFormat('%w', date) === startOfWeek &&
  23107. dateStr.substr(6) === blank.substr(6)) {
  23108. n = 'week';
  23109. break;
  23110. }
  23111. // The first format that is too great for the range
  23112. if (timeUnits[n] > range) {
  23113. n = lastN;
  23114. break;
  23115. }
  23116. // If the point is placed every day at 23:59, we need to show
  23117. // the minutes as well. #2637.
  23118. if (strpos[n] &&
  23119. dateStr.substr(strpos[n]) !== blank.substr(strpos[n])) {
  23120. break;
  23121. }
  23122. // Weeks are outside the hierarchy, only apply them on
  23123. // Mondays/Sundays like in the first condition
  23124. if (n !== 'week') {
  23125. lastN = n;
  23126. }
  23127. }
  23128. if (n) {
  23129. format = time.resolveDTLFormat(dateTimeLabelFormats[n]).main;
  23130. }
  23131. return format;
  23132. };
  23133. /**
  23134. * Creates the Tooltip label element if it does not exist, then returns it.
  23135. *
  23136. * @function Highcharts.Tooltip#getLabel
  23137. * @return {Highcharts.SVGElement}
  23138. */
  23139. Tooltip.prototype.getLabel = function () {
  23140. var _a,
  23141. _b,
  23142. _c;
  23143. var tooltip = this,
  23144. renderer = this.chart.renderer,
  23145. styledMode = this.chart.styledMode,
  23146. options = this.options,
  23147. className = ('tooltip' + (defined(options.className) ?
  23148. ' ' + options.className :
  23149. '')),
  23150. pointerEvents = (((_a = options.style) === null || _a === void 0 ? void 0 : _a.pointerEvents) ||
  23151. (!this.followPointer && options.stickOnContact ? 'auto' : 'none')),
  23152. container,
  23153. onMouseEnter = function () {
  23154. tooltip.inContact = true;
  23155. }, onMouseLeave = function () {
  23156. var series = tooltip.chart.hoverSeries;
  23157. tooltip.inContact = false;
  23158. if (series &&
  23159. series.onMouseOut) {
  23160. series.onMouseOut();
  23161. }
  23162. };
  23163. if (!this.label) {
  23164. if (this.outside) {
  23165. var chartStyle = (_b = this.chart.options.chart) === null || _b === void 0 ? void 0 : _b.style;
  23166. /**
  23167. * Reference to the tooltip's container, when
  23168. * [Highcharts.Tooltip#outside] is set to true, otherwise
  23169. * it's undefined.
  23170. *
  23171. * @name Highcharts.Tooltip#container
  23172. * @type {Highcharts.HTMLDOMElement|undefined}
  23173. */
  23174. this.container = container = H.doc.createElement('div');
  23175. container.className = 'highcharts-tooltip-container';
  23176. css(container, {
  23177. position: 'absolute',
  23178. top: '1px',
  23179. pointerEvents: pointerEvents,
  23180. zIndex: Math.max((((_c = this.options.style) === null || _c === void 0 ? void 0 : _c.zIndex) || 0), ((chartStyle === null || chartStyle === void 0 ? void 0 : chartStyle.zIndex) || 0) + 3)
  23181. });
  23182. H.doc.body.appendChild(container);
  23183. /**
  23184. * Reference to the tooltip's renderer, when
  23185. * [Highcharts.Tooltip#outside] is set to true, otherwise
  23186. * it's undefined.
  23187. *
  23188. * @name Highcharts.Tooltip#renderer
  23189. * @type {Highcharts.SVGRenderer|undefined}
  23190. */
  23191. this.renderer = renderer = new H.Renderer(container, 0, 0, chartStyle, void 0, void 0, renderer.styledMode);
  23192. }
  23193. // Create the label
  23194. if (this.split) {
  23195. this.label = renderer.g(className);
  23196. }
  23197. else {
  23198. this.label = renderer
  23199. .label('', 0, 0, options.shape || 'callout', null, null, options.useHTML, null, className)
  23200. .attr({
  23201. padding: options.padding,
  23202. r: options.borderRadius
  23203. });
  23204. if (!styledMode) {
  23205. this.label
  23206. .attr({
  23207. fill: options.backgroundColor,
  23208. 'stroke-width': options.borderWidth
  23209. })
  23210. // #2301, #2657
  23211. .css(options.style)
  23212. .css({ pointerEvents: pointerEvents })
  23213. .shadow(options.shadow);
  23214. }
  23215. }
  23216. if (styledMode) {
  23217. // Apply the drop-shadow filter
  23218. this.applyFilter();
  23219. this.label.addClass('highcharts-tooltip-' + this.chart.index);
  23220. }
  23221. // Split tooltip use updateTooltipContainer to position the tooltip
  23222. // container.
  23223. if (tooltip.outside && !tooltip.split) {
  23224. var label_1 = this.label;
  23225. var xSetter_1 = label_1.xSetter,
  23226. ySetter_1 = label_1.ySetter;
  23227. label_1.xSetter = function (value) {
  23228. xSetter_1.call(label_1, tooltip.distance);
  23229. container.style.left = value + 'px';
  23230. };
  23231. label_1.ySetter = function (value) {
  23232. ySetter_1.call(label_1, tooltip.distance);
  23233. container.style.top = value + 'px';
  23234. };
  23235. }
  23236. this.label
  23237. .on('mouseenter', onMouseEnter)
  23238. .on('mouseleave', onMouseLeave)
  23239. .attr({ zIndex: 8 })
  23240. .add();
  23241. }
  23242. return this.label;
  23243. };
  23244. /**
  23245. * Place the tooltip in a chart without spilling over
  23246. * and not covering the point it self.
  23247. *
  23248. * @private
  23249. * @function Highcharts.Tooltip#getPosition
  23250. *
  23251. * @param {number} boxWidth
  23252. *
  23253. * @param {number} boxHeight
  23254. *
  23255. * @param {Highcharts.Point} point
  23256. *
  23257. * @return {Highcharts.PositionObject}
  23258. */
  23259. Tooltip.prototype.getPosition = function (boxWidth, boxHeight, point) {
  23260. var chart = this.chart,
  23261. distance = this.distance,
  23262. ret = {},
  23263. // Don't use h if chart isn't inverted (#7242) ???
  23264. h = (chart.inverted && point.h) || 0, // #4117 ???
  23265. swapped,
  23266. outside = this.outside,
  23267. outerWidth = outside ?
  23268. // substract distance to prevent scrollbars
  23269. doc.documentElement.clientWidth - 2 * distance :
  23270. chart.chartWidth,
  23271. outerHeight = outside ?
  23272. Math.max(doc.body.scrollHeight,
  23273. doc.documentElement.scrollHeight,
  23274. doc.body.offsetHeight,
  23275. doc.documentElement.offsetHeight,
  23276. doc.documentElement.clientHeight) :
  23277. chart.chartHeight,
  23278. chartPosition = chart.pointer.getChartPosition(),
  23279. scaleX = function (val) { return ( // eslint-disable-line no-confusing-arrow
  23280. val * chartPosition.scaleX); },
  23281. scaleY = function (val) { return ( // eslint-disable-line no-confusing-arrow
  23282. val * chartPosition.scaleY); },
  23283. // Build parameter arrays for firstDimension()/secondDimension()
  23284. buildDimensionArray = function (dim) {
  23285. var isX = dim === 'x';
  23286. return [
  23287. dim,
  23288. isX ? outerWidth : outerHeight,
  23289. isX ? boxWidth : boxHeight
  23290. ].concat(outside ? [
  23291. // If we are using tooltip.outside, we need to scale the
  23292. // position to match scaling of the container in case there
  23293. // is a transform/zoom on the container. #11329
  23294. isX ? scaleX(boxWidth) : scaleY(boxHeight),
  23295. isX ? chartPosition.left - distance +
  23296. scaleX(point.plotX + chart.plotLeft) :
  23297. chartPosition.top - distance +
  23298. scaleY(point.plotY + chart.plotTop),
  23299. 0,
  23300. isX ? outerWidth : outerHeight
  23301. ] : [
  23302. // Not outside, no scaling is needed
  23303. isX ? boxWidth : boxHeight,
  23304. isX ? point.plotX + chart.plotLeft :
  23305. point.plotY + chart.plotTop,
  23306. isX ? chart.plotLeft : chart.plotTop,
  23307. isX ? chart.plotLeft + chart.plotWidth :
  23308. chart.plotTop + chart.plotHeight
  23309. ]);
  23310. }, first = buildDimensionArray('y'), second = buildDimensionArray('x'),
  23311. // The far side is right or bottom
  23312. preferFarSide = !this.followPointer && pick(point.ttBelow, !chart.inverted === !!point.negative), // #4984
  23313. /*
  23314. * Handle the preferred dimension. When the preferred dimension is
  23315. * tooltip on top or bottom of the point, it will look for space
  23316. * there.
  23317. *
  23318. * @private
  23319. */
  23320. firstDimension = function (dim, outerSize, innerSize, scaledInnerSize, // #11329
  23321. point, min, max) {
  23322. var scaledDist = outside ?
  23323. (dim === 'y' ? scaleY(distance) : scaleX(distance)) :
  23324. distance,
  23325. scaleDiff = (innerSize - scaledInnerSize) / 2,
  23326. roomLeft = scaledInnerSize < point - distance,
  23327. roomRight = point + distance + scaledInnerSize < outerSize,
  23328. alignedLeft = point - scaledDist - innerSize + scaleDiff,
  23329. alignedRight = point + scaledDist - scaleDiff;
  23330. if (preferFarSide && roomRight) {
  23331. ret[dim] = alignedRight;
  23332. }
  23333. else if (!preferFarSide && roomLeft) {
  23334. ret[dim] = alignedLeft;
  23335. }
  23336. else if (roomLeft) {
  23337. ret[dim] = Math.min(max - scaledInnerSize, alignedLeft - h < 0 ? alignedLeft : alignedLeft - h);
  23338. }
  23339. else if (roomRight) {
  23340. ret[dim] = Math.max(min, alignedRight + h + innerSize > outerSize ?
  23341. alignedRight :
  23342. alignedRight + h);
  23343. }
  23344. else {
  23345. return false;
  23346. }
  23347. },
  23348. /*
  23349. * Handle the secondary dimension. If the preferred dimension is
  23350. * tooltip on top or bottom of the point, the second dimension is to
  23351. * align the tooltip above the point, trying to align center but
  23352. * allowing left or right align within the chart box.
  23353. *
  23354. * @private
  23355. */
  23356. secondDimension = function (dim, outerSize, innerSize, scaledInnerSize, // #11329
  23357. point) {
  23358. var retVal;
  23359. // Too close to the edge, return false and swap dimensions
  23360. if (point < distance || point > outerSize - distance) {
  23361. retVal = false;
  23362. // Align left/top
  23363. }
  23364. else if (point < innerSize / 2) {
  23365. ret[dim] = 1;
  23366. // Align right/bottom
  23367. }
  23368. else if (point > outerSize - scaledInnerSize / 2) {
  23369. ret[dim] = outerSize - scaledInnerSize - 2;
  23370. // Align center
  23371. }
  23372. else {
  23373. ret[dim] = point - innerSize / 2;
  23374. }
  23375. return retVal;
  23376. },
  23377. /*
  23378. * Swap the dimensions
  23379. */
  23380. swap = function (count) {
  23381. var temp = first;
  23382. first = second;
  23383. second = temp;
  23384. swapped = count;
  23385. }, run = function () {
  23386. if (firstDimension.apply(0, first) !== false) {
  23387. if (secondDimension.apply(0, second) === false &&
  23388. !swapped) {
  23389. swap(true);
  23390. run();
  23391. }
  23392. }
  23393. else if (!swapped) {
  23394. swap(true);
  23395. run();
  23396. }
  23397. else {
  23398. ret.x = ret.y = 0;
  23399. }
  23400. };
  23401. // Under these conditions, prefer the tooltip on the side of the point
  23402. if (chart.inverted || this.len > 1) {
  23403. swap();
  23404. }
  23405. run();
  23406. return ret;
  23407. };
  23408. /**
  23409. * Get the best X date format based on the closest point range on the axis.
  23410. *
  23411. * @private
  23412. * @function Highcharts.Tooltip#getXDateFormat
  23413. *
  23414. * @param {Highcharts.Point} point
  23415. *
  23416. * @param {Highcharts.TooltipOptions} options
  23417. *
  23418. * @param {Highcharts.Axis} xAxis
  23419. *
  23420. * @return {string}
  23421. */
  23422. Tooltip.prototype.getXDateFormat = function (point, options, xAxis) {
  23423. var xDateFormat,
  23424. dateTimeLabelFormats = options.dateTimeLabelFormats,
  23425. closestPointRange = xAxis && xAxis.closestPointRange;
  23426. if (closestPointRange) {
  23427. xDateFormat = this.getDateFormat(closestPointRange, point.x, xAxis.options.startOfWeek, dateTimeLabelFormats);
  23428. }
  23429. else {
  23430. xDateFormat = dateTimeLabelFormats.day;
  23431. }
  23432. return xDateFormat || dateTimeLabelFormats.year; // #2546, 2581
  23433. };
  23434. /**
  23435. * Hides the tooltip with a fade out animation.
  23436. *
  23437. * @function Highcharts.Tooltip#hide
  23438. *
  23439. * @param {number} [delay]
  23440. * The fade out in milliseconds. If no value is provided the value
  23441. * of the tooltip.hideDelay option is used. A value of 0 disables
  23442. * the fade out animation.
  23443. */
  23444. Tooltip.prototype.hide = function (delay) {
  23445. var tooltip = this;
  23446. // disallow duplicate timers (#1728, #1766)
  23447. U.clearTimeout(this.hideTimer);
  23448. delay = pick(delay, this.options.hideDelay, 500);
  23449. if (!this.isHidden) {
  23450. this.hideTimer = syncTimeout(function () {
  23451. // If there is a delay, do fadeOut with the default duration. If
  23452. // the hideDelay is 0, we assume no animation is wanted, so we
  23453. // pass 0 duration. #12994.
  23454. tooltip.getLabel().fadeOut(delay ? void 0 : delay);
  23455. tooltip.isHidden = true;
  23456. }, delay);
  23457. }
  23458. };
  23459. /**
  23460. * @private
  23461. * @function Highcharts.Tooltip#init
  23462. *
  23463. * @param {Highcharts.Chart} chart
  23464. * The chart instance.
  23465. *
  23466. * @param {Highcharts.TooltipOptions} options
  23467. * Tooltip options.
  23468. */
  23469. Tooltip.prototype.init = function (chart, options) {
  23470. /**
  23471. * Chart of the tooltip.
  23472. *
  23473. * @readonly
  23474. * @name Highcharts.Tooltip#chart
  23475. * @type {Highcharts.Chart}
  23476. */
  23477. this.chart = chart;
  23478. /**
  23479. * Used tooltip options.
  23480. *
  23481. * @readonly
  23482. * @name Highcharts.Tooltip#options
  23483. * @type {Highcharts.TooltipOptions}
  23484. */
  23485. this.options = options;
  23486. /**
  23487. * List of crosshairs.
  23488. *
  23489. * @private
  23490. * @readonly
  23491. * @name Highcharts.Tooltip#crosshairs
  23492. * @type {Array<null>}
  23493. */
  23494. this.crosshairs = [];
  23495. /**
  23496. * Current values of x and y when animating.
  23497. *
  23498. * @private
  23499. * @readonly
  23500. * @name Highcharts.Tooltip#now
  23501. * @type {Highcharts.PositionObject}
  23502. */
  23503. this.now = { x: 0, y: 0 };
  23504. /**
  23505. * Tooltips are initially hidden.
  23506. *
  23507. * @private
  23508. * @readonly
  23509. * @name Highcharts.Tooltip#isHidden
  23510. * @type {boolean}
  23511. */
  23512. this.isHidden = true;
  23513. /**
  23514. * True, if the tooltip is split into one label per series, with the
  23515. * header close to the axis.
  23516. *
  23517. * @readonly
  23518. * @name Highcharts.Tooltip#split
  23519. * @type {boolean|undefined}
  23520. */
  23521. this.split = options.split && !chart.inverted && !chart.polar;
  23522. /**
  23523. * When the tooltip is shared, the entire plot area will capture mouse
  23524. * movement or touch events.
  23525. *
  23526. * @readonly
  23527. * @name Highcharts.Tooltip#shared
  23528. * @type {boolean|undefined}
  23529. */
  23530. this.shared = options.shared || this.split;
  23531. /**
  23532. * Whether to allow the tooltip to render outside the chart's SVG
  23533. * element box. By default (false), the tooltip is rendered within the
  23534. * chart's SVG element, which results in the tooltip being aligned
  23535. * inside the chart area.
  23536. *
  23537. * @readonly
  23538. * @name Highcharts.Tooltip#outside
  23539. * @type {boolean}
  23540. *
  23541. * @todo
  23542. * Split tooltip does not support outside in the first iteration. Should
  23543. * not be too complicated to implement.
  23544. */
  23545. this.outside = pick(options.outside, Boolean(chart.scrollablePixelsX || chart.scrollablePixelsY));
  23546. };
  23547. /**
  23548. * Returns true, if the pointer is in contact with the tooltip tracker.
  23549. */
  23550. Tooltip.prototype.isStickyOnContact = function () {
  23551. return !!(!this.followPointer &&
  23552. this.options.stickOnContact &&
  23553. this.inContact);
  23554. };
  23555. /**
  23556. * Moves the tooltip with a soft animation to a new position.
  23557. *
  23558. * @private
  23559. * @function Highcharts.Tooltip#move
  23560. *
  23561. * @param {number} x
  23562. *
  23563. * @param {number} y
  23564. *
  23565. * @param {number} anchorX
  23566. *
  23567. * @param {number} anchorY
  23568. */
  23569. Tooltip.prototype.move = function (x, y, anchorX, anchorY) {
  23570. var tooltip = this,
  23571. now = tooltip.now,
  23572. animate = tooltip.options.animation !== false &&
  23573. !tooltip.isHidden &&
  23574. // When we get close to the target position, abort animation and
  23575. // land on the right place (#3056)
  23576. (Math.abs(x - now.x) > 1 || Math.abs(y - now.y) > 1),
  23577. skipAnchor = tooltip.followPointer || tooltip.len > 1;
  23578. // Get intermediate values for animation
  23579. extend(now, {
  23580. x: animate ? (2 * now.x + x) / 3 : x,
  23581. y: animate ? (now.y + y) / 2 : y,
  23582. anchorX: skipAnchor ?
  23583. void 0 :
  23584. animate ? (2 * now.anchorX + anchorX) / 3 : anchorX,
  23585. anchorY: skipAnchor ?
  23586. void 0 :
  23587. animate ? (now.anchorY + anchorY) / 2 : anchorY
  23588. });
  23589. // Move to the intermediate value
  23590. tooltip.getLabel().attr(now);
  23591. tooltip.drawTracker();
  23592. // Run on next tick of the mouse tracker
  23593. if (animate) {
  23594. // Never allow two timeouts
  23595. U.clearTimeout(this.tooltipTimeout);
  23596. // Set the fixed interval ticking for the smooth tooltip
  23597. this.tooltipTimeout = setTimeout(function () {
  23598. // The interval function may still be running during destroy,
  23599. // so check that the chart is really there before calling.
  23600. if (tooltip) {
  23601. tooltip.move(x, y, anchorX, anchorY);
  23602. }
  23603. }, 32);
  23604. }
  23605. };
  23606. /**
  23607. * Refresh the tooltip's text and position.
  23608. *
  23609. * @function Highcharts.Tooltip#refresh
  23610. *
  23611. * @param {Highcharts.Point|Array<Highcharts.Point>} pointOrPoints
  23612. * Either a point or an array of points.
  23613. *
  23614. * @param {Highcharts.PointerEventObject} [mouseEvent]
  23615. * Mouse event, that is responsible for the refresh and should be
  23616. * used for the tooltip update.
  23617. */
  23618. Tooltip.prototype.refresh = function (pointOrPoints, mouseEvent) {
  23619. var tooltip = this,
  23620. chart = this.chart,
  23621. options = tooltip.options,
  23622. x,
  23623. y,
  23624. point = pointOrPoints,
  23625. anchor,
  23626. textConfig = {},
  23627. text,
  23628. pointConfig = [],
  23629. formatter = options.formatter || tooltip.defaultFormatter,
  23630. shared = tooltip.shared,
  23631. currentSeries,
  23632. styledMode = chart.styledMode;
  23633. if (!options.enabled) {
  23634. return;
  23635. }
  23636. U.clearTimeout(this.hideTimer);
  23637. // get the reference point coordinates (pie charts use tooltipPos)
  23638. tooltip.followPointer = splat(point)[0].series.tooltipOptions
  23639. .followPointer;
  23640. anchor = tooltip.getAnchor(point, mouseEvent);
  23641. x = anchor[0];
  23642. y = anchor[1];
  23643. // shared tooltip, array is sent over
  23644. if (shared &&
  23645. !(point.series &&
  23646. point.series.noSharedTooltip)) {
  23647. chart.pointer.applyInactiveState(point);
  23648. // Now set hover state for the choosen ones:
  23649. point.forEach(function (item) {
  23650. item.setState('hover');
  23651. pointConfig.push(item.getLabelConfig());
  23652. });
  23653. textConfig = {
  23654. x: point[0].category,
  23655. y: point[0].y
  23656. };
  23657. textConfig.points = pointConfig;
  23658. point = point[0];
  23659. // single point tooltip
  23660. }
  23661. else {
  23662. textConfig = point.getLabelConfig();
  23663. }
  23664. this.len = pointConfig.length; // #6128
  23665. text = formatter.call(textConfig, tooltip);
  23666. // register the current series
  23667. currentSeries = point.series;
  23668. this.distance = pick(currentSeries.tooltipOptions.distance, 16);
  23669. // update the inner HTML
  23670. if (text === false) {
  23671. this.hide();
  23672. }
  23673. else {
  23674. // update text
  23675. if (tooltip.split) {
  23676. this.renderSplit(text, splat(pointOrPoints));
  23677. }
  23678. else {
  23679. var label = tooltip.getLabel();
  23680. // Prevent the tooltip from flowing over the chart box (#6659)
  23681. if (!options.style.width || styledMode) {
  23682. label.css({
  23683. width: this.chart.spacingBox.width + 'px'
  23684. });
  23685. }
  23686. label.attr({
  23687. text: text && text.join ?
  23688. text.join('') :
  23689. text
  23690. });
  23691. // Set the stroke color of the box to reflect the point
  23692. label.removeClass(/highcharts-color-[\d]+/g)
  23693. .addClass('highcharts-color-' +
  23694. pick(point.colorIndex, currentSeries.colorIndex));
  23695. if (!styledMode) {
  23696. label.attr({
  23697. stroke: (options.borderColor ||
  23698. point.color ||
  23699. currentSeries.color ||
  23700. palette.neutralColor60)
  23701. });
  23702. }
  23703. tooltip.updatePosition({
  23704. plotX: x,
  23705. plotY: y,
  23706. negative: point.negative,
  23707. ttBelow: point.ttBelow,
  23708. h: anchor[2] || 0
  23709. });
  23710. }
  23711. // show it
  23712. if (tooltip.isHidden && tooltip.label) {
  23713. tooltip.label.attr({
  23714. opacity: 1
  23715. }).show();
  23716. }
  23717. tooltip.isHidden = false;
  23718. }
  23719. fireEvent(this, 'refresh');
  23720. };
  23721. /**
  23722. * Render the split tooltip. Loops over each point's text and adds
  23723. * a label next to the point, then uses the distribute function to
  23724. * find best non-overlapping positions.
  23725. *
  23726. * @private
  23727. * @function Highcharts.Tooltip#renderSplit
  23728. *
  23729. * @param {string|Array<(boolean|string)>} labels
  23730. *
  23731. * @param {Array<Highcharts.Point>} points
  23732. */
  23733. Tooltip.prototype.renderSplit = function (labels, points) {
  23734. var tooltip = this;
  23735. var chart = tooltip.chart,
  23736. _a = tooltip.chart,
  23737. chartWidth = _a.chartWidth,
  23738. chartHeight = _a.chartHeight,
  23739. plotHeight = _a.plotHeight,
  23740. plotLeft = _a.plotLeft,
  23741. plotTop = _a.plotTop,
  23742. pointer = _a.pointer,
  23743. ren = _a.renderer,
  23744. _b = _a.scrollablePixelsY,
  23745. scrollablePixelsY = _b === void 0 ? 0 : _b,
  23746. _c = _a.scrollingContainer,
  23747. _d = _c === void 0 ? { scrollLeft: 0,
  23748. scrollTop: 0 } : _c,
  23749. scrollLeft = _d.scrollLeft,
  23750. scrollTop = _d.scrollTop,
  23751. styledMode = _a.styledMode,
  23752. distance = tooltip.distance,
  23753. options = tooltip.options,
  23754. positioner = tooltip.options.positioner;
  23755. // The area which the tooltip should be limited to. Limit to scrollable
  23756. // plot area if enabled, otherwise limit to the chart container.
  23757. var bounds = {
  23758. left: scrollLeft,
  23759. right: scrollLeft + chartWidth,
  23760. top: scrollTop,
  23761. bottom: scrollTop + chartHeight
  23762. };
  23763. var tooltipLabel = tooltip.getLabel();
  23764. var headerTop = Boolean(chart.xAxis[0] && chart.xAxis[0].opposite);
  23765. var distributionBoxTop = plotTop + scrollTop;
  23766. var headerHeight = 0;
  23767. var adjustedPlotHeight = plotHeight - scrollablePixelsY;
  23768. /**
  23769. * Calculates the anchor position for the partial tooltip
  23770. *
  23771. * @private
  23772. * @param {Highcharts.Point} point The point related to the tooltip
  23773. * @return {object} Returns an object with anchorX and anchorY
  23774. */
  23775. function getAnchor(point) {
  23776. var isHeader = point.isHeader,
  23777. _a = point.plotX,
  23778. plotX = _a === void 0 ? 0 : _a,
  23779. _b = point.plotY,
  23780. plotY = _b === void 0 ? 0 : _b,
  23781. series = point.series;
  23782. var anchorX;
  23783. var anchorY;
  23784. if (isHeader) {
  23785. // Set anchorX to plotX
  23786. anchorX = plotLeft + plotX;
  23787. // Set anchorY to center of visible plot area.
  23788. anchorY = plotTop + plotHeight / 2;
  23789. }
  23790. else {
  23791. var xAxis = series.xAxis,
  23792. yAxis = series.yAxis;
  23793. // Set anchorX to plotX. Limit to within xAxis.
  23794. anchorX = xAxis.pos + clamp(plotX, -distance, xAxis.len + distance);
  23795. // Set anchorY, limit to the scrollable plot area
  23796. if (yAxis.pos + plotY >= scrollTop + plotTop &&
  23797. yAxis.pos + plotY <= scrollTop + plotTop + plotHeight - scrollablePixelsY) {
  23798. anchorY = yAxis.pos + plotY;
  23799. }
  23800. }
  23801. // Limit values to plot area
  23802. anchorX = clamp(anchorX, bounds.left - distance, bounds.right + distance);
  23803. return { anchorX: anchorX, anchorY: anchorY };
  23804. }
  23805. /**
  23806. * Calculates the position of the partial tooltip
  23807. *
  23808. * @private
  23809. * @param {number} anchorX The partial tooltip anchor x position
  23810. * @param {number} anchorY The partial tooltip anchor y position
  23811. * @param {boolean} isHeader Whether the partial tooltip is a header
  23812. * @param {number} boxWidth Width of the partial tooltip
  23813. * @return {Highcharts.PositionObject} Returns the partial tooltip x and
  23814. * y position
  23815. */
  23816. function defaultPositioner(anchorX, anchorY, isHeader, boxWidth, alignedLeft) {
  23817. if (alignedLeft === void 0) { alignedLeft = true; }
  23818. var y;
  23819. var x;
  23820. if (isHeader) {
  23821. y = headerTop ? 0 : adjustedPlotHeight;
  23822. x = clamp(anchorX - (boxWidth / 2), bounds.left, bounds.right - boxWidth);
  23823. }
  23824. else {
  23825. y = anchorY - distributionBoxTop;
  23826. x = alignedLeft ?
  23827. anchorX - boxWidth - distance :
  23828. anchorX + distance;
  23829. x = clamp(x, alignedLeft ? x : bounds.left, bounds.right);
  23830. }
  23831. // NOTE: y is relative to distributionBoxTop
  23832. return { x: x, y: y };
  23833. }
  23834. /**
  23835. * Updates the attributes and styling of the partial tooltip. Creates a
  23836. * new partial tooltip if it does not exists.
  23837. *
  23838. * @private
  23839. * @param {Highcharts.SVGElement|undefined} partialTooltip
  23840. * The partial tooltip to update
  23841. * @param {Highcharts.Point} point
  23842. * The point related to the partial tooltip
  23843. * @param {boolean|string} str The text for the partial tooltip
  23844. * @return {Highcharts.SVGElement} Returns the updated partial tooltip
  23845. */
  23846. function updatePartialTooltip(partialTooltip, point, str) {
  23847. var tt = partialTooltip;
  23848. var isHeader = point.isHeader,
  23849. series = point.series;
  23850. var colorClass = 'highcharts-color-' + pick(point.colorIndex, series.colorIndex, 'none');
  23851. if (!tt) {
  23852. var attribs = {
  23853. padding: options.padding,
  23854. r: options.borderRadius
  23855. };
  23856. if (!styledMode) {
  23857. attribs.fill = options.backgroundColor;
  23858. attribs['stroke-width'] = options.borderWidth;
  23859. }
  23860. tt = ren
  23861. .label('', 0, 0, (options[isHeader ? 'headerShape' : 'shape']) ||
  23862. 'callout', void 0, void 0, options.useHTML)
  23863. .addClass((isHeader ? 'highcharts-tooltip-header ' : '') +
  23864. 'highcharts-tooltip-box ' +
  23865. colorClass)
  23866. .attr(attribs)
  23867. .add(tooltipLabel);
  23868. }
  23869. tt.isActive = true;
  23870. tt.attr({
  23871. text: str
  23872. });
  23873. if (!styledMode) {
  23874. tt.css(options.style)
  23875. .shadow(options.shadow)
  23876. .attr({
  23877. stroke: (options.borderColor ||
  23878. point.color ||
  23879. series.color ||
  23880. palette.neutralColor80)
  23881. });
  23882. }
  23883. return tt;
  23884. }
  23885. // Graceful degradation for legacy formatters
  23886. if (isString(labels)) {
  23887. labels = [false, labels];
  23888. }
  23889. // Create the individual labels for header and points, ignore footer
  23890. var boxes = labels.slice(0,
  23891. points.length + 1).reduce(function (boxes,
  23892. str,
  23893. i) {
  23894. if (str !== false && str !== '') {
  23895. var point = (points[i - 1] ||
  23896. {
  23897. // Item 0 is the header. Instead of this, we could also
  23898. // use the crosshair label
  23899. isHeader: true,
  23900. plotX: points[0].plotX,
  23901. plotY: plotHeight,
  23902. series: {}
  23903. });
  23904. var isHeader = point.isHeader;
  23905. // Store the tooltip label referance on the series
  23906. var owner = isHeader ? tooltip : point.series;
  23907. var tt = owner.tt = updatePartialTooltip(owner.tt,
  23908. point,
  23909. str);
  23910. // Get X position now, so we can move all to the other side in
  23911. // case of overflow
  23912. var bBox = tt.getBBox();
  23913. var boxWidth = bBox.width + tt.strokeWidth();
  23914. if (isHeader) {
  23915. headerHeight = bBox.height;
  23916. adjustedPlotHeight += headerHeight;
  23917. if (headerTop) {
  23918. distributionBoxTop -= headerHeight;
  23919. }
  23920. }
  23921. var _a = getAnchor(point),
  23922. anchorX = _a.anchorX,
  23923. anchorY = _a.anchorY;
  23924. if (typeof anchorY === 'number') {
  23925. var size = bBox.height + 1;
  23926. var boxPosition = (positioner ?
  23927. positioner.call(tooltip,
  23928. boxWidth,
  23929. size,
  23930. point) :
  23931. defaultPositioner(anchorX,
  23932. anchorY,
  23933. isHeader,
  23934. boxWidth));
  23935. boxes.push({
  23936. // 0-align to the top, 1-align to the bottom
  23937. align: positioner ? 0 : void 0,
  23938. anchorX: anchorX,
  23939. anchorY: anchorY,
  23940. boxWidth: boxWidth,
  23941. point: point,
  23942. rank: pick(boxPosition.rank, isHeader ? 1 : 0),
  23943. size: size,
  23944. target: boxPosition.y,
  23945. tt: tt,
  23946. x: boxPosition.x
  23947. });
  23948. }
  23949. else {
  23950. // Hide tooltips which anchorY is outside the visible plot
  23951. // area
  23952. tt.isActive = false;
  23953. }
  23954. }
  23955. return boxes;
  23956. }, []);
  23957. // If overflow left then align all labels to the right
  23958. if (!positioner && boxes.some(function (box) { return box.x < bounds.left; })) {
  23959. boxes = boxes.map(function (box) {
  23960. var _a = defaultPositioner(box.anchorX,
  23961. box.anchorY,
  23962. box.point.isHeader,
  23963. box.boxWidth,
  23964. false),
  23965. x = _a.x,
  23966. y = _a.y;
  23967. return extend(box, {
  23968. target: y,
  23969. x: x
  23970. });
  23971. });
  23972. }
  23973. // Clean previous run (for missing points)
  23974. tooltip.cleanSplit();
  23975. // Distribute and put in place
  23976. H.distribute(boxes, adjustedPlotHeight);
  23977. boxes.forEach(function (box) {
  23978. var anchorX = box.anchorX,
  23979. anchorY = box.anchorY,
  23980. pos = box.pos,
  23981. x = box.x;
  23982. // Put the label in place
  23983. box.tt.attr({
  23984. visibility: typeof pos === 'undefined' ? 'hidden' : 'inherit',
  23985. x: x,
  23986. /* NOTE: y should equal pos to be consistent with !split
  23987. * tooltip, but is currently relative to plotTop. Is left as is
  23988. * to avoid breaking change. Remove distributionBoxTop to make
  23989. * it consistent.
  23990. */
  23991. y: pos + distributionBoxTop,
  23992. anchorX: anchorX,
  23993. anchorY: anchorY
  23994. });
  23995. });
  23996. /* If we have a seperate tooltip container, then update the necessary
  23997. * container properties.
  23998. * Test that tooltip has its own container and renderer before executing
  23999. * the operation.
  24000. */
  24001. var container = tooltip.container,
  24002. outside = tooltip.outside,
  24003. renderer = tooltip.renderer;
  24004. if (outside && container && renderer) {
  24005. // Set container size to fit the tooltip
  24006. var _e = tooltipLabel.getBBox(),
  24007. width = _e.width,
  24008. height = _e.height,
  24009. x = _e.x,
  24010. y = _e.y;
  24011. renderer.setSize(width + x, height + y, false);
  24012. // Position the tooltip container to the chart container
  24013. var chartPosition = pointer.getChartPosition();
  24014. container.style.left = chartPosition.left + 'px';
  24015. container.style.top = chartPosition.top + 'px';
  24016. }
  24017. };
  24018. /**
  24019. * If the `stickOnContact` option is active, this will add a tracker shape.
  24020. *
  24021. * @private
  24022. * @function Highcharts.Tooltip#drawTracker
  24023. */
  24024. Tooltip.prototype.drawTracker = function () {
  24025. var tooltip = this;
  24026. if (tooltip.followPointer ||
  24027. !tooltip.options.stickOnContact) {
  24028. if (tooltip.tracker) {
  24029. tooltip.tracker.destroy();
  24030. }
  24031. return;
  24032. }
  24033. var chart = tooltip.chart;
  24034. var label = tooltip.label;
  24035. var point = chart.hoverPoint;
  24036. if (!label || !point) {
  24037. return;
  24038. }
  24039. var box = {
  24040. x: 0,
  24041. y: 0,
  24042. width: 0,
  24043. height: 0
  24044. };
  24045. // Combine anchor and tooltip
  24046. var anchorPos = this.getAnchor(point);
  24047. var labelBBox = label.getBBox();
  24048. anchorPos[0] += chart.plotLeft - label.translateX;
  24049. anchorPos[1] += chart.plotTop - label.translateY;
  24050. // When the mouse pointer is between the anchor point and the label,
  24051. // the label should stick.
  24052. box.x = Math.min(0, anchorPos[0]);
  24053. box.y = Math.min(0, anchorPos[1]);
  24054. box.width = (anchorPos[0] < 0 ?
  24055. Math.max(Math.abs(anchorPos[0]), (labelBBox.width - anchorPos[0])) :
  24056. Math.max(Math.abs(anchorPos[0]), labelBBox.width));
  24057. box.height = (anchorPos[1] < 0 ?
  24058. Math.max(Math.abs(anchorPos[1]), (labelBBox.height - Math.abs(anchorPos[1]))) :
  24059. Math.max(Math.abs(anchorPos[1]), labelBBox.height));
  24060. if (tooltip.tracker) {
  24061. tooltip.tracker.attr(box);
  24062. }
  24063. else {
  24064. tooltip.tracker = label.renderer
  24065. .rect(box)
  24066. .addClass('highcharts-tracker')
  24067. .add(label);
  24068. if (!chart.styledMode) {
  24069. tooltip.tracker.attr({
  24070. fill: 'rgba(0,0,0,0)'
  24071. });
  24072. }
  24073. }
  24074. };
  24075. /**
  24076. * @private
  24077. */
  24078. Tooltip.prototype.styledModeFormat = function (formatString) {
  24079. return formatString
  24080. .replace('style="font-size: 10px"', 'class="highcharts-header"')
  24081. .replace(/style="color:{(point|series)\.color}"/g, 'class="highcharts-color-{$1.colorIndex}"');
  24082. };
  24083. /**
  24084. * Format the footer/header of the tooltip
  24085. * #3397: abstraction to enable formatting of footer and header
  24086. *
  24087. * @private
  24088. * @function Highcharts.Tooltip#tooltipFooterHeaderFormatter
  24089. * @param {Highcharts.PointLabelObject} labelConfig
  24090. * @param {boolean} [isFooter]
  24091. * @return {string}
  24092. */
  24093. Tooltip.prototype.tooltipFooterHeaderFormatter = function (labelConfig, isFooter) {
  24094. var footOrHead = isFooter ? 'footer' : 'header',
  24095. series = labelConfig.series,
  24096. tooltipOptions = series.tooltipOptions,
  24097. xDateFormat = tooltipOptions.xDateFormat,
  24098. xAxis = series.xAxis,
  24099. isDateTime = (xAxis &&
  24100. xAxis.options.type === 'datetime' &&
  24101. isNumber(labelConfig.key)),
  24102. formatString = tooltipOptions[footOrHead + 'Format'],
  24103. e = {
  24104. isFooter: isFooter,
  24105. labelConfig: labelConfig
  24106. };
  24107. fireEvent(this, 'headerFormatter', e, function (e) {
  24108. // Guess the best date format based on the closest point distance
  24109. // (#568, #3418)
  24110. if (isDateTime && !xDateFormat) {
  24111. xDateFormat = this.getXDateFormat(labelConfig, tooltipOptions, xAxis);
  24112. }
  24113. // Insert the footer date format if any
  24114. if (isDateTime && xDateFormat) {
  24115. ((labelConfig.point && labelConfig.point.tooltipDateKeys) ||
  24116. ['key']).forEach(function (key) {
  24117. formatString = formatString.replace('{point.' + key + '}', '{point.' + key + ':' + xDateFormat + '}');
  24118. });
  24119. }
  24120. // Replace default header style with class name
  24121. if (series.chart.styledMode) {
  24122. formatString = this.styledModeFormat(formatString);
  24123. }
  24124. e.text = format(formatString, {
  24125. point: labelConfig,
  24126. series: series
  24127. }, this.chart);
  24128. });
  24129. return e.text;
  24130. };
  24131. /**
  24132. * Updates the tooltip with the provided tooltip options.
  24133. *
  24134. * @function Highcharts.Tooltip#update
  24135. *
  24136. * @param {Highcharts.TooltipOptions} options
  24137. * The tooltip options to update.
  24138. */
  24139. Tooltip.prototype.update = function (options) {
  24140. this.destroy();
  24141. // Update user options (#6218)
  24142. merge(true, this.chart.options.tooltip.userOptions, options);
  24143. this.init(this.chart, merge(true, this.options, options));
  24144. };
  24145. /**
  24146. * Find the new position and perform the move
  24147. *
  24148. * @private
  24149. * @function Highcharts.Tooltip#updatePosition
  24150. *
  24151. * @param {Highcharts.Point} point
  24152. */
  24153. Tooltip.prototype.updatePosition = function (point) {
  24154. var chart = this.chart,
  24155. pointer = chart.pointer,
  24156. label = this.getLabel(),
  24157. pos,
  24158. anchorX = point.plotX + chart.plotLeft,
  24159. anchorY = point.plotY + chart.plotTop,
  24160. pad;
  24161. // Needed for outside: true (#11688)
  24162. var chartPosition = pointer.getChartPosition();
  24163. pos = (this.options.positioner || this.getPosition).call(this, label.width, label.height, point);
  24164. // Set the renderer size dynamically to prevent document size to change
  24165. if (this.outside) {
  24166. pad = (this.options.borderWidth || 0) + 2 * this.distance;
  24167. this.renderer.setSize(label.width + pad, label.height + pad, false);
  24168. // Anchor and tooltip container need scaling if chart container has
  24169. // scale transform/css zoom. #11329.
  24170. if (chartPosition.scaleX !== 1 || chartPosition.scaleY !== 1) {
  24171. css(this.container, {
  24172. transform: "scale(" + chartPosition.scaleX + ", " + chartPosition.scaleY + ")"
  24173. });
  24174. anchorX *= chartPosition.scaleX;
  24175. anchorY *= chartPosition.scaleY;
  24176. }
  24177. anchorX += chartPosition.left - pos.x;
  24178. anchorY += chartPosition.top - pos.y;
  24179. }
  24180. // do the move
  24181. this.move(Math.round(pos.x), Math.round(pos.y || 0), // can be undefined (#3977)
  24182. anchorX, anchorY);
  24183. };
  24184. return Tooltip;
  24185. }());
  24186. H.Tooltip = Tooltip;
  24187. return H.Tooltip;
  24188. });
  24189. _registerModule(_modules, 'Core/Pointer.js', [_modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Core/Color/Palette.js'], _modules['Core/Tooltip.js'], _modules['Core/Utilities.js']], function (Color, H, palette, Tooltip, U) {
  24190. /* *
  24191. *
  24192. * (c) 2010-2021 Torstein Honsi
  24193. *
  24194. * License: www.highcharts.com/license
  24195. *
  24196. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  24197. *
  24198. * */
  24199. var color = Color.parse;
  24200. var charts = H.charts,
  24201. noop = H.noop;
  24202. var addEvent = U.addEvent,
  24203. attr = U.attr,
  24204. css = U.css,
  24205. defined = U.defined,
  24206. extend = U.extend,
  24207. find = U.find,
  24208. fireEvent = U.fireEvent,
  24209. isNumber = U.isNumber,
  24210. isObject = U.isObject,
  24211. objectEach = U.objectEach,
  24212. offset = U.offset,
  24213. pick = U.pick,
  24214. splat = U.splat;
  24215. /**
  24216. * One position in relation to an axis.
  24217. *
  24218. * @interface Highcharts.PointerAxisCoordinateObject
  24219. */ /**
  24220. * Related axis.
  24221. *
  24222. * @name Highcharts.PointerAxisCoordinateObject#axis
  24223. * @type {Highcharts.Axis}
  24224. */ /**
  24225. * Axis value.
  24226. *
  24227. * @name Highcharts.PointerAxisCoordinateObject#value
  24228. * @type {number}
  24229. */
  24230. /**
  24231. * Positions in terms of axis values.
  24232. *
  24233. * @interface Highcharts.PointerAxisCoordinatesObject
  24234. */ /**
  24235. * Positions on the x-axis.
  24236. * @name Highcharts.PointerAxisCoordinatesObject#xAxis
  24237. * @type {Array<Highcharts.PointerAxisCoordinateObject>}
  24238. */ /**
  24239. * Positions on the y-axis.
  24240. * @name Highcharts.PointerAxisCoordinatesObject#yAxis
  24241. * @type {Array<Highcharts.PointerAxisCoordinateObject>}
  24242. */
  24243. /**
  24244. * Pointer coordinates.
  24245. *
  24246. * @interface Highcharts.PointerCoordinatesObject
  24247. */ /**
  24248. * @name Highcharts.PointerCoordinatesObject#chartX
  24249. * @type {number}
  24250. */ /**
  24251. * @name Highcharts.PointerCoordinatesObject#chartY
  24252. * @type {number}
  24253. */
  24254. /**
  24255. * A native browser mouse or touch event, extended with position information
  24256. * relative to the {@link Chart.container}.
  24257. *
  24258. * @interface Highcharts.PointerEventObject
  24259. * @extends global.PointerEvent
  24260. */ /**
  24261. * The X coordinate of the pointer interaction relative to the chart.
  24262. *
  24263. * @name Highcharts.PointerEventObject#chartX
  24264. * @type {number}
  24265. */ /**
  24266. * The Y coordinate of the pointer interaction relative to the chart.
  24267. *
  24268. * @name Highcharts.PointerEventObject#chartY
  24269. * @type {number}
  24270. */
  24271. /**
  24272. * Axis-specific data of a selection.
  24273. *
  24274. * @interface Highcharts.SelectDataObject
  24275. */ /**
  24276. * @name Highcharts.SelectDataObject#axis
  24277. * @type {Highcharts.Axis}
  24278. */ /**
  24279. * @name Highcharts.SelectDataObject#max
  24280. * @type {number}
  24281. */ /**
  24282. * @name Highcharts.SelectDataObject#min
  24283. * @type {number}
  24284. */
  24285. /**
  24286. * Object for select events.
  24287. *
  24288. * @interface Highcharts.SelectEventObject
  24289. */ /**
  24290. * @name Highcharts.SelectEventObject#originalEvent
  24291. * @type {global.Event}
  24292. */ /**
  24293. * @name Highcharts.SelectEventObject#xAxis
  24294. * @type {Array<Highcharts.SelectDataObject>}
  24295. */ /**
  24296. * @name Highcharts.SelectEventObject#yAxis
  24297. * @type {Array<Highcharts.SelectDataObject>}
  24298. */
  24299. /**
  24300. * Chart position and scale.
  24301. *
  24302. * @interface Highcharts.ChartPositionObject
  24303. */ /**
  24304. * @name Highcharts.ChartPositionObject#left
  24305. * @type {number}
  24306. */ /**
  24307. * @name Highcharts.ChartPositionObject#scaleX
  24308. * @type {number}
  24309. */ /**
  24310. * @name Highcharts.ChartPositionObject#scaleY
  24311. * @type {number}
  24312. */ /**
  24313. * @name Highcharts.ChartPositionObject#top
  24314. * @type {number}
  24315. */
  24316. ''; // detach doclets above
  24317. /* eslint-disable no-invalid-this, valid-jsdoc */
  24318. /**
  24319. * The mouse and touch tracker object. Each {@link Chart} item has one
  24320. * assosiated Pointer item that can be accessed from the {@link Chart.pointer}
  24321. * property.
  24322. *
  24323. * @class
  24324. * @name Highcharts.Pointer
  24325. *
  24326. * @param {Highcharts.Chart} chart
  24327. * The chart instance.
  24328. *
  24329. * @param {Highcharts.Options} options
  24330. * The root options object. The pointer uses options from the chart and
  24331. * tooltip structures.
  24332. */
  24333. var Pointer = /** @class */ (function () {
  24334. /* *
  24335. *
  24336. * Constructors
  24337. *
  24338. * */
  24339. function Pointer(chart, options) {
  24340. this.lastValidTouch = {};
  24341. this.pinchDown = [];
  24342. this.runChartClick = false;
  24343. this.chart = chart;
  24344. this.hasDragged = false;
  24345. this.options = options;
  24346. this.unbindContainerMouseLeave = function () { };
  24347. this.unbindContainerMouseEnter = function () { };
  24348. this.init(chart, options);
  24349. }
  24350. /* *
  24351. *
  24352. * Functions
  24353. *
  24354. * */
  24355. /**
  24356. * Set inactive state to all series that are not currently hovered,
  24357. * or, if `inactiveOtherPoints` is set to true, set inactive state to
  24358. * all points within that series.
  24359. *
  24360. * @private
  24361. * @function Highcharts.Pointer#applyInactiveState
  24362. * @param {Array<Highcharts.Point>} points
  24363. * Currently hovered points
  24364. */
  24365. Pointer.prototype.applyInactiveState = function (points) {
  24366. var activeSeries = [],
  24367. series;
  24368. // Get all active series from the hovered points
  24369. (points || []).forEach(function (item) {
  24370. series = item.series;
  24371. // Include itself
  24372. activeSeries.push(series);
  24373. // Include parent series
  24374. if (series.linkedParent) {
  24375. activeSeries.push(series.linkedParent);
  24376. }
  24377. // Include all child series
  24378. if (series.linkedSeries) {
  24379. activeSeries = activeSeries.concat(series.linkedSeries);
  24380. }
  24381. // Include navigator series
  24382. if (series.navigatorSeries) {
  24383. activeSeries.push(series.navigatorSeries);
  24384. }
  24385. });
  24386. // Now loop over all series, filtering out active series
  24387. this.chart.series.forEach(function (inactiveSeries) {
  24388. if (activeSeries.indexOf(inactiveSeries) === -1) {
  24389. // Inactive series
  24390. inactiveSeries.setState('inactive', true);
  24391. }
  24392. else if (inactiveSeries.options.inactiveOtherPoints) {
  24393. // Active series, but other points should be inactivated
  24394. inactiveSeries.setAllPointsToState('inactive');
  24395. }
  24396. });
  24397. };
  24398. /**
  24399. * Destroys the Pointer object and disconnects DOM events.
  24400. *
  24401. * @function Highcharts.Pointer#destroy
  24402. */
  24403. Pointer.prototype.destroy = function () {
  24404. var pointer = this;
  24405. if (typeof pointer.unDocMouseMove !== 'undefined') {
  24406. pointer.unDocMouseMove();
  24407. }
  24408. this.unbindContainerMouseLeave();
  24409. if (!H.chartCount) {
  24410. if (H.unbindDocumentMouseUp) {
  24411. H.unbindDocumentMouseUp = H.unbindDocumentMouseUp();
  24412. }
  24413. if (H.unbindDocumentTouchEnd) {
  24414. H.unbindDocumentTouchEnd = H.unbindDocumentTouchEnd();
  24415. }
  24416. }
  24417. // memory and CPU leak
  24418. clearInterval(pointer.tooltipTimeout);
  24419. objectEach(pointer, function (_val, prop) {
  24420. pointer[prop] = void 0;
  24421. });
  24422. };
  24423. /**
  24424. * Perform a drag operation in response to a mousemove event while the mouse
  24425. * is down.
  24426. *
  24427. * @private
  24428. * @function Highcharts.Pointer#drag
  24429. */
  24430. Pointer.prototype.drag = function (e) {
  24431. var chart = this.chart,
  24432. chartOptions = chart.options.chart,
  24433. chartX = e.chartX,
  24434. chartY = e.chartY,
  24435. zoomHor = this.zoomHor,
  24436. zoomVert = this.zoomVert,
  24437. plotLeft = chart.plotLeft,
  24438. plotTop = chart.plotTop,
  24439. plotWidth = chart.plotWidth,
  24440. plotHeight = chart.plotHeight,
  24441. clickedInside,
  24442. size,
  24443. selectionMarker = this.selectionMarker,
  24444. mouseDownX = (this.mouseDownX || 0),
  24445. mouseDownY = (this.mouseDownY || 0),
  24446. panningEnabled = isObject(chartOptions.panning) ?
  24447. chartOptions.panning && chartOptions.panning.enabled :
  24448. chartOptions.panning,
  24449. panKey = (chartOptions.panKey && e[chartOptions.panKey + 'Key']);
  24450. // If the device supports both touch and mouse (like IE11), and we are
  24451. // touch-dragging inside the plot area, don't handle the mouse event.
  24452. // #4339.
  24453. if (selectionMarker && selectionMarker.touch) {
  24454. return;
  24455. }
  24456. // If the mouse is outside the plot area, adjust to cooordinates
  24457. // inside to prevent the selection marker from going outside
  24458. if (chartX < plotLeft) {
  24459. chartX = plotLeft;
  24460. }
  24461. else if (chartX > plotLeft + plotWidth) {
  24462. chartX = plotLeft + plotWidth;
  24463. }
  24464. if (chartY < plotTop) {
  24465. chartY = plotTop;
  24466. }
  24467. else if (chartY > plotTop + plotHeight) {
  24468. chartY = plotTop + plotHeight;
  24469. }
  24470. // determine if the mouse has moved more than 10px
  24471. this.hasDragged = Math.sqrt(Math.pow(mouseDownX - chartX, 2) +
  24472. Math.pow(mouseDownY - chartY, 2));
  24473. if (this.hasDragged > 10) {
  24474. clickedInside = chart.isInsidePlot(mouseDownX - plotLeft, mouseDownY - plotTop);
  24475. // make a selection
  24476. if (chart.hasCartesianSeries &&
  24477. (this.zoomX || this.zoomY) &&
  24478. clickedInside &&
  24479. !panKey) {
  24480. if (!selectionMarker) {
  24481. this.selectionMarker = selectionMarker =
  24482. chart.renderer.rect(plotLeft, plotTop, zoomHor ? 1 : plotWidth, zoomVert ? 1 : plotHeight, 0)
  24483. .attr({
  24484. 'class': 'highcharts-selection-marker',
  24485. zIndex: 7
  24486. })
  24487. .add();
  24488. if (!chart.styledMode) {
  24489. selectionMarker.attr({
  24490. fill: (chartOptions.selectionMarkerFill ||
  24491. color(palette.highlightColor80)
  24492. .setOpacity(0.25).get())
  24493. });
  24494. }
  24495. }
  24496. }
  24497. // adjust the width of the selection marker
  24498. if (selectionMarker && zoomHor) {
  24499. size = chartX - mouseDownX;
  24500. selectionMarker.attr({
  24501. width: Math.abs(size),
  24502. x: (size > 0 ? 0 : size) + mouseDownX
  24503. });
  24504. }
  24505. // adjust the height of the selection marker
  24506. if (selectionMarker && zoomVert) {
  24507. size = chartY - mouseDownY;
  24508. selectionMarker.attr({
  24509. height: Math.abs(size),
  24510. y: (size > 0 ? 0 : size) + mouseDownY
  24511. });
  24512. }
  24513. // panning
  24514. if (clickedInside &&
  24515. !selectionMarker &&
  24516. panningEnabled) {
  24517. chart.pan(e, chartOptions.panning);
  24518. }
  24519. }
  24520. };
  24521. /**
  24522. * Start a drag operation.
  24523. *
  24524. * @private
  24525. * @function Highcharts.Pointer#dragStart
  24526. */
  24527. Pointer.prototype.dragStart = function (e) {
  24528. var chart = this.chart;
  24529. // Record the start position
  24530. chart.mouseIsDown = e.type;
  24531. chart.cancelClick = false;
  24532. chart.mouseDownX = this.mouseDownX = e.chartX;
  24533. chart.mouseDownY = this.mouseDownY = e.chartY;
  24534. };
  24535. /**
  24536. * On mouse up or touch end across the entire document, drop the selection.
  24537. *
  24538. * @private
  24539. * @function Highcharts.Pointer#drop
  24540. *
  24541. * @param {global.Event} e
  24542. */
  24543. Pointer.prototype.drop = function (e) {
  24544. var pointer = this,
  24545. chart = this.chart,
  24546. hasPinched = this.hasPinched;
  24547. if (this.selectionMarker) {
  24548. var selectionData = {
  24549. originalEvent: e,
  24550. xAxis: [],
  24551. yAxis: []
  24552. },
  24553. selectionBox = this.selectionMarker,
  24554. selectionLeft = selectionBox.attr ?
  24555. selectionBox.attr('x') :
  24556. selectionBox.x,
  24557. selectionTop = selectionBox.attr ?
  24558. selectionBox.attr('y') :
  24559. selectionBox.y,
  24560. selectionWidth = selectionBox.attr ?
  24561. selectionBox.attr('width') :
  24562. selectionBox.width,
  24563. selectionHeight = selectionBox.attr ?
  24564. selectionBox.attr('height') :
  24565. selectionBox.height,
  24566. runZoom;
  24567. // a selection has been made
  24568. if (this.hasDragged || hasPinched) {
  24569. // record each axis' min and max
  24570. chart.axes.forEach(function (axis) {
  24571. if (axis.zoomEnabled &&
  24572. defined(axis.min) &&
  24573. (hasPinched ||
  24574. pointer[{
  24575. xAxis: 'zoomX',
  24576. yAxis: 'zoomY'
  24577. }[axis.coll]]) &&
  24578. isNumber(selectionLeft) &&
  24579. isNumber(selectionTop)) { // #859, #3569
  24580. var horiz = axis.horiz,
  24581. minPixelPadding = e.type === 'touchend' ?
  24582. axis.minPixelPadding :
  24583. 0, // #1207, #3075
  24584. selectionMin = axis.toValue((horiz ? selectionLeft : selectionTop) +
  24585. minPixelPadding),
  24586. selectionMax = axis.toValue((horiz ?
  24587. selectionLeft + selectionWidth :
  24588. selectionTop + selectionHeight) - minPixelPadding);
  24589. selectionData[axis.coll].push({
  24590. axis: axis,
  24591. // Min/max for reversed axes
  24592. min: Math.min(selectionMin, selectionMax),
  24593. max: Math.max(selectionMin, selectionMax)
  24594. });
  24595. runZoom = true;
  24596. }
  24597. });
  24598. if (runZoom) {
  24599. fireEvent(chart, 'selection', selectionData, function (args) {
  24600. chart.zoom(extend(args, hasPinched ?
  24601. { animation: false } :
  24602. null));
  24603. });
  24604. }
  24605. }
  24606. if (isNumber(chart.index)) {
  24607. this.selectionMarker = this.selectionMarker.destroy();
  24608. }
  24609. // Reset scaling preview
  24610. if (hasPinched) {
  24611. this.scaleGroups();
  24612. }
  24613. }
  24614. // Reset all. Check isNumber because it may be destroyed on mouse up
  24615. // (#877)
  24616. if (chart && isNumber(chart.index)) {
  24617. css(chart.container, { cursor: chart._cursor });
  24618. chart.cancelClick = this.hasDragged > 10; // #370
  24619. chart.mouseIsDown = this.hasDragged = this.hasPinched = false;
  24620. this.pinchDown = [];
  24621. }
  24622. };
  24623. /**
  24624. * Finds the closest point to a set of coordinates, using the k-d-tree
  24625. * algorithm.
  24626. *
  24627. * @function Highcharts.Pointer#findNearestKDPoint
  24628. *
  24629. * @param {Array<Highcharts.Series>} series
  24630. * All the series to search in.
  24631. *
  24632. * @param {boolean|undefined} shared
  24633. * Whether it is a shared tooltip or not.
  24634. *
  24635. * @param {Highcharts.PointerEventObject} e
  24636. * The pointer event object, containing chart coordinates of the
  24637. * pointer.
  24638. *
  24639. * @return {Highcharts.Point|undefined}
  24640. * The point closest to given coordinates.
  24641. */
  24642. Pointer.prototype.findNearestKDPoint = function (series, shared, e) {
  24643. var chart = this.chart;
  24644. var hoverPoint = chart.hoverPoint;
  24645. var tooltip = chart.tooltip;
  24646. if (hoverPoint &&
  24647. tooltip &&
  24648. tooltip.isStickyOnContact()) {
  24649. return hoverPoint;
  24650. }
  24651. var closest;
  24652. /** @private */
  24653. function sort(p1, p2) {
  24654. var isCloserX = p1.distX - p2.distX,
  24655. isCloser = p1.dist - p2.dist,
  24656. isAbove = (p2.series.group && p2.series.group.zIndex) -
  24657. (p1.series.group && p1.series.group.zIndex),
  24658. result;
  24659. // We have two points which are not in the same place on xAxis
  24660. // and shared tooltip:
  24661. if (isCloserX !== 0 && shared) { // #5721
  24662. result = isCloserX;
  24663. // Points are not exactly in the same place on x/yAxis:
  24664. }
  24665. else if (isCloser !== 0) {
  24666. result = isCloser;
  24667. // The same xAxis and yAxis position, sort by z-index:
  24668. }
  24669. else if (isAbove !== 0) {
  24670. result = isAbove;
  24671. // The same zIndex, sort by array index:
  24672. }
  24673. else {
  24674. result =
  24675. p1.series.index > p2.series.index ?
  24676. -1 :
  24677. 1;
  24678. }
  24679. return result;
  24680. }
  24681. series.forEach(function (s) {
  24682. var noSharedTooltip = s.noSharedTooltip && shared,
  24683. compareX = (!noSharedTooltip &&
  24684. s.options.findNearestPointBy.indexOf('y') < 0),
  24685. point = s.searchPoint(e,
  24686. compareX);
  24687. if ( // Check that we actually found a point on the series.
  24688. isObject(point, true) && point.series &&
  24689. // Use the new point if it is closer.
  24690. (!isObject(closest, true) ||
  24691. (sort(closest, point) > 0))) {
  24692. closest = point;
  24693. }
  24694. });
  24695. return closest;
  24696. };
  24697. /**
  24698. * @private
  24699. * @function Highcharts.Pointer#getChartCoordinatesFromPoint
  24700. * @param {Highcharts.Point} point
  24701. * @param {boolean} [inverted]
  24702. * @return {Highcharts.PointerCoordinatesObject|undefined}
  24703. */
  24704. Pointer.prototype.getChartCoordinatesFromPoint = function (point, inverted) {
  24705. var series = point.series,
  24706. xAxis = series.xAxis,
  24707. yAxis = series.yAxis,
  24708. plotX = pick(point.clientX,
  24709. point.plotX),
  24710. shapeArgs = point.shapeArgs;
  24711. if (xAxis && yAxis) {
  24712. return inverted ? {
  24713. chartX: xAxis.len + xAxis.pos - plotX,
  24714. chartY: yAxis.len + yAxis.pos - point.plotY
  24715. } : {
  24716. chartX: plotX + xAxis.pos,
  24717. chartY: point.plotY + yAxis.pos
  24718. };
  24719. }
  24720. if (shapeArgs && shapeArgs.x && shapeArgs.y) {
  24721. // E.g. pies do not have axes
  24722. return {
  24723. chartX: shapeArgs.x,
  24724. chartY: shapeArgs.y
  24725. };
  24726. }
  24727. };
  24728. /**
  24729. * Return the cached chartPosition if it is available on the Pointer,
  24730. * otherwise find it. Running offset is quite expensive, so it should be
  24731. * avoided when we know the chart hasn't moved.
  24732. *
  24733. * @function Highcharts.Pointer#getChartPosition
  24734. *
  24735. * @return {Highcharts.ChartPositionObject}
  24736. * The offset of the chart container within the page
  24737. */
  24738. Pointer.prototype.getChartPosition = function () {
  24739. if (this.chartPosition) {
  24740. return this.chartPosition;
  24741. }
  24742. var container = this.chart.container;
  24743. var pos = offset(container);
  24744. this.chartPosition = {
  24745. left: pos.left,
  24746. top: pos.top,
  24747. scaleX: 1,
  24748. scaleY: 1
  24749. };
  24750. var offsetWidth = container.offsetWidth;
  24751. var offsetHeight = container.offsetHeight;
  24752. // #13342 - tooltip was not visible in Chrome, when chart
  24753. // updates height.
  24754. if (offsetWidth > 2 && // #13342
  24755. offsetHeight > 2 // #13342
  24756. ) {
  24757. this.chartPosition.scaleX = pos.width / offsetWidth;
  24758. this.chartPosition.scaleY = pos.height / offsetHeight;
  24759. }
  24760. return this.chartPosition;
  24761. };
  24762. /**
  24763. * Get the click position in terms of axis values.
  24764. *
  24765. * @function Highcharts.Pointer#getCoordinates
  24766. *
  24767. * @param {Highcharts.PointerEventObject} e
  24768. * Pointer event, extended with `chartX` and `chartY` properties.
  24769. *
  24770. * @return {Highcharts.PointerAxisCoordinatesObject}
  24771. */
  24772. Pointer.prototype.getCoordinates = function (e) {
  24773. var coordinates = {
  24774. xAxis: [],
  24775. yAxis: []
  24776. };
  24777. this.chart.axes.forEach(function (axis) {
  24778. coordinates[axis.isXAxis ? 'xAxis' : 'yAxis'].push({
  24779. axis: axis,
  24780. value: axis.toValue(e[axis.horiz ? 'chartX' : 'chartY'])
  24781. });
  24782. });
  24783. return coordinates;
  24784. };
  24785. /**
  24786. * Calculates what is the current hovered point/points and series.
  24787. *
  24788. * @private
  24789. * @function Highcharts.Pointer#getHoverData
  24790. *
  24791. * @param {Highcharts.Point|undefined} existingHoverPoint
  24792. * The point currrently beeing hovered.
  24793. *
  24794. * @param {Highcharts.Series|undefined} existingHoverSeries
  24795. * The series currently beeing hovered.
  24796. *
  24797. * @param {Array<Highcharts.Series>} series
  24798. * All the series in the chart.
  24799. *
  24800. * @param {boolean} isDirectTouch
  24801. * Is the pointer directly hovering the point.
  24802. *
  24803. * @param {boolean|undefined} shared
  24804. * Whether it is a shared tooltip or not.
  24805. *
  24806. * @param {Highcharts.PointerEventObject} [e]
  24807. * The triggering event, containing chart coordinates of the pointer.
  24808. *
  24809. * @return {object}
  24810. * Object containing resulting hover data: hoverPoint, hoverSeries,
  24811. * and hoverPoints.
  24812. */
  24813. Pointer.prototype.getHoverData = function (existingHoverPoint, existingHoverSeries, series, isDirectTouch, shared, e) {
  24814. var hoverPoint,
  24815. hoverPoints = [],
  24816. hoverSeries = existingHoverSeries,
  24817. useExisting = !!(isDirectTouch && existingHoverPoint),
  24818. notSticky = hoverSeries && !hoverSeries.stickyTracking,
  24819. // Which series to look in for the hover point
  24820. searchSeries,
  24821. // Parameters needed for beforeGetHoverData event.
  24822. eventArgs = {
  24823. chartX: e ? e.chartX : void 0,
  24824. chartY: e ? e.chartY : void 0,
  24825. shared: shared
  24826. },
  24827. filter = function (s) {
  24828. return (s.visible &&
  24829. !(!shared && s.directTouch) && // #3821
  24830. pick(s.options.enableMouseTracking,
  24831. true));
  24832. };
  24833. // Find chart.hoverPane and update filter method in polar.
  24834. fireEvent(this, 'beforeGetHoverData', eventArgs);
  24835. searchSeries = notSticky ?
  24836. // Only search on hovered series if it has stickyTracking false
  24837. [hoverSeries] :
  24838. // Filter what series to look in.
  24839. series.filter(function (s) {
  24840. return eventArgs.filter ? eventArgs.filter(s) : filter(s) &&
  24841. s.stickyTracking;
  24842. });
  24843. // Use existing hovered point or find the one closest to coordinates.
  24844. hoverPoint = useExisting || !e ?
  24845. existingHoverPoint :
  24846. this.findNearestKDPoint(searchSeries, shared, e);
  24847. // Assign hover series
  24848. hoverSeries = hoverPoint && hoverPoint.series;
  24849. // If we have a hoverPoint, assign hoverPoints.
  24850. if (hoverPoint) {
  24851. // When tooltip is shared, it displays more than one point
  24852. if (shared && !hoverSeries.noSharedTooltip) {
  24853. searchSeries = series.filter(function (s) {
  24854. return eventArgs.filter ?
  24855. eventArgs.filter(s) : filter(s) && !s.noSharedTooltip;
  24856. });
  24857. // Get all points with the same x value as the hoverPoint
  24858. searchSeries.forEach(function (s) {
  24859. var point = find(s.points,
  24860. function (p) {
  24861. return p.x === hoverPoint.x && !p.isNull;
  24862. });
  24863. if (isObject(point)) {
  24864. /*
  24865. * Boost returns a minimal point. Convert it to a usable
  24866. * point for tooltip and states.
  24867. */
  24868. if (s.chart.isBoosting) {
  24869. point = s.getPoint(point);
  24870. }
  24871. hoverPoints.push(point);
  24872. }
  24873. });
  24874. }
  24875. else {
  24876. hoverPoints.push(hoverPoint);
  24877. }
  24878. }
  24879. // Check whether the hoverPoint is inside pane we are hovering over.
  24880. eventArgs = { hoverPoint: hoverPoint };
  24881. fireEvent(this, 'afterGetHoverData', eventArgs);
  24882. return {
  24883. hoverPoint: eventArgs.hoverPoint,
  24884. hoverSeries: hoverSeries,
  24885. hoverPoints: hoverPoints
  24886. };
  24887. };
  24888. /**
  24889. * @private
  24890. * @function Highcharts.Pointer#getPointFromEvent
  24891. *
  24892. * @param {global.Event} e
  24893. *
  24894. * @return {Highcharts.Point|undefined}
  24895. */
  24896. Pointer.prototype.getPointFromEvent = function (e) {
  24897. var target = e.target,
  24898. point;
  24899. while (target && !point) {
  24900. point = target.point;
  24901. target = target.parentNode;
  24902. }
  24903. return point;
  24904. };
  24905. /**
  24906. * @private
  24907. * @function Highcharts.Pointer#onTrackerMouseOut
  24908. */
  24909. Pointer.prototype.onTrackerMouseOut = function (e) {
  24910. var chart = this.chart;
  24911. var relatedTarget = e.relatedTarget || e.toElement;
  24912. var series = chart.hoverSeries;
  24913. this.isDirectTouch = false;
  24914. if (series &&
  24915. relatedTarget &&
  24916. !series.stickyTracking &&
  24917. !this.inClass(relatedTarget, 'highcharts-tooltip') &&
  24918. (!this.inClass(relatedTarget, 'highcharts-series-' + series.index) || // #2499, #4465, #5553
  24919. !this.inClass(relatedTarget, 'highcharts-tracker'))) {
  24920. series.onMouseOut();
  24921. }
  24922. };
  24923. /**
  24924. * Utility to detect whether an element has, or has a parent with, a
  24925. * specificclass name. Used on detection of tracker objects and on deciding
  24926. * whether hovering the tooltip should cause the active series to mouse out.
  24927. *
  24928. * @function Highcharts.Pointer#inClass
  24929. *
  24930. * @param {Highcharts.SVGDOMElement|Highcharts.HTMLDOMElement} element
  24931. * The element to investigate.
  24932. *
  24933. * @param {string} className
  24934. * The class name to look for.
  24935. *
  24936. * @return {boolean|undefined}
  24937. * True if either the element or one of its parents has the given
  24938. * class name.
  24939. */
  24940. Pointer.prototype.inClass = function (element, className) {
  24941. var elemClassName;
  24942. while (element) {
  24943. elemClassName = attr(element, 'class');
  24944. if (elemClassName) {
  24945. if (elemClassName.indexOf(className) !== -1) {
  24946. return true;
  24947. }
  24948. if (elemClassName.indexOf('highcharts-container') !== -1) {
  24949. return false;
  24950. }
  24951. }
  24952. element = element.parentNode;
  24953. }
  24954. };
  24955. /**
  24956. * Initialize the Pointer.
  24957. *
  24958. * @private
  24959. * @function Highcharts.Pointer#init
  24960. *
  24961. * @param {Highcharts.Chart} chart
  24962. * The Chart instance.
  24963. *
  24964. * @param {Highcharts.Options} options
  24965. * The root options object. The pointer uses options from the chart
  24966. * and tooltip structures.
  24967. *
  24968. * @return {void}
  24969. */
  24970. Pointer.prototype.init = function (chart, options) {
  24971. // Store references
  24972. this.options = options;
  24973. this.chart = chart;
  24974. // Do we need to handle click on a touch device?
  24975. this.runChartClick =
  24976. options.chart.events &&
  24977. !!options.chart.events.click;
  24978. this.pinchDown = [];
  24979. this.lastValidTouch = {};
  24980. if (Tooltip) {
  24981. /**
  24982. * Tooltip object for points of series.
  24983. *
  24984. * @name Highcharts.Chart#tooltip
  24985. * @type {Highcharts.Tooltip}
  24986. */
  24987. chart.tooltip = new Tooltip(chart, options.tooltip);
  24988. this.followTouchMove = pick(options.tooltip.followTouchMove, true);
  24989. }
  24990. this.setDOMEvents();
  24991. };
  24992. /**
  24993. * Takes a browser event object and extends it with custom Highcharts
  24994. * properties `chartX` and `chartY` in order to work on the internal
  24995. * coordinate system.
  24996. *
  24997. * @function Highcharts.Pointer#normalize
  24998. *
  24999. * @param {global.MouseEvent|global.PointerEvent|global.TouchEvent} e
  25000. * Event object in standard browsers.
  25001. *
  25002. * @param {Highcharts.OffsetObject} [chartPosition]
  25003. * Additional chart offset.
  25004. *
  25005. * @return {Highcharts.PointerEventObject}
  25006. * A browser event with extended properties `chartX` and `chartY`.
  25007. */
  25008. Pointer.prototype.normalize = function (e, chartPosition) {
  25009. var touches = e.touches;
  25010. // iOS (#2757)
  25011. var ePos = (touches ?
  25012. touches.length ?
  25013. touches.item(0) :
  25014. (pick(// #13534
  25015. touches.changedTouches,
  25016. e.changedTouches))[0] :
  25017. e);
  25018. // Get mouse position
  25019. if (!chartPosition) {
  25020. chartPosition = this.getChartPosition();
  25021. }
  25022. var chartX = ePos.pageX - chartPosition.left,
  25023. chartY = ePos.pageY - chartPosition.top;
  25024. // #11329 - when there is scaling on a parent element, we need to take
  25025. // this into account
  25026. chartX /= chartPosition.scaleX;
  25027. chartY /= chartPosition.scaleY;
  25028. return extend(e, {
  25029. chartX: Math.round(chartX),
  25030. chartY: Math.round(chartY)
  25031. });
  25032. };
  25033. /**
  25034. * @private
  25035. * @function Highcharts.Pointer#onContainerClick
  25036. */
  25037. Pointer.prototype.onContainerClick = function (e) {
  25038. var chart = this.chart;
  25039. var hoverPoint = chart.hoverPoint;
  25040. var pEvt = this.normalize(e);
  25041. var plotLeft = chart.plotLeft;
  25042. var plotTop = chart.plotTop;
  25043. if (!chart.cancelClick) {
  25044. // On tracker click, fire the series and point events. #783, #1583
  25045. if (hoverPoint &&
  25046. this.inClass(pEvt.target, 'highcharts-tracker')) {
  25047. // the series click event
  25048. fireEvent(hoverPoint.series, 'click', extend(pEvt, {
  25049. point: hoverPoint
  25050. }));
  25051. // the point click event
  25052. if (chart.hoverPoint) { // it may be destroyed (#1844)
  25053. hoverPoint.firePointEvent('click', pEvt);
  25054. }
  25055. // When clicking outside a tracker, fire a chart event
  25056. }
  25057. else {
  25058. extend(pEvt, this.getCoordinates(pEvt));
  25059. // fire a click event in the chart
  25060. if (chart.isInsidePlot((pEvt.chartX - plotLeft), (pEvt.chartY - plotTop))) {
  25061. fireEvent(chart, 'click', pEvt);
  25062. }
  25063. }
  25064. }
  25065. };
  25066. /**
  25067. * @private
  25068. * @function Highcharts.Pointer#onContainerMouseDown
  25069. *
  25070. * @param {global.MouseEvent} e
  25071. */
  25072. Pointer.prototype.onContainerMouseDown = function (e) {
  25073. var isPrimaryButton = ((e.buttons || e.button) & 1) === 1;
  25074. // Normalize before the 'if' for the legacy IE (#7850)
  25075. e = this.normalize(e);
  25076. // #11635, Firefox does not reliable fire move event after click scroll
  25077. if (H.isFirefox &&
  25078. e.button !== 0) {
  25079. this.onContainerMouseMove(e);
  25080. }
  25081. // #11635, limiting to primary button (incl. IE 8 support)
  25082. if (typeof e.button === 'undefined' ||
  25083. isPrimaryButton) {
  25084. this.zoomOption(e);
  25085. // #295, #13737 solve conflict between container drag and chart zoom
  25086. if (isPrimaryButton &&
  25087. e.preventDefault) {
  25088. e.preventDefault();
  25089. }
  25090. this.dragStart(e);
  25091. }
  25092. };
  25093. /**
  25094. * When mouse leaves the container, hide the tooltip.
  25095. *
  25096. * @private
  25097. * @function Highcharts.Pointer#onContainerMouseLeave
  25098. *
  25099. * @param {global.MouseEvent} e
  25100. *
  25101. * @return {void}
  25102. */
  25103. Pointer.prototype.onContainerMouseLeave = function (e) {
  25104. var chart = charts[pick(H.hoverChartIndex, -1)];
  25105. var tooltip = this.chart.tooltip;
  25106. e = this.normalize(e);
  25107. // #4886, MS Touch end fires mouseleave but with no related target
  25108. if (chart &&
  25109. (e.relatedTarget || e.toElement)) {
  25110. chart.pointer.reset();
  25111. // Also reset the chart position, used in #149 fix
  25112. chart.pointer.chartPosition = void 0;
  25113. }
  25114. if ( // #11635, Firefox wheel scroll does not fire out events consistently
  25115. tooltip &&
  25116. !tooltip.isHidden) {
  25117. this.reset();
  25118. }
  25119. };
  25120. /**
  25121. * When mouse enters the container, delete pointer's chartPosition.
  25122. *
  25123. * @private
  25124. * @function Highcharts.Pointer#onContainerMouseEnter
  25125. *
  25126. * @param {global.MouseEvent} e
  25127. *
  25128. * @return {void}
  25129. */
  25130. Pointer.prototype.onContainerMouseEnter = function (e) {
  25131. delete this.chartPosition;
  25132. };
  25133. /**
  25134. * The mousemove, touchmove and touchstart event handler
  25135. *
  25136. * @private
  25137. * @function Highcharts.Pointer#onContainerMouseMove
  25138. *
  25139. * @param {global.MouseEvent} e
  25140. *
  25141. * @return {void}
  25142. */
  25143. Pointer.prototype.onContainerMouseMove = function (e) {
  25144. var chart = this.chart;
  25145. var pEvt = this.normalize(e);
  25146. this.setHoverChartIndex();
  25147. // In IE8 we apparently need this returnValue set to false in order to
  25148. // avoid text being selected. But in Chrome, e.returnValue is prevented,
  25149. // plus we don't need to run e.preventDefault to prevent selected text
  25150. // in modern browsers. So we set it conditionally. Remove it when IE8 is
  25151. // no longer needed. #2251, #3224.
  25152. if (!pEvt.preventDefault) {
  25153. pEvt.returnValue = false;
  25154. }
  25155. if (chart.mouseIsDown === 'mousedown' || this.touchSelect(pEvt)) {
  25156. this.drag(pEvt);
  25157. }
  25158. // Show the tooltip and run mouse over events (#977)
  25159. if (!chart.openMenu &&
  25160. (this.inClass(pEvt.target, 'highcharts-tracker') ||
  25161. chart.isInsidePlot((pEvt.chartX - chart.plotLeft), (pEvt.chartY - chart.plotTop)))) {
  25162. this.runPointActions(pEvt);
  25163. }
  25164. };
  25165. /**
  25166. * @private
  25167. * @function Highcharts.Pointer#onDocumentTouchEnd
  25168. *
  25169. * @param {Highcharts.PointerEventObject} e
  25170. *
  25171. * @return {void}
  25172. */
  25173. Pointer.prototype.onDocumentTouchEnd = function (e) {
  25174. if (charts[H.hoverChartIndex]) {
  25175. charts[H.hoverChartIndex].pointer.drop(e);
  25176. }
  25177. };
  25178. /**
  25179. * @private
  25180. * @function Highcharts.Pointer#onContainerTouchMove
  25181. *
  25182. * @param {Highcharts.PointerEventObject} e
  25183. *
  25184. * @return {void}
  25185. */
  25186. Pointer.prototype.onContainerTouchMove = function (e) {
  25187. if (this.touchSelect(e)) {
  25188. this.onContainerMouseMove(e);
  25189. }
  25190. else {
  25191. this.touch(e);
  25192. }
  25193. };
  25194. /**
  25195. * @private
  25196. * @function Highcharts.Pointer#onContainerTouchStart
  25197. *
  25198. * @param {Highcharts.PointerEventObject} e
  25199. *
  25200. * @return {void}
  25201. */
  25202. Pointer.prototype.onContainerTouchStart = function (e) {
  25203. if (this.touchSelect(e)) {
  25204. this.onContainerMouseDown(e);
  25205. }
  25206. else {
  25207. this.zoomOption(e);
  25208. this.touch(e, true);
  25209. }
  25210. };
  25211. /**
  25212. * Special handler for mouse move that will hide the tooltip when the mouse
  25213. * leaves the plotarea. Issue #149 workaround. The mouseleave event does not
  25214. * always fire.
  25215. *
  25216. * @private
  25217. * @function Highcharts.Pointer#onDocumentMouseMove
  25218. *
  25219. * @param {global.MouseEvent} e
  25220. *
  25221. * @return {void}
  25222. */
  25223. Pointer.prototype.onDocumentMouseMove = function (e) {
  25224. var chart = this.chart;
  25225. var chartPosition = this.chartPosition;
  25226. var pEvt = this.normalize(e,
  25227. chartPosition);
  25228. var tooltip = chart.tooltip;
  25229. // If we're outside, hide the tooltip
  25230. if (chartPosition &&
  25231. (!tooltip ||
  25232. !tooltip.isStickyOnContact()) &&
  25233. !chart.isInsidePlot(pEvt.chartX - chart.plotLeft, pEvt.chartY - chart.plotTop) &&
  25234. !this.inClass(pEvt.target, 'highcharts-tracker')) {
  25235. this.reset();
  25236. }
  25237. };
  25238. /**
  25239. * @private
  25240. * @function Highcharts.Pointer#onDocumentMouseUp
  25241. *
  25242. * @param {global.MouseEvent} e
  25243. *
  25244. * @return {void}
  25245. */
  25246. Pointer.prototype.onDocumentMouseUp = function (e) {
  25247. var chart = charts[pick(H.hoverChartIndex, -1)];
  25248. if (chart) {
  25249. chart.pointer.drop(e);
  25250. }
  25251. };
  25252. /**
  25253. * Handle touch events with two touches
  25254. *
  25255. * @private
  25256. * @function Highcharts.Pointer#pinch
  25257. *
  25258. * @param {Highcharts.PointerEventObject} e
  25259. *
  25260. * @return {void}
  25261. */
  25262. Pointer.prototype.pinch = function (e) {
  25263. var self = this,
  25264. chart = self.chart,
  25265. pinchDown = self.pinchDown,
  25266. touches = (e.touches || []),
  25267. touchesLength = touches.length,
  25268. lastValidTouch = self.lastValidTouch,
  25269. hasZoom = self.hasZoom,
  25270. selectionMarker = self.selectionMarker,
  25271. transform = {},
  25272. fireClickEvent = touchesLength === 1 && ((self.inClass(e.target, 'highcharts-tracker') &&
  25273. chart.runTrackerClick) ||
  25274. self.runChartClick),
  25275. clip = {};
  25276. // Don't initiate panning until the user has pinched. This prevents us
  25277. // from blocking page scrolling as users scroll down a long page
  25278. // (#4210).
  25279. if (touchesLength > 1) {
  25280. self.initiated = true;
  25281. }
  25282. // On touch devices, only proceed to trigger click if a handler is
  25283. // defined
  25284. if (hasZoom && self.initiated && !fireClickEvent && e.cancelable !== false) {
  25285. e.preventDefault();
  25286. }
  25287. // Normalize each touch
  25288. [].map.call(touches, function (e) {
  25289. return self.normalize(e);
  25290. });
  25291. // Register the touch start position
  25292. if (e.type === 'touchstart') {
  25293. [].forEach.call(touches, function (e, i) {
  25294. pinchDown[i] = { chartX: e.chartX, chartY: e.chartY };
  25295. });
  25296. lastValidTouch.x = [pinchDown[0].chartX, pinchDown[1] &&
  25297. pinchDown[1].chartX];
  25298. lastValidTouch.y = [pinchDown[0].chartY, pinchDown[1] &&
  25299. pinchDown[1].chartY];
  25300. // Identify the data bounds in pixels
  25301. chart.axes.forEach(function (axis) {
  25302. if (axis.zoomEnabled) {
  25303. var bounds = chart.bounds[axis.horiz ? 'h' : 'v'],
  25304. minPixelPadding = axis.minPixelPadding,
  25305. min = axis.toPixels(Math.min(pick(axis.options.min,
  25306. axis.dataMin),
  25307. axis.dataMin)),
  25308. max = axis.toPixels(Math.max(pick(axis.options.max,
  25309. axis.dataMax),
  25310. axis.dataMax)),
  25311. absMin = Math.min(min,
  25312. max),
  25313. absMax = Math.max(min,
  25314. max);
  25315. // Store the bounds for use in the touchmove handler
  25316. bounds.min = Math.min(axis.pos, absMin - minPixelPadding);
  25317. bounds.max = Math.max(axis.pos + axis.len, absMax + minPixelPadding);
  25318. }
  25319. });
  25320. self.res = true; // reset on next move
  25321. // Optionally move the tooltip on touchmove
  25322. }
  25323. else if (self.followTouchMove && touchesLength === 1) {
  25324. this.runPointActions(self.normalize(e));
  25325. // Event type is touchmove, handle panning and pinching
  25326. }
  25327. else if (pinchDown.length) { // can be 0 when releasing, if touchend
  25328. // fires first
  25329. // Set the marker
  25330. if (!selectionMarker) {
  25331. self.selectionMarker = selectionMarker = extend({
  25332. destroy: noop,
  25333. touch: true
  25334. }, chart.plotBox);
  25335. }
  25336. self.pinchTranslate(pinchDown, touches, transform, selectionMarker, clip, lastValidTouch);
  25337. self.hasPinched = hasZoom;
  25338. // Scale and translate the groups to provide visual feedback during
  25339. // pinching
  25340. self.scaleGroups(transform, clip);
  25341. if (self.res) {
  25342. self.res = false;
  25343. this.reset(false, 0);
  25344. }
  25345. }
  25346. };
  25347. /**
  25348. * Run translation operations
  25349. *
  25350. * @private
  25351. * @function Highcharts.Pointer#pinchTranslate
  25352. *
  25353. * @param {Array<*>} pinchDown
  25354. *
  25355. * @param {Array<Highcharts.PointerEventObject>} touches
  25356. *
  25357. * @param {*} transform
  25358. *
  25359. * @param {*} selectionMarker
  25360. *
  25361. * @param {*} clip
  25362. *
  25363. * @param {*} lastValidTouch
  25364. *
  25365. * @return {void}
  25366. */
  25367. Pointer.prototype.pinchTranslate = function (pinchDown, touches, transform, selectionMarker, clip, lastValidTouch) {
  25368. if (this.zoomHor) {
  25369. this.pinchTranslateDirection(true, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch);
  25370. }
  25371. if (this.zoomVert) {
  25372. this.pinchTranslateDirection(false, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch);
  25373. }
  25374. };
  25375. /**
  25376. * Run translation operations for each direction (horizontal and vertical)
  25377. * independently.
  25378. *
  25379. * @private
  25380. * @function Highcharts.Pointer#pinchTranslateDirection
  25381. *
  25382. * @param {boolean} horiz
  25383. *
  25384. * @param {Array<*>} pinchDown
  25385. *
  25386. * @param {Array<Highcharts.PointerEventObject>} touches
  25387. *
  25388. * @param {*} transform
  25389. *
  25390. * @param {*} selectionMarker
  25391. *
  25392. * @param {*} clip
  25393. *
  25394. * @param {*} lastValidTouch
  25395. *
  25396. * @param {number|undefined} [forcedScale=1]
  25397. *
  25398. * @return {void}
  25399. */
  25400. Pointer.prototype.pinchTranslateDirection = function (horiz, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch, forcedScale) {
  25401. 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 = forcedScale || 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 () {
  25402. // Don't zoom if fingers are too close on this axis
  25403. if (typeof touch1Now === 'number' &&
  25404. Math.abs(touch0Start - touch1Start) > 20) {
  25405. scale = forcedScale ||
  25406. Math.abs(touch0Now - touch1Now) /
  25407. Math.abs(touch0Start - touch1Start);
  25408. }
  25409. clipXY = ((plotLeftTop - touch0Now) / scale) + touch0Start;
  25410. selectionWH = chart['plot' + (horiz ? 'Width' : 'Height')] / scale;
  25411. };
  25412. // Set the scale, first pass
  25413. setScale();
  25414. // The clip position (x or y) is altered if out of bounds, the selection
  25415. // position is not
  25416. selectionXY = clipXY;
  25417. // Out of bounds
  25418. if (selectionXY < bounds.min) {
  25419. selectionXY = bounds.min;
  25420. outOfBounds = true;
  25421. }
  25422. else if (selectionXY + selectionWH > bounds.max) {
  25423. selectionXY = bounds.max - selectionWH;
  25424. outOfBounds = true;
  25425. }
  25426. // Is the chart dragged off its bounds, determined by dataMin and
  25427. // dataMax?
  25428. if (outOfBounds) {
  25429. // Modify the touchNow position in order to create an elastic drag
  25430. // movement. This indicates to the user that the chart is responsive
  25431. // but can't be dragged further.
  25432. touch0Now -= 0.8 * (touch0Now - lastValidTouch[xy][0]);
  25433. if (typeof touch1Now === 'number') {
  25434. touch1Now -= 0.8 * (touch1Now - lastValidTouch[xy][1]);
  25435. }
  25436. // Set the scale, second pass to adapt to the modified touchNow
  25437. // positions
  25438. setScale();
  25439. }
  25440. else {
  25441. lastValidTouch[xy] = [touch0Now, touch1Now];
  25442. }
  25443. // Set geometry for clipping, selection and transformation
  25444. if (!inverted) {
  25445. clip[xy] = clipXY - plotLeftTop;
  25446. clip[wh] = selectionWH;
  25447. }
  25448. scaleKey = inverted ? (horiz ? 'scaleY' : 'scaleX') : 'scale' + XY;
  25449. transformScale = inverted ? 1 / scale : scale;
  25450. selectionMarker[wh] = selectionWH;
  25451. selectionMarker[xy] = selectionXY;
  25452. transform[scaleKey] = scale;
  25453. transform['translate' + XY] = (transformScale * plotLeftTop) +
  25454. (touch0Now - (transformScale * touch0Start));
  25455. };
  25456. /**
  25457. * Reset the tracking by hiding the tooltip, the hover series state and the
  25458. * hover point
  25459. *
  25460. * @function Highcharts.Pointer#reset
  25461. *
  25462. * @param {boolean} [allowMove]
  25463. * Instead of destroying the tooltip altogether, allow moving it if
  25464. * possible.
  25465. *
  25466. * @param {number} [delay]
  25467. *
  25468. * @return {void}
  25469. */
  25470. Pointer.prototype.reset = function (allowMove, delay) {
  25471. var pointer = this,
  25472. chart = pointer.chart,
  25473. hoverSeries = chart.hoverSeries,
  25474. hoverPoint = chart.hoverPoint,
  25475. hoverPoints = chart.hoverPoints,
  25476. tooltip = chart.tooltip,
  25477. tooltipPoints = tooltip && tooltip.shared ?
  25478. hoverPoints :
  25479. hoverPoint;
  25480. // Check if the points have moved outside the plot area (#1003, #4736,
  25481. // #5101)
  25482. if (allowMove && tooltipPoints) {
  25483. splat(tooltipPoints).forEach(function (point) {
  25484. if (point.series.isCartesian &&
  25485. typeof point.plotX === 'undefined') {
  25486. allowMove = false;
  25487. }
  25488. });
  25489. }
  25490. // Just move the tooltip, #349
  25491. if (allowMove) {
  25492. if (tooltip && tooltipPoints && splat(tooltipPoints).length) {
  25493. tooltip.refresh(tooltipPoints);
  25494. if (tooltip.shared && hoverPoints) { // #8284
  25495. hoverPoints.forEach(function (point) {
  25496. point.setState(point.state, true);
  25497. if (point.series.isCartesian) {
  25498. if (point.series.xAxis.crosshair) {
  25499. point.series.xAxis
  25500. .drawCrosshair(null, point);
  25501. }
  25502. if (point.series.yAxis.crosshair) {
  25503. point.series.yAxis
  25504. .drawCrosshair(null, point);
  25505. }
  25506. }
  25507. });
  25508. }
  25509. else if (hoverPoint) { // #2500
  25510. hoverPoint.setState(hoverPoint.state, true);
  25511. chart.axes.forEach(function (axis) {
  25512. if (axis.crosshair &&
  25513. hoverPoint.series[axis.coll] === axis) {
  25514. axis.drawCrosshair(null, hoverPoint);
  25515. }
  25516. });
  25517. }
  25518. }
  25519. // Full reset
  25520. }
  25521. else {
  25522. if (hoverPoint) {
  25523. hoverPoint.onMouseOut();
  25524. }
  25525. if (hoverPoints) {
  25526. hoverPoints.forEach(function (point) {
  25527. point.setState();
  25528. });
  25529. }
  25530. if (hoverSeries) {
  25531. hoverSeries.onMouseOut();
  25532. }
  25533. if (tooltip) {
  25534. tooltip.hide(delay);
  25535. }
  25536. if (pointer.unDocMouseMove) {
  25537. pointer.unDocMouseMove = pointer.unDocMouseMove();
  25538. }
  25539. // Remove crosshairs
  25540. chart.axes.forEach(function (axis) {
  25541. axis.hideCrosshair();
  25542. });
  25543. pointer.hoverX = chart.hoverPoints = chart.hoverPoint = null;
  25544. }
  25545. };
  25546. /**
  25547. * With line type charts with a single tracker, get the point closest to the
  25548. * mouse. Run Point.onMouseOver and display tooltip for the point or points.
  25549. *
  25550. * @private
  25551. * @function Highcharts.Pointer#runPointActions
  25552. *
  25553. * @fires Highcharts.Point#event:mouseOut
  25554. * @fires Highcharts.Point#event:mouseOver
  25555. */
  25556. Pointer.prototype.runPointActions = function (e, p) {
  25557. var pointer = this,
  25558. chart = pointer.chart,
  25559. series = chart.series,
  25560. tooltip = (chart.tooltip && chart.tooltip.options.enabled ?
  25561. chart.tooltip :
  25562. void 0),
  25563. shared = (tooltip ?
  25564. tooltip.shared :
  25565. false),
  25566. hoverPoint = p || chart.hoverPoint,
  25567. hoverSeries = hoverPoint && hoverPoint.series || chart.hoverSeries,
  25568. // onMouseOver or already hovering a series with directTouch
  25569. isDirectTouch = (!e || e.type !== 'touchmove') && (!!p || ((hoverSeries && hoverSeries.directTouch) &&
  25570. pointer.isDirectTouch)),
  25571. hoverData = this.getHoverData(hoverPoint,
  25572. hoverSeries,
  25573. series,
  25574. isDirectTouch,
  25575. shared,
  25576. e),
  25577. useSharedTooltip,
  25578. followPointer,
  25579. anchor,
  25580. points;
  25581. // Update variables from hoverData.
  25582. hoverPoint = hoverData.hoverPoint;
  25583. points = hoverData.hoverPoints;
  25584. hoverSeries = hoverData.hoverSeries;
  25585. followPointer = hoverSeries && hoverSeries.tooltipOptions.followPointer;
  25586. useSharedTooltip = (shared &&
  25587. hoverSeries &&
  25588. !hoverSeries.noSharedTooltip);
  25589. // Refresh tooltip for kdpoint if new hover point or tooltip was hidden
  25590. // #3926, #4200
  25591. if (hoverPoint &&
  25592. // !(hoverSeries && hoverSeries.directTouch) &&
  25593. (hoverPoint !== chart.hoverPoint || (tooltip && tooltip.isHidden))) {
  25594. (chart.hoverPoints || []).forEach(function (p) {
  25595. if (points.indexOf(p) === -1) {
  25596. p.setState();
  25597. }
  25598. });
  25599. // Set normal state to previous series
  25600. if (chart.hoverSeries !== hoverSeries) {
  25601. hoverSeries.onMouseOver();
  25602. }
  25603. pointer.applyInactiveState(points);
  25604. // Do mouseover on all points (#3919, #3985, #4410, #5622)
  25605. (points || []).forEach(function (p) {
  25606. p.setState('hover');
  25607. });
  25608. // If tracking is on series in stead of on each point,
  25609. // fire mouseOver on hover point. // #4448
  25610. if (chart.hoverPoint) {
  25611. chart.hoverPoint.firePointEvent('mouseOut');
  25612. }
  25613. // Hover point may have been destroyed in the event handlers (#7127)
  25614. if (!hoverPoint.series) {
  25615. return;
  25616. }
  25617. /**
  25618. * Contains all hovered points.
  25619. *
  25620. * @name Highcharts.Chart#hoverPoints
  25621. * @type {Array<Highcharts.Point>|null}
  25622. */
  25623. chart.hoverPoints = points;
  25624. /**
  25625. * Contains the original hovered point.
  25626. *
  25627. * @name Highcharts.Chart#hoverPoint
  25628. * @type {Highcharts.Point|null}
  25629. */
  25630. chart.hoverPoint = hoverPoint;
  25631. /**
  25632. * Hover state should not be lost when axis is updated (#12569)
  25633. * Axis.update runs pointer.reset which uses chart.hoverPoint.state
  25634. * to apply state which does not exist in hoverPoint yet.
  25635. * The mouseOver event should be triggered when hoverPoint
  25636. * is correct.
  25637. */
  25638. hoverPoint.firePointEvent('mouseOver');
  25639. // Draw tooltip if necessary
  25640. if (tooltip) {
  25641. tooltip.refresh(useSharedTooltip ? points : hoverPoint, e);
  25642. }
  25643. // Update positions (regardless of kdpoint or hoverPoint)
  25644. }
  25645. else if (followPointer && tooltip && !tooltip.isHidden) {
  25646. anchor = tooltip.getAnchor([{}], e);
  25647. tooltip.updatePosition({ plotX: anchor[0], plotY: anchor[1] });
  25648. }
  25649. // Start the event listener to pick up the tooltip and crosshairs
  25650. if (!pointer.unDocMouseMove) {
  25651. pointer.unDocMouseMove = addEvent(chart.container.ownerDocument, 'mousemove', function (e) {
  25652. var chart = charts[H.hoverChartIndex];
  25653. if (chart) {
  25654. chart.pointer.onDocumentMouseMove(e);
  25655. }
  25656. });
  25657. }
  25658. // Issues related to crosshair #4927, #5269 #5066, #5658
  25659. chart.axes.forEach(function drawAxisCrosshair(axis) {
  25660. var snap = pick((axis.crosshair || {}).snap,
  25661. true);
  25662. var point;
  25663. if (snap) {
  25664. point = chart.hoverPoint; // #13002
  25665. if (!point || point.series[axis.coll] !== axis) {
  25666. point = find(points, function (p) {
  25667. return p.series[axis.coll] === axis;
  25668. });
  25669. }
  25670. }
  25671. // Axis has snapping crosshairs, and one of the hover points belongs
  25672. // to axis. Always call drawCrosshair when it is not snap.
  25673. if (point || !snap) {
  25674. axis.drawCrosshair(e, point);
  25675. // Axis has snapping crosshairs, but no hover point belongs to axis
  25676. }
  25677. else {
  25678. axis.hideCrosshair();
  25679. }
  25680. });
  25681. };
  25682. /**
  25683. * Scale series groups to a certain scale and translation.
  25684. *
  25685. * @private
  25686. * @function Highcharts.Pointer#scaleGroups
  25687. */
  25688. Pointer.prototype.scaleGroups = function (attribs, clip) {
  25689. var chart = this.chart,
  25690. seriesAttribs;
  25691. // Scale each series
  25692. chart.series.forEach(function (series) {
  25693. seriesAttribs = attribs || series.getPlotBox(); // #1701
  25694. if (series.xAxis && series.xAxis.zoomEnabled && series.group) {
  25695. series.group.attr(seriesAttribs);
  25696. if (series.markerGroup) {
  25697. series.markerGroup.attr(seriesAttribs);
  25698. series.markerGroup.clip(clip ? chart.clipRect : null);
  25699. }
  25700. if (series.dataLabelsGroup) {
  25701. series.dataLabelsGroup.attr(seriesAttribs);
  25702. }
  25703. }
  25704. });
  25705. // Clip
  25706. chart.clipRect.attr(clip || chart.clipBox);
  25707. };
  25708. /**
  25709. * Set the JS DOM events on the container and document. This method should
  25710. * contain a one-to-one assignment between methods and their handlers. Any
  25711. * advanced logic should be moved to the handler reflecting the event's
  25712. * name.
  25713. *
  25714. * @private
  25715. * @function Highcharts.Pointer#setDOMEvents
  25716. */
  25717. Pointer.prototype.setDOMEvents = function () {
  25718. var _this = this;
  25719. var container = this.chart.container,
  25720. ownerDoc = container.ownerDocument;
  25721. container.onmousedown = this.onContainerMouseDown.bind(this);
  25722. container.onmousemove = this.onContainerMouseMove.bind(this);
  25723. container.onclick = this.onContainerClick.bind(this);
  25724. this.unbindContainerMouseEnter = addEvent(container, 'mouseenter', this.onContainerMouseEnter.bind(this));
  25725. this.unbindContainerMouseLeave = addEvent(container, 'mouseleave', this.onContainerMouseLeave.bind(this));
  25726. if (!H.unbindDocumentMouseUp) {
  25727. H.unbindDocumentMouseUp = addEvent(ownerDoc, 'mouseup', this.onDocumentMouseUp.bind(this));
  25728. }
  25729. // In case we are dealing with overflow, reset the chart position when
  25730. // scrolling parent elements
  25731. var parent = this.chart.renderTo.parentElement;
  25732. while (parent && parent.tagName !== 'BODY') {
  25733. addEvent(parent, 'scroll', function () {
  25734. delete _this.chartPosition;
  25735. });
  25736. parent = parent.parentElement;
  25737. }
  25738. if (H.hasTouch) {
  25739. addEvent(container, 'touchstart', this.onContainerTouchStart.bind(this), { passive: false });
  25740. addEvent(container, 'touchmove', this.onContainerTouchMove.bind(this), { passive: false });
  25741. if (!H.unbindDocumentTouchEnd) {
  25742. H.unbindDocumentTouchEnd = addEvent(ownerDoc, 'touchend', this.onDocumentTouchEnd.bind(this), { passive: false });
  25743. }
  25744. }
  25745. };
  25746. /**
  25747. * Sets the index of the hovered chart and leaves the previous hovered
  25748. * chart, to reset states like tooltip.
  25749. *
  25750. * @private
  25751. * @function Highcharts.Pointer#setHoverChartIndex
  25752. */
  25753. Pointer.prototype.setHoverChartIndex = function () {
  25754. var chart = this.chart;
  25755. var hoverChart = H.charts[pick(H.hoverChartIndex, -1)];
  25756. if (hoverChart &&
  25757. hoverChart !== chart) {
  25758. hoverChart.pointer.onContainerMouseLeave({ relatedTarget: true });
  25759. }
  25760. if (!hoverChart ||
  25761. !hoverChart.mouseIsDown) {
  25762. H.hoverChartIndex = chart.index;
  25763. }
  25764. };
  25765. /**
  25766. * General touch handler shared by touchstart and touchmove.
  25767. *
  25768. * @private
  25769. * @function Highcharts.Pointer#touch
  25770. */
  25771. Pointer.prototype.touch = function (e, start) {
  25772. var chart = this.chart,
  25773. hasMoved,
  25774. pinchDown,
  25775. isInside;
  25776. this.setHoverChartIndex();
  25777. if (e.touches.length === 1) {
  25778. e = this.normalize(e);
  25779. isInside = chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop);
  25780. if (isInside && !chart.openMenu) {
  25781. // Run mouse events and display tooltip etc
  25782. if (start) {
  25783. this.runPointActions(e);
  25784. }
  25785. // Android fires touchmove events after the touchstart even if
  25786. // the finger hasn't moved, or moved only a pixel or two. In iOS
  25787. // however, the touchmove doesn't fire unless the finger moves
  25788. // more than ~4px. So we emulate this behaviour in Android by
  25789. // checking how much it moved, and cancelling on small
  25790. // distances. #3450.
  25791. if (e.type === 'touchmove') {
  25792. pinchDown = this.pinchDown;
  25793. hasMoved = pinchDown[0] ? Math.sqrt(// #5266
  25794. Math.pow(pinchDown[0].chartX - e.chartX, 2) +
  25795. Math.pow(pinchDown[0].chartY - e.chartY, 2)) >= 4 : false;
  25796. }
  25797. if (pick(hasMoved, true)) {
  25798. this.pinch(e);
  25799. }
  25800. }
  25801. else if (start) {
  25802. // Hide the tooltip on touching outside the plot area (#1203)
  25803. this.reset();
  25804. }
  25805. }
  25806. else if (e.touches.length === 2) {
  25807. this.pinch(e);
  25808. }
  25809. };
  25810. /**
  25811. * Returns true if the chart is set up for zooming by single touch and the
  25812. * event is capable
  25813. * @param {PointEvent} e
  25814. * Event object
  25815. */
  25816. Pointer.prototype.touchSelect = function (e) {
  25817. return Boolean(this.chart.options.chart.zoomBySingleTouch &&
  25818. e.touches &&
  25819. e.touches.length === 1);
  25820. };
  25821. /**
  25822. * Resolve the zoomType option, this is reset on all touch start and mouse
  25823. * down events.
  25824. *
  25825. * @private
  25826. * @function Highcharts.Pointer#zoomOption
  25827. *
  25828. * @param {global.Event} e
  25829. * Event object.
  25830. *
  25831. * @param {void}
  25832. */
  25833. Pointer.prototype.zoomOption = function (e) {
  25834. var chart = this.chart,
  25835. options = chart.options.chart,
  25836. zoomType = options.zoomType || '',
  25837. inverted = chart.inverted,
  25838. zoomX,
  25839. zoomY;
  25840. // Look for the pinchType option
  25841. if (/touch/.test(e.type)) {
  25842. zoomType = pick(options.pinchType, zoomType);
  25843. }
  25844. this.zoomX = zoomX = /x/.test(zoomType);
  25845. this.zoomY = zoomY = /y/.test(zoomType);
  25846. this.zoomHor = (zoomX && !inverted) || (zoomY && inverted);
  25847. this.zoomVert = (zoomY && !inverted) || (zoomX && inverted);
  25848. this.hasZoom = zoomX || zoomY;
  25849. };
  25850. return Pointer;
  25851. }());
  25852. H.Pointer = Pointer;
  25853. return Pointer;
  25854. });
  25855. _registerModule(_modules, 'Core/MSPointer.js', [_modules['Core/Globals.js'], _modules['Core/Pointer.js'], _modules['Core/Utilities.js']], function (H, Pointer, U) {
  25856. /* *
  25857. *
  25858. * (c) 2010-2021 Torstein Honsi
  25859. *
  25860. * License: www.highcharts.com/license
  25861. *
  25862. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  25863. *
  25864. * */
  25865. var __extends = (this && this.__extends) || (function () {
  25866. var extendStatics = function (d,
  25867. b) {
  25868. extendStatics = Object.setPrototypeOf ||
  25869. ({ __proto__: [] } instanceof Array && function (d,
  25870. b) { d.__proto__ = b; }) ||
  25871. function (d,
  25872. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  25873. return extendStatics(d, b);
  25874. };
  25875. return function (d, b) {
  25876. extendStatics(d, b);
  25877. function __() { this.constructor = d; }
  25878. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  25879. };
  25880. })();
  25881. var charts = H.charts,
  25882. doc = H.doc,
  25883. noop = H.noop,
  25884. win = H.win;
  25885. var addEvent = U.addEvent,
  25886. css = U.css,
  25887. objectEach = U.objectEach,
  25888. removeEvent = U.removeEvent;
  25889. /* globals MSPointerEvent, PointerEvent */
  25890. // The touches object keeps track of the points being touched at all times
  25891. var touches = {};
  25892. var hasPointerEvent = !!win.PointerEvent;
  25893. /* eslint-disable valid-jsdoc */
  25894. /** @private */
  25895. function getWebkitTouches() {
  25896. var fake = [];
  25897. fake.item = function (i) {
  25898. return this[i];
  25899. };
  25900. objectEach(touches, function (touch) {
  25901. fake.push({
  25902. pageX: touch.pageX,
  25903. pageY: touch.pageY,
  25904. target: touch.target
  25905. });
  25906. });
  25907. return fake;
  25908. }
  25909. /** @private */
  25910. function translateMSPointer(e, method, wktype, func) {
  25911. var p;
  25912. if ((e.pointerType === 'touch' ||
  25913. e.pointerType === e.MSPOINTER_TYPE_TOUCH) && charts[H.hoverChartIndex]) {
  25914. func(e);
  25915. p = charts[H.hoverChartIndex].pointer;
  25916. p[method]({
  25917. type: wktype,
  25918. target: e.currentTarget,
  25919. preventDefault: noop,
  25920. touches: getWebkitTouches()
  25921. });
  25922. }
  25923. }
  25924. /** @private */
  25925. var MSPointer = /** @class */ (function (_super) {
  25926. __extends(MSPointer, _super);
  25927. function MSPointer() {
  25928. return _super !== null && _super.apply(this, arguments) || this;
  25929. }
  25930. /* *
  25931. *
  25932. * Functions
  25933. *
  25934. * */
  25935. /**
  25936. * Add or remove the MS Pointer specific events
  25937. *
  25938. * @private
  25939. * @function Highcharts.Pointer#batchMSEvents
  25940. *
  25941. * @param {Function} fn
  25942. *
  25943. * @return {void}
  25944. */
  25945. MSPointer.prototype.batchMSEvents = function (fn) {
  25946. fn(this.chart.container, hasPointerEvent ? 'pointerdown' : 'MSPointerDown', this.onContainerPointerDown);
  25947. fn(this.chart.container, hasPointerEvent ? 'pointermove' : 'MSPointerMove', this.onContainerPointerMove);
  25948. fn(doc, hasPointerEvent ? 'pointerup' : 'MSPointerUp', this.onDocumentPointerUp);
  25949. };
  25950. // Destroy MS events also
  25951. MSPointer.prototype.destroy = function () {
  25952. this.batchMSEvents(removeEvent);
  25953. _super.prototype.destroy.call(this);
  25954. };
  25955. // Disable default IE actions for pinch and such on chart element
  25956. MSPointer.prototype.init = function (chart, options) {
  25957. _super.prototype.init.call(this, chart, options);
  25958. if (this.hasZoom) { // #4014
  25959. css(chart.container, {
  25960. '-ms-touch-action': 'none',
  25961. 'touch-action': 'none'
  25962. });
  25963. }
  25964. };
  25965. /**
  25966. * @private
  25967. * @function Highcharts.Pointer#onContainerPointerDown
  25968. *
  25969. * @param {Highcharts.PointerEventObject} e
  25970. *
  25971. * @return {void}
  25972. */
  25973. MSPointer.prototype.onContainerPointerDown = function (e) {
  25974. translateMSPointer(e, 'onContainerTouchStart', 'touchstart', function (e) {
  25975. touches[e.pointerId] = {
  25976. pageX: e.pageX,
  25977. pageY: e.pageY,
  25978. target: e.currentTarget
  25979. };
  25980. });
  25981. };
  25982. /**
  25983. * @private
  25984. * @function Highcharts.Pointer#onContainerPointerMove
  25985. *
  25986. * @param {Highcharts.PointerEventObject} e
  25987. *
  25988. * @return {void}
  25989. */
  25990. MSPointer.prototype.onContainerPointerMove = function (e) {
  25991. translateMSPointer(e, 'onContainerTouchMove', 'touchmove', function (e) {
  25992. touches[e.pointerId] = ({ pageX: e.pageX, pageY: e.pageY });
  25993. if (!touches[e.pointerId].target) {
  25994. touches[e.pointerId].target = e.currentTarget;
  25995. }
  25996. });
  25997. };
  25998. /**
  25999. * @private
  26000. * @function Highcharts.Pointer#onDocumentPointerUp
  26001. *
  26002. * @param {Highcharts.PointerEventObject} e
  26003. *
  26004. * @return {void}
  26005. */
  26006. MSPointer.prototype.onDocumentPointerUp = function (e) {
  26007. translateMSPointer(e, 'onDocumentTouchEnd', 'touchend', function (e) {
  26008. delete touches[e.pointerId];
  26009. });
  26010. };
  26011. // Add IE specific touch events to chart
  26012. MSPointer.prototype.setDOMEvents = function () {
  26013. _super.prototype.setDOMEvents.call(this);
  26014. if (this.hasZoom || this.followTouchMove) {
  26015. this.batchMSEvents(addEvent);
  26016. }
  26017. };
  26018. return MSPointer;
  26019. }(Pointer));
  26020. return MSPointer;
  26021. });
  26022. _registerModule(_modules, 'Core/Series/Point.js', [_modules['Core/Renderer/HTML/AST.js'], _modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Globals.js'], _modules['Core/Options.js'], _modules['Core/Utilities.js']], function (AST, A, H, O, U) {
  26023. /* *
  26024. *
  26025. * (c) 2010-2021 Torstein Honsi
  26026. *
  26027. * License: www.highcharts.com/license
  26028. *
  26029. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  26030. *
  26031. * */
  26032. var animObject = A.animObject;
  26033. var defaultOptions = O.defaultOptions;
  26034. var addEvent = U.addEvent,
  26035. defined = U.defined,
  26036. erase = U.erase,
  26037. extend = U.extend,
  26038. fireEvent = U.fireEvent,
  26039. format = U.format,
  26040. getNestedProperty = U.getNestedProperty,
  26041. isArray = U.isArray,
  26042. isFunction = U.isFunction,
  26043. isNumber = U.isNumber,
  26044. isObject = U.isObject,
  26045. merge = U.merge,
  26046. objectEach = U.objectEach,
  26047. pick = U.pick,
  26048. syncTimeout = U.syncTimeout,
  26049. removeEvent = U.removeEvent,
  26050. uniqueKey = U.uniqueKey;
  26051. /**
  26052. * Function callback when a series point is clicked. Return false to cancel the
  26053. * action.
  26054. *
  26055. * @callback Highcharts.PointClickCallbackFunction
  26056. *
  26057. * @param {Highcharts.Point} this
  26058. * The point where the event occured.
  26059. *
  26060. * @param {Highcharts.PointClickEventObject} event
  26061. * Event arguments.
  26062. */
  26063. /**
  26064. * Common information for a click event on a series point.
  26065. *
  26066. * @interface Highcharts.PointClickEventObject
  26067. * @extends Highcharts.PointerEventObject
  26068. */ /**
  26069. * Clicked point.
  26070. * @name Highcharts.PointClickEventObject#point
  26071. * @type {Highcharts.Point}
  26072. */
  26073. /**
  26074. * Configuration hash for the data label and tooltip formatters.
  26075. *
  26076. * @interface Highcharts.PointLabelObject
  26077. */ /**
  26078. * The point's current color.
  26079. * @name Highcharts.PointLabelObject#color
  26080. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject|undefined}
  26081. */ /**
  26082. * The point's current color index, used in styled mode instead of `color`. The
  26083. * color index is inserted in class names used for styling.
  26084. * @name Highcharts.PointLabelObject#colorIndex
  26085. * @type {number}
  26086. */ /**
  26087. * The name of the related point.
  26088. * @name Highcharts.PointLabelObject#key
  26089. * @type {string|undefined}
  26090. */ /**
  26091. * The percentage for related points in a stacked series or pies.
  26092. * @name Highcharts.PointLabelObject#percentage
  26093. * @type {number}
  26094. */ /**
  26095. * The related point. The point name, if defined, is available through
  26096. * `this.point.name`.
  26097. * @name Highcharts.PointLabelObject#point
  26098. * @type {Highcharts.Point}
  26099. */ /**
  26100. * The related series. The series name is available through `this.series.name`.
  26101. * @name Highcharts.PointLabelObject#series
  26102. * @type {Highcharts.Series}
  26103. */ /**
  26104. * The total of values in either a stack for stacked series, or a pie in a pie
  26105. * series.
  26106. * @name Highcharts.PointLabelObject#total
  26107. * @type {number|undefined}
  26108. */ /**
  26109. * For categorized axes this property holds the category name for the point. For
  26110. * other axes it holds the X value.
  26111. * @name Highcharts.PointLabelObject#x
  26112. * @type {number|string|undefined}
  26113. */ /**
  26114. * The y value of the point.
  26115. * @name Highcharts.PointLabelObject#y
  26116. * @type {number|undefined}
  26117. */
  26118. /**
  26119. * Gets fired when the mouse leaves the area close to the point.
  26120. *
  26121. * @callback Highcharts.PointMouseOutCallbackFunction
  26122. *
  26123. * @param {Highcharts.Point} this
  26124. * Point where the event occured.
  26125. *
  26126. * @param {global.PointerEvent} event
  26127. * Event that occured.
  26128. */
  26129. /**
  26130. * Gets fired when the mouse enters the area close to the point.
  26131. *
  26132. * @callback Highcharts.PointMouseOverCallbackFunction
  26133. *
  26134. * @param {Highcharts.Point} this
  26135. * Point where the event occured.
  26136. *
  26137. * @param {global.Event} event
  26138. * Event that occured.
  26139. */
  26140. /**
  26141. * The generic point options for all series.
  26142. *
  26143. * In TypeScript you have to extend `PointOptionsObject` with an additional
  26144. * declaration to allow custom data options:
  26145. *
  26146. * ```
  26147. * declare interface PointOptionsObject {
  26148. * customProperty: string;
  26149. * }
  26150. * ```
  26151. *
  26152. * @interface Highcharts.PointOptionsObject
  26153. */
  26154. /**
  26155. * Possible option types for a data point. Use `null` to indicate a gap.
  26156. *
  26157. * @typedef {number|string|Highcharts.PointOptionsObject|Array<(number|string|null)>|null} Highcharts.PointOptionsType
  26158. */
  26159. /**
  26160. * Gets fired when the point is removed using the `.remove()` method.
  26161. *
  26162. * @callback Highcharts.PointRemoveCallbackFunction
  26163. *
  26164. * @param {Highcharts.Point} this
  26165. * Point where the event occured.
  26166. *
  26167. * @param {global.Event} event
  26168. * Event that occured.
  26169. */
  26170. /**
  26171. * Possible key values for the point state options.
  26172. *
  26173. * @typedef {"hover"|"inactive"|"normal"|"select"} Highcharts.PointStateValue
  26174. */
  26175. /**
  26176. * Gets fired when the point is updated programmatically through the `.update()`
  26177. * method.
  26178. *
  26179. * @callback Highcharts.PointUpdateCallbackFunction
  26180. *
  26181. * @param {Highcharts.Point} this
  26182. * Point where the event occured.
  26183. *
  26184. * @param {Highcharts.PointUpdateEventObject} event
  26185. * Event that occured.
  26186. */
  26187. /**
  26188. * Information about the update event.
  26189. *
  26190. * @interface Highcharts.PointUpdateEventObject
  26191. * @extends global.Event
  26192. */ /**
  26193. * Options data of the update event.
  26194. * @name Highcharts.PointUpdateEventObject#options
  26195. * @type {Highcharts.PointOptionsType}
  26196. */
  26197. /**
  26198. * @interface Highcharts.PointEventsOptionsObject
  26199. */ /**
  26200. * Fires when the point is selected either programmatically or following a click
  26201. * on the point. One parameter, `event`, is passed to the function. Returning
  26202. * `false` cancels the operation.
  26203. * @name Highcharts.PointEventsOptionsObject#select
  26204. * @type {Highcharts.PointSelectCallbackFunction|undefined}
  26205. */ /**
  26206. * Fires when the point is unselected either programmatically or following a
  26207. * click on the point. One parameter, `event`, is passed to the function.
  26208. * Returning `false` cancels the operation.
  26209. * @name Highcharts.PointEventsOptionsObject#unselect
  26210. * @type {Highcharts.PointUnselectCallbackFunction|undefined}
  26211. */
  26212. /**
  26213. * Information about the select/unselect event.
  26214. *
  26215. * @interface Highcharts.PointInteractionEventObject
  26216. * @extends global.Event
  26217. */ /**
  26218. * @name Highcharts.PointInteractionEventObject#accumulate
  26219. * @type {boolean}
  26220. */
  26221. /**
  26222. * Gets fired when the point is selected either programmatically or following a
  26223. * click on the point.
  26224. *
  26225. * @callback Highcharts.PointSelectCallbackFunction
  26226. *
  26227. * @param {Highcharts.Point} this
  26228. * Point where the event occured.
  26229. *
  26230. * @param {Highcharts.PointInteractionEventObject} event
  26231. * Event that occured.
  26232. */
  26233. /**
  26234. * Fires when the point is unselected either programmatically or following a
  26235. * click on the point.
  26236. *
  26237. * @callback Highcharts.PointUnselectCallbackFunction
  26238. *
  26239. * @param {Highcharts.Point} this
  26240. * Point where the event occured.
  26241. *
  26242. * @param {Highcharts.PointInteractionEventObject} event
  26243. * Event that occured.
  26244. */
  26245. ''; // detach doclet above
  26246. /* eslint-disable no-invalid-this, valid-jsdoc */
  26247. /**
  26248. * The Point object. The point objects are generated from the `series.data`
  26249. * configuration objects or raw numbers. They can be accessed from the
  26250. * `Series.points` array. Other ways to instantiate points are through {@link
  26251. * Highcharts.Series#addPoint} or {@link Highcharts.Series#setData}.
  26252. *
  26253. * @class
  26254. * @name Highcharts.Point
  26255. */
  26256. var Point = /** @class */ (function () {
  26257. function Point() {
  26258. /* *
  26259. *
  26260. * Properties
  26261. *
  26262. * */
  26263. /**
  26264. * For categorized axes this property holds the category name for the
  26265. * point. For other axes it holds the X value.
  26266. *
  26267. * @name Highcharts.Point#category
  26268. * @type {string}
  26269. */
  26270. this.category = void 0;
  26271. /**
  26272. * The point's current color index, used in styled mode instead of
  26273. * `color`. The color index is inserted in class names used for styling.
  26274. *
  26275. * @name Highcharts.Point#colorIndex
  26276. * @type {number}
  26277. */
  26278. this.colorIndex = void 0;
  26279. this.formatPrefix = 'point';
  26280. this.id = void 0;
  26281. this.isNull = false;
  26282. /**
  26283. * The name of the point. The name can be given as the first position of the
  26284. * point configuration array, or as a `name` property in the configuration:
  26285. *
  26286. * @example
  26287. * // Array config
  26288. * data: [
  26289. * ['John', 1],
  26290. * ['Jane', 2]
  26291. * ]
  26292. *
  26293. * // Object config
  26294. * data: [{
  26295. * name: 'John',
  26296. * y: 1
  26297. * }, {
  26298. * name: 'Jane',
  26299. * y: 2
  26300. * }]
  26301. *
  26302. * @name Highcharts.Point#name
  26303. * @type {string}
  26304. */
  26305. this.name = void 0;
  26306. /**
  26307. * The point's options as applied in the initial configuration, or
  26308. * extended through `Point.update`.
  26309. *
  26310. * In TypeScript you have to extend `PointOptionsObject` via an
  26311. * additional interface to allow custom data options:
  26312. *
  26313. * ```
  26314. * declare interface PointOptionsObject {
  26315. * customProperty: string;
  26316. * }
  26317. * ```
  26318. *
  26319. * @name Highcharts.Point#options
  26320. * @type {Highcharts.PointOptionsObject}
  26321. */
  26322. this.options = void 0;
  26323. /**
  26324. * The percentage for points in a stacked series or pies.
  26325. *
  26326. * @name Highcharts.Point#percentage
  26327. * @type {number|undefined}
  26328. */
  26329. this.percentage = void 0;
  26330. this.selected = false;
  26331. /**
  26332. * The series object associated with the point.
  26333. *
  26334. * @name Highcharts.Point#series
  26335. * @type {Highcharts.Series}
  26336. */
  26337. this.series = void 0;
  26338. /**
  26339. * The total of values in either a stack for stacked series, or a pie in a
  26340. * pie series.
  26341. *
  26342. * @name Highcharts.Point#total
  26343. * @type {number|undefined}
  26344. */
  26345. this.total = void 0;
  26346. /**
  26347. * For certain series types, like pie charts, where individual points can
  26348. * be shown or hidden.
  26349. *
  26350. * @name Highcharts.Point#visible
  26351. * @type {boolean}
  26352. * @default true
  26353. */
  26354. this.visible = true;
  26355. this.x = void 0;
  26356. }
  26357. /* *
  26358. *
  26359. * Functions
  26360. *
  26361. * */
  26362. /**
  26363. * Animate SVG elements associated with the point.
  26364. *
  26365. * @private
  26366. * @function Highcharts.Point#animateBeforeDestroy
  26367. */
  26368. Point.prototype.animateBeforeDestroy = function () {
  26369. var point = this,
  26370. animateParams = { x: point.startXPos,
  26371. opacity: 0 },
  26372. isDataLabel,
  26373. graphicalProps = point.getGraphicalProps();
  26374. graphicalProps.singular.forEach(function (prop) {
  26375. isDataLabel = prop === 'dataLabel';
  26376. point[prop] = point[prop].animate(isDataLabel ? {
  26377. x: point[prop].startXPos,
  26378. y: point[prop].startYPos,
  26379. opacity: 0
  26380. } : animateParams);
  26381. });
  26382. graphicalProps.plural.forEach(function (plural) {
  26383. point[plural].forEach(function (item) {
  26384. if (item.element) {
  26385. item.animate(extend({ x: point.startXPos }, (item.startYPos ? {
  26386. x: item.startXPos,
  26387. y: item.startYPos
  26388. } : {})));
  26389. }
  26390. });
  26391. });
  26392. };
  26393. /**
  26394. * Apply the options containing the x and y data and possible some extra
  26395. * properties. Called on point init or from point.update.
  26396. *
  26397. * @private
  26398. * @function Highcharts.Point#applyOptions
  26399. *
  26400. * @param {Highcharts.PointOptionsType} options
  26401. * The point options as defined in series.data.
  26402. *
  26403. * @param {number} [x]
  26404. * Optionally, the x value.
  26405. *
  26406. * @return {Highcharts.Point}
  26407. * The Point instance.
  26408. */
  26409. Point.prototype.applyOptions = function (options, x) {
  26410. var point = this,
  26411. series = point.series,
  26412. pointValKey = series.options.pointValKey || series.pointValKey;
  26413. options = Point.prototype.optionsToObject.call(this, options);
  26414. // copy options directly to point
  26415. extend(point, options);
  26416. point.options = point.options ? extend(point.options, options) : options;
  26417. // Since options are copied into the Point instance, some accidental
  26418. // options must be shielded (#5681)
  26419. if (options.group) {
  26420. delete point.group;
  26421. }
  26422. if (options.dataLabels) {
  26423. delete point.dataLabels;
  26424. }
  26425. /**
  26426. * The y value of the point.
  26427. * @name Highcharts.Point#y
  26428. * @type {number|undefined}
  26429. */
  26430. // For higher dimension series types. For instance, for ranges, point.y
  26431. // is mapped to point.low.
  26432. if (pointValKey) {
  26433. point.y = Point.prototype.getNestedProperty.call(point, pointValKey);
  26434. }
  26435. point.isNull = pick(point.isValid && !point.isValid(), point.x === null || !isNumber(point.y)); // #3571, check for NaN
  26436. point.formatPrefix = point.isNull ? 'null' : 'point'; // #9233, #10874
  26437. // The point is initially selected by options (#5777)
  26438. if (point.selected) {
  26439. point.state = 'select';
  26440. }
  26441. /**
  26442. * The x value of the point.
  26443. * @name Highcharts.Point#x
  26444. * @type {number}
  26445. */
  26446. // If no x is set by now, get auto incremented value. All points must
  26447. // have an x value, however the y value can be null to create a gap in
  26448. // the series
  26449. if ('name' in point &&
  26450. typeof x === 'undefined' &&
  26451. series.xAxis &&
  26452. series.xAxis.hasNames) {
  26453. point.x = series.xAxis.nameToX(point);
  26454. }
  26455. if (typeof point.x === 'undefined' && series) {
  26456. if (typeof x === 'undefined') {
  26457. point.x = series.autoIncrement(point);
  26458. }
  26459. else {
  26460. point.x = x;
  26461. }
  26462. }
  26463. return point;
  26464. };
  26465. /**
  26466. * Destroy a point to clear memory. Its reference still stays in
  26467. * `series.data`.
  26468. *
  26469. * @private
  26470. * @function Highcharts.Point#destroy
  26471. */
  26472. Point.prototype.destroy = function () {
  26473. var point = this,
  26474. series = point.series,
  26475. chart = series.chart,
  26476. dataSorting = series.options.dataSorting,
  26477. hoverPoints = chart.hoverPoints,
  26478. globalAnimation = point.series.chart.renderer.globalAnimation,
  26479. animation = animObject(globalAnimation),
  26480. prop;
  26481. /**
  26482. * Allow to call after animation.
  26483. * @private
  26484. */
  26485. function destroyPoint() {
  26486. // Remove all events and elements
  26487. if (point.graphic || point.dataLabel || point.dataLabels) {
  26488. removeEvent(point);
  26489. point.destroyElements();
  26490. }
  26491. for (prop in point) { // eslint-disable-line guard-for-in
  26492. point[prop] = null;
  26493. }
  26494. }
  26495. if (point.legendItem) { // pies have legend items
  26496. chart.legend.destroyItem(point);
  26497. }
  26498. if (hoverPoints) {
  26499. point.setState();
  26500. erase(hoverPoints, point);
  26501. if (!hoverPoints.length) {
  26502. chart.hoverPoints = null;
  26503. }
  26504. }
  26505. if (point === chart.hoverPoint) {
  26506. point.onMouseOut();
  26507. }
  26508. // Remove properties after animation
  26509. if (!dataSorting || !dataSorting.enabled) {
  26510. destroyPoint();
  26511. }
  26512. else {
  26513. this.animateBeforeDestroy();
  26514. syncTimeout(destroyPoint, animation.duration);
  26515. }
  26516. chart.pointCount--;
  26517. };
  26518. /**
  26519. * Destroy SVG elements associated with the point.
  26520. *
  26521. * @private
  26522. * @function Highcharts.Point#destroyElements
  26523. * @param {Highcharts.Dictionary<number>} [kinds]
  26524. */
  26525. Point.prototype.destroyElements = function (kinds) {
  26526. var point = this,
  26527. props = point.getGraphicalProps(kinds);
  26528. props.singular.forEach(function (prop) {
  26529. point[prop] = point[prop].destroy();
  26530. });
  26531. props.plural.forEach(function (plural) {
  26532. point[plural].forEach(function (item) {
  26533. if (item.element) {
  26534. item.destroy();
  26535. }
  26536. });
  26537. delete point[plural];
  26538. });
  26539. };
  26540. /**
  26541. * Fire an event on the Point object.
  26542. *
  26543. * @private
  26544. * @function Highcharts.Point#firePointEvent
  26545. *
  26546. * @param {string} eventType
  26547. * Type of the event.
  26548. *
  26549. * @param {Highcharts.Dictionary<any>|Event} [eventArgs]
  26550. * Additional event arguments.
  26551. *
  26552. * @param {Highcharts.EventCallbackFunction<Highcharts.Point>|Function} [defaultFunction]
  26553. * Default event handler.
  26554. *
  26555. * @fires Highcharts.Point#event:*
  26556. */
  26557. Point.prototype.firePointEvent = function (eventType, eventArgs, defaultFunction) {
  26558. var point = this,
  26559. series = this.series,
  26560. seriesOptions = series.options;
  26561. // load event handlers on demand to save time on mouseover/out
  26562. if (seriesOptions.point.events[eventType] ||
  26563. (point.options &&
  26564. point.options.events &&
  26565. point.options.events[eventType])) {
  26566. point.importEvents();
  26567. }
  26568. // add default handler if in selection mode
  26569. if (eventType === 'click' && seriesOptions.allowPointSelect) {
  26570. defaultFunction = function (event) {
  26571. // Control key is for Windows, meta (= Cmd key) for Mac, Shift
  26572. // for Opera.
  26573. if (point.select) { // #2911
  26574. point.select(null, event.ctrlKey || event.metaKey || event.shiftKey);
  26575. }
  26576. };
  26577. }
  26578. fireEvent(point, eventType, eventArgs, defaultFunction);
  26579. };
  26580. /**
  26581. * Get the CSS class names for individual points. Used internally where the
  26582. * returned value is set on every point.
  26583. *
  26584. * @function Highcharts.Point#getClassName
  26585. *
  26586. * @return {string}
  26587. * The class names.
  26588. */
  26589. Point.prototype.getClassName = function () {
  26590. var point = this;
  26591. return 'highcharts-point' +
  26592. (point.selected ? ' highcharts-point-select' : '') +
  26593. (point.negative ? ' highcharts-negative' : '') +
  26594. (point.isNull ? ' highcharts-null-point' : '') +
  26595. (typeof point.colorIndex !== 'undefined' ?
  26596. ' highcharts-color-' + point.colorIndex : '') +
  26597. (point.options.className ? ' ' + point.options.className : '') +
  26598. (point.zone && point.zone.className ? ' ' +
  26599. point.zone.className.replace('highcharts-negative', '') : '');
  26600. };
  26601. /**
  26602. * Get props of all existing graphical point elements.
  26603. *
  26604. * @private
  26605. * @function Highcharts.Point#getGraphicalProps
  26606. * @param {Highcharts.Dictionary<number>} [kinds]
  26607. * @return {Highcharts.PointGraphicalProps}
  26608. */
  26609. Point.prototype.getGraphicalProps = function (kinds) {
  26610. var point = this,
  26611. props = [],
  26612. prop,
  26613. i,
  26614. graphicalProps = { singular: [],
  26615. plural: [] };
  26616. kinds = kinds || { graphic: 1, dataLabel: 1 };
  26617. if (kinds.graphic) {
  26618. props.push('graphic', 'upperGraphic', 'shadowGroup');
  26619. }
  26620. if (kinds.dataLabel) {
  26621. props.push('dataLabel', 'dataLabelUpper', 'connector');
  26622. }
  26623. i = props.length;
  26624. while (i--) {
  26625. prop = props[i];
  26626. if (point[prop]) {
  26627. graphicalProps.singular.push(prop);
  26628. }
  26629. }
  26630. ['dataLabel', 'connector'].forEach(function (prop) {
  26631. var plural = prop + 's';
  26632. if (kinds[prop] && point[plural]) {
  26633. graphicalProps.plural.push(plural);
  26634. }
  26635. });
  26636. return graphicalProps;
  26637. };
  26638. /**
  26639. * Return the configuration hash needed for the data label and tooltip
  26640. * formatters.
  26641. *
  26642. * @function Highcharts.Point#getLabelConfig
  26643. *
  26644. * @return {Highcharts.PointLabelObject}
  26645. * Abstract object used in formatters and formats.
  26646. */
  26647. Point.prototype.getLabelConfig = function () {
  26648. return {
  26649. x: this.category,
  26650. y: this.y,
  26651. color: this.color,
  26652. colorIndex: this.colorIndex,
  26653. key: this.name || this.category,
  26654. series: this.series,
  26655. point: this,
  26656. percentage: this.percentage,
  26657. total: this.total || this.stackTotal
  26658. };
  26659. };
  26660. /**
  26661. * Returns the value of the point property for a given value.
  26662. * @private
  26663. */
  26664. Point.prototype.getNestedProperty = function (key) {
  26665. if (!key) {
  26666. return;
  26667. }
  26668. if (key.indexOf('custom.') === 0) {
  26669. return getNestedProperty(key, this.options);
  26670. }
  26671. return this[key];
  26672. };
  26673. /**
  26674. * In a series with `zones`, return the zone that the point belongs to.
  26675. *
  26676. * @function Highcharts.Point#getZone
  26677. *
  26678. * @return {Highcharts.SeriesZonesOptionsObject}
  26679. * The zone item.
  26680. */
  26681. Point.prototype.getZone = function () {
  26682. var series = this.series,
  26683. zones = series.zones,
  26684. zoneAxis = series.zoneAxis || 'y',
  26685. i = 0,
  26686. zone;
  26687. zone = zones[i];
  26688. while (this[zoneAxis] >= zone.value) {
  26689. zone = zones[++i];
  26690. }
  26691. // For resetting or reusing the point (#8100)
  26692. if (!this.nonZonedColor) {
  26693. this.nonZonedColor = this.color;
  26694. }
  26695. if (zone && zone.color && !this.options.color) {
  26696. this.color = zone.color;
  26697. }
  26698. else {
  26699. this.color = this.nonZonedColor;
  26700. }
  26701. return zone;
  26702. };
  26703. /**
  26704. * Utility to check if point has new shape type. Used in column series and
  26705. * all others that are based on column series.
  26706. *
  26707. * @return boolean|undefined
  26708. */
  26709. Point.prototype.hasNewShapeType = function () {
  26710. var point = this;
  26711. var oldShapeType = point.graphic &&
  26712. (point.graphic.symbolName || point.graphic.element.nodeName);
  26713. return oldShapeType !== this.shapeType;
  26714. };
  26715. /**
  26716. * Initialize the point. Called internally based on the `series.data`
  26717. * option.
  26718. *
  26719. * @function Highcharts.Point#init
  26720. *
  26721. * @param {Highcharts.Series} series
  26722. * The series object containing this point.
  26723. *
  26724. * @param {Highcharts.PointOptionsType} options
  26725. * The data in either number, array or object format.
  26726. *
  26727. * @param {number} [x]
  26728. * Optionally, the X value of the point.
  26729. *
  26730. * @return {Highcharts.Point}
  26731. * The Point instance.
  26732. *
  26733. * @fires Highcharts.Point#event:afterInit
  26734. */
  26735. Point.prototype.init = function (series, options, x) {
  26736. this.series = series;
  26737. this.applyOptions(options, x);
  26738. // Add a unique ID to the point if none is assigned
  26739. this.id = defined(this.id) ? this.id : uniqueKey();
  26740. this.resolveColor();
  26741. series.chart.pointCount++;
  26742. fireEvent(this, 'afterInit');
  26743. return this;
  26744. };
  26745. /**
  26746. * Transform number or array configs into objects. Also called for object
  26747. * configs. Used internally to unify the different configuration formats for
  26748. * points. For example, a simple number `10` in a line series will be
  26749. * transformed to `{ y: 10 }`, and an array config like `[1, 10]` in a
  26750. * scatter series will be transformed to `{ x: 1, y: 10 }`.
  26751. *
  26752. * @function Highcharts.Point#optionsToObject
  26753. *
  26754. * @param {Highcharts.PointOptionsType} options
  26755. * The input option.
  26756. *
  26757. * @return {Highcharts.Dictionary<*>}
  26758. * Transformed options.
  26759. */
  26760. Point.prototype.optionsToObject = function (options) {
  26761. var ret = {},
  26762. series = this.series,
  26763. keys = series.options.keys,
  26764. pointArrayMap = keys || series.pointArrayMap || ['y'],
  26765. valueCount = pointArrayMap.length,
  26766. firstItemType,
  26767. i = 0,
  26768. j = 0;
  26769. if (isNumber(options) || options === null) {
  26770. ret[pointArrayMap[0]] = options;
  26771. }
  26772. else if (isArray(options)) {
  26773. // with leading x value
  26774. if (!keys && options.length > valueCount) {
  26775. firstItemType = typeof options[0];
  26776. if (firstItemType === 'string') {
  26777. ret.name = options[0];
  26778. }
  26779. else if (firstItemType === 'number') {
  26780. ret.x = options[0];
  26781. }
  26782. i++;
  26783. }
  26784. while (j < valueCount) {
  26785. // Skip undefined positions for keys
  26786. if (!keys || typeof options[i] !== 'undefined') {
  26787. if (pointArrayMap[j].indexOf('.') > 0) {
  26788. // Handle nested keys, e.g. ['color.pattern.image']
  26789. // Avoid function call unless necessary.
  26790. Point.prototype.setNestedProperty(ret, options[i], pointArrayMap[j]);
  26791. }
  26792. else {
  26793. ret[pointArrayMap[j]] = options[i];
  26794. }
  26795. }
  26796. i++;
  26797. j++;
  26798. }
  26799. }
  26800. else if (typeof options === 'object') {
  26801. ret = options;
  26802. // This is the fastest way to detect if there are individual point
  26803. // dataLabels that need to be considered in drawDataLabels. These
  26804. // can only occur in object configs.
  26805. if (options.dataLabels) {
  26806. series._hasPointLabels = true;
  26807. }
  26808. // Same approach as above for markers
  26809. if (options.marker) {
  26810. series._hasPointMarkers = true;
  26811. }
  26812. }
  26813. return ret;
  26814. };
  26815. /**
  26816. * @private
  26817. * @function Highcharts.Point#resolveColor
  26818. * @return {void}
  26819. */
  26820. Point.prototype.resolveColor = function () {
  26821. var series = this.series,
  26822. colors,
  26823. optionsChart = series.chart.options.chart,
  26824. colorCount = optionsChart.colorCount,
  26825. styledMode = series.chart.styledMode,
  26826. colorIndex;
  26827. // remove points nonZonedColor for later recalculation
  26828. delete this.nonZonedColor;
  26829. /**
  26830. * The point's current color.
  26831. *
  26832. * @name Highcharts.Point#color
  26833. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject|undefined}
  26834. */
  26835. if (!styledMode && !this.options.color) {
  26836. this.color = series.color; // #3445
  26837. }
  26838. if (series.options.colorByPoint) {
  26839. if (!styledMode) {
  26840. colors = series.options.colors || series.chart.options.colors;
  26841. this.color = this.color || colors[series.colorCounter];
  26842. colorCount = colors.length;
  26843. }
  26844. colorIndex = series.colorCounter;
  26845. series.colorCounter++;
  26846. // loop back to zero
  26847. if (series.colorCounter === colorCount) {
  26848. series.colorCounter = 0;
  26849. }
  26850. }
  26851. else {
  26852. colorIndex = series.colorIndex;
  26853. }
  26854. this.colorIndex = pick(this.options.colorIndex, colorIndex);
  26855. };
  26856. /**
  26857. * Set a value in an object, on the property defined by key. The key
  26858. * supports nested properties using dot notation. The function modifies the
  26859. * input object and does not make a copy.
  26860. *
  26861. * @function Highcharts.Point#setNestedProperty<T>
  26862. *
  26863. * @param {T} object
  26864. * The object to set the value on.
  26865. *
  26866. * @param {*} value
  26867. * The value to set.
  26868. *
  26869. * @param {string} key
  26870. * Key to the property to set.
  26871. *
  26872. * @return {T}
  26873. * The modified object.
  26874. */
  26875. Point.prototype.setNestedProperty = function (object, value, key) {
  26876. var nestedKeys = key.split('.');
  26877. nestedKeys.reduce(function (result, key, i, arr) {
  26878. var isLastKey = arr.length - 1 === i;
  26879. result[key] = (isLastKey ?
  26880. value :
  26881. isObject(result[key], true) ?
  26882. result[key] :
  26883. {});
  26884. return result[key];
  26885. }, object);
  26886. return object;
  26887. };
  26888. /**
  26889. * Extendable method for formatting each point's tooltip line.
  26890. *
  26891. * @function Highcharts.Point#tooltipFormatter
  26892. *
  26893. * @param {string} pointFormat
  26894. * The point format.
  26895. *
  26896. * @return {string}
  26897. * A string to be concatenated in to the common tooltip text.
  26898. */
  26899. Point.prototype.tooltipFormatter = function (pointFormat) {
  26900. // Insert options for valueDecimals, valuePrefix, and valueSuffix
  26901. var series = this.series, seriesTooltipOptions = series.tooltipOptions, valueDecimals = pick(seriesTooltipOptions.valueDecimals, ''), valuePrefix = seriesTooltipOptions.valuePrefix || '', valueSuffix = seriesTooltipOptions.valueSuffix || '';
  26902. // Replace default point style with class name
  26903. if (series.chart.styledMode) {
  26904. pointFormat =
  26905. series.chart.tooltip.styledModeFormat(pointFormat);
  26906. }
  26907. // Loop over the point array map and replace unformatted values with
  26908. // sprintf formatting markup
  26909. (series.pointArrayMap || ['y']).forEach(function (key) {
  26910. key = '{point.' + key; // without the closing bracket
  26911. if (valuePrefix || valueSuffix) {
  26912. pointFormat = pointFormat.replace(RegExp(key + '}', 'g'), valuePrefix + key + '}' + valueSuffix);
  26913. }
  26914. pointFormat = pointFormat.replace(RegExp(key + '}', 'g'), key + ':,.' + valueDecimals + 'f}');
  26915. });
  26916. return format(pointFormat, {
  26917. point: this,
  26918. series: this.series
  26919. }, series.chart);
  26920. };
  26921. /**
  26922. * Update point with new options (typically x/y data) and optionally redraw
  26923. * the series.
  26924. *
  26925. * @sample highcharts/members/point-update-column/
  26926. * Update column value
  26927. * @sample highcharts/members/point-update-pie/
  26928. * Update pie slice
  26929. * @sample maps/members/point-update/
  26930. * Update map area value in Highmaps
  26931. *
  26932. * @function Highcharts.Point#update
  26933. *
  26934. * @param {Highcharts.PointOptionsType} options
  26935. * The point options. Point options are handled as described under
  26936. * the `series.type.data` item for each series type. For example
  26937. * for a line series, if options is a single number, the point will
  26938. * be given that number as the marin y value. If it is an array, it
  26939. * will be interpreted as x and y values respectively. If it is an
  26940. * object, advanced options are applied.
  26941. *
  26942. * @param {boolean} [redraw=true]
  26943. * Whether to redraw the chart after the point is updated. If doing
  26944. * more operations on the chart, it is best practice to set
  26945. * `redraw` to false and call `chart.redraw()` after.
  26946. *
  26947. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=true]
  26948. * Whether to apply animation, and optionally animation
  26949. * configuration.
  26950. *
  26951. * @fires Highcharts.Point#event:update
  26952. */
  26953. Point.prototype.update = function (options, redraw, animation, runEvent) {
  26954. var point = this,
  26955. series = point.series,
  26956. graphic = point.graphic,
  26957. i,
  26958. chart = series.chart,
  26959. seriesOptions = series.options;
  26960. redraw = pick(redraw, true);
  26961. /**
  26962. * @private
  26963. */
  26964. function update() {
  26965. point.applyOptions(options);
  26966. // Update visuals, #4146
  26967. // Handle dummy graphic elements for a11y, #12718
  26968. var hasDummyGraphic = graphic && point.hasDummyGraphic;
  26969. var shouldDestroyGraphic = point.y === null ? !hasDummyGraphic : hasDummyGraphic;
  26970. if (graphic && shouldDestroyGraphic) {
  26971. point.graphic = graphic.destroy();
  26972. delete point.hasDummyGraphic;
  26973. }
  26974. if (isObject(options, true)) {
  26975. // Destroy so we can get new elements
  26976. if (graphic && graphic.element) {
  26977. // "null" is also a valid symbol
  26978. if (options &&
  26979. options.marker &&
  26980. typeof options.marker.symbol !== 'undefined') {
  26981. point.graphic = graphic.destroy();
  26982. }
  26983. }
  26984. if (options && options.dataLabels && point.dataLabel) {
  26985. point.dataLabel = point.dataLabel.destroy(); // #2468
  26986. }
  26987. if (point.connector) {
  26988. point.connector = point.connector.destroy(); // #7243
  26989. }
  26990. }
  26991. // record changes in the parallel arrays
  26992. i = point.index;
  26993. series.updateParallelArrays(point, i);
  26994. // Record the options to options.data. If the old or the new config
  26995. // is an object, use point options, otherwise use raw options
  26996. // (#4701, #4916).
  26997. seriesOptions.data[i] = (isObject(seriesOptions.data[i], true) ||
  26998. isObject(options, true)) ?
  26999. point.options :
  27000. pick(options, seriesOptions.data[i]);
  27001. // redraw
  27002. series.isDirty = series.isDirtyData = true;
  27003. if (!series.fixedBox && series.hasCartesianSeries) { // #1906, #2320
  27004. chart.isDirtyBox = true;
  27005. }
  27006. if (seriesOptions.legendType === 'point') { // #1831, #1885
  27007. chart.isDirtyLegend = true;
  27008. }
  27009. if (redraw) {
  27010. chart.redraw(animation);
  27011. }
  27012. }
  27013. // Fire the event with a default handler of doing the update
  27014. if (runEvent === false) { // When called from setData
  27015. update();
  27016. }
  27017. else {
  27018. point.firePointEvent('update', { options: options }, update);
  27019. }
  27020. };
  27021. /**
  27022. * Remove a point and optionally redraw the series and if necessary the axes
  27023. *
  27024. * @sample highcharts/plotoptions/series-point-events-remove/
  27025. * Remove point and confirm
  27026. * @sample highcharts/members/point-remove/
  27027. * Remove pie slice
  27028. * @sample maps/members/point-remove/
  27029. * Remove selected points in Highmaps
  27030. *
  27031. * @function Highcharts.Point#remove
  27032. *
  27033. * @param {boolean} [redraw=true]
  27034. * Whether to redraw the chart or wait for an explicit call. When
  27035. * doing more operations on the chart, for example running
  27036. * `point.remove()` in a loop, it is best practice to set `redraw`
  27037. * to false and call `chart.redraw()` after.
  27038. *
  27039. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=false]
  27040. * Whether to apply animation, and optionally animation
  27041. * configuration.
  27042. */
  27043. Point.prototype.remove = function (redraw, animation) {
  27044. this.series.removePoint(this.series.data.indexOf(this), redraw, animation);
  27045. };
  27046. /**
  27047. * Toggle the selection status of a point.
  27048. *
  27049. * @see Highcharts.Chart#getSelectedPoints
  27050. *
  27051. * @sample highcharts/members/point-select/
  27052. * Select a point from a button
  27053. * @sample highcharts/chart/events-selection-points/
  27054. * Select a range of points through a drag selection
  27055. * @sample maps/series/data-id/
  27056. * Select a point in Highmaps
  27057. *
  27058. * @function Highcharts.Point#select
  27059. *
  27060. * @param {boolean} [selected]
  27061. * When `true`, the point is selected. When `false`, the point is
  27062. * unselected. When `null` or `undefined`, the selection state is toggled.
  27063. *
  27064. * @param {boolean} [accumulate=false]
  27065. * When `true`, the selection is added to other selected points.
  27066. * When `false`, other selected points are deselected. Internally in
  27067. * Highcharts, when
  27068. * [allowPointSelect](https://api.highcharts.com/highcharts/plotOptions.series.allowPointSelect)
  27069. * is `true`, selected points are accumulated on Control, Shift or Cmd
  27070. * clicking the point.
  27071. *
  27072. * @fires Highcharts.Point#event:select
  27073. * @fires Highcharts.Point#event:unselect
  27074. */
  27075. Point.prototype.select = function (selected, accumulate) {
  27076. var point = this,
  27077. series = point.series,
  27078. chart = series.chart;
  27079. selected = pick(selected, !point.selected);
  27080. this.selectedStaging = selected;
  27081. // fire the event with the default handler
  27082. point.firePointEvent(selected ? 'select' : 'unselect', { accumulate: accumulate }, function () {
  27083. /**
  27084. * Whether the point is selected or not.
  27085. *
  27086. * @see Point#select
  27087. * @see Chart#getSelectedPoints
  27088. *
  27089. * @name Highcharts.Point#selected
  27090. * @type {boolean}
  27091. */
  27092. point.selected = point.options.selected = selected;
  27093. series.options.data[series.data.indexOf(point)] =
  27094. point.options;
  27095. point.setState(selected && 'select');
  27096. // unselect all other points unless Ctrl or Cmd + click
  27097. if (!accumulate) {
  27098. chart.getSelectedPoints().forEach(function (loopPoint) {
  27099. var loopSeries = loopPoint.series;
  27100. if (loopPoint.selected && loopPoint !== point) {
  27101. loopPoint.selected = loopPoint.options.selected =
  27102. false;
  27103. loopSeries.options.data[loopSeries.data.indexOf(loopPoint)] = loopPoint.options;
  27104. // Programatically selecting a point should restore
  27105. // normal state, but when click happened on other
  27106. // point, set inactive state to match other points
  27107. loopPoint.setState(chart.hoverPoints &&
  27108. loopSeries.options.inactiveOtherPoints ?
  27109. 'inactive' : '');
  27110. loopPoint.firePointEvent('unselect');
  27111. }
  27112. });
  27113. }
  27114. });
  27115. delete this.selectedStaging;
  27116. };
  27117. /**
  27118. * Runs on mouse over the point. Called internally from mouse and touch
  27119. * events.
  27120. *
  27121. * @function Highcharts.Point#onMouseOver
  27122. *
  27123. * @param {Highcharts.PointerEventObject} [e]
  27124. * The event arguments.
  27125. */
  27126. Point.prototype.onMouseOver = function (e) {
  27127. var point = this,
  27128. series = point.series,
  27129. chart = series.chart,
  27130. pointer = chart.pointer;
  27131. e = e ?
  27132. pointer.normalize(e) :
  27133. // In cases where onMouseOver is called directly without an event
  27134. pointer.getChartCoordinatesFromPoint(point, chart.inverted);
  27135. pointer.runPointActions(e, point);
  27136. };
  27137. /**
  27138. * Runs on mouse out from the point. Called internally from mouse and touch
  27139. * events.
  27140. *
  27141. * @function Highcharts.Point#onMouseOut
  27142. * @fires Highcharts.Point#event:mouseOut
  27143. */
  27144. Point.prototype.onMouseOut = function () {
  27145. var point = this,
  27146. chart = point.series.chart;
  27147. point.firePointEvent('mouseOut');
  27148. if (!point.series.options.inactiveOtherPoints) {
  27149. (chart.hoverPoints || []).forEach(function (p) {
  27150. p.setState();
  27151. });
  27152. }
  27153. chart.hoverPoints = chart.hoverPoint = null;
  27154. };
  27155. /**
  27156. * Import events from the series' and point's options. Only do it on
  27157. * demand, to save processing time on hovering.
  27158. *
  27159. * @private
  27160. * @function Highcharts.Point#importEvents
  27161. */
  27162. Point.prototype.importEvents = function () {
  27163. if (!this.hasImportedEvents) {
  27164. var point = this,
  27165. options = merge(point.series.options.point,
  27166. point.options),
  27167. events = options.events;
  27168. point.events = events;
  27169. objectEach(events, function (event, eventType) {
  27170. if (isFunction(event)) {
  27171. addEvent(point, eventType, event);
  27172. }
  27173. });
  27174. this.hasImportedEvents = true;
  27175. }
  27176. };
  27177. /**
  27178. * Set the point's state.
  27179. *
  27180. * @function Highcharts.Point#setState
  27181. *
  27182. * @param {Highcharts.PointStateValue|""} [state]
  27183. * The new state, can be one of `'hover'`, `'select'`, `'inactive'`,
  27184. * or `''` (an empty string), `'normal'` or `undefined` to set to
  27185. * normal state.
  27186. * @param {boolean} [move]
  27187. * State for animation.
  27188. *
  27189. * @fires Highcharts.Point#event:afterSetState
  27190. */
  27191. Point.prototype.setState = function (state, move) {
  27192. var point = this,
  27193. series = point.series,
  27194. previousState = point.state,
  27195. stateOptions = (series.options.states[state || 'normal'] ||
  27196. {}),
  27197. markerOptions = (defaultOptions.plotOptions[series.type].marker &&
  27198. series.options.marker),
  27199. normalDisabled = (markerOptions && markerOptions.enabled === false),
  27200. markerStateOptions = ((markerOptions &&
  27201. markerOptions.states &&
  27202. markerOptions.states[state || 'normal']) || {}),
  27203. stateDisabled = markerStateOptions.enabled === false,
  27204. stateMarkerGraphic = series.stateMarkerGraphic,
  27205. pointMarker = point.marker || {},
  27206. chart = series.chart,
  27207. halo = series.halo,
  27208. haloOptions,
  27209. markerAttribs,
  27210. pointAttribs,
  27211. pointAttribsAnimation,
  27212. hasMarkers = (markerOptions && series.markerAttribs),
  27213. newSymbol;
  27214. state = state || ''; // empty string
  27215. if (
  27216. // already has this state
  27217. (state === point.state && !move) ||
  27218. // selected points don't respond to hover
  27219. (point.selected && state !== 'select') ||
  27220. // series' state options is disabled
  27221. (stateOptions.enabled === false) ||
  27222. // general point marker's state options is disabled
  27223. (state && (stateDisabled ||
  27224. (normalDisabled &&
  27225. markerStateOptions.enabled === false))) ||
  27226. // individual point marker's state options is disabled
  27227. (state &&
  27228. pointMarker.states &&
  27229. pointMarker.states[state] &&
  27230. pointMarker.states[state].enabled === false) // #1610
  27231. ) {
  27232. return;
  27233. }
  27234. point.state = state;
  27235. if (hasMarkers) {
  27236. markerAttribs = series.markerAttribs(point, state);
  27237. }
  27238. // Apply hover styles to the existing point
  27239. if (point.graphic) {
  27240. if (previousState) {
  27241. point.graphic.removeClass('highcharts-point-' + previousState);
  27242. }
  27243. if (state) {
  27244. point.graphic.addClass('highcharts-point-' + state);
  27245. }
  27246. if (!chart.styledMode) {
  27247. pointAttribs = series.pointAttribs(point, state);
  27248. pointAttribsAnimation = pick(chart.options.chart.animation, stateOptions.animation);
  27249. // Some inactive points (e.g. slices in pie) should apply
  27250. // oppacity also for it's labels
  27251. if (series.options.inactiveOtherPoints && pointAttribs.opacity) {
  27252. (point.dataLabels || []).forEach(function (label) {
  27253. if (label) {
  27254. label.animate({
  27255. opacity: pointAttribs.opacity
  27256. }, pointAttribsAnimation);
  27257. }
  27258. });
  27259. if (point.connector) {
  27260. point.connector.animate({
  27261. opacity: pointAttribs.opacity
  27262. }, pointAttribsAnimation);
  27263. }
  27264. }
  27265. point.graphic.animate(pointAttribs, pointAttribsAnimation);
  27266. }
  27267. if (markerAttribs) {
  27268. point.graphic.animate(markerAttribs, pick(
  27269. // Turn off globally:
  27270. chart.options.chart.animation, markerStateOptions.animation, markerOptions.animation));
  27271. }
  27272. // Zooming in from a range with no markers to a range with markers
  27273. if (stateMarkerGraphic) {
  27274. stateMarkerGraphic.hide();
  27275. }
  27276. }
  27277. else {
  27278. // if a graphic is not applied to each point in the normal state,
  27279. // create a shared graphic for the hover state
  27280. if (state && markerStateOptions) {
  27281. newSymbol = pointMarker.symbol || series.symbol;
  27282. // If the point has another symbol than the previous one, throw
  27283. // away the state marker graphic and force a new one (#1459)
  27284. if (stateMarkerGraphic &&
  27285. stateMarkerGraphic.currentSymbol !== newSymbol) {
  27286. stateMarkerGraphic = stateMarkerGraphic.destroy();
  27287. }
  27288. // Add a new state marker graphic
  27289. if (markerAttribs) {
  27290. if (!stateMarkerGraphic) {
  27291. if (newSymbol) {
  27292. series.stateMarkerGraphic = stateMarkerGraphic =
  27293. chart.renderer
  27294. .symbol(newSymbol, markerAttribs.x, markerAttribs.y, markerAttribs.width, markerAttribs.height)
  27295. .add(series.markerGroup);
  27296. stateMarkerGraphic.currentSymbol = newSymbol;
  27297. }
  27298. // Move the existing graphic
  27299. }
  27300. else {
  27301. stateMarkerGraphic[move ? 'animate' : 'attr']({
  27302. x: markerAttribs.x,
  27303. y: markerAttribs.y
  27304. });
  27305. }
  27306. }
  27307. if (!chart.styledMode && stateMarkerGraphic) {
  27308. stateMarkerGraphic.attr(series.pointAttribs(point, state));
  27309. }
  27310. }
  27311. if (stateMarkerGraphic) {
  27312. stateMarkerGraphic[state && point.isInside ? 'show' : 'hide'](); // #2450
  27313. stateMarkerGraphic.element.point = point; // #4310
  27314. }
  27315. }
  27316. // Show me your halo
  27317. haloOptions = stateOptions.halo;
  27318. var markerGraphic = (point.graphic || stateMarkerGraphic);
  27319. var markerVisibility = (markerGraphic && markerGraphic.visibility || 'inherit');
  27320. if (haloOptions &&
  27321. haloOptions.size &&
  27322. markerGraphic &&
  27323. markerVisibility !== 'hidden' &&
  27324. !point.isCluster) {
  27325. if (!halo) {
  27326. series.halo = halo = chart.renderer.path()
  27327. // #5818, #5903, #6705
  27328. .add(markerGraphic.parentGroup);
  27329. }
  27330. halo.show()[move ? 'animate' : 'attr']({
  27331. d: point.haloPath(haloOptions.size)
  27332. });
  27333. halo.attr({
  27334. 'class': 'highcharts-halo highcharts-color-' +
  27335. pick(point.colorIndex, series.colorIndex) +
  27336. (point.className ? ' ' + point.className : ''),
  27337. 'visibility': markerVisibility,
  27338. 'zIndex': -1 // #4929, #8276
  27339. });
  27340. halo.point = point; // #6055
  27341. if (!chart.styledMode) {
  27342. halo.attr(extend({
  27343. 'fill': point.color || series.color,
  27344. 'fill-opacity': haloOptions.opacity
  27345. }, AST.filterUserAttributes(haloOptions.attributes || {})));
  27346. }
  27347. }
  27348. else if (halo && halo.point && halo.point.haloPath) {
  27349. // Animate back to 0 on the current halo point (#6055)
  27350. halo.animate({ d: halo.point.haloPath(0) }, null,
  27351. // Hide after unhovering. The `complete` callback runs in the
  27352. // halo's context (#7681).
  27353. halo.hide);
  27354. }
  27355. fireEvent(point, 'afterSetState');
  27356. };
  27357. /**
  27358. * Get the path definition for the halo, which is usually a shadow-like
  27359. * circle around the currently hovered point.
  27360. *
  27361. * @function Highcharts.Point#haloPath
  27362. *
  27363. * @param {number} size
  27364. * The radius of the circular halo.
  27365. *
  27366. * @return {Highcharts.SVGPathArray}
  27367. * The path definition.
  27368. */
  27369. Point.prototype.haloPath = function (size) {
  27370. var series = this.series,
  27371. chart = series.chart;
  27372. return chart.renderer.symbols.circle(Math.floor(this.plotX) - size, this.plotY - size, size * 2, size * 2);
  27373. };
  27374. return Point;
  27375. }());
  27376. H.Point = Point;
  27377. return Point;
  27378. });
  27379. _registerModule(_modules, 'Core/Legend.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Globals.js'], _modules['Core/Series/Point.js'], _modules['Core/Utilities.js']], function (A, H, Point, U) {
  27380. /* *
  27381. *
  27382. * (c) 2010-2021 Torstein Honsi
  27383. *
  27384. * License: www.highcharts.com/license
  27385. *
  27386. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  27387. *
  27388. * */
  27389. var animObject = A.animObject,
  27390. setAnimation = A.setAnimation;
  27391. var isFirefox = H.isFirefox,
  27392. marginNames = H.marginNames,
  27393. win = H.win;
  27394. var addEvent = U.addEvent,
  27395. createElement = U.createElement,
  27396. css = U.css,
  27397. defined = U.defined,
  27398. discardElement = U.discardElement,
  27399. find = U.find,
  27400. fireEvent = U.fireEvent,
  27401. format = U.format,
  27402. isNumber = U.isNumber,
  27403. merge = U.merge,
  27404. pick = U.pick,
  27405. relativeLength = U.relativeLength,
  27406. stableSort = U.stableSort,
  27407. syncTimeout = U.syncTimeout,
  27408. wrap = U.wrap;
  27409. /**
  27410. * Gets fired when the legend item belonging to a point is clicked. The default
  27411. * action is to toggle the visibility of the point. This can be prevented by
  27412. * returning `false` or calling `event.preventDefault()`.
  27413. *
  27414. * @callback Highcharts.PointLegendItemClickCallbackFunction
  27415. *
  27416. * @param {Highcharts.Point} this
  27417. * The point on which the event occured.
  27418. *
  27419. * @param {Highcharts.PointLegendItemClickEventObject} event
  27420. * The event that occured.
  27421. */
  27422. /**
  27423. * Information about the legend click event.
  27424. *
  27425. * @interface Highcharts.PointLegendItemClickEventObject
  27426. */ /**
  27427. * Related browser event.
  27428. * @name Highcharts.PointLegendItemClickEventObject#browserEvent
  27429. * @type {Highcharts.PointerEvent}
  27430. */ /**
  27431. * Prevent the default action of toggle the visibility of the point.
  27432. * @name Highcharts.PointLegendItemClickEventObject#preventDefault
  27433. * @type {Function}
  27434. */ /**
  27435. * Related point.
  27436. * @name Highcharts.PointLegendItemClickEventObject#target
  27437. * @type {Highcharts.Point}
  27438. */ /**
  27439. * Event type.
  27440. * @name Highcharts.PointLegendItemClickEventObject#type
  27441. * @type {"legendItemClick"}
  27442. */
  27443. /**
  27444. * Gets fired when the legend item belonging to a series is clicked. The default
  27445. * action is to toggle the visibility of the series. This can be prevented by
  27446. * returning `false` or calling `event.preventDefault()`.
  27447. *
  27448. * @callback Highcharts.SeriesLegendItemClickCallbackFunction
  27449. *
  27450. * @param {Highcharts.Series} this
  27451. * The series where the event occured.
  27452. *
  27453. * @param {Highcharts.SeriesLegendItemClickEventObject} event
  27454. * The event that occured.
  27455. */
  27456. /**
  27457. * Information about the legend click event.
  27458. *
  27459. * @interface Highcharts.SeriesLegendItemClickEventObject
  27460. */ /**
  27461. * Related browser event.
  27462. * @name Highcharts.SeriesLegendItemClickEventObject#browserEvent
  27463. * @type {Highcharts.PointerEvent}
  27464. */ /**
  27465. * Prevent the default action of toggle the visibility of the series.
  27466. * @name Highcharts.SeriesLegendItemClickEventObject#preventDefault
  27467. * @type {Function}
  27468. */ /**
  27469. * Related series.
  27470. * @name Highcharts.SeriesLegendItemClickEventObject#target
  27471. * @type {Highcharts.Series}
  27472. */ /**
  27473. * Event type.
  27474. * @name Highcharts.SeriesLegendItemClickEventObject#type
  27475. * @type {"legendItemClick"}
  27476. */
  27477. /* eslint-disable no-invalid-this, valid-jsdoc */
  27478. /**
  27479. * The overview of the chart's series. The legend object is instanciated
  27480. * internally in the chart constructor, and is available from the `chart.legend`
  27481. * property. Each chart has only one legend.
  27482. *
  27483. * @class
  27484. * @name Highcharts.Legend
  27485. *
  27486. * @param {Highcharts.Chart} chart
  27487. * The chart instance.
  27488. *
  27489. * @param {Highcharts.LegendOptions} options
  27490. * Legend options.
  27491. */
  27492. var Legend = /** @class */ (function () {
  27493. /* *
  27494. *
  27495. * Constructors
  27496. *
  27497. * */
  27498. function Legend(chart, options) {
  27499. /* *
  27500. *
  27501. * Properties
  27502. *
  27503. * */
  27504. this.allItems = [];
  27505. this.box = void 0;
  27506. this.contentGroup = void 0;
  27507. this.display = false;
  27508. this.group = void 0;
  27509. this.initialItemY = 0;
  27510. this.itemHeight = 0;
  27511. this.itemMarginBottom = 0;
  27512. this.itemMarginTop = 0;
  27513. this.itemX = 0;
  27514. this.itemY = 0;
  27515. this.lastItemY = 0;
  27516. this.lastLineHeight = 0;
  27517. this.legendHeight = 0;
  27518. this.legendWidth = 0;
  27519. this.maxItemWidth = 0;
  27520. this.maxLegendWidth = 0;
  27521. this.offsetWidth = 0;
  27522. this.options = {};
  27523. this.padding = 0;
  27524. this.pages = [];
  27525. this.proximate = false;
  27526. this.scrollGroup = void 0;
  27527. this.symbolHeight = 0;
  27528. this.symbolWidth = 0;
  27529. this.titleHeight = 0;
  27530. this.totalItemWidth = 0;
  27531. this.widthOption = 0;
  27532. this.chart = chart;
  27533. this.init(chart, options);
  27534. }
  27535. /* *
  27536. *
  27537. * Functions
  27538. *
  27539. * */
  27540. /**
  27541. * Initialize the legend.
  27542. *
  27543. * @private
  27544. * @function Highcharts.Legend#init
  27545. *
  27546. * @param {Highcharts.Chart} chart
  27547. * The chart instance.
  27548. *
  27549. * @param {Highcharts.LegendOptions} options
  27550. * Legend options.
  27551. */
  27552. Legend.prototype.init = function (chart, options) {
  27553. /**
  27554. * Chart of this legend.
  27555. *
  27556. * @readonly
  27557. * @name Highcharts.Legend#chart
  27558. * @type {Highcharts.Chart}
  27559. */
  27560. this.chart = chart;
  27561. this.setOptions(options);
  27562. if (options.enabled) {
  27563. // Render it
  27564. this.render();
  27565. // move checkboxes
  27566. addEvent(this.chart, 'endResize', function () {
  27567. this.legend.positionCheckboxes();
  27568. });
  27569. if (this.proximate) {
  27570. this.unchartrender = addEvent(this.chart, 'render', function () {
  27571. this.legend.proximatePositions();
  27572. this.legend.positionItems();
  27573. });
  27574. }
  27575. else if (this.unchartrender) {
  27576. this.unchartrender();
  27577. }
  27578. }
  27579. };
  27580. /**
  27581. * @private
  27582. * @function Highcharts.Legend#setOptions
  27583. * @param {Highcharts.LegendOptions} options
  27584. */
  27585. Legend.prototype.setOptions = function (options) {
  27586. var padding = pick(options.padding, 8);
  27587. /**
  27588. * Legend options.
  27589. *
  27590. * @readonly
  27591. * @name Highcharts.Legend#options
  27592. * @type {Highcharts.LegendOptions}
  27593. */
  27594. this.options = options;
  27595. if (!this.chart.styledMode) {
  27596. this.itemStyle = options.itemStyle;
  27597. this.itemHiddenStyle = merge(this.itemStyle, options.itemHiddenStyle);
  27598. }
  27599. this.itemMarginTop = options.itemMarginTop || 0;
  27600. this.itemMarginBottom = options.itemMarginBottom || 0;
  27601. this.padding = padding;
  27602. this.initialItemY = padding - 5; // 5 is pixels above the text
  27603. this.symbolWidth = pick(options.symbolWidth, 16);
  27604. this.pages = [];
  27605. this.proximate = options.layout === 'proximate' && !this.chart.inverted;
  27606. this.baseline = void 0; // #12705: baseline has to be reset on every update
  27607. };
  27608. /**
  27609. * Update the legend with new options. Equivalent to running `chart.update`
  27610. * with a legend configuration option.
  27611. *
  27612. * @sample highcharts/legend/legend-update/
  27613. * Legend update
  27614. *
  27615. * @function Highcharts.Legend#update
  27616. *
  27617. * @param {Highcharts.LegendOptions} options
  27618. * Legend options.
  27619. *
  27620. * @param {boolean} [redraw=true]
  27621. * Whether to redraw the chart after the axis is altered. If doing more
  27622. * operations on the chart, it is a good idea to set redraw to false and
  27623. * call {@link Chart#redraw} after. Whether to redraw the chart.
  27624. *
  27625. * @fires Highcharts.Legends#event:afterUpdate
  27626. */
  27627. Legend.prototype.update = function (options, redraw) {
  27628. var chart = this.chart;
  27629. this.setOptions(merge(true, this.options, options));
  27630. this.destroy();
  27631. chart.isDirtyLegend = chart.isDirtyBox = true;
  27632. if (pick(redraw, true)) {
  27633. chart.redraw();
  27634. }
  27635. fireEvent(this, 'afterUpdate');
  27636. };
  27637. /**
  27638. * Set the colors for the legend item.
  27639. *
  27640. * @private
  27641. * @function Highcharts.Legend#colorizeItem
  27642. * @param {Highcharts.BubbleLegend|Highcharts.Point|Highcharts.Series} item
  27643. * A Series or Point instance
  27644. * @param {boolean} [visible=false]
  27645. * Dimmed or colored
  27646. *
  27647. * @todo
  27648. * Make events official: Fires the event `afterColorizeItem`.
  27649. */
  27650. Legend.prototype.colorizeItem = function (item, visible) {
  27651. item.legendGroup[visible ? 'removeClass' : 'addClass']('highcharts-legend-item-hidden');
  27652. if (!this.chart.styledMode) {
  27653. var legend = this,
  27654. options = legend.options,
  27655. legendItem = item.legendItem,
  27656. legendLine = item.legendLine,
  27657. legendSymbol = item.legendSymbol,
  27658. hiddenColor = legend.itemHiddenStyle.color,
  27659. textColor = visible ?
  27660. options.itemStyle.color :
  27661. hiddenColor,
  27662. symbolColor = visible ?
  27663. (item.color || hiddenColor) :
  27664. hiddenColor,
  27665. markerOptions = item.options && item.options.marker,
  27666. symbolAttr = { fill: symbolColor };
  27667. if (legendItem) {
  27668. legendItem.css({
  27669. fill: textColor,
  27670. color: textColor // #1553, oldIE
  27671. });
  27672. }
  27673. if (legendLine) {
  27674. legendLine.attr({ stroke: symbolColor });
  27675. }
  27676. if (legendSymbol) {
  27677. // Apply marker options
  27678. if (markerOptions && legendSymbol.isMarker) { // #585
  27679. symbolAttr = item.pointAttribs();
  27680. if (!visible) {
  27681. // #6769
  27682. symbolAttr.stroke = symbolAttr.fill = hiddenColor;
  27683. }
  27684. }
  27685. legendSymbol.attr(symbolAttr);
  27686. }
  27687. }
  27688. fireEvent(this, 'afterColorizeItem', { item: item, visible: visible });
  27689. };
  27690. /**
  27691. * @private
  27692. * @function Highcharts.Legend#positionItems
  27693. */
  27694. Legend.prototype.positionItems = function () {
  27695. // Now that the legend width and height are established, put the items
  27696. // in the final position
  27697. this.allItems.forEach(this.positionItem, this);
  27698. if (!this.chart.isResizing) {
  27699. this.positionCheckboxes();
  27700. }
  27701. };
  27702. /**
  27703. * Position the legend item.
  27704. *
  27705. * @private
  27706. * @function Highcharts.Legend#positionItem
  27707. * @param {Highcharts.BubbleLegend|Highcharts.Point|Highcharts.Series} item
  27708. * The item to position
  27709. */
  27710. Legend.prototype.positionItem = function (item) {
  27711. var _this = this;
  27712. var legend = this,
  27713. options = legend.options,
  27714. symbolPadding = options.symbolPadding,
  27715. ltr = !options.rtl,
  27716. legendItemPos = item._legendItemPos,
  27717. itemX = legendItemPos[0],
  27718. itemY = legendItemPos[1],
  27719. checkbox = item.checkbox,
  27720. legendGroup = item.legendGroup;
  27721. if (legendGroup && legendGroup.element) {
  27722. var attribs = {
  27723. translateX: ltr ?
  27724. itemX :
  27725. legend.legendWidth - itemX - 2 * symbolPadding - 4,
  27726. translateY: itemY
  27727. };
  27728. var complete = function () {
  27729. fireEvent(_this, 'afterPositionItem', { item: item });
  27730. };
  27731. if (defined(legendGroup.translateY)) {
  27732. legendGroup.animate(attribs, void 0, complete);
  27733. }
  27734. else {
  27735. legendGroup.attr(attribs);
  27736. complete();
  27737. }
  27738. }
  27739. if (checkbox) {
  27740. checkbox.x = itemX;
  27741. checkbox.y = itemY;
  27742. }
  27743. };
  27744. /**
  27745. * Destroy a single legend item, used internally on removing series items.
  27746. *
  27747. * @private
  27748. * @function Highcharts.Legend#destroyItem
  27749. * @param {Highcharts.BubbleLegend|Highcharts.Point|Highcharts.Series} item
  27750. * The item to remove
  27751. */
  27752. Legend.prototype.destroyItem = function (item) {
  27753. var checkbox = item.checkbox;
  27754. // destroy SVG elements
  27755. ['legendItem', 'legendLine', 'legendSymbol', 'legendGroup'].forEach(function (key) {
  27756. if (item[key]) {
  27757. item[key] = item[key].destroy();
  27758. }
  27759. });
  27760. if (checkbox) {
  27761. discardElement(item.checkbox);
  27762. }
  27763. };
  27764. /**
  27765. * Destroy the legend. Used internally. To reflow objects, `chart.redraw`
  27766. * must be called after destruction.
  27767. *
  27768. * @private
  27769. * @function Highcharts.Legend#destroy
  27770. */
  27771. Legend.prototype.destroy = function () {
  27772. /**
  27773. * @private
  27774. * @param {string} key
  27775. * @return {void}
  27776. */
  27777. function destroyItems(key) {
  27778. if (this[key]) {
  27779. this[key] = this[key].destroy();
  27780. }
  27781. }
  27782. // Destroy items
  27783. this.getAllItems().forEach(function (item) {
  27784. ['legendItem', 'legendGroup'].forEach(destroyItems, item);
  27785. });
  27786. // Destroy legend elements
  27787. [
  27788. 'clipRect',
  27789. 'up',
  27790. 'down',
  27791. 'pager',
  27792. 'nav',
  27793. 'box',
  27794. 'title',
  27795. 'group'
  27796. ].forEach(destroyItems, this);
  27797. this.display = null; // Reset in .render on update.
  27798. };
  27799. /**
  27800. * Position the checkboxes after the width is determined.
  27801. *
  27802. * @private
  27803. * @function Highcharts.Legend#positionCheckboxes
  27804. */
  27805. Legend.prototype.positionCheckboxes = function () {
  27806. var alignAttr = this.group && this.group.alignAttr,
  27807. translateY,
  27808. clipHeight = this.clipHeight || this.legendHeight,
  27809. titleHeight = this.titleHeight;
  27810. if (alignAttr) {
  27811. translateY = alignAttr.translateY;
  27812. this.allItems.forEach(function (item) {
  27813. var checkbox = item.checkbox,
  27814. top;
  27815. if (checkbox) {
  27816. top = translateY + titleHeight + checkbox.y +
  27817. (this.scrollOffset || 0) + 3;
  27818. css(checkbox, {
  27819. left: (alignAttr.translateX + item.checkboxOffset +
  27820. checkbox.x - 20) + 'px',
  27821. top: top + 'px',
  27822. display: this.proximate || (top > translateY - 6 &&
  27823. top < translateY + clipHeight - 6) ?
  27824. '' :
  27825. 'none'
  27826. });
  27827. }
  27828. }, this);
  27829. }
  27830. };
  27831. /**
  27832. * Render the legend title on top of the legend.
  27833. *
  27834. * @private
  27835. * @function Highcharts.Legend#renderTitle
  27836. */
  27837. Legend.prototype.renderTitle = function () {
  27838. var options = this.options,
  27839. padding = this.padding,
  27840. titleOptions = options.title,
  27841. titleHeight = 0,
  27842. bBox;
  27843. if (titleOptions.text) {
  27844. if (!this.title) {
  27845. /**
  27846. * SVG element of the legend title.
  27847. *
  27848. * @readonly
  27849. * @name Highcharts.Legend#title
  27850. * @type {Highcharts.SVGElement}
  27851. */
  27852. this.title = this.chart.renderer.label(titleOptions.text, padding - 3, padding - 4, null, null, null, options.useHTML, null, 'legend-title')
  27853. .attr({ zIndex: 1 });
  27854. if (!this.chart.styledMode) {
  27855. this.title.css(titleOptions.style);
  27856. }
  27857. this.title.add(this.group);
  27858. }
  27859. // Set the max title width (#7253)
  27860. if (!titleOptions.width) {
  27861. this.title.css({
  27862. width: this.maxLegendWidth + 'px'
  27863. });
  27864. }
  27865. bBox = this.title.getBBox();
  27866. titleHeight = bBox.height;
  27867. this.offsetWidth = bBox.width; // #1717
  27868. this.contentGroup.attr({ translateY: titleHeight });
  27869. }
  27870. this.titleHeight = titleHeight;
  27871. };
  27872. /**
  27873. * Set the legend item text.
  27874. *
  27875. * @function Highcharts.Legend#setText
  27876. * @param {Highcharts.Point|Highcharts.Series} item
  27877. * The item for which to update the text in the legend.
  27878. */
  27879. Legend.prototype.setText = function (item) {
  27880. var options = this.options;
  27881. item.legendItem.attr({
  27882. text: options.labelFormat ?
  27883. format(options.labelFormat, item, this.chart) :
  27884. options.labelFormatter.call(item)
  27885. });
  27886. };
  27887. /**
  27888. * Render a single specific legend item. Called internally from the `render`
  27889. * function.
  27890. *
  27891. * @private
  27892. * @function Highcharts.Legend#renderItem
  27893. * @param {Highcharts.BubbleLegend|Highcharts.Point|Highcharts.Series} item
  27894. * The item to render.
  27895. */
  27896. Legend.prototype.renderItem = function (item) {
  27897. var legend = this,
  27898. chart = legend.chart,
  27899. renderer = chart.renderer,
  27900. options = legend.options,
  27901. horizontal = options.layout === 'horizontal',
  27902. symbolWidth = legend.symbolWidth,
  27903. symbolPadding = options.symbolPadding,
  27904. itemStyle = legend.itemStyle,
  27905. itemHiddenStyle = legend.itemHiddenStyle,
  27906. itemDistance = horizontal ? pick(options.itemDistance, 20) : 0,
  27907. ltr = !options.rtl,
  27908. bBox,
  27909. li = item.legendItem,
  27910. isSeries = !item.series,
  27911. series = !isSeries && item.series.drawLegendSymbol ?
  27912. item.series :
  27913. item,
  27914. seriesOptions = series.options,
  27915. showCheckbox = legend.createCheckboxForItem &&
  27916. seriesOptions &&
  27917. seriesOptions.showCheckbox,
  27918. // full width minus text width
  27919. itemExtraWidth = symbolWidth + symbolPadding +
  27920. itemDistance + (showCheckbox ? 20 : 0),
  27921. useHTML = options.useHTML,
  27922. itemClassName = item.options.className;
  27923. if (!li) { // generate it once, later move it
  27924. // Generate the group box, a group to hold the symbol and text. Text
  27925. // is to be appended in Legend class.
  27926. item.legendGroup = renderer
  27927. .g('legend-item')
  27928. .addClass('highcharts-' + series.type + '-series ' +
  27929. 'highcharts-color-' + item.colorIndex +
  27930. (itemClassName ? ' ' + itemClassName : '') +
  27931. (isSeries ?
  27932. ' highcharts-series-' + item.index :
  27933. ''))
  27934. .attr({ zIndex: 1 })
  27935. .add(legend.scrollGroup);
  27936. // Generate the list item text and add it to the group
  27937. item.legendItem = li = renderer.text('', ltr ?
  27938. symbolWidth + symbolPadding :
  27939. -symbolPadding, legend.baseline || 0, useHTML);
  27940. if (!chart.styledMode) {
  27941. // merge to prevent modifying original (#1021)
  27942. li.css(merge(item.visible ?
  27943. itemStyle :
  27944. itemHiddenStyle));
  27945. }
  27946. li
  27947. .attr({
  27948. align: ltr ? 'left' : 'right',
  27949. zIndex: 2
  27950. })
  27951. .add(item.legendGroup);
  27952. // Get the baseline for the first item - the font size is equal for
  27953. // all
  27954. if (!legend.baseline) {
  27955. legend.fontMetrics = renderer.fontMetrics(chart.styledMode ? 12 : itemStyle.fontSize, li);
  27956. legend.baseline =
  27957. legend.fontMetrics.f + 3 + legend.itemMarginTop;
  27958. li.attr('y', legend.baseline);
  27959. }
  27960. // Draw the legend symbol inside the group box
  27961. legend.symbolHeight =
  27962. options.symbolHeight || legend.fontMetrics.f;
  27963. series.drawLegendSymbol(legend, item);
  27964. if (legend.setItemEvents) {
  27965. legend.setItemEvents(item, li, useHTML);
  27966. }
  27967. }
  27968. // Add the HTML checkbox on top
  27969. if (showCheckbox && !item.checkbox && legend.createCheckboxForItem) {
  27970. legend.createCheckboxForItem(item);
  27971. }
  27972. // Colorize the items
  27973. legend.colorizeItem(item, item.visible);
  27974. // Take care of max width and text overflow (#6659)
  27975. if (chart.styledMode || !itemStyle.width) {
  27976. li.css({
  27977. width: ((options.itemWidth ||
  27978. legend.widthOption ||
  27979. chart.spacingBox.width) - itemExtraWidth) + 'px'
  27980. });
  27981. }
  27982. // Always update the text
  27983. legend.setText(item);
  27984. // calculate the positions for the next line
  27985. bBox = li.getBBox();
  27986. item.itemWidth = item.checkboxOffset =
  27987. options.itemWidth ||
  27988. item.legendItemWidth ||
  27989. bBox.width + itemExtraWidth;
  27990. legend.maxItemWidth = Math.max(legend.maxItemWidth, item.itemWidth);
  27991. legend.totalItemWidth += item.itemWidth;
  27992. legend.itemHeight = item.itemHeight = Math.round(item.legendItemHeight || bBox.height || legend.symbolHeight);
  27993. };
  27994. /**
  27995. * Get the position of the item in the layout. We now know the
  27996. * maxItemWidth from the previous loop.
  27997. *
  27998. * @private
  27999. * @function Highcharts.Legend#layoutItem
  28000. * @param {Highcharts.BubbleLegend|Highcharts.Point|Highcharts.Series} item
  28001. */
  28002. Legend.prototype.layoutItem = function (item) {
  28003. var options = this.options,
  28004. padding = this.padding,
  28005. horizontal = options.layout === 'horizontal',
  28006. itemHeight = item.itemHeight,
  28007. itemMarginBottom = this.itemMarginBottom,
  28008. itemMarginTop = this.itemMarginTop,
  28009. itemDistance = horizontal ? pick(options.itemDistance, 20) : 0,
  28010. maxLegendWidth = this.maxLegendWidth,
  28011. itemWidth = (options.alignColumns &&
  28012. this.totalItemWidth > maxLegendWidth) ?
  28013. this.maxItemWidth :
  28014. item.itemWidth;
  28015. // If the item exceeds the width, start a new line
  28016. if (horizontal &&
  28017. this.itemX - padding + itemWidth > maxLegendWidth) {
  28018. this.itemX = padding;
  28019. if (this.lastLineHeight) { // Not for the first line (#10167)
  28020. this.itemY += (itemMarginTop +
  28021. this.lastLineHeight +
  28022. itemMarginBottom);
  28023. }
  28024. this.lastLineHeight = 0; // reset for next line (#915, #3976)
  28025. }
  28026. // Set the edge positions
  28027. this.lastItemY = itemMarginTop + this.itemY + itemMarginBottom;
  28028. this.lastLineHeight = Math.max(// #915
  28029. itemHeight, this.lastLineHeight);
  28030. // cache the position of the newly generated or reordered items
  28031. item._legendItemPos = [this.itemX, this.itemY];
  28032. // advance
  28033. if (horizontal) {
  28034. this.itemX += itemWidth;
  28035. }
  28036. else {
  28037. this.itemY +=
  28038. itemMarginTop + itemHeight + itemMarginBottom;
  28039. this.lastLineHeight = itemHeight;
  28040. }
  28041. // the width of the widest item
  28042. this.offsetWidth = this.widthOption || Math.max((horizontal ? this.itemX - padding - (item.checkbox ?
  28043. // decrease by itemDistance only when no checkbox #4853
  28044. 0 :
  28045. itemDistance) : itemWidth) + padding, this.offsetWidth);
  28046. };
  28047. /**
  28048. * Get all items, which is one item per series for most series and one
  28049. * item per point for pie series and its derivatives. Fires the event
  28050. * `afterGetAllItems`.
  28051. *
  28052. * @private
  28053. * @function Highcharts.Legend#getAllItems
  28054. * @return {Array<(Highcharts.BubbleLegend|Highcharts.Point|Highcharts.Series)>}
  28055. * The current items in the legend.
  28056. * @fires Highcharts.Legend#event:afterGetAllItems
  28057. */
  28058. Legend.prototype.getAllItems = function () {
  28059. var allItems = [];
  28060. this.chart.series.forEach(function (series) {
  28061. var seriesOptions = series && series.options;
  28062. // Handle showInLegend. If the series is linked to another series,
  28063. // defaults to false.
  28064. if (series && pick(seriesOptions.showInLegend, !defined(seriesOptions.linkedTo) ? void 0 : false, true)) {
  28065. // Use points or series for the legend item depending on
  28066. // legendType
  28067. allItems = allItems.concat(series.legendItems ||
  28068. (seriesOptions.legendType === 'point' ?
  28069. series.data :
  28070. series));
  28071. }
  28072. });
  28073. fireEvent(this, 'afterGetAllItems', { allItems: allItems });
  28074. return allItems;
  28075. };
  28076. /**
  28077. * Get a short, three letter string reflecting the alignment and layout.
  28078. *
  28079. * @private
  28080. * @function Highcharts.Legend#getAlignment
  28081. * @return {string}
  28082. * The alignment, empty string if floating
  28083. */
  28084. Legend.prototype.getAlignment = function () {
  28085. var options = this.options;
  28086. // Use the first letter of each alignment option in order to detect
  28087. // the side. (#4189 - use charAt(x) notation instead of [x] for IE7)
  28088. if (this.proximate) {
  28089. return options.align.charAt(0) + 'tv';
  28090. }
  28091. return options.floating ? '' : (options.align.charAt(0) +
  28092. options.verticalAlign.charAt(0) +
  28093. options.layout.charAt(0));
  28094. };
  28095. /**
  28096. * Adjust the chart margins by reserving space for the legend on only one
  28097. * side of the chart. If the position is set to a corner, top or bottom is
  28098. * reserved for horizontal legends and left or right for vertical ones.
  28099. *
  28100. * @private
  28101. * @function Highcharts.Legend#adjustMargins
  28102. * @param {Array<number>} margin
  28103. * @param {Array<number>} spacing
  28104. */
  28105. Legend.prototype.adjustMargins = function (margin, spacing) {
  28106. var chart = this.chart,
  28107. options = this.options,
  28108. alignment = this.getAlignment();
  28109. if (alignment) {
  28110. ([
  28111. /(lth|ct|rth)/,
  28112. /(rtv|rm|rbv)/,
  28113. /(rbh|cb|lbh)/,
  28114. /(lbv|lm|ltv)/
  28115. ]).forEach(function (alignments, side) {
  28116. if (alignments.test(alignment) && !defined(margin[side])) {
  28117. // Now we have detected on which side of the chart we should
  28118. // reserve space for the legend
  28119. chart[marginNames[side]] = Math.max(chart[marginNames[side]], (chart.legend[(side + 1) % 2 ? 'legendHeight' : 'legendWidth'] +
  28120. [1, -1, -1, 1][side] * options[(side % 2) ? 'x' : 'y'] +
  28121. pick(options.margin, 12) +
  28122. spacing[side] +
  28123. (chart.titleOffset[side] || 0)));
  28124. }
  28125. });
  28126. }
  28127. };
  28128. /**
  28129. * @private
  28130. * @function Highcharts.Legend#proximatePositions
  28131. */
  28132. Legend.prototype.proximatePositions = function () {
  28133. var chart = this.chart,
  28134. boxes = [],
  28135. alignLeft = this.options.align === 'left';
  28136. this.allItems.forEach(function (item) {
  28137. var lastPoint,
  28138. height,
  28139. useFirstPoint = alignLeft,
  28140. target,
  28141. top;
  28142. if (item.yAxis) {
  28143. if (item.xAxis.options.reversed) {
  28144. useFirstPoint = !useFirstPoint;
  28145. }
  28146. if (item.points) {
  28147. lastPoint = find(useFirstPoint ?
  28148. item.points :
  28149. item.points.slice(0).reverse(), function (item) {
  28150. return isNumber(item.plotY);
  28151. });
  28152. }
  28153. height = this.itemMarginTop +
  28154. item.legendItem.getBBox().height +
  28155. this.itemMarginBottom;
  28156. top = item.yAxis.top - chart.plotTop;
  28157. if (item.visible) {
  28158. target = lastPoint ?
  28159. lastPoint.plotY :
  28160. item.yAxis.height;
  28161. target += top - 0.3 * height;
  28162. }
  28163. else {
  28164. target = top + item.yAxis.height;
  28165. }
  28166. boxes.push({
  28167. target: target,
  28168. size: height,
  28169. item: item
  28170. });
  28171. }
  28172. }, this);
  28173. H.distribute(boxes, chart.plotHeight);
  28174. boxes.forEach(function (box) {
  28175. box.item._legendItemPos[1] =
  28176. chart.plotTop - chart.spacing[0] + box.pos;
  28177. });
  28178. };
  28179. /**
  28180. * Render the legend. This method can be called both before and after
  28181. * `chart.render`. If called after, it will only rearrange items instead
  28182. * of creating new ones. Called internally on initial render and after
  28183. * redraws.
  28184. *
  28185. * @private
  28186. * @function Highcharts.Legend#render
  28187. */
  28188. Legend.prototype.render = function () {
  28189. var legend = this,
  28190. chart = legend.chart,
  28191. renderer = chart.renderer,
  28192. legendGroup = legend.group,
  28193. allItems,
  28194. display,
  28195. legendWidth,
  28196. legendHeight,
  28197. box = legend.box,
  28198. options = legend.options,
  28199. padding = legend.padding,
  28200. allowedWidth;
  28201. legend.itemX = padding;
  28202. legend.itemY = legend.initialItemY;
  28203. legend.offsetWidth = 0;
  28204. legend.lastItemY = 0;
  28205. legend.widthOption = relativeLength(options.width, chart.spacingBox.width - padding);
  28206. // Compute how wide the legend is allowed to be
  28207. allowedWidth =
  28208. chart.spacingBox.width - 2 * padding - options.x;
  28209. if (['rm', 'lm'].indexOf(legend.getAlignment().substring(0, 2)) > -1) {
  28210. allowedWidth /= 2;
  28211. }
  28212. legend.maxLegendWidth = legend.widthOption || allowedWidth;
  28213. if (!legendGroup) {
  28214. /**
  28215. * SVG group of the legend.
  28216. *
  28217. * @readonly
  28218. * @name Highcharts.Legend#group
  28219. * @type {Highcharts.SVGElement}
  28220. */
  28221. legend.group = legendGroup = renderer.g('legend')
  28222. .attr({ zIndex: 7 })
  28223. .add();
  28224. legend.contentGroup = renderer.g()
  28225. .attr({ zIndex: 1 }) // above background
  28226. .add(legendGroup);
  28227. legend.scrollGroup = renderer.g()
  28228. .add(legend.contentGroup);
  28229. }
  28230. legend.renderTitle();
  28231. // add each series or point
  28232. allItems = legend.getAllItems();
  28233. // sort by legendIndex
  28234. stableSort(allItems, function (a, b) {
  28235. return ((a.options && a.options.legendIndex) || 0) -
  28236. ((b.options && b.options.legendIndex) || 0);
  28237. });
  28238. // reversed legend
  28239. if (options.reversed) {
  28240. allItems.reverse();
  28241. }
  28242. /**
  28243. * All items for the legend, which is an array of series for most series
  28244. * and an array of points for pie series and its derivatives.
  28245. *
  28246. * @readonly
  28247. * @name Highcharts.Legend#allItems
  28248. * @type {Array<(Highcharts.Point|Highcharts.Series)>}
  28249. */
  28250. legend.allItems = allItems;
  28251. legend.display = display = !!allItems.length;
  28252. // Render the items. First we run a loop to set the text and properties
  28253. // and read all the bounding boxes. The next loop computes the item
  28254. // positions based on the bounding boxes.
  28255. legend.lastLineHeight = 0;
  28256. legend.maxItemWidth = 0;
  28257. legend.totalItemWidth = 0;
  28258. legend.itemHeight = 0;
  28259. allItems.forEach(legend.renderItem, legend);
  28260. allItems.forEach(legend.layoutItem, legend);
  28261. // Get the box
  28262. legendWidth = (legend.widthOption || legend.offsetWidth) + padding;
  28263. legendHeight = legend.lastItemY + legend.lastLineHeight +
  28264. legend.titleHeight;
  28265. legendHeight = legend.handleOverflow(legendHeight);
  28266. legendHeight += padding;
  28267. // Draw the border and/or background
  28268. if (!box) {
  28269. /**
  28270. * SVG element of the legend box.
  28271. *
  28272. * @readonly
  28273. * @name Highcharts.Legend#box
  28274. * @type {Highcharts.SVGElement}
  28275. */
  28276. legend.box = box = renderer.rect()
  28277. .addClass('highcharts-legend-box')
  28278. .attr({
  28279. r: options.borderRadius
  28280. })
  28281. .add(legendGroup);
  28282. box.isNew = true;
  28283. }
  28284. // Presentational
  28285. if (!chart.styledMode) {
  28286. box
  28287. .attr({
  28288. stroke: options.borderColor,
  28289. 'stroke-width': options.borderWidth || 0,
  28290. fill: options.backgroundColor || 'none'
  28291. })
  28292. .shadow(options.shadow);
  28293. }
  28294. if (legendWidth > 0 && legendHeight > 0) {
  28295. box[box.isNew ? 'attr' : 'animate'](box.crisp.call({}, {
  28296. x: 0,
  28297. y: 0,
  28298. width: legendWidth,
  28299. height: legendHeight
  28300. }, box.strokeWidth()));
  28301. box.isNew = false;
  28302. }
  28303. // hide the border if no items
  28304. box[display ? 'show' : 'hide']();
  28305. // Open for responsiveness
  28306. if (chart.styledMode && legendGroup.getStyle('display') === 'none') {
  28307. legendWidth = legendHeight = 0;
  28308. }
  28309. legend.legendWidth = legendWidth;
  28310. legend.legendHeight = legendHeight;
  28311. if (display) {
  28312. legend.align();
  28313. }
  28314. if (!this.proximate) {
  28315. this.positionItems();
  28316. }
  28317. fireEvent(this, 'afterRender');
  28318. };
  28319. /**
  28320. * Align the legend to chart's box.
  28321. *
  28322. * @private
  28323. * @function Highcharts.align
  28324. * @param {Highcharts.BBoxObject} alignTo
  28325. * @return {void}
  28326. */
  28327. Legend.prototype.align = function (alignTo) {
  28328. if (alignTo === void 0) { alignTo = this.chart.spacingBox; }
  28329. var chart = this.chart,
  28330. options = this.options;
  28331. // If aligning to the top and the layout is horizontal, adjust for
  28332. // the title (#7428)
  28333. var y = alignTo.y;
  28334. if (/(lth|ct|rth)/.test(this.getAlignment()) &&
  28335. chart.titleOffset[0] > 0) {
  28336. y += chart.titleOffset[0];
  28337. }
  28338. else if (/(lbh|cb|rbh)/.test(this.getAlignment()) &&
  28339. chart.titleOffset[2] > 0) {
  28340. y -= chart.titleOffset[2];
  28341. }
  28342. if (y !== alignTo.y) {
  28343. alignTo = merge(alignTo, { y: y });
  28344. }
  28345. this.group.align(merge(options, {
  28346. width: this.legendWidth,
  28347. height: this.legendHeight,
  28348. verticalAlign: this.proximate ? 'top' : options.verticalAlign
  28349. }), true, alignTo);
  28350. };
  28351. /**
  28352. * Set up the overflow handling by adding navigation with up and down arrows
  28353. * below the legend.
  28354. *
  28355. * @private
  28356. * @function Highcharts.Legend#handleOverflow
  28357. * @param {number} legendHeight
  28358. * @return {number}
  28359. */
  28360. Legend.prototype.handleOverflow = function (legendHeight) {
  28361. var legend = this,
  28362. chart = this.chart,
  28363. renderer = chart.renderer,
  28364. options = this.options,
  28365. optionsY = options.y,
  28366. alignTop = options.verticalAlign === 'top',
  28367. padding = this.padding,
  28368. spaceHeight = (chart.spacingBox.height +
  28369. (alignTop ? -optionsY : optionsY) - padding),
  28370. maxHeight = options.maxHeight,
  28371. clipHeight,
  28372. clipRect = this.clipRect,
  28373. navOptions = options.navigation,
  28374. animation = pick(navOptions.animation,
  28375. true),
  28376. arrowSize = navOptions.arrowSize || 12,
  28377. nav = this.nav,
  28378. pages = this.pages,
  28379. lastY,
  28380. allItems = this.allItems,
  28381. clipToHeight = function (height) {
  28382. if (typeof height === 'number') {
  28383. clipRect.attr({
  28384. height: height
  28385. });
  28386. }
  28387. else if (clipRect) { // Reset (#5912)
  28388. legend.clipRect = clipRect.destroy();
  28389. legend.contentGroup.clip();
  28390. }
  28391. // useHTML
  28392. if (legend.contentGroup.div) {
  28393. legend.contentGroup.div.style.clip = height ?
  28394. 'rect(' + padding + 'px,9999px,' +
  28395. (padding + height) + 'px,0)' :
  28396. 'auto';
  28397. }
  28398. }, addTracker = function (key) {
  28399. legend[key] = renderer
  28400. .circle(0, 0, arrowSize * 1.3)
  28401. .translate(arrowSize / 2, arrowSize / 2)
  28402. .add(nav);
  28403. if (!chart.styledMode) {
  28404. legend[key].attr('fill', 'rgba(0,0,0,0.0001)');
  28405. }
  28406. return legend[key];
  28407. };
  28408. // Adjust the height
  28409. if (options.layout === 'horizontal' &&
  28410. options.verticalAlign !== 'middle' &&
  28411. !options.floating) {
  28412. spaceHeight /= 2;
  28413. }
  28414. if (maxHeight) {
  28415. spaceHeight = Math.min(spaceHeight, maxHeight);
  28416. }
  28417. // Reset the legend height and adjust the clipping rectangle
  28418. pages.length = 0;
  28419. if (legendHeight > spaceHeight &&
  28420. navOptions.enabled !== false) {
  28421. this.clipHeight = clipHeight =
  28422. Math.max(spaceHeight - 20 - this.titleHeight - padding, 0);
  28423. this.currentPage = pick(this.currentPage, 1);
  28424. this.fullHeight = legendHeight;
  28425. // Fill pages with Y positions so that the top of each a legend item
  28426. // defines the scroll top for each page (#2098)
  28427. allItems.forEach(function (item, i) {
  28428. var y = item._legendItemPos[1],
  28429. h = Math.round(item.legendItem.getBBox().height),
  28430. len = pages.length;
  28431. if (!len || (y - pages[len - 1] > clipHeight &&
  28432. (lastY || y) !== pages[len - 1])) {
  28433. pages.push(lastY || y);
  28434. len++;
  28435. }
  28436. // Keep track of which page each item is on
  28437. item.pageIx = len - 1;
  28438. if (lastY) {
  28439. allItems[i - 1].pageIx = len - 1;
  28440. }
  28441. if (i === allItems.length - 1 &&
  28442. y + h - pages[len - 1] > clipHeight &&
  28443. y !== lastY // #2617
  28444. ) {
  28445. pages.push(y);
  28446. item.pageIx = len;
  28447. }
  28448. if (y !== lastY) {
  28449. lastY = y;
  28450. }
  28451. });
  28452. // Only apply clipping if needed. Clipping causes blurred legend in
  28453. // PDF export (#1787)
  28454. if (!clipRect) {
  28455. clipRect = legend.clipRect =
  28456. renderer.clipRect(0, padding, 9999, 0);
  28457. legend.contentGroup.clip(clipRect);
  28458. }
  28459. clipToHeight(clipHeight);
  28460. // Add navigation elements
  28461. if (!nav) {
  28462. this.nav = nav = renderer.g()
  28463. .attr({ zIndex: 1 })
  28464. .add(this.group);
  28465. this.up = renderer
  28466. .symbol('triangle', 0, 0, arrowSize, arrowSize)
  28467. .add(nav);
  28468. addTracker('upTracker')
  28469. .on('click', function () {
  28470. legend.scroll(-1, animation);
  28471. });
  28472. this.pager = renderer.text('', 15, 10)
  28473. .addClass('highcharts-legend-navigation');
  28474. if (!chart.styledMode) {
  28475. this.pager.css(navOptions.style);
  28476. }
  28477. this.pager.add(nav);
  28478. this.down = renderer
  28479. .symbol('triangle-down', 0, 0, arrowSize, arrowSize)
  28480. .add(nav);
  28481. addTracker('downTracker')
  28482. .on('click', function () {
  28483. legend.scroll(1, animation);
  28484. });
  28485. }
  28486. // Set initial position
  28487. legend.scroll(0);
  28488. legendHeight = spaceHeight;
  28489. // Reset
  28490. }
  28491. else if (nav) {
  28492. clipToHeight();
  28493. this.nav = nav.destroy(); // #6322
  28494. this.scrollGroup.attr({
  28495. translateY: 1
  28496. });
  28497. this.clipHeight = 0; // #1379
  28498. }
  28499. return legendHeight;
  28500. };
  28501. /**
  28502. * Scroll the legend by a number of pages.
  28503. *
  28504. * @private
  28505. * @function Highcharts.Legend#scroll
  28506. *
  28507. * @param {number} scrollBy
  28508. * The number of pages to scroll.
  28509. *
  28510. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
  28511. * Whether and how to apply animation.
  28512. *
  28513. * @return {void}
  28514. */
  28515. Legend.prototype.scroll = function (scrollBy, animation) {
  28516. var _this = this;
  28517. var chart = this.chart,
  28518. pages = this.pages,
  28519. pageCount = pages.length,
  28520. currentPage = this.currentPage + scrollBy,
  28521. clipHeight = this.clipHeight,
  28522. navOptions = this.options.navigation,
  28523. pager = this.pager,
  28524. padding = this.padding;
  28525. // When resizing while looking at the last page
  28526. if (currentPage > pageCount) {
  28527. currentPage = pageCount;
  28528. }
  28529. if (currentPage > 0) {
  28530. if (typeof animation !== 'undefined') {
  28531. setAnimation(animation, chart);
  28532. }
  28533. this.nav.attr({
  28534. translateX: padding,
  28535. translateY: clipHeight + this.padding + 7 + this.titleHeight,
  28536. visibility: 'visible'
  28537. });
  28538. [this.up, this.upTracker].forEach(function (elem) {
  28539. elem.attr({
  28540. 'class': currentPage === 1 ?
  28541. 'highcharts-legend-nav-inactive' :
  28542. 'highcharts-legend-nav-active'
  28543. });
  28544. });
  28545. pager.attr({
  28546. text: currentPage + '/' + pageCount
  28547. });
  28548. [this.down, this.downTracker].forEach(function (elem) {
  28549. elem.attr({
  28550. // adjust to text width
  28551. x: 18 + this.pager.getBBox().width,
  28552. 'class': currentPage === pageCount ?
  28553. 'highcharts-legend-nav-inactive' :
  28554. 'highcharts-legend-nav-active'
  28555. });
  28556. }, this);
  28557. if (!chart.styledMode) {
  28558. this.up
  28559. .attr({
  28560. fill: currentPage === 1 ?
  28561. navOptions.inactiveColor :
  28562. navOptions.activeColor
  28563. });
  28564. this.upTracker
  28565. .css({
  28566. cursor: currentPage === 1 ? 'default' : 'pointer'
  28567. });
  28568. this.down
  28569. .attr({
  28570. fill: currentPage === pageCount ?
  28571. navOptions.inactiveColor :
  28572. navOptions.activeColor
  28573. });
  28574. this.downTracker
  28575. .css({
  28576. cursor: currentPage === pageCount ?
  28577. 'default' :
  28578. 'pointer'
  28579. });
  28580. }
  28581. this.scrollOffset = -pages[currentPage - 1] + this.initialItemY;
  28582. this.scrollGroup.animate({
  28583. translateY: this.scrollOffset
  28584. });
  28585. this.currentPage = currentPage;
  28586. this.positionCheckboxes();
  28587. // Fire event after scroll animation is complete
  28588. var animOptions = animObject(pick(animation,
  28589. chart.renderer.globalAnimation,
  28590. true));
  28591. syncTimeout(function () {
  28592. fireEvent(_this, 'afterScroll', { currentPage: currentPage });
  28593. }, animOptions.duration);
  28594. }
  28595. };
  28596. /**
  28597. * @private
  28598. * @function Highcharts.Legend#setItemEvents
  28599. * @param {Highcharts.BubbleLegend|Point|Highcharts.Series} item
  28600. * @param {Highcharts.SVGElement} legendItem
  28601. * @param {boolean} [useHTML=false]
  28602. * @fires Highcharts.Point#event:legendItemClick
  28603. * @fires Highcharts.Series#event:legendItemClick
  28604. */
  28605. Legend.prototype.setItemEvents = function (item, legendItem, useHTML) {
  28606. var legend = this,
  28607. boxWrapper = legend.chart.renderer.boxWrapper,
  28608. isPoint = item instanceof Point,
  28609. activeClass = 'highcharts-legend-' +
  28610. (isPoint ? 'point' : 'series') + '-active',
  28611. styledMode = legend.chart.styledMode,
  28612. // When `useHTML`, the symbol is rendered in other group, so
  28613. // we need to apply events listeners to both places
  28614. legendItems = useHTML ?
  28615. [legendItem,
  28616. item.legendSymbol] :
  28617. [item.legendGroup];
  28618. // Set the events on the item group, or in case of useHTML, the item
  28619. // itself (#1249)
  28620. legendItems.forEach(function (element) {
  28621. if (element) {
  28622. element
  28623. .on('mouseover', function () {
  28624. if (item.visible) {
  28625. legend.allItems.forEach(function (inactiveItem) {
  28626. if (item !== inactiveItem) {
  28627. inactiveItem.setState('inactive', !isPoint);
  28628. }
  28629. });
  28630. }
  28631. item.setState('hover');
  28632. // A CSS class to dim or hide other than the hovered
  28633. // series.
  28634. // Works only if hovered series is visible (#10071).
  28635. if (item.visible) {
  28636. boxWrapper.addClass(activeClass);
  28637. }
  28638. if (!styledMode) {
  28639. legendItem.css(legend.options.itemHoverStyle);
  28640. }
  28641. })
  28642. .on('mouseout', function () {
  28643. if (!legend.chart.styledMode) {
  28644. legendItem.css(merge(item.visible ?
  28645. legend.itemStyle :
  28646. legend.itemHiddenStyle));
  28647. }
  28648. legend.allItems.forEach(function (inactiveItem) {
  28649. if (item !== inactiveItem) {
  28650. inactiveItem.setState('', !isPoint);
  28651. }
  28652. });
  28653. // A CSS class to dim or hide other than the hovered
  28654. // series.
  28655. boxWrapper.removeClass(activeClass);
  28656. item.setState();
  28657. })
  28658. .on('click', function (event) {
  28659. var strLegendItemClick = 'legendItemClick',
  28660. fnLegendItemClick = function () {
  28661. if (item.setVisible) {
  28662. item.setVisible();
  28663. }
  28664. // Reset inactive state
  28665. legend.allItems.forEach(function (inactiveItem) {
  28666. if (item !== inactiveItem) {
  28667. inactiveItem.setState(item.visible ? 'inactive' : '', !isPoint);
  28668. }
  28669. });
  28670. };
  28671. // A CSS class to dim or hide other than the hovered
  28672. // series. Event handling in iOS causes the activeClass
  28673. // to be added prior to click in some cases (#7418).
  28674. boxWrapper.removeClass(activeClass);
  28675. // Pass over the click/touch event. #4.
  28676. event = {
  28677. browserEvent: event
  28678. };
  28679. // click the name or symbol
  28680. if (item.firePointEvent) { // point
  28681. item.firePointEvent(strLegendItemClick, event, fnLegendItemClick);
  28682. }
  28683. else {
  28684. fireEvent(item, strLegendItemClick, event, fnLegendItemClick);
  28685. }
  28686. });
  28687. }
  28688. });
  28689. };
  28690. /**
  28691. * @private
  28692. * @function Highcharts.Legend#createCheckboxForItem
  28693. * @param {Highcharts.BubbleLegend|Point|Highcharts.Series} item
  28694. * @fires Highcharts.Series#event:checkboxClick
  28695. */
  28696. Legend.prototype.createCheckboxForItem = function (item) {
  28697. var legend = this;
  28698. item.checkbox = createElement('input', {
  28699. type: 'checkbox',
  28700. className: 'highcharts-legend-checkbox',
  28701. checked: item.selected,
  28702. defaultChecked: item.selected // required by IE7
  28703. }, legend.options.itemCheckboxStyle, legend.chart.container);
  28704. addEvent(item.checkbox, 'click', function (event) {
  28705. var target = event.target;
  28706. fireEvent(item.series || item, 'checkboxClick', {
  28707. checked: target.checked,
  28708. item: item
  28709. }, function () {
  28710. item.select();
  28711. });
  28712. });
  28713. };
  28714. return Legend;
  28715. }());
  28716. // Workaround for #2030, horizontal legend items not displaying in IE11 Preview,
  28717. // and for #2580, a similar drawing flaw in Firefox 26.
  28718. // Explore if there's a general cause for this. The problem may be related
  28719. // to nested group elements, as the legend item texts are within 4 group
  28720. // elements.
  28721. if (/Trident\/7\.0/.test(win.navigator && win.navigator.userAgent) ||
  28722. isFirefox) {
  28723. wrap(Legend.prototype, 'positionItem', function (proceed, item) {
  28724. var legend = this,
  28725. // If chart destroyed in sync, this is undefined (#2030)
  28726. runPositionItem = function () {
  28727. if (item._legendItemPos) {
  28728. proceed.call(legend,
  28729. item);
  28730. }
  28731. };
  28732. // Do it now, for export and to get checkbox placement
  28733. runPositionItem();
  28734. // Do it after to work around the core issue
  28735. if (!legend.bubbleLegend) {
  28736. setTimeout(runPositionItem);
  28737. }
  28738. });
  28739. }
  28740. H.Legend = Legend;
  28741. return H.Legend;
  28742. });
  28743. _registerModule(_modules, 'Core/Series/SeriesRegistry.js', [_modules['Core/Globals.js'], _modules['Core/Options.js'], _modules['Core/Series/Point.js'], _modules['Core/Utilities.js']], function (H, O, Point, U) {
  28744. /* *
  28745. *
  28746. * (c) 2010-2021 Torstein Honsi
  28747. *
  28748. * License: www.highcharts.com/license
  28749. *
  28750. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  28751. *
  28752. * */
  28753. var defaultOptions = O.defaultOptions;
  28754. var error = U.error,
  28755. extendClass = U.extendClass,
  28756. merge = U.merge;
  28757. /* *
  28758. *
  28759. * Namespace
  28760. *
  28761. * */
  28762. var SeriesRegistry;
  28763. (function (SeriesRegistry) {
  28764. /* *
  28765. *
  28766. * Static Properties
  28767. *
  28768. * */
  28769. SeriesRegistry.seriesTypes = {};
  28770. /* *
  28771. *
  28772. * Static Functions
  28773. *
  28774. * */
  28775. /* eslint-disable valid-jsdoc */
  28776. /**
  28777. * Internal function to initialize an individual series.
  28778. * @private
  28779. */
  28780. function getSeries(chart, options) {
  28781. if (options === void 0) { options = {}; }
  28782. var optionsChart = chart.options.chart,
  28783. type = (options.type ||
  28784. optionsChart.type ||
  28785. optionsChart.defaultSeriesType ||
  28786. ''),
  28787. SeriesClass = SeriesRegistry.seriesTypes[type];
  28788. // No such series type
  28789. if (!SeriesRegistry) {
  28790. error(17, true, chart, { missingModuleFor: type });
  28791. }
  28792. var series = new SeriesClass();
  28793. if (typeof series.init === 'function') {
  28794. series.init(chart, options);
  28795. }
  28796. return series;
  28797. }
  28798. SeriesRegistry.getSeries = getSeries;
  28799. /**
  28800. * Registers class pattern of a series.
  28801. *
  28802. * @private
  28803. */
  28804. function registerSeriesType(seriesType, seriesClass) {
  28805. var defaultPlotOptions = defaultOptions.plotOptions || {},
  28806. seriesOptions = seriesClass.defaultOptions;
  28807. if (!seriesClass.prototype.pointClass) {
  28808. seriesClass.prototype.pointClass = Point;
  28809. }
  28810. seriesClass.prototype.type = seriesType;
  28811. if (seriesOptions) {
  28812. defaultPlotOptions[seriesType] = seriesOptions;
  28813. }
  28814. SeriesRegistry.seriesTypes[seriesType] = seriesClass;
  28815. }
  28816. SeriesRegistry.registerSeriesType = registerSeriesType;
  28817. /**
  28818. * Old factory to create new series prototypes.
  28819. *
  28820. * @deprecated
  28821. * @function Highcharts.seriesType
  28822. *
  28823. * @param {string} type
  28824. * The series type name.
  28825. *
  28826. * @param {string} parent
  28827. * The parent series type name. Use `line` to inherit from the basic
  28828. * {@link Series} object.
  28829. *
  28830. * @param {Highcharts.SeriesOptionsType|Highcharts.Dictionary<*>} options
  28831. * The additional default options that are merged with the parent's options.
  28832. *
  28833. * @param {Highcharts.Dictionary<*>} [props]
  28834. * The properties (functions and primitives) to set on the new prototype.
  28835. *
  28836. * @param {Highcharts.Dictionary<*>} [pointProps]
  28837. * Members for a series-specific extension of the {@link Point} prototype if
  28838. * needed.
  28839. *
  28840. * @return {Highcharts.Series}
  28841. * The newly created prototype as extended from {@link Series} or its
  28842. * derivatives.
  28843. */
  28844. function seriesType(type, parent, options, seriesProto, pointProto) {
  28845. var defaultPlotOptions = defaultOptions.plotOptions || {};
  28846. parent = parent || '';
  28847. // Merge the options
  28848. defaultPlotOptions[type] = merge(defaultPlotOptions[parent], options);
  28849. // Create the class
  28850. registerSeriesType(type, extendClass(SeriesRegistry.seriesTypes[parent] || function () { }, seriesProto));
  28851. SeriesRegistry.seriesTypes[type].prototype.type = type;
  28852. // Create the point class if needed
  28853. if (pointProto) {
  28854. SeriesRegistry.seriesTypes[type].prototype.pointClass =
  28855. extendClass(Point, pointProto);
  28856. }
  28857. return SeriesRegistry.seriesTypes[type];
  28858. }
  28859. SeriesRegistry.seriesType = seriesType;
  28860. /* eslint-enable valid-jsdoc */
  28861. })(SeriesRegistry || (SeriesRegistry = {}));
  28862. /* *
  28863. *
  28864. * Compatibility
  28865. *
  28866. * */
  28867. H.seriesType = SeriesRegistry.seriesType;
  28868. H.seriesTypes = SeriesRegistry.seriesTypes;
  28869. /* *
  28870. *
  28871. * Export
  28872. *
  28873. * */
  28874. return SeriesRegistry;
  28875. });
  28876. _registerModule(_modules, 'Core/Chart/Chart.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Axis/Axis.js'], _modules['Core/Globals.js'], _modules['Core/Legend.js'], _modules['Core/MSPointer.js'], _modules['Core/Options.js'], _modules['Core/Color/Palette.js'], _modules['Core/Pointer.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Time.js'], _modules['Core/Utilities.js'], _modules['Core/Renderer/HTML/AST.js']], function (A, Axis, H, Legend, MSPointer, O, palette, Pointer, SeriesRegistry, Time, U, AST) {
  28877. /* *
  28878. *
  28879. * (c) 2010-2021 Torstein Honsi
  28880. *
  28881. * License: www.highcharts.com/license
  28882. *
  28883. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  28884. *
  28885. * */
  28886. var animate = A.animate,
  28887. animObject = A.animObject,
  28888. setAnimation = A.setAnimation;
  28889. var charts = H.charts,
  28890. doc = H.doc,
  28891. win = H.win;
  28892. var defaultOptions = O.defaultOptions,
  28893. time = O.time;
  28894. var seriesTypes = SeriesRegistry.seriesTypes;
  28895. var addEvent = U.addEvent,
  28896. attr = U.attr,
  28897. cleanRecursively = U.cleanRecursively,
  28898. createElement = U.createElement,
  28899. css = U.css,
  28900. defined = U.defined,
  28901. discardElement = U.discardElement,
  28902. erase = U.erase,
  28903. error = U.error,
  28904. extend = U.extend,
  28905. find = U.find,
  28906. fireEvent = U.fireEvent,
  28907. getStyle = U.getStyle,
  28908. isArray = U.isArray,
  28909. isFunction = U.isFunction,
  28910. isNumber = U.isNumber,
  28911. isObject = U.isObject,
  28912. isString = U.isString,
  28913. merge = U.merge,
  28914. numberFormat = U.numberFormat,
  28915. objectEach = U.objectEach,
  28916. pick = U.pick,
  28917. pInt = U.pInt,
  28918. relativeLength = U.relativeLength,
  28919. removeEvent = U.removeEvent,
  28920. splat = U.splat,
  28921. syncTimeout = U.syncTimeout,
  28922. uniqueKey = U.uniqueKey;
  28923. var marginNames = H.marginNames;
  28924. /* eslint-disable no-invalid-this, valid-jsdoc */
  28925. /**
  28926. * The Chart class. The recommended constructor is {@link Highcharts#chart}.
  28927. *
  28928. * @example
  28929. * var chart = Highcharts.chart('container', {
  28930. * title: {
  28931. * text: 'My chart'
  28932. * },
  28933. * series: [{
  28934. * data: [1, 3, 2, 4]
  28935. * }]
  28936. * })
  28937. *
  28938. * @class
  28939. * @name Highcharts.Chart
  28940. *
  28941. * @param {string|Highcharts.HTMLDOMElement} [renderTo]
  28942. * The DOM element to render to, or its id.
  28943. *
  28944. * @param {Highcharts.Options} options
  28945. * The chart options structure.
  28946. *
  28947. * @param {Highcharts.ChartCallbackFunction} [callback]
  28948. * Function to run when the chart has loaded and and all external images
  28949. * are loaded. Defining a
  28950. * [chart.events.load](https://api.highcharts.com/highcharts/chart.events.load)
  28951. * handler is equivalent.
  28952. */
  28953. var Chart = /** @class */ (function () {
  28954. function Chart(a, b, c) {
  28955. this.axes = void 0;
  28956. this.axisOffset = void 0;
  28957. this.bounds = void 0;
  28958. this.chartHeight = void 0;
  28959. this.chartWidth = void 0;
  28960. this.clipBox = void 0;
  28961. this.colorCounter = void 0;
  28962. this.container = void 0;
  28963. this.index = void 0;
  28964. this.isResizing = void 0;
  28965. this.labelCollectors = void 0;
  28966. this.legend = void 0;
  28967. this.margin = void 0;
  28968. this.numberFormatter = void 0;
  28969. this.options = void 0;
  28970. this.plotBox = void 0;
  28971. this.plotHeight = void 0;
  28972. this.plotLeft = void 0;
  28973. this.plotTop = void 0;
  28974. this.plotWidth = void 0;
  28975. this.pointCount = void 0;
  28976. this.pointer = void 0;
  28977. this.renderer = void 0;
  28978. this.renderTo = void 0;
  28979. this.series = void 0;
  28980. this.spacing = void 0;
  28981. this.spacingBox = void 0;
  28982. this.symbolCounter = void 0;
  28983. this.time = void 0;
  28984. this.titleOffset = void 0;
  28985. this.userOptions = void 0;
  28986. this.xAxis = void 0;
  28987. this.yAxis = void 0;
  28988. this.getArgs(a, b, c);
  28989. }
  28990. /* *
  28991. *
  28992. * Functions
  28993. *
  28994. * */
  28995. /**
  28996. * Handle the arguments passed to the constructor.
  28997. *
  28998. * @private
  28999. * @function Highcharts.Chart#getArgs
  29000. *
  29001. * @param {...Array<*>} arguments
  29002. * All arguments for the constructor.
  29003. *
  29004. * @fires Highcharts.Chart#event:init
  29005. * @fires Highcharts.Chart#event:afterInit
  29006. */
  29007. Chart.prototype.getArgs = function (a, b, c) {
  29008. // Remove the optional first argument, renderTo, and
  29009. // set it on this.
  29010. if (isString(a) || a.nodeName) {
  29011. this.renderTo = a;
  29012. this.init(b, c);
  29013. }
  29014. else {
  29015. this.init(a, b);
  29016. }
  29017. };
  29018. /**
  29019. * Overridable function that initializes the chart. The constructor's
  29020. * arguments are passed on directly.
  29021. *
  29022. * @function Highcharts.Chart#init
  29023. *
  29024. * @param {Highcharts.Options} userOptions
  29025. * Custom options.
  29026. *
  29027. * @param {Function} [callback]
  29028. * Function to run when the chart has loaded and and all external
  29029. * images are loaded.
  29030. *
  29031. * @return {void}
  29032. *
  29033. * @fires Highcharts.Chart#event:init
  29034. * @fires Highcharts.Chart#event:afterInit
  29035. */
  29036. Chart.prototype.init = function (userOptions, callback) {
  29037. // Handle regular options
  29038. var options,
  29039. // skip merging data points to increase performance
  29040. seriesOptions = userOptions.series,
  29041. userPlotOptions = userOptions.plotOptions || {};
  29042. // Fire the event with a default function
  29043. fireEvent(this, 'init', { args: arguments }, function () {
  29044. userOptions.series = null;
  29045. options = merge(defaultOptions, userOptions); // do the merge
  29046. var optionsChart = options.chart || {};
  29047. // Override (by copy of user options) or clear tooltip options
  29048. // in chart.options.plotOptions (#6218)
  29049. objectEach(options.plotOptions, function (typeOptions, type) {
  29050. if (isObject(typeOptions)) { // #8766
  29051. typeOptions.tooltip = (userPlotOptions[type] && // override by copy:
  29052. merge(userPlotOptions[type].tooltip)) || void 0; // or clear
  29053. }
  29054. });
  29055. // User options have higher priority than default options
  29056. // (#6218). In case of exporting: path is changed
  29057. options.tooltip.userOptions = (userOptions.chart &&
  29058. userOptions.chart.forExport &&
  29059. userOptions.tooltip.userOptions) || userOptions.tooltip;
  29060. // set back the series data
  29061. options.series = userOptions.series = seriesOptions;
  29062. /**
  29063. * The original options given to the constructor or a chart factory
  29064. * like {@link Highcharts.chart} and {@link Highcharts.stockChart}.
  29065. *
  29066. * @name Highcharts.Chart#userOptions
  29067. * @type {Highcharts.Options}
  29068. */
  29069. this.userOptions = userOptions;
  29070. var chartEvents = optionsChart.events;
  29071. this.margin = [];
  29072. this.spacing = [];
  29073. // Pixel data bounds for touch zoom
  29074. this.bounds = { h: {}, v: {} };
  29075. // An array of functions that returns labels that should be
  29076. // considered for anti-collision
  29077. this.labelCollectors = [];
  29078. this.callback = callback;
  29079. this.isResizing = 0;
  29080. /**
  29081. * The options structure for the chart after merging
  29082. * {@link #defaultOptions} and {@link #userOptions}. It contains
  29083. * members for the sub elements like series, legend, tooltip etc.
  29084. *
  29085. * @name Highcharts.Chart#options
  29086. * @type {Highcharts.Options}
  29087. */
  29088. this.options = options;
  29089. /**
  29090. * All the axes in the chart.
  29091. *
  29092. * @see Highcharts.Chart.xAxis
  29093. * @see Highcharts.Chart.yAxis
  29094. *
  29095. * @name Highcharts.Chart#axes
  29096. * @type {Array<Highcharts.Axis>}
  29097. */
  29098. this.axes = [];
  29099. /**
  29100. * All the current series in the chart.
  29101. *
  29102. * @name Highcharts.Chart#series
  29103. * @type {Array<Highcharts.Series>}
  29104. */
  29105. this.series = [];
  29106. /**
  29107. * The `Time` object associated with the chart. Since v6.0.5,
  29108. * time settings can be applied individually for each chart. If
  29109. * no individual settings apply, the `Time` object is shared by
  29110. * all instances.
  29111. *
  29112. * @name Highcharts.Chart#time
  29113. * @type {Highcharts.Time}
  29114. */
  29115. this.time =
  29116. userOptions.time && Object.keys(userOptions.time).length ?
  29117. new Time(userOptions.time) :
  29118. H.time;
  29119. /**
  29120. * Callback function to override the default function that formats
  29121. * all the numbers in the chart. Returns a string with the formatted
  29122. * number.
  29123. *
  29124. * @name Highcharts.Chart#numberFormatter
  29125. * @type {Highcharts.NumberFormatterCallbackFunction}
  29126. */
  29127. this.numberFormatter = optionsChart.numberFormatter || numberFormat;
  29128. /**
  29129. * Whether the chart is in styled mode, meaning all presentatinoal
  29130. * attributes are avoided.
  29131. *
  29132. * @name Highcharts.Chart#styledMode
  29133. * @type {boolean}
  29134. */
  29135. this.styledMode = optionsChart.styledMode;
  29136. this.hasCartesianSeries = optionsChart.showAxes;
  29137. var chart = this;
  29138. /**
  29139. * Index position of the chart in the {@link Highcharts#charts}
  29140. * property.
  29141. *
  29142. * @name Highcharts.Chart#index
  29143. * @type {number}
  29144. * @readonly
  29145. */
  29146. chart.index = charts.length; // Add the chart to the global lookup
  29147. charts.push(chart);
  29148. H.chartCount++;
  29149. // Chart event handlers
  29150. if (chartEvents) {
  29151. objectEach(chartEvents, function (event, eventType) {
  29152. if (isFunction(event)) {
  29153. addEvent(chart, eventType, event);
  29154. }
  29155. });
  29156. }
  29157. /**
  29158. * A collection of the X axes in the chart.
  29159. *
  29160. * @name Highcharts.Chart#xAxis
  29161. * @type {Array<Highcharts.Axis>}
  29162. */
  29163. chart.xAxis = [];
  29164. /**
  29165. * A collection of the Y axes in the chart.
  29166. *
  29167. * @name Highcharts.Chart#yAxis
  29168. * @type {Array<Highcharts.Axis>}
  29169. *
  29170. * @todo
  29171. * Make events official: Fire the event `afterInit`.
  29172. */
  29173. chart.yAxis = [];
  29174. chart.pointCount = chart.colorCounter = chart.symbolCounter = 0;
  29175. // Fire after init but before first render, before axes and series
  29176. // have been initialized.
  29177. fireEvent(chart, 'afterInit');
  29178. chart.firstRender();
  29179. });
  29180. };
  29181. /**
  29182. * Internal function to unitialize an individual series.
  29183. *
  29184. * @private
  29185. * @function Highcharts.Chart#initSeries
  29186. */
  29187. Chart.prototype.initSeries = function (options) {
  29188. var chart = this,
  29189. optionsChart = chart.options.chart,
  29190. type = (options.type ||
  29191. optionsChart.type ||
  29192. optionsChart.defaultSeriesType),
  29193. series,
  29194. SeriesClass = seriesTypes[type];
  29195. // No such series type
  29196. if (!SeriesClass) {
  29197. error(17, true, chart, { missingModuleFor: type });
  29198. }
  29199. series = new SeriesClass();
  29200. if (typeof series.init === 'function') {
  29201. series.init(chart, options);
  29202. }
  29203. return series;
  29204. };
  29205. /**
  29206. * Internal function to set data for all series with enabled sorting.
  29207. *
  29208. * @private
  29209. * @function Highcharts.Chart#setSeriesData
  29210. */
  29211. Chart.prototype.setSeriesData = function () {
  29212. this.getSeriesOrderByLinks().forEach(function (series) {
  29213. // We need to set data for series with sorting after series init
  29214. if (!series.points && !series.data && series.enabledDataSorting) {
  29215. series.setData(series.options.data, false);
  29216. }
  29217. });
  29218. };
  29219. /**
  29220. * Sort and return chart series in order depending on the number of linked
  29221. * series.
  29222. *
  29223. * @private
  29224. * @function Highcharts.Series#getSeriesOrderByLinks
  29225. * @return {Array<Highcharts.Series>}
  29226. */
  29227. Chart.prototype.getSeriesOrderByLinks = function () {
  29228. return this.series.concat().sort(function (a, b) {
  29229. if (a.linkedSeries.length || b.linkedSeries.length) {
  29230. return b.linkedSeries.length - a.linkedSeries.length;
  29231. }
  29232. return 0;
  29233. });
  29234. };
  29235. /**
  29236. * Order all series above a given index. When series are added and ordered
  29237. * by configuration, only the last series is handled (#248, #1123, #2456,
  29238. * #6112). This function is called on series initialization and destroy.
  29239. *
  29240. * @private
  29241. * @function Highcharts.Series#orderSeries
  29242. * @param {number} [fromIndex]
  29243. * If this is given, only the series above this index are handled.
  29244. */
  29245. Chart.prototype.orderSeries = function (fromIndex) {
  29246. var series = this.series,
  29247. i = fromIndex || 0;
  29248. for (; i < series.length; i++) {
  29249. if (series[i]) {
  29250. /**
  29251. * Contains the series' index in the `Chart.series` array.
  29252. *
  29253. * @name Highcharts.Series#index
  29254. * @type {number}
  29255. * @readonly
  29256. */
  29257. series[i].index = i;
  29258. series[i].name = series[i].getName();
  29259. }
  29260. }
  29261. };
  29262. /**
  29263. * Check whether a given point is within the plot area.
  29264. *
  29265. * @function Highcharts.Chart#isInsidePlot
  29266. *
  29267. * @param {number} plotX
  29268. * Pixel x relative to the plot area.
  29269. *
  29270. * @param {number} plotY
  29271. * Pixel y relative to the plot area.
  29272. *
  29273. * @param {boolean} [inverted]
  29274. * Whether the chart is inverted.
  29275. *
  29276. * @return {boolean}
  29277. * Returns true if the given point is inside the plot area.
  29278. */
  29279. Chart.prototype.isInsidePlot = function (plotX, plotY, inverted) {
  29280. var x = inverted ? plotY : plotX,
  29281. y = inverted ? plotX : plotY,
  29282. e = {
  29283. x: x,
  29284. y: y,
  29285. isInsidePlot: x >= 0 &&
  29286. x <= this.plotWidth &&
  29287. y >= 0 &&
  29288. y <= this.plotHeight
  29289. };
  29290. fireEvent(this, 'afterIsInsidePlot', e);
  29291. return e.isInsidePlot;
  29292. };
  29293. /**
  29294. * Redraw the chart after changes have been done to the data, axis extremes
  29295. * chart size or chart elements. All methods for updating axes, series or
  29296. * points have a parameter for redrawing the chart. This is `true` by
  29297. * default. But in many cases you want to do more than one operation on the
  29298. * chart before redrawing, for example add a number of points. In those
  29299. * cases it is a waste of resources to redraw the chart for each new point
  29300. * added. So you add the points and call `chart.redraw()` after.
  29301. *
  29302. * @function Highcharts.Chart#redraw
  29303. *
  29304. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
  29305. * If or how to apply animation to the redraw.
  29306. *
  29307. * @fires Highcharts.Chart#event:afterSetExtremes
  29308. * @fires Highcharts.Chart#event:beforeRedraw
  29309. * @fires Highcharts.Chart#event:predraw
  29310. * @fires Highcharts.Chart#event:redraw
  29311. * @fires Highcharts.Chart#event:render
  29312. * @fires Highcharts.Chart#event:updatedData
  29313. */
  29314. Chart.prototype.redraw = function (animation) {
  29315. fireEvent(this, 'beforeRedraw');
  29316. var chart = this,
  29317. axes = chart.hasCartesianSeries ? chart.axes : chart.colorAxis || [],
  29318. series = chart.series,
  29319. pointer = chart.pointer,
  29320. legend = chart.legend,
  29321. legendUserOptions = chart.userOptions.legend,
  29322. redrawLegend = chart.isDirtyLegend,
  29323. hasStackedSeries,
  29324. hasDirtyStacks,
  29325. isDirtyBox = chart.isDirtyBox,
  29326. i,
  29327. serie,
  29328. renderer = chart.renderer,
  29329. isHiddenChart = renderer.isHidden(),
  29330. afterRedraw = [];
  29331. // Handle responsive rules, not only on resize (#6130)
  29332. if (chart.setResponsive) {
  29333. chart.setResponsive(false);
  29334. }
  29335. // Set the global animation. When chart.hasRendered is not true, the
  29336. // redraw call comes from a responsive rule and animation should not
  29337. // occur.
  29338. setAnimation(chart.hasRendered ? animation : false, chart);
  29339. if (isHiddenChart) {
  29340. chart.temporaryDisplay();
  29341. }
  29342. // Adjust title layout (reflow multiline text)
  29343. chart.layOutTitles();
  29344. // link stacked series
  29345. i = series.length;
  29346. while (i--) {
  29347. serie = series[i];
  29348. if (serie.options.stacking || serie.options.centerInCategory) {
  29349. hasStackedSeries = true;
  29350. if (serie.isDirty) {
  29351. hasDirtyStacks = true;
  29352. break;
  29353. }
  29354. }
  29355. }
  29356. if (hasDirtyStacks) { // mark others as dirty
  29357. i = series.length;
  29358. while (i--) {
  29359. serie = series[i];
  29360. if (serie.options.stacking) {
  29361. serie.isDirty = true;
  29362. }
  29363. }
  29364. }
  29365. // Handle updated data in the series
  29366. series.forEach(function (serie) {
  29367. if (serie.isDirty) {
  29368. if (serie.options.legendType === 'point') {
  29369. if (typeof serie.updateTotals === 'function') {
  29370. serie.updateTotals();
  29371. }
  29372. redrawLegend = true;
  29373. }
  29374. else if (legendUserOptions &&
  29375. (legendUserOptions.labelFormatter ||
  29376. legendUserOptions.labelFormat)) {
  29377. redrawLegend = true; // #2165
  29378. }
  29379. }
  29380. if (serie.isDirtyData) {
  29381. fireEvent(serie, 'updatedData');
  29382. }
  29383. });
  29384. // handle added or removed series
  29385. if (redrawLegend && legend && legend.options.enabled) {
  29386. // draw legend graphics
  29387. legend.render();
  29388. chart.isDirtyLegend = false;
  29389. }
  29390. // reset stacks
  29391. if (hasStackedSeries) {
  29392. chart.getStacks();
  29393. }
  29394. // set axes scales
  29395. axes.forEach(function (axis) {
  29396. axis.updateNames();
  29397. axis.setScale();
  29398. });
  29399. chart.getMargins(); // #3098
  29400. // If one axis is dirty, all axes must be redrawn (#792, #2169)
  29401. axes.forEach(function (axis) {
  29402. if (axis.isDirty) {
  29403. isDirtyBox = true;
  29404. }
  29405. });
  29406. // redraw axes
  29407. axes.forEach(function (axis) {
  29408. // Fire 'afterSetExtremes' only if extremes are set
  29409. var key = axis.min + ',' + axis.max;
  29410. if (axis.extKey !== key) { // #821, #4452
  29411. axis.extKey = key;
  29412. // prevent a recursive call to chart.redraw() (#1119)
  29413. afterRedraw.push(function () {
  29414. fireEvent(axis, 'afterSetExtremes', extend(axis.eventArgs, axis.getExtremes())); // #747, #751
  29415. delete axis.eventArgs;
  29416. });
  29417. }
  29418. if (isDirtyBox || hasStackedSeries) {
  29419. axis.redraw();
  29420. }
  29421. });
  29422. // the plot areas size has changed
  29423. if (isDirtyBox) {
  29424. chart.drawChartBox();
  29425. }
  29426. // Fire an event before redrawing series, used by the boost module to
  29427. // clear previous series renderings.
  29428. fireEvent(chart, 'predraw');
  29429. // redraw affected series
  29430. series.forEach(function (serie) {
  29431. if ((isDirtyBox || serie.isDirty) && serie.visible) {
  29432. serie.redraw();
  29433. }
  29434. // Set it here, otherwise we will have unlimited 'updatedData' calls
  29435. // for a hidden series after setData(). Fixes #6012
  29436. serie.isDirtyData = false;
  29437. });
  29438. // move tooltip or reset
  29439. if (pointer) {
  29440. pointer.reset(true);
  29441. }
  29442. // redraw if canvas
  29443. renderer.draw();
  29444. // Fire the events
  29445. fireEvent(chart, 'redraw');
  29446. fireEvent(chart, 'render');
  29447. if (isHiddenChart) {
  29448. chart.temporaryDisplay(true);
  29449. }
  29450. // Fire callbacks that are put on hold until after the redraw
  29451. afterRedraw.forEach(function (callback) {
  29452. callback.call();
  29453. });
  29454. };
  29455. /**
  29456. * Get an axis, series or point object by `id` as given in the configuration
  29457. * options. Returns `undefined` if no item is found.
  29458. *
  29459. * @sample highcharts/plotoptions/series-id/
  29460. * Get series by id
  29461. *
  29462. * @function Highcharts.Chart#get
  29463. *
  29464. * @param {string} id
  29465. * The id as given in the configuration options.
  29466. *
  29467. * @return {Highcharts.Axis|Highcharts.Series|Highcharts.Point|undefined}
  29468. * The retrieved item.
  29469. */
  29470. Chart.prototype.get = function (id) {
  29471. var ret,
  29472. series = this.series,
  29473. i;
  29474. /**
  29475. * @private
  29476. * @param {Highcharts.Axis|Highcharts.Series} item
  29477. * @return {boolean}
  29478. */
  29479. function itemById(item) {
  29480. return (item.id === id ||
  29481. (item.options && item.options.id === id));
  29482. }
  29483. ret =
  29484. // Search axes
  29485. find(this.axes, itemById) ||
  29486. // Search series
  29487. find(this.series, itemById);
  29488. // Search points
  29489. for (i = 0; !ret && i < series.length; i++) {
  29490. ret = find(series[i].points || [], itemById);
  29491. }
  29492. return ret;
  29493. };
  29494. /**
  29495. * Create the Axis instances based on the config options.
  29496. *
  29497. * @private
  29498. * @function Highcharts.Chart#getAxes
  29499. * @fires Highcharts.Chart#event:afterGetAxes
  29500. * @fires Highcharts.Chart#event:getAxes
  29501. */
  29502. Chart.prototype.getAxes = function () {
  29503. var chart = this,
  29504. options = this.options,
  29505. xAxisOptions = options.xAxis = splat(options.xAxis || {}),
  29506. yAxisOptions = options.yAxis = splat(options.yAxis || {}),
  29507. optionsArray;
  29508. fireEvent(this, 'getAxes');
  29509. // make sure the options are arrays and add some members
  29510. xAxisOptions.forEach(function (axis, i) {
  29511. axis.index = i;
  29512. axis.isX = true;
  29513. });
  29514. yAxisOptions.forEach(function (axis, i) {
  29515. axis.index = i;
  29516. });
  29517. // concatenate all axis options into one array
  29518. optionsArray = xAxisOptions.concat(yAxisOptions);
  29519. optionsArray.forEach(function (axisOptions) {
  29520. new Axis(chart, axisOptions); // eslint-disable-line no-new
  29521. });
  29522. fireEvent(this, 'afterGetAxes');
  29523. };
  29524. /**
  29525. * Returns an array of all currently selected points in the chart. Points
  29526. * can be selected by clicking or programmatically by the
  29527. * {@link Highcharts.Point#select}
  29528. * function.
  29529. *
  29530. * @sample highcharts/plotoptions/series-allowpointselect-line/
  29531. * Get selected points
  29532. *
  29533. * @function Highcharts.Chart#getSelectedPoints
  29534. *
  29535. * @return {Array<Highcharts.Point>}
  29536. * The currently selected points.
  29537. */
  29538. Chart.prototype.getSelectedPoints = function () {
  29539. var points = [];
  29540. this.series.forEach(function (serie) {
  29541. // For one-to-one points inspect series.data in order to retrieve
  29542. // points outside the visible range (#6445). For grouped data,
  29543. // inspect the generated series.points.
  29544. points = points.concat(serie.getPointsCollection().filter(function (point) {
  29545. return pick(point.selectedStaging, point.selected);
  29546. }));
  29547. });
  29548. return points;
  29549. };
  29550. /**
  29551. * Returns an array of all currently selected series in the chart. Series
  29552. * can be selected either programmatically by the
  29553. * {@link Highcharts.Series#select}
  29554. * function or by checking the checkbox next to the legend item if
  29555. * [series.showCheckBox](https://api.highcharts.com/highcharts/plotOptions.series.showCheckbox)
  29556. * is true.
  29557. *
  29558. * @sample highcharts/members/chart-getselectedseries/
  29559. * Get selected series
  29560. *
  29561. * @function Highcharts.Chart#getSelectedSeries
  29562. *
  29563. * @return {Array<Highcharts.Series>}
  29564. * The currently selected series.
  29565. */
  29566. Chart.prototype.getSelectedSeries = function () {
  29567. return this.series.filter(function (serie) {
  29568. return serie.selected;
  29569. });
  29570. };
  29571. /**
  29572. * Set a new title or subtitle for the chart.
  29573. *
  29574. * @sample highcharts/members/chart-settitle/
  29575. * Set title text and styles
  29576. *
  29577. * @function Highcharts.Chart#setTitle
  29578. *
  29579. * @param {Highcharts.TitleOptions} [titleOptions]
  29580. * New title options. The title text itself is set by the
  29581. * `titleOptions.text` property.
  29582. *
  29583. * @param {Highcharts.SubtitleOptions} [subtitleOptions]
  29584. * New subtitle options. The subtitle text itself is set by the
  29585. * `subtitleOptions.text` property.
  29586. *
  29587. * @param {boolean} [redraw]
  29588. * Whether to redraw the chart or wait for a later call to
  29589. * `chart.redraw()`.
  29590. */
  29591. Chart.prototype.setTitle = function (titleOptions, subtitleOptions, redraw) {
  29592. this.applyDescription('title', titleOptions);
  29593. this.applyDescription('subtitle', subtitleOptions);
  29594. // The initial call also adds the caption. On update, chart.update will
  29595. // relay to Chart.setCaption.
  29596. this.applyDescription('caption', void 0);
  29597. this.layOutTitles(redraw);
  29598. };
  29599. /**
  29600. * Apply a title, subtitle or caption for the chart
  29601. *
  29602. * @private
  29603. * @function Highcharts.Chart#applyDescription
  29604. * @param name {string}
  29605. * Either title, subtitle or caption
  29606. * @param {Highcharts.TitleOptions|Highcharts.SubtitleOptions|Highcharts.CaptionOptions|undefined} explicitOptions
  29607. * The options to set, will be merged with default options.
  29608. */
  29609. Chart.prototype.applyDescription = function (name, explicitOptions) {
  29610. var chart = this;
  29611. // Default style
  29612. var style = name === 'title' ? {
  29613. color: palette.neutralColor80,
  29614. fontSize: this.options.isStock ? '16px' : '18px' // #2944
  29615. } : {
  29616. color: palette.neutralColor60
  29617. };
  29618. // Merge default options with explicit options
  29619. var options = this.options[name] = merge(
  29620. // Default styles
  29621. (!this.styledMode && { style: style }),
  29622. this.options[name],
  29623. explicitOptions);
  29624. var elem = this[name];
  29625. if (elem && explicitOptions) {
  29626. this[name] = elem = elem.destroy(); // remove old
  29627. }
  29628. if (options && !elem) {
  29629. elem = this.renderer.text(options.text, 0, 0, options.useHTML)
  29630. .attr({
  29631. align: options.align,
  29632. 'class': 'highcharts-' + name,
  29633. zIndex: options.zIndex || 4
  29634. })
  29635. .add();
  29636. // Update methods, shortcut to Chart.setTitle, Chart.setSubtitle and
  29637. // Chart.setCaption
  29638. elem.update = function (updateOptions) {
  29639. var fn = {
  29640. title: 'setTitle',
  29641. subtitle: 'setSubtitle',
  29642. caption: 'setCaption'
  29643. }[name];
  29644. chart[fn](updateOptions);
  29645. };
  29646. // Presentational
  29647. if (!this.styledMode) {
  29648. elem.css(options.style);
  29649. }
  29650. /**
  29651. * The chart title. The title has an `update` method that allows
  29652. * modifying the options directly or indirectly via
  29653. * `chart.update`.
  29654. *
  29655. * @sample highcharts/members/title-update/
  29656. * Updating titles
  29657. *
  29658. * @name Highcharts.Chart#title
  29659. * @type {Highcharts.TitleObject}
  29660. */
  29661. /**
  29662. * The chart subtitle. The subtitle has an `update` method that
  29663. * allows modifying the options directly or indirectly via
  29664. * `chart.update`.
  29665. *
  29666. * @name Highcharts.Chart#subtitle
  29667. * @type {Highcharts.SubtitleObject}
  29668. */
  29669. this[name] = elem;
  29670. }
  29671. };
  29672. /**
  29673. * Internal function to lay out the chart title, subtitle and caption, and
  29674. * cache the full offset height for use in `getMargins`. The result is
  29675. * stored in `this.titleOffset`.
  29676. *
  29677. * @private
  29678. * @function Highcharts.Chart#layOutTitles
  29679. *
  29680. * @param {boolean} [redraw=true]
  29681. * @fires Highcharts.Chart#event:afterLayOutTitles
  29682. */
  29683. Chart.prototype.layOutTitles = function (redraw) {
  29684. var titleOffset = [0, 0, 0],
  29685. requiresDirtyBox,
  29686. renderer = this.renderer,
  29687. spacingBox = this.spacingBox;
  29688. // Lay out the title and the subtitle respectively
  29689. ['title', 'subtitle', 'caption'].forEach(function (key) {
  29690. var title = this[key], titleOptions = this.options[key], verticalAlign = titleOptions.verticalAlign || 'top', offset = key === 'title' ? -3 :
  29691. // Floating subtitle (#6574)
  29692. verticalAlign === 'top' ? titleOffset[0] + 2 : 0, titleSize, height;
  29693. if (title) {
  29694. if (!this.styledMode) {
  29695. titleSize = titleOptions.style.fontSize;
  29696. }
  29697. titleSize = renderer.fontMetrics(titleSize, title).b;
  29698. title
  29699. .css({
  29700. width: (titleOptions.width ||
  29701. spacingBox.width + (titleOptions.widthAdjust || 0)) + 'px'
  29702. });
  29703. // Skip the cache for HTML (#3481, #11666)
  29704. height = Math.round(title.getBBox(titleOptions.useHTML).height);
  29705. title.align(extend({
  29706. y: verticalAlign === 'bottom' ?
  29707. titleSize :
  29708. offset + titleSize,
  29709. height: height
  29710. }, titleOptions), false, 'spacingBox');
  29711. if (!titleOptions.floating) {
  29712. if (verticalAlign === 'top') {
  29713. titleOffset[0] = Math.ceil(titleOffset[0] +
  29714. height);
  29715. }
  29716. else if (verticalAlign === 'bottom') {
  29717. titleOffset[2] = Math.ceil(titleOffset[2] +
  29718. height);
  29719. }
  29720. }
  29721. }
  29722. }, this);
  29723. // Handle title.margin and caption.margin
  29724. if (titleOffset[0] &&
  29725. (this.options.title.verticalAlign || 'top') === 'top') {
  29726. titleOffset[0] += this.options.title.margin;
  29727. }
  29728. if (titleOffset[2] &&
  29729. this.options.caption.verticalAlign === 'bottom') {
  29730. titleOffset[2] += this.options.caption.margin;
  29731. }
  29732. requiresDirtyBox = (!this.titleOffset ||
  29733. this.titleOffset.join(',') !== titleOffset.join(','));
  29734. // Used in getMargins
  29735. this.titleOffset = titleOffset;
  29736. fireEvent(this, 'afterLayOutTitles');
  29737. if (!this.isDirtyBox && requiresDirtyBox) {
  29738. this.isDirtyBox = this.isDirtyLegend = requiresDirtyBox;
  29739. // Redraw if necessary (#2719, #2744)
  29740. if (this.hasRendered && pick(redraw, true) && this.isDirtyBox) {
  29741. this.redraw();
  29742. }
  29743. }
  29744. };
  29745. /**
  29746. * Internal function to get the chart width and height according to options
  29747. * and container size. Sets {@link Chart.chartWidth} and
  29748. * {@link Chart.chartHeight}.
  29749. *
  29750. * @private
  29751. * @function Highcharts.Chart#getChartSize
  29752. */
  29753. Chart.prototype.getChartSize = function () {
  29754. var chart = this,
  29755. optionsChart = chart.options.chart,
  29756. widthOption = optionsChart.width,
  29757. heightOption = optionsChart.height,
  29758. renderTo = chart.renderTo;
  29759. // Get inner width and height
  29760. if (!defined(widthOption)) {
  29761. chart.containerWidth = getStyle(renderTo, 'width');
  29762. }
  29763. if (!defined(heightOption)) {
  29764. chart.containerHeight = getStyle(renderTo, 'height');
  29765. }
  29766. /**
  29767. * The current pixel width of the chart.
  29768. *
  29769. * @name Highcharts.Chart#chartWidth
  29770. * @type {number}
  29771. */
  29772. chart.chartWidth = Math.max(// #1393
  29773. 0, widthOption || chart.containerWidth || 600 // #1460
  29774. );
  29775. /**
  29776. * The current pixel height of the chart.
  29777. *
  29778. * @name Highcharts.Chart#chartHeight
  29779. * @type {number}
  29780. */
  29781. chart.chartHeight = Math.max(0, relativeLength(heightOption, chart.chartWidth) ||
  29782. (chart.containerHeight > 1 ?
  29783. chart.containerHeight :
  29784. 400));
  29785. };
  29786. /**
  29787. * If the renderTo element has no offsetWidth, most likely one or more of
  29788. * its parents are hidden. Loop up the DOM tree to temporarily display the
  29789. * parents, then save the original display properties, and when the true
  29790. * size is retrieved, reset them. Used on first render and on redraws.
  29791. *
  29792. * @private
  29793. * @function Highcharts.Chart#temporaryDisplay
  29794. *
  29795. * @param {boolean} [revert]
  29796. * Revert to the saved original styles.
  29797. */
  29798. Chart.prototype.temporaryDisplay = function (revert) {
  29799. var node = this.renderTo,
  29800. tempStyle;
  29801. if (!revert) {
  29802. while (node && node.style) {
  29803. // When rendering to a detached node, it needs to be temporarily
  29804. // attached in order to read styling and bounding boxes (#5783,
  29805. // #7024).
  29806. if (!doc.body.contains(node) && !node.parentNode) {
  29807. node.hcOrigDetached = true;
  29808. doc.body.appendChild(node);
  29809. }
  29810. if (getStyle(node, 'display', false) === 'none' ||
  29811. node.hcOricDetached) {
  29812. node.hcOrigStyle = {
  29813. display: node.style.display,
  29814. height: node.style.height,
  29815. overflow: node.style.overflow
  29816. };
  29817. tempStyle = {
  29818. display: 'block',
  29819. overflow: 'hidden'
  29820. };
  29821. if (node !== this.renderTo) {
  29822. tempStyle.height = 0;
  29823. }
  29824. css(node, tempStyle);
  29825. // If it still doesn't have an offset width after setting
  29826. // display to block, it probably has an !important priority
  29827. // #2631, 6803
  29828. if (!node.offsetWidth) {
  29829. node.style.setProperty('display', 'block', 'important');
  29830. }
  29831. }
  29832. node = node.parentNode;
  29833. if (node === doc.body) {
  29834. break;
  29835. }
  29836. }
  29837. }
  29838. else {
  29839. while (node && node.style) {
  29840. if (node.hcOrigStyle) {
  29841. css(node, node.hcOrigStyle);
  29842. delete node.hcOrigStyle;
  29843. }
  29844. if (node.hcOrigDetached) {
  29845. doc.body.removeChild(node);
  29846. node.hcOrigDetached = false;
  29847. }
  29848. node = node.parentNode;
  29849. }
  29850. }
  29851. };
  29852. /**
  29853. * Set the {@link Chart.container|chart container's} class name, in
  29854. * addition to `highcharts-container`.
  29855. *
  29856. * @function Highcharts.Chart#setClassName
  29857. *
  29858. * @param {string} [className]
  29859. * The additional class name.
  29860. */
  29861. Chart.prototype.setClassName = function (className) {
  29862. this.container.className = 'highcharts-container ' + (className || '');
  29863. };
  29864. /**
  29865. * Get the containing element, determine the size and create the inner
  29866. * container div to hold the chart.
  29867. *
  29868. * @private
  29869. * @function Highcharts.Chart#afterGetContainer
  29870. * @fires Highcharts.Chart#event:afterGetContainer
  29871. */
  29872. Chart.prototype.getContainer = function () {
  29873. var chart = this,
  29874. container,
  29875. options = chart.options,
  29876. optionsChart = options.chart,
  29877. chartWidth,
  29878. chartHeight,
  29879. renderTo = chart.renderTo,
  29880. indexAttrName = 'data-highcharts-chart',
  29881. oldChartIndex,
  29882. Ren,
  29883. containerId = uniqueKey(),
  29884. containerStyle,
  29885. key;
  29886. if (!renderTo) {
  29887. chart.renderTo = renderTo =
  29888. optionsChart.renderTo;
  29889. }
  29890. if (isString(renderTo)) {
  29891. chart.renderTo = renderTo =
  29892. doc.getElementById(renderTo);
  29893. }
  29894. // Display an error if the renderTo is wrong
  29895. if (!renderTo) {
  29896. error(13, true, chart);
  29897. }
  29898. // If the container already holds a chart, destroy it. The check for
  29899. // hasRendered is there because web pages that are saved to disk from
  29900. // the browser, will preserve the data-highcharts-chart attribute and
  29901. // the SVG contents, but not an interactive chart. So in this case,
  29902. // charts[oldChartIndex] will point to the wrong chart if any (#2609).
  29903. oldChartIndex = pInt(attr(renderTo, indexAttrName));
  29904. if (isNumber(oldChartIndex) &&
  29905. charts[oldChartIndex] &&
  29906. charts[oldChartIndex].hasRendered) {
  29907. charts[oldChartIndex].destroy();
  29908. }
  29909. // Make a reference to the chart from the div
  29910. attr(renderTo, indexAttrName, chart.index);
  29911. // remove previous chart
  29912. renderTo.innerHTML = '';
  29913. // If the container doesn't have an offsetWidth, it has or is a child of
  29914. // a node that has display:none. We need to temporarily move it out to a
  29915. // visible state to determine the size, else the legend and tooltips
  29916. // won't render properly. The skipClone option is used in sparklines as
  29917. // a micro optimization, saving about 1-2 ms each chart.
  29918. if (!optionsChart.skipClone && !renderTo.offsetWidth) {
  29919. chart.temporaryDisplay();
  29920. }
  29921. // get the width and height
  29922. chart.getChartSize();
  29923. chartWidth = chart.chartWidth;
  29924. chartHeight = chart.chartHeight;
  29925. // Allow table cells and flex-boxes to shrink without the chart blocking
  29926. // them out (#6427)
  29927. css(renderTo, { overflow: 'hidden' });
  29928. // Create the inner container
  29929. if (!chart.styledMode) {
  29930. containerStyle = extend({
  29931. position: 'relative',
  29932. // needed for context menu (avoidscrollbars) and content
  29933. // overflow in IE
  29934. overflow: 'hidden',
  29935. width: chartWidth + 'px',
  29936. height: chartHeight + 'px',
  29937. textAlign: 'left',
  29938. lineHeight: 'normal',
  29939. zIndex: 0,
  29940. '-webkit-tap-highlight-color': 'rgba(0,0,0,0)',
  29941. userSelect: 'none' // #13503
  29942. }, optionsChart.style);
  29943. }
  29944. /**
  29945. * The containing HTML element of the chart. The container is
  29946. * dynamically inserted into the element given as the `renderTo`
  29947. * parameter in the {@link Highcharts#chart} constructor.
  29948. *
  29949. * @name Highcharts.Chart#container
  29950. * @type {Highcharts.HTMLDOMElement}
  29951. */
  29952. container = createElement('div', {
  29953. id: containerId
  29954. }, containerStyle, renderTo);
  29955. chart.container = container;
  29956. // cache the cursor (#1650)
  29957. chart._cursor = container.style.cursor;
  29958. // Initialize the renderer
  29959. Ren = H[optionsChart.renderer] || H.Renderer;
  29960. /**
  29961. * The renderer instance of the chart. Each chart instance has only one
  29962. * associated renderer.
  29963. *
  29964. * @name Highcharts.Chart#renderer
  29965. * @type {Highcharts.SVGRenderer}
  29966. */
  29967. chart.renderer = new Ren(container, chartWidth, chartHeight, null, optionsChart.forExport, options.exporting && options.exporting.allowHTML, chart.styledMode);
  29968. // Set the initial animation from the options
  29969. setAnimation(void 0, chart);
  29970. chart.setClassName(optionsChart.className);
  29971. if (!chart.styledMode) {
  29972. chart.renderer.setStyle(optionsChart.style);
  29973. }
  29974. else {
  29975. // Initialize definitions
  29976. for (key in options.defs) { // eslint-disable-line guard-for-in
  29977. this.renderer.definition(options.defs[key]);
  29978. }
  29979. }
  29980. // Add a reference to the charts index
  29981. chart.renderer.chartIndex = chart.index;
  29982. fireEvent(this, 'afterGetContainer');
  29983. };
  29984. /**
  29985. * Calculate margins by rendering axis labels in a preliminary position.
  29986. * Title, subtitle and legend have already been rendered at this stage, but
  29987. * will be moved into their final positions.
  29988. *
  29989. * @private
  29990. * @function Highcharts.Chart#getMargins
  29991. * @fires Highcharts.Chart#event:getMargins
  29992. */
  29993. Chart.prototype.getMargins = function (skipAxes) {
  29994. var _a = this,
  29995. spacing = _a.spacing,
  29996. margin = _a.margin,
  29997. titleOffset = _a.titleOffset;
  29998. this.resetMargins();
  29999. // Adjust for title and subtitle
  30000. if (titleOffset[0] && !defined(margin[0])) {
  30001. this.plotTop = Math.max(this.plotTop, titleOffset[0] + spacing[0]);
  30002. }
  30003. if (titleOffset[2] && !defined(margin[2])) {
  30004. this.marginBottom = Math.max(this.marginBottom, titleOffset[2] + spacing[2]);
  30005. }
  30006. // Adjust for legend
  30007. if (this.legend && this.legend.display) {
  30008. this.legend.adjustMargins(margin, spacing);
  30009. }
  30010. fireEvent(this, 'getMargins');
  30011. if (!skipAxes) {
  30012. this.getAxisMargins();
  30013. }
  30014. };
  30015. /**
  30016. * @private
  30017. * @function Highcharts.Chart#getAxisMargins
  30018. */
  30019. Chart.prototype.getAxisMargins = function () {
  30020. var chart = this,
  30021. // [top, right, bottom, left]
  30022. axisOffset = chart.axisOffset = [0, 0, 0, 0],
  30023. colorAxis = chart.colorAxis,
  30024. margin = chart.margin,
  30025. getOffset = function (axes) {
  30026. axes.forEach(function (axis) {
  30027. if (axis.visible) {
  30028. axis.getOffset();
  30029. }
  30030. });
  30031. };
  30032. // pre-render axes to get labels offset width
  30033. if (chart.hasCartesianSeries) {
  30034. getOffset(chart.axes);
  30035. }
  30036. else if (colorAxis && colorAxis.length) {
  30037. getOffset(colorAxis);
  30038. }
  30039. // Add the axis offsets
  30040. marginNames.forEach(function (m, side) {
  30041. if (!defined(margin[side])) {
  30042. chart[m] += axisOffset[side];
  30043. }
  30044. });
  30045. chart.setChartSize();
  30046. };
  30047. /**
  30048. * Reflows the chart to its container. By default, the chart reflows
  30049. * automatically to its container following a `window.resize` event, as per
  30050. * the [chart.reflow](https://api.highcharts.com/highcharts/chart.reflow)
  30051. * option. However, there are no reliable events for div resize, so if the
  30052. * container is resized without a window resize event, this must be called
  30053. * explicitly.
  30054. *
  30055. * @sample highcharts/members/chart-reflow/
  30056. * Resize div and reflow
  30057. * @sample highcharts/chart/events-container/
  30058. * Pop up and reflow
  30059. *
  30060. * @function Highcharts.Chart#reflow
  30061. *
  30062. * @param {global.Event} [e]
  30063. * Event arguments. Used primarily when the function is called
  30064. * internally as a response to window resize.
  30065. */
  30066. Chart.prototype.reflow = function (e) {
  30067. var chart = this, optionsChart = chart.options.chart, renderTo = chart.renderTo, hasUserSize = (defined(optionsChart.width) &&
  30068. defined(optionsChart.height)), width = optionsChart.width || getStyle(renderTo, 'width'), height = optionsChart.height || getStyle(renderTo, 'height'), target = e ? e.target : win;
  30069. delete chart.pointer.chartPosition;
  30070. // Width and height checks for display:none. Target is doc in IE8 and
  30071. // Opera, win in Firefox, Chrome and IE9.
  30072. if (!hasUserSize &&
  30073. !chart.isPrinting &&
  30074. width &&
  30075. height &&
  30076. (target === win || target === doc)) {
  30077. if (width !== chart.containerWidth ||
  30078. height !== chart.containerHeight) {
  30079. U.clearTimeout(chart.reflowTimeout);
  30080. // When called from window.resize, e is set, else it's called
  30081. // directly (#2224)
  30082. chart.reflowTimeout = syncTimeout(function () {
  30083. // Set size, it may have been destroyed in the meantime
  30084. // (#1257)
  30085. if (chart.container) {
  30086. chart.setSize(void 0, void 0, false);
  30087. }
  30088. }, e ? 100 : 0);
  30089. }
  30090. chart.containerWidth = width;
  30091. chart.containerHeight = height;
  30092. }
  30093. };
  30094. /**
  30095. * Toggle the event handlers necessary for auto resizing, depending on the
  30096. * `chart.reflow` option.
  30097. *
  30098. * @private
  30099. * @function Highcharts.Chart#setReflow
  30100. */
  30101. Chart.prototype.setReflow = function (reflow) {
  30102. var chart = this;
  30103. if (reflow !== false && !this.unbindReflow) {
  30104. this.unbindReflow = addEvent(win, 'resize', function (e) {
  30105. // a removed event listener still runs in Edge and IE if the
  30106. // listener was removed while the event runs, so check if the
  30107. // chart is not destroyed (#11609)
  30108. if (chart.options) {
  30109. chart.reflow(e);
  30110. }
  30111. });
  30112. addEvent(this, 'destroy', this.unbindReflow);
  30113. }
  30114. else if (reflow === false && this.unbindReflow) {
  30115. // Unbind and unset
  30116. this.unbindReflow = this.unbindReflow();
  30117. }
  30118. // The following will add listeners to re-fit the chart before and after
  30119. // printing (#2284). However it only works in WebKit. Should have worked
  30120. // in Firefox, but not supported in IE.
  30121. /*
  30122. if (win.matchMedia) {
  30123. win.matchMedia('print').addListener(function reflow() {
  30124. chart.reflow();
  30125. });
  30126. }
  30127. //*/
  30128. };
  30129. /**
  30130. * Resize the chart to a given width and height. In order to set the width
  30131. * only, the height argument may be skipped. To set the height only, pass
  30132. * `undefined` for the width.
  30133. *
  30134. * @sample highcharts/members/chart-setsize-button/
  30135. * Test resizing from buttons
  30136. * @sample highcharts/members/chart-setsize-jquery-resizable/
  30137. * Add a jQuery UI resizable
  30138. * @sample stock/members/chart-setsize/
  30139. * Highstock with UI resizable
  30140. *
  30141. * @function Highcharts.Chart#setSize
  30142. *
  30143. * @param {number|null} [width]
  30144. * The new pixel width of the chart. Since v4.2.6, the argument can
  30145. * be `undefined` in order to preserve the current value (when
  30146. * setting height only), or `null` to adapt to the width of the
  30147. * containing element.
  30148. *
  30149. * @param {number|null} [height]
  30150. * The new pixel height of the chart. Since v4.2.6, the argument can
  30151. * be `undefined` in order to preserve the current value, or `null`
  30152. * in order to adapt to the height of the containing element.
  30153. *
  30154. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=true]
  30155. * Whether and how to apply animation.
  30156. *
  30157. * @return {void}
  30158. *
  30159. * @fires Highcharts.Chart#event:endResize
  30160. * @fires Highcharts.Chart#event:resize
  30161. */
  30162. Chart.prototype.setSize = function (width, height, animation) {
  30163. var chart = this,
  30164. renderer = chart.renderer,
  30165. globalAnimation;
  30166. // Handle the isResizing counter
  30167. chart.isResizing += 1;
  30168. // set the animation for the current process
  30169. setAnimation(animation, chart);
  30170. globalAnimation = renderer.globalAnimation;
  30171. chart.oldChartHeight = chart.chartHeight;
  30172. chart.oldChartWidth = chart.chartWidth;
  30173. if (typeof width !== 'undefined') {
  30174. chart.options.chart.width = width;
  30175. }
  30176. if (typeof height !== 'undefined') {
  30177. chart.options.chart.height = height;
  30178. }
  30179. chart.getChartSize();
  30180. // Resize the container with the global animation applied if enabled
  30181. // (#2503)
  30182. if (!chart.styledMode) {
  30183. (globalAnimation ? animate : css)(chart.container, {
  30184. width: chart.chartWidth + 'px',
  30185. height: chart.chartHeight + 'px'
  30186. }, globalAnimation);
  30187. }
  30188. chart.setChartSize(true);
  30189. renderer.setSize(chart.chartWidth, chart.chartHeight, globalAnimation);
  30190. // handle axes
  30191. chart.axes.forEach(function (axis) {
  30192. axis.isDirty = true;
  30193. axis.setScale();
  30194. });
  30195. chart.isDirtyLegend = true; // force legend redraw
  30196. chart.isDirtyBox = true; // force redraw of plot and chart border
  30197. chart.layOutTitles(); // #2857
  30198. chart.getMargins();
  30199. chart.redraw(globalAnimation);
  30200. chart.oldChartHeight = null;
  30201. fireEvent(chart, 'resize');
  30202. // Fire endResize and set isResizing back. If animation is disabled,
  30203. // fire without delay
  30204. syncTimeout(function () {
  30205. if (chart) {
  30206. fireEvent(chart, 'endResize', null, function () {
  30207. chart.isResizing -= 1;
  30208. });
  30209. }
  30210. }, animObject(globalAnimation).duration);
  30211. };
  30212. /**
  30213. * Set the public chart properties. This is done before and after the
  30214. * pre-render to determine margin sizes.
  30215. *
  30216. * @private
  30217. * @function Highcharts.Chart#setChartSize
  30218. * @fires Highcharts.Chart#event:afterSetChartSize
  30219. */
  30220. Chart.prototype.setChartSize = function (skipAxes) {
  30221. var chart = this,
  30222. inverted = chart.inverted,
  30223. renderer = chart.renderer,
  30224. chartWidth = chart.chartWidth,
  30225. chartHeight = chart.chartHeight,
  30226. optionsChart = chart.options.chart,
  30227. spacing = chart.spacing,
  30228. clipOffset = chart.clipOffset,
  30229. clipX,
  30230. clipY,
  30231. plotLeft,
  30232. plotTop,
  30233. plotWidth,
  30234. plotHeight,
  30235. plotBorderWidth;
  30236. /**
  30237. * The current left position of the plot area in pixels.
  30238. *
  30239. * @name Highcharts.Chart#plotLeft
  30240. * @type {number}
  30241. */
  30242. chart.plotLeft = plotLeft = Math.round(chart.plotLeft);
  30243. /**
  30244. * The current top position of the plot area in pixels.
  30245. *
  30246. * @name Highcharts.Chart#plotTop
  30247. * @type {number}
  30248. */
  30249. chart.plotTop = plotTop = Math.round(chart.plotTop);
  30250. /**
  30251. * The current width of the plot area in pixels.
  30252. *
  30253. * @name Highcharts.Chart#plotWidth
  30254. * @type {number}
  30255. */
  30256. chart.plotWidth = plotWidth = Math.max(0, Math.round(chartWidth - plotLeft - chart.marginRight));
  30257. /**
  30258. * The current height of the plot area in pixels.
  30259. *
  30260. * @name Highcharts.Chart#plotHeight
  30261. * @type {number}
  30262. */
  30263. chart.plotHeight = plotHeight = Math.max(0, Math.round(chartHeight - plotTop - chart.marginBottom));
  30264. chart.plotSizeX = inverted ? plotHeight : plotWidth;
  30265. chart.plotSizeY = inverted ? plotWidth : plotHeight;
  30266. chart.plotBorderWidth = optionsChart.plotBorderWidth || 0;
  30267. // Set boxes used for alignment
  30268. chart.spacingBox = renderer.spacingBox = {
  30269. x: spacing[3],
  30270. y: spacing[0],
  30271. width: chartWidth - spacing[3] - spacing[1],
  30272. height: chartHeight - spacing[0] - spacing[2]
  30273. };
  30274. chart.plotBox = renderer.plotBox = {
  30275. x: plotLeft,
  30276. y: plotTop,
  30277. width: plotWidth,
  30278. height: plotHeight
  30279. };
  30280. plotBorderWidth = 2 * Math.floor(chart.plotBorderWidth / 2);
  30281. clipX = Math.ceil(Math.max(plotBorderWidth, clipOffset[3]) / 2);
  30282. clipY = Math.ceil(Math.max(plotBorderWidth, clipOffset[0]) / 2);
  30283. chart.clipBox = {
  30284. x: clipX,
  30285. y: clipY,
  30286. width: Math.floor(chart.plotSizeX -
  30287. Math.max(plotBorderWidth, clipOffset[1]) / 2 -
  30288. clipX),
  30289. height: Math.max(0, Math.floor(chart.plotSizeY -
  30290. Math.max(plotBorderWidth, clipOffset[2]) / 2 -
  30291. clipY))
  30292. };
  30293. if (!skipAxes) {
  30294. chart.axes.forEach(function (axis) {
  30295. axis.setAxisSize();
  30296. axis.setAxisTranslation();
  30297. });
  30298. }
  30299. fireEvent(chart, 'afterSetChartSize', { skipAxes: skipAxes });
  30300. };
  30301. /**
  30302. * Initial margins before auto size margins are applied.
  30303. *
  30304. * @private
  30305. * @function Highcharts.Chart#resetMargins
  30306. */
  30307. Chart.prototype.resetMargins = function () {
  30308. fireEvent(this, 'resetMargins');
  30309. var chart = this,
  30310. chartOptions = chart.options.chart;
  30311. // Create margin and spacing array
  30312. ['margin', 'spacing'].forEach(function splashArrays(target) {
  30313. var value = chartOptions[target],
  30314. values = isObject(value) ? value : [value,
  30315. value,
  30316. value,
  30317. value];
  30318. [
  30319. 'Top',
  30320. 'Right',
  30321. 'Bottom',
  30322. 'Left'
  30323. ].forEach(function (sideName, side) {
  30324. chart[target][side] = pick(chartOptions[target + sideName], values[side]);
  30325. });
  30326. });
  30327. // Set margin names like chart.plotTop, chart.plotLeft,
  30328. // chart.marginRight, chart.marginBottom.
  30329. marginNames.forEach(function (m, side) {
  30330. chart[m] = pick(chart.margin[side], chart.spacing[side]);
  30331. });
  30332. chart.axisOffset = [0, 0, 0, 0]; // top, right, bottom, left
  30333. chart.clipOffset = [0, 0, 0, 0];
  30334. };
  30335. /**
  30336. * Internal function to draw or redraw the borders and backgrounds for chart
  30337. * and plot area.
  30338. *
  30339. * @private
  30340. * @function Highcharts.Chart#drawChartBox
  30341. * @fires Highcharts.Chart#event:afterDrawChartBox
  30342. */
  30343. Chart.prototype.drawChartBox = function () {
  30344. var chart = this,
  30345. optionsChart = chart.options.chart,
  30346. renderer = chart.renderer,
  30347. chartWidth = chart.chartWidth,
  30348. chartHeight = chart.chartHeight,
  30349. chartBackground = chart.chartBackground,
  30350. plotBackground = chart.plotBackground,
  30351. plotBorder = chart.plotBorder,
  30352. chartBorderWidth,
  30353. styledMode = chart.styledMode,
  30354. plotBGImage = chart.plotBGImage,
  30355. chartBackgroundColor = optionsChart.backgroundColor,
  30356. plotBackgroundColor = optionsChart.plotBackgroundColor,
  30357. plotBackgroundImage = optionsChart.plotBackgroundImage,
  30358. mgn,
  30359. bgAttr,
  30360. plotLeft = chart.plotLeft,
  30361. plotTop = chart.plotTop,
  30362. plotWidth = chart.plotWidth,
  30363. plotHeight = chart.plotHeight,
  30364. plotBox = chart.plotBox,
  30365. clipRect = chart.clipRect,
  30366. clipBox = chart.clipBox,
  30367. verb = 'animate';
  30368. // Chart area
  30369. if (!chartBackground) {
  30370. chart.chartBackground = chartBackground = renderer.rect()
  30371. .addClass('highcharts-background')
  30372. .add();
  30373. verb = 'attr';
  30374. }
  30375. if (!styledMode) {
  30376. // Presentational
  30377. chartBorderWidth = optionsChart.borderWidth || 0;
  30378. mgn = chartBorderWidth + (optionsChart.shadow ? 8 : 0);
  30379. bgAttr = {
  30380. fill: chartBackgroundColor || 'none'
  30381. };
  30382. if (chartBorderWidth || chartBackground['stroke-width']) { // #980
  30383. bgAttr.stroke = optionsChart.borderColor;
  30384. bgAttr['stroke-width'] = chartBorderWidth;
  30385. }
  30386. chartBackground
  30387. .attr(bgAttr)
  30388. .shadow(optionsChart.shadow);
  30389. }
  30390. else {
  30391. chartBorderWidth = mgn = chartBackground.strokeWidth();
  30392. }
  30393. chartBackground[verb]({
  30394. x: mgn / 2,
  30395. y: mgn / 2,
  30396. width: chartWidth - mgn - chartBorderWidth % 2,
  30397. height: chartHeight - mgn - chartBorderWidth % 2,
  30398. r: optionsChart.borderRadius
  30399. });
  30400. // Plot background
  30401. verb = 'animate';
  30402. if (!plotBackground) {
  30403. verb = 'attr';
  30404. chart.plotBackground = plotBackground = renderer.rect()
  30405. .addClass('highcharts-plot-background')
  30406. .add();
  30407. }
  30408. plotBackground[verb](plotBox);
  30409. if (!styledMode) {
  30410. // Presentational attributes for the background
  30411. plotBackground
  30412. .attr({
  30413. fill: plotBackgroundColor || 'none'
  30414. })
  30415. .shadow(optionsChart.plotShadow);
  30416. // Create the background image
  30417. if (plotBackgroundImage) {
  30418. if (!plotBGImage) {
  30419. chart.plotBGImage = renderer.image(plotBackgroundImage, plotLeft, plotTop, plotWidth, plotHeight).add();
  30420. }
  30421. else {
  30422. if (plotBackgroundImage !== plotBGImage.attr('href')) {
  30423. plotBGImage.attr('href', plotBackgroundImage);
  30424. }
  30425. plotBGImage.animate(plotBox);
  30426. }
  30427. }
  30428. }
  30429. // Plot clip
  30430. if (!clipRect) {
  30431. chart.clipRect = renderer.clipRect(clipBox);
  30432. }
  30433. else {
  30434. clipRect.animate({
  30435. width: clipBox.width,
  30436. height: clipBox.height
  30437. });
  30438. }
  30439. // Plot area border
  30440. verb = 'animate';
  30441. if (!plotBorder) {
  30442. verb = 'attr';
  30443. chart.plotBorder = plotBorder = renderer.rect()
  30444. .addClass('highcharts-plot-border')
  30445. .attr({
  30446. zIndex: 1 // Above the grid
  30447. })
  30448. .add();
  30449. }
  30450. if (!styledMode) {
  30451. // Presentational
  30452. plotBorder.attr({
  30453. stroke: optionsChart.plotBorderColor,
  30454. 'stroke-width': optionsChart.plotBorderWidth || 0,
  30455. fill: 'none'
  30456. });
  30457. }
  30458. plotBorder[verb](plotBorder.crisp({
  30459. x: plotLeft,
  30460. y: plotTop,
  30461. width: plotWidth,
  30462. height: plotHeight
  30463. }, -plotBorder.strokeWidth())); // #3282 plotBorder should be negative;
  30464. // reset
  30465. chart.isDirtyBox = false;
  30466. fireEvent(this, 'afterDrawChartBox');
  30467. };
  30468. /**
  30469. * Detect whether a certain chart property is needed based on inspecting its
  30470. * options and series. This mainly applies to the chart.inverted property,
  30471. * and in extensions to the chart.angular and chart.polar properties.
  30472. *
  30473. * @private
  30474. * @function Highcharts.Chart#propFromSeries
  30475. * @return {void}
  30476. */
  30477. Chart.prototype.propFromSeries = function () {
  30478. var chart = this,
  30479. optionsChart = chart.options.chart,
  30480. klass,
  30481. seriesOptions = chart.options.series,
  30482. i,
  30483. value;
  30484. /**
  30485. * The flag is set to `true` if a series of the chart is inverted.
  30486. *
  30487. * @name Highcharts.Chart#inverted
  30488. * @type {boolean|undefined}
  30489. */
  30490. ['inverted', 'angular', 'polar'].forEach(function (key) {
  30491. // The default series type's class
  30492. klass = seriesTypes[(optionsChart.type || optionsChart.defaultSeriesType)];
  30493. // Get the value from available chart-wide properties
  30494. value =
  30495. // It is set in the options:
  30496. optionsChart[key] ||
  30497. // The default series class:
  30498. (klass && klass.prototype[key]);
  30499. // requires it
  30500. // 4. Check if any the chart's series require it
  30501. i = seriesOptions && seriesOptions.length;
  30502. while (!value && i--) {
  30503. klass = seriesTypes[seriesOptions[i].type];
  30504. if (klass && klass.prototype[key]) {
  30505. value = true;
  30506. }
  30507. }
  30508. // Set the chart property
  30509. chart[key] = value;
  30510. });
  30511. };
  30512. /**
  30513. * Internal function to link two or more series together, based on the
  30514. * `linkedTo` option. This is done from `Chart.render`, and after
  30515. * `Chart.addSeries` and `Series.remove`.
  30516. *
  30517. * @private
  30518. * @function Highcharts.Chart#linkSeries
  30519. * @fires Highcharts.Chart#event:afterLinkSeries
  30520. */
  30521. Chart.prototype.linkSeries = function () {
  30522. var chart = this,
  30523. chartSeries = chart.series;
  30524. // Reset links
  30525. chartSeries.forEach(function (series) {
  30526. series.linkedSeries.length = 0;
  30527. });
  30528. // Apply new links
  30529. chartSeries.forEach(function (series) {
  30530. var linkedTo = series.options.linkedTo;
  30531. if (isString(linkedTo)) {
  30532. if (linkedTo === ':previous') {
  30533. linkedTo = chart.series[series.index - 1];
  30534. }
  30535. else {
  30536. linkedTo = chart.get(linkedTo);
  30537. }
  30538. // #3341 avoid mutual linking
  30539. if (linkedTo && linkedTo.linkedParent !== series) {
  30540. linkedTo.linkedSeries.push(series);
  30541. series.linkedParent = linkedTo;
  30542. if (linkedTo.enabledDataSorting) {
  30543. series.setDataSortingOptions();
  30544. }
  30545. series.visible = pick(series.options.visible, linkedTo.options.visible, series.visible); // #3879
  30546. }
  30547. }
  30548. });
  30549. fireEvent(this, 'afterLinkSeries');
  30550. };
  30551. /**
  30552. * Render series for the chart.
  30553. *
  30554. * @private
  30555. * @function Highcharts.Chart#renderSeries
  30556. */
  30557. Chart.prototype.renderSeries = function () {
  30558. this.series.forEach(function (serie) {
  30559. serie.translate();
  30560. serie.render();
  30561. });
  30562. };
  30563. /**
  30564. * Render labels for the chart.
  30565. *
  30566. * @private
  30567. * @function Highcharts.Chart#renderLabels
  30568. */
  30569. Chart.prototype.renderLabels = function () {
  30570. var chart = this,
  30571. labels = chart.options.labels;
  30572. if (labels.items) {
  30573. labels.items.forEach(function (label) {
  30574. var style = extend(labels.style,
  30575. label.style),
  30576. x = pInt(style.left) + chart.plotLeft,
  30577. y = pInt(style.top) + chart.plotTop + 12;
  30578. // delete to prevent rewriting in IE
  30579. delete style.left;
  30580. delete style.top;
  30581. chart.renderer.text(label.html, x, y)
  30582. .attr({ zIndex: 2 })
  30583. .css(style)
  30584. .add();
  30585. });
  30586. }
  30587. };
  30588. /**
  30589. * Render all graphics for the chart. Runs internally on initialization.
  30590. *
  30591. * @private
  30592. * @function Highcharts.Chart#render
  30593. */
  30594. Chart.prototype.render = function () {
  30595. var chart = this,
  30596. axes = chart.axes,
  30597. colorAxis = chart.colorAxis,
  30598. renderer = chart.renderer,
  30599. options = chart.options,
  30600. correction = 0, // correction for X axis labels
  30601. tempWidth,
  30602. tempHeight,
  30603. redoHorizontal,
  30604. redoVertical,
  30605. renderAxes = function (axes) {
  30606. axes.forEach(function (axis) {
  30607. if (axis.visible) {
  30608. axis.render();
  30609. }
  30610. });
  30611. };
  30612. // Title
  30613. chart.setTitle();
  30614. /**
  30615. * The overview of the chart's series.
  30616. *
  30617. * @name Highcharts.Chart#legend
  30618. * @type {Highcharts.Legend}
  30619. */
  30620. chart.legend = new Legend(chart, options.legend);
  30621. // Get stacks
  30622. if (chart.getStacks) {
  30623. chart.getStacks();
  30624. }
  30625. // Get chart margins
  30626. chart.getMargins(true);
  30627. chart.setChartSize();
  30628. // Record preliminary dimensions for later comparison
  30629. tempWidth = chart.plotWidth;
  30630. axes.some(function (axis) {
  30631. if (axis.horiz &&
  30632. axis.visible &&
  30633. axis.options.labels.enabled &&
  30634. axis.series.length) {
  30635. // 21 is the most common correction for X axis labels
  30636. correction = 21;
  30637. return true;
  30638. }
  30639. });
  30640. // use Math.max to prevent negative plotHeight
  30641. chart.plotHeight = Math.max(chart.plotHeight - correction, 0);
  30642. tempHeight = chart.plotHeight;
  30643. // Get margins by pre-rendering axes
  30644. axes.forEach(function (axis) {
  30645. axis.setScale();
  30646. });
  30647. chart.getAxisMargins();
  30648. // If the plot area size has changed significantly, calculate tick
  30649. // positions again
  30650. redoHorizontal = tempWidth / chart.plotWidth > 1.1;
  30651. // Height is more sensitive, use lower threshold
  30652. redoVertical = tempHeight / chart.plotHeight > 1.05;
  30653. if (redoHorizontal || redoVertical) {
  30654. axes.forEach(function (axis) {
  30655. if ((axis.horiz && redoHorizontal) ||
  30656. (!axis.horiz && redoVertical)) {
  30657. // update to reflect the new margins
  30658. axis.setTickInterval(true);
  30659. }
  30660. });
  30661. chart.getMargins(); // second pass to check for new labels
  30662. }
  30663. // Draw the borders and backgrounds
  30664. chart.drawChartBox();
  30665. // Axes
  30666. if (chart.hasCartesianSeries) {
  30667. renderAxes(axes);
  30668. }
  30669. else if (colorAxis && colorAxis.length) {
  30670. renderAxes(colorAxis);
  30671. }
  30672. // The series
  30673. if (!chart.seriesGroup) {
  30674. chart.seriesGroup = renderer.g('series-group')
  30675. .attr({ zIndex: 3 })
  30676. .add();
  30677. }
  30678. chart.renderSeries();
  30679. // Labels
  30680. chart.renderLabels();
  30681. // Credits
  30682. chart.addCredits();
  30683. // Handle responsiveness
  30684. if (chart.setResponsive) {
  30685. chart.setResponsive();
  30686. }
  30687. // Set flag
  30688. chart.hasRendered = true;
  30689. };
  30690. /**
  30691. * Set a new credits label for the chart.
  30692. *
  30693. * @sample highcharts/credits/credits-update/
  30694. * Add and update credits
  30695. *
  30696. * @function Highcharts.Chart#addCredits
  30697. *
  30698. * @param {Highcharts.CreditsOptions} [credits]
  30699. * A configuration object for the new credits.
  30700. */
  30701. Chart.prototype.addCredits = function (credits) {
  30702. var chart = this,
  30703. creds = merge(true,
  30704. this.options.credits,
  30705. credits);
  30706. if (creds.enabled && !this.credits) {
  30707. /**
  30708. * The chart's credits label. The label has an `update` method that
  30709. * allows setting new options as per the
  30710. * [credits options set](https://api.highcharts.com/highcharts/credits).
  30711. *
  30712. * @name Highcharts.Chart#credits
  30713. * @type {Highcharts.SVGElement}
  30714. */
  30715. this.credits = this.renderer.text(creds.text + (this.mapCredits || ''), 0, 0)
  30716. .addClass('highcharts-credits')
  30717. .on('click', function () {
  30718. if (creds.href) {
  30719. win.location.href = creds.href;
  30720. }
  30721. })
  30722. .attr({
  30723. align: creds.position.align,
  30724. zIndex: 8
  30725. });
  30726. if (!chart.styledMode) {
  30727. this.credits.css(creds.style);
  30728. }
  30729. this.credits
  30730. .add()
  30731. .align(creds.position);
  30732. // Dynamically update
  30733. this.credits.update = function (options) {
  30734. chart.credits = chart.credits.destroy();
  30735. chart.addCredits(options);
  30736. };
  30737. }
  30738. };
  30739. /**
  30740. * Remove the chart and purge memory. This method is called internally
  30741. * before adding a second chart into the same container, as well as on
  30742. * window unload to prevent leaks.
  30743. *
  30744. * @sample highcharts/members/chart-destroy/
  30745. * Destroy the chart from a button
  30746. * @sample stock/members/chart-destroy/
  30747. * Destroy with Highstock
  30748. *
  30749. * @function Highcharts.Chart#destroy
  30750. *
  30751. * @fires Highcharts.Chart#event:destroy
  30752. */
  30753. Chart.prototype.destroy = function () {
  30754. var chart = this,
  30755. axes = chart.axes,
  30756. series = chart.series,
  30757. container = chart.container,
  30758. i,
  30759. parentNode = container && container.parentNode;
  30760. // fire the chart.destoy event
  30761. fireEvent(chart, 'destroy');
  30762. // Delete the chart from charts lookup array
  30763. if (chart.renderer.forExport) {
  30764. erase(charts, chart); // #6569
  30765. }
  30766. else {
  30767. charts[chart.index] = void 0;
  30768. }
  30769. H.chartCount--;
  30770. chart.renderTo.removeAttribute('data-highcharts-chart');
  30771. // remove events
  30772. removeEvent(chart);
  30773. // ==== Destroy collections:
  30774. // Destroy axes
  30775. i = axes.length;
  30776. while (i--) {
  30777. axes[i] = axes[i].destroy();
  30778. }
  30779. // Destroy scroller & scroller series before destroying base series
  30780. if (this.scroller && this.scroller.destroy) {
  30781. this.scroller.destroy();
  30782. }
  30783. // Destroy each series
  30784. i = series.length;
  30785. while (i--) {
  30786. series[i] = series[i].destroy();
  30787. }
  30788. // ==== Destroy chart properties:
  30789. [
  30790. 'title', 'subtitle', 'chartBackground', 'plotBackground',
  30791. 'plotBGImage', 'plotBorder', 'seriesGroup', 'clipRect', 'credits',
  30792. 'pointer', 'rangeSelector', 'legend', 'resetZoomButton', 'tooltip',
  30793. 'renderer'
  30794. ].forEach(function (name) {
  30795. var prop = chart[name];
  30796. if (prop && prop.destroy) {
  30797. chart[name] = prop.destroy();
  30798. }
  30799. });
  30800. // Remove container and all SVG, check container as it can break in IE
  30801. // when destroyed before finished loading
  30802. if (container) {
  30803. container.innerHTML = '';
  30804. removeEvent(container);
  30805. if (parentNode) {
  30806. discardElement(container);
  30807. }
  30808. }
  30809. // clean it all up
  30810. objectEach(chart, function (val, key) {
  30811. delete chart[key];
  30812. });
  30813. };
  30814. /**
  30815. * Prepare for first rendering after all data are loaded.
  30816. *
  30817. * @private
  30818. * @function Highcharts.Chart#firstRender
  30819. * @fires Highcharts.Chart#event:beforeRender
  30820. */
  30821. Chart.prototype.firstRender = function () {
  30822. var chart = this,
  30823. options = chart.options;
  30824. // Hook for oldIE to check whether the chart is ready to render
  30825. if (chart.isReadyToRender && !chart.isReadyToRender()) {
  30826. return;
  30827. }
  30828. // Create the container
  30829. chart.getContainer();
  30830. chart.resetMargins();
  30831. chart.setChartSize();
  30832. // Set the common chart properties (mainly invert) from the given series
  30833. chart.propFromSeries();
  30834. // get axes
  30835. chart.getAxes();
  30836. // Initialize the series
  30837. (isArray(options.series) ? options.series : []).forEach(
  30838. // #9680
  30839. function (serieOptions) {
  30840. chart.initSeries(serieOptions);
  30841. });
  30842. chart.linkSeries();
  30843. chart.setSeriesData();
  30844. // Run an event after axes and series are initialized, but before
  30845. // render. At this stage, the series data is indexed and cached in the
  30846. // xData and yData arrays, so we can access those before rendering. Used
  30847. // in Highstock.
  30848. fireEvent(chart, 'beforeRender');
  30849. // depends on inverted and on margins being set
  30850. if (Pointer) {
  30851. if (!H.hasTouch && (win.PointerEvent || win.MSPointerEvent)) {
  30852. chart.pointer = new MSPointer(chart, options);
  30853. }
  30854. else {
  30855. /**
  30856. * The Pointer that keeps track of mouse and touch interaction.
  30857. *
  30858. * @memberof Highcharts.Chart
  30859. * @name pointer
  30860. * @type {Highcharts.Pointer}
  30861. * @instance
  30862. */
  30863. chart.pointer = new Pointer(chart, options);
  30864. }
  30865. }
  30866. chart.render();
  30867. chart.pointer.getChartPosition(); // #14973
  30868. // Fire the load event if there are no external images
  30869. if (!chart.renderer.imgCount && !chart.hasLoaded) {
  30870. chart.onload();
  30871. }
  30872. // If the chart was rendered outside the top container, put it back in
  30873. // (#3679)
  30874. chart.temporaryDisplay(true);
  30875. };
  30876. /**
  30877. * Internal function that runs on chart load, async if any images are loaded
  30878. * in the chart. Runs the callbacks and triggers the `load` and `render`
  30879. * events.
  30880. *
  30881. * @private
  30882. * @function Highcharts.Chart#onload
  30883. * @fires Highcharts.Chart#event:load
  30884. * @fires Highcharts.Chart#event:render
  30885. */
  30886. Chart.prototype.onload = function () {
  30887. // Run callbacks, first the ones registered by modules, then user's one
  30888. this.callbacks.concat([this.callback]).forEach(function (fn) {
  30889. // Chart destroyed in its own callback (#3600)
  30890. if (fn && typeof this.index !== 'undefined') {
  30891. fn.apply(this, [this]);
  30892. }
  30893. }, this);
  30894. fireEvent(this, 'load');
  30895. fireEvent(this, 'render');
  30896. // Set up auto resize, check for not destroyed (#6068)
  30897. if (defined(this.index)) {
  30898. this.setReflow(this.options.chart.reflow);
  30899. }
  30900. // Don't run again
  30901. this.hasLoaded = true;
  30902. };
  30903. /**
  30904. * Add a series to the chart after render time. Note that this method should
  30905. * never be used when adding data synchronously at chart render time, as it
  30906. * adds expense to the calculations and rendering. When adding data at the
  30907. * same time as the chart is initialized, add the series as a configuration
  30908. * option instead. With multiple axes, the `offset` is dynamically adjusted.
  30909. *
  30910. * @sample highcharts/members/chart-addseries/
  30911. * Add a series from a button
  30912. * @sample stock/members/chart-addseries/
  30913. * Add a series in Highstock
  30914. *
  30915. * @function Highcharts.Chart#addSeries
  30916. *
  30917. * @param {Highcharts.SeriesOptionsType} options
  30918. * The config options for the series.
  30919. *
  30920. * @param {boolean} [redraw=true]
  30921. * Whether to redraw the chart after adding.
  30922. *
  30923. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
  30924. * Whether to apply animation, and optionally animation
  30925. * configuration.
  30926. *
  30927. * @return {Highcharts.Series}
  30928. * The newly created series object.
  30929. *
  30930. * @fires Highcharts.Chart#event:addSeries
  30931. * @fires Highcharts.Chart#event:afterAddSeries
  30932. */
  30933. Chart.prototype.addSeries = function (options, redraw, animation) {
  30934. var series,
  30935. chart = this;
  30936. if (options) { // <- not necessary
  30937. redraw = pick(redraw, true); // defaults to true
  30938. fireEvent(chart, 'addSeries', { options: options }, function () {
  30939. series = chart.initSeries(options);
  30940. chart.isDirtyLegend = true;
  30941. chart.linkSeries();
  30942. if (series.enabledDataSorting) {
  30943. // We need to call `setData` after `linkSeries`
  30944. series.setData(options.data, false);
  30945. }
  30946. fireEvent(chart, 'afterAddSeries', { series: series });
  30947. if (redraw) {
  30948. chart.redraw(animation);
  30949. }
  30950. });
  30951. }
  30952. return series;
  30953. };
  30954. /**
  30955. * Add an axis to the chart after render time. Note that this method should
  30956. * never be used when adding data synchronously at chart render time, as it
  30957. * adds expense to the calculations and rendering. When adding data at the
  30958. * same time as the chart is initialized, add the axis as a configuration
  30959. * option instead.
  30960. *
  30961. * @sample highcharts/members/chart-addaxis/
  30962. * Add and remove axes
  30963. *
  30964. * @function Highcharts.Chart#addAxis
  30965. *
  30966. * @param {Highcharts.AxisOptions} options
  30967. * The axis options.
  30968. *
  30969. * @param {boolean} [isX=false]
  30970. * Whether it is an X axis or a value axis.
  30971. *
  30972. * @param {boolean} [redraw=true]
  30973. * Whether to redraw the chart after adding.
  30974. *
  30975. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=true]
  30976. * Whether and how to apply animation in the redraw.
  30977. *
  30978. * @return {Highcharts.Axis}
  30979. * The newly generated Axis object.
  30980. */
  30981. Chart.prototype.addAxis = function (options, isX, redraw, animation) {
  30982. return this.createAxis(isX ? 'xAxis' : 'yAxis', { axis: options, redraw: redraw, animation: animation });
  30983. };
  30984. /**
  30985. * Add a color axis to the chart after render time. Note that this method
  30986. * should never be used when adding data synchronously at chart render time,
  30987. * as it adds expense to the calculations and rendering. When adding data at
  30988. * the same time as the chart is initialized, add the axis as a
  30989. * configuration option instead.
  30990. *
  30991. * @sample highcharts/members/chart-addaxis/
  30992. * Add and remove axes
  30993. *
  30994. * @function Highcharts.Chart#addColorAxis
  30995. *
  30996. * @param {Highcharts.ColorAxisOptions} options
  30997. * The axis options.
  30998. *
  30999. * @param {boolean} [redraw=true]
  31000. * Whether to redraw the chart after adding.
  31001. *
  31002. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=true]
  31003. * Whether and how to apply animation in the redraw.
  31004. *
  31005. * @return {Highcharts.ColorAxis}
  31006. * The newly generated Axis object.
  31007. */
  31008. Chart.prototype.addColorAxis = function (options, redraw, animation) {
  31009. return this.createAxis('colorAxis', { axis: options, redraw: redraw, animation: animation });
  31010. };
  31011. /**
  31012. * Factory for creating different axis types.
  31013. *
  31014. * @private
  31015. * @function Highcharts.Chart#createAxis
  31016. *
  31017. * @param {string} type
  31018. * An axis type.
  31019. *
  31020. * @param {...Array<*>} arguments
  31021. * All arguments for the constructor.
  31022. *
  31023. * @return {Highcharts.Axis | Highcharts.ColorAxis}
  31024. * The newly generated Axis object.
  31025. */
  31026. Chart.prototype.createAxis = function (type, options) {
  31027. var chartOptions = this.options,
  31028. isColorAxis = type === 'colorAxis',
  31029. axisOptions = options.axis,
  31030. redraw = options.redraw,
  31031. animation = options.animation,
  31032. userOptions = merge(axisOptions, {
  31033. index: this[type].length,
  31034. isX: type === 'xAxis'
  31035. }),
  31036. axis;
  31037. if (isColorAxis) {
  31038. axis = new H.ColorAxis(this, userOptions);
  31039. }
  31040. else {
  31041. axis = new Axis(this, userOptions);
  31042. }
  31043. // Push the new axis options to the chart options
  31044. chartOptions[type] = splat(chartOptions[type] || {});
  31045. chartOptions[type].push(userOptions);
  31046. if (isColorAxis) {
  31047. this.isDirtyLegend = true;
  31048. // Clear before 'bindAxes' (#11924)
  31049. this.axes.forEach(function (axis) {
  31050. axis.series = [];
  31051. });
  31052. this.series.forEach(function (series) {
  31053. series.bindAxes();
  31054. series.isDirtyData = true;
  31055. });
  31056. }
  31057. if (pick(redraw, true)) {
  31058. this.redraw(animation);
  31059. }
  31060. return axis;
  31061. };
  31062. /**
  31063. * Dim the chart and show a loading text or symbol. Options for the loading
  31064. * screen are defined in {@link
  31065. * https://api.highcharts.com/highcharts/loading|the loading options}.
  31066. *
  31067. * @sample highcharts/members/chart-hideloading/
  31068. * Show and hide loading from a button
  31069. * @sample highcharts/members/chart-showloading/
  31070. * Apply different text labels
  31071. * @sample stock/members/chart-show-hide-loading/
  31072. * Toggle loading in Highstock
  31073. *
  31074. * @function Highcharts.Chart#showLoading
  31075. *
  31076. * @param {string} [str]
  31077. * An optional text to show in the loading label instead of the
  31078. * default one. The default text is set in
  31079. * [lang.loading](https://api.highcharts.com/highcharts/lang.loading).
  31080. */
  31081. Chart.prototype.showLoading = function (str) {
  31082. var chart = this,
  31083. options = chart.options,
  31084. loadingDiv = chart.loadingDiv,
  31085. loadingSpan = chart.loadingSpan,
  31086. loadingOptions = options.loading,
  31087. setLoadingSize = function () {
  31088. if (loadingDiv) {
  31089. css(loadingDiv, {
  31090. left: chart.plotLeft + 'px',
  31091. top: chart.plotTop + 'px',
  31092. width: chart.plotWidth + 'px',
  31093. height: chart.plotHeight + 'px'
  31094. });
  31095. }
  31096. };
  31097. // create the layer at the first call
  31098. if (!loadingDiv) {
  31099. chart.loadingDiv = loadingDiv = createElement('div', {
  31100. className: 'highcharts-loading highcharts-loading-hidden'
  31101. }, null, chart.container);
  31102. }
  31103. if (!loadingSpan) {
  31104. chart.loadingSpan = loadingSpan = createElement('span', { className: 'highcharts-loading-inner' }, null, loadingDiv);
  31105. addEvent(chart, 'redraw', setLoadingSize); // #1080
  31106. }
  31107. loadingDiv.className = 'highcharts-loading';
  31108. // Update text
  31109. AST.setElementHTML(loadingSpan, pick(str, options.lang.loading, ''));
  31110. if (!chart.styledMode) {
  31111. // Update visuals
  31112. css(loadingDiv, extend(loadingOptions.style, {
  31113. zIndex: 10
  31114. }));
  31115. css(loadingSpan, loadingOptions.labelStyle);
  31116. // Show it
  31117. if (!chart.loadingShown) {
  31118. css(loadingDiv, {
  31119. opacity: 0,
  31120. display: ''
  31121. });
  31122. animate(loadingDiv, {
  31123. opacity: loadingOptions.style.opacity || 0.5
  31124. }, {
  31125. duration: loadingOptions.showDuration || 0
  31126. });
  31127. }
  31128. }
  31129. chart.loadingShown = true;
  31130. setLoadingSize();
  31131. };
  31132. /**
  31133. * Hide the loading layer.
  31134. *
  31135. * @see Highcharts.Chart#showLoading
  31136. *
  31137. * @sample highcharts/members/chart-hideloading/
  31138. * Show and hide loading from a button
  31139. * @sample stock/members/chart-show-hide-loading/
  31140. * Toggle loading in Highstock
  31141. *
  31142. * @function Highcharts.Chart#hideLoading
  31143. */
  31144. Chart.prototype.hideLoading = function () {
  31145. var options = this.options,
  31146. loadingDiv = this.loadingDiv;
  31147. if (loadingDiv) {
  31148. loadingDiv.className =
  31149. 'highcharts-loading highcharts-loading-hidden';
  31150. if (!this.styledMode) {
  31151. animate(loadingDiv, {
  31152. opacity: 0
  31153. }, {
  31154. duration: options.loading.hideDuration || 100,
  31155. complete: function () {
  31156. css(loadingDiv, { display: 'none' });
  31157. }
  31158. });
  31159. }
  31160. }
  31161. this.loadingShown = false;
  31162. };
  31163. /**
  31164. * A generic function to update any element of the chart. Elements can be
  31165. * enabled and disabled, moved, re-styled, re-formatted etc.
  31166. *
  31167. * A special case is configuration objects that take arrays, for example
  31168. * [xAxis](https://api.highcharts.com/highcharts/xAxis),
  31169. * [yAxis](https://api.highcharts.com/highcharts/yAxis) or
  31170. * [series](https://api.highcharts.com/highcharts/series). For these
  31171. * collections, an `id` option is used to map the new option set to an
  31172. * existing object. If an existing object of the same id is not found, the
  31173. * corresponding item is updated. So for example, running `chart.update`
  31174. * with a series item without an id, will cause the existing chart's series
  31175. * with the same index in the series array to be updated. When the
  31176. * `oneToOne` parameter is true, `chart.update` will also take care of
  31177. * adding and removing items from the collection. Read more under the
  31178. * parameter description below.
  31179. *
  31180. * Note that when changing series data, `chart.update` may mutate the passed
  31181. * data options.
  31182. *
  31183. * See also the
  31184. * [responsive option set](https://api.highcharts.com/highcharts/responsive).
  31185. * Switching between `responsive.rules` basically runs `chart.update` under
  31186. * the hood.
  31187. *
  31188. * @sample highcharts/members/chart-update/
  31189. * Update chart geometry
  31190. *
  31191. * @function Highcharts.Chart#update
  31192. *
  31193. * @param {Highcharts.Options} options
  31194. * A configuration object for the new chart options.
  31195. *
  31196. * @param {boolean} [redraw=true]
  31197. * Whether to redraw the chart.
  31198. *
  31199. * @param {boolean} [oneToOne=false]
  31200. * When `true`, the `series`, `xAxis`, `yAxis` and `annotations`
  31201. * collections will be updated one to one, and items will be either
  31202. * added or removed to match the new updated options. For example,
  31203. * if the chart has two series and we call `chart.update` with a
  31204. * configuration containing three series, one will be added. If we
  31205. * call `chart.update` with one series, one will be removed. Setting
  31206. * an empty `series` array will remove all series, but leaving out
  31207. * the`series` property will leave all series untouched. If the
  31208. * series have id's, the new series options will be matched by id,
  31209. * and the remaining ones removed.
  31210. *
  31211. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=true]
  31212. * Whether to apply animation, and optionally animation
  31213. * configuration.
  31214. *
  31215. * @fires Highcharts.Chart#event:update
  31216. * @fires Highcharts.Chart#event:afterUpdate
  31217. */
  31218. Chart.prototype.update = function (options, redraw, oneToOne, animation) {
  31219. var chart = this,
  31220. adders = {
  31221. credits: 'addCredits',
  31222. title: 'setTitle',
  31223. subtitle: 'setSubtitle',
  31224. caption: 'setCaption'
  31225. },
  31226. optionsChart,
  31227. updateAllAxes,
  31228. updateAllSeries,
  31229. newWidth,
  31230. newHeight,
  31231. runSetSize,
  31232. isResponsiveOptions = options.isResponsiveOptions,
  31233. itemsForRemoval = [];
  31234. fireEvent(chart, 'update', { options: options });
  31235. // If there are responsive rules in action, undo the responsive rules
  31236. // before we apply the updated options and replay the responsive rules
  31237. // on top from the chart.redraw function (#9617).
  31238. if (!isResponsiveOptions) {
  31239. chart.setResponsive(false, true);
  31240. }
  31241. options = cleanRecursively(options, chart.options);
  31242. chart.userOptions = merge(chart.userOptions, options);
  31243. // If the top-level chart option is present, some special updates are
  31244. // required
  31245. optionsChart = options.chart;
  31246. if (optionsChart) {
  31247. merge(true, chart.options.chart, optionsChart);
  31248. // Setter function
  31249. if ('className' in optionsChart) {
  31250. chart.setClassName(optionsChart.className);
  31251. }
  31252. if ('reflow' in optionsChart) {
  31253. chart.setReflow(optionsChart.reflow);
  31254. }
  31255. if ('inverted' in optionsChart ||
  31256. 'polar' in optionsChart ||
  31257. 'type' in optionsChart) {
  31258. // Parse options.chart.inverted and options.chart.polar together
  31259. // with the available series.
  31260. chart.propFromSeries();
  31261. updateAllAxes = true;
  31262. }
  31263. if ('alignTicks' in optionsChart) { // #6452
  31264. updateAllAxes = true;
  31265. }
  31266. objectEach(optionsChart, function (val, key) {
  31267. if (chart.propsRequireUpdateSeries.indexOf('chart.' + key) !==
  31268. -1) {
  31269. updateAllSeries = true;
  31270. }
  31271. // Only dirty box
  31272. if (chart.propsRequireDirtyBox.indexOf(key) !== -1) {
  31273. chart.isDirtyBox = true;
  31274. }
  31275. // Chart setSize
  31276. if (chart.propsRequireReflow.indexOf(key) !== -1) {
  31277. if (isResponsiveOptions) {
  31278. chart.isDirtyBox = true;
  31279. }
  31280. else {
  31281. runSetSize = true;
  31282. }
  31283. }
  31284. });
  31285. if (!chart.styledMode && 'style' in optionsChart) {
  31286. chart.renderer.setStyle(optionsChart.style);
  31287. }
  31288. }
  31289. // Moved up, because tooltip needs updated plotOptions (#6218)
  31290. if (!chart.styledMode && options.colors) {
  31291. this.options.colors = options.colors;
  31292. }
  31293. if (options.time) {
  31294. // Maintaining legacy global time. If the chart is instanciated
  31295. // first with global time, then updated with time options, we need
  31296. // to create a new Time instance to avoid mutating the global time
  31297. // (#10536).
  31298. if (this.time === time) {
  31299. this.time = new Time(options.time);
  31300. }
  31301. // If we're updating, the time class is different from other chart
  31302. // classes (chart.legend, chart.tooltip etc) in that it doesn't know
  31303. // about the chart. The other chart[something].update functions also
  31304. // set the chart.options[something]. For the time class however we
  31305. // need to update the chart options separately. #14230.
  31306. merge(true, chart.options.time, options.time);
  31307. }
  31308. // Some option stuctures correspond one-to-one to chart objects that
  31309. // have update methods, for example
  31310. // options.credits => chart.credits
  31311. // options.legend => chart.legend
  31312. // options.title => chart.title
  31313. // options.tooltip => chart.tooltip
  31314. // options.subtitle => chart.subtitle
  31315. // options.mapNavigation => chart.mapNavigation
  31316. // options.navigator => chart.navigator
  31317. // options.scrollbar => chart.scrollbar
  31318. objectEach(options, function (val, key) {
  31319. if (chart[key] &&
  31320. typeof chart[key].update === 'function') {
  31321. chart[key].update(val, false);
  31322. // If a one-to-one object does not exist, look for an adder function
  31323. }
  31324. else if (typeof chart[adders[key]] === 'function') {
  31325. chart[adders[key]](val);
  31326. // Else, just merge the options. For nodes like loading, noData,
  31327. // plotOptions
  31328. }
  31329. else if (key !== 'color' &&
  31330. chart.collectionsWithUpdate.indexOf(key) === -1) {
  31331. merge(true, chart.options[key], options[key]);
  31332. }
  31333. if (key !== 'chart' &&
  31334. chart.propsRequireUpdateSeries.indexOf(key) !== -1) {
  31335. updateAllSeries = true;
  31336. }
  31337. });
  31338. // Setters for collections. For axes and series, each item is referred
  31339. // by an id. If the id is not found, it defaults to the corresponding
  31340. // item in the collection, so setting one series without an id, will
  31341. // update the first series in the chart. Setting two series without
  31342. // an id will update the first and the second respectively (#6019)
  31343. // chart.update and responsive.
  31344. this.collectionsWithUpdate.forEach(function (coll) {
  31345. var indexMap;
  31346. if (options[coll]) {
  31347. // In stock charts, the navigator series are also part of the
  31348. // chart.series array, but those series should not be handled
  31349. // here (#8196).
  31350. if (coll === 'series') {
  31351. indexMap = [];
  31352. chart[coll].forEach(function (s, i) {
  31353. if (!s.options.isInternal) {
  31354. indexMap.push(pick(s.options.index, i));
  31355. }
  31356. });
  31357. }
  31358. splat(options[coll]).forEach(function (newOptions, i) {
  31359. var hasId = defined(newOptions.id);
  31360. var item;
  31361. // Match by id
  31362. if (hasId) {
  31363. item = chart.get(newOptions.id);
  31364. }
  31365. // No match by id found, match by index instead
  31366. if (!item && chart[coll]) {
  31367. item = chart[coll][indexMap ? indexMap[i] : i];
  31368. // Check if we grabbed an item with an exising but
  31369. // different id (#13541)
  31370. if (item && hasId && defined(item.options.id)) {
  31371. item = void 0;
  31372. }
  31373. }
  31374. if (item && item.coll === coll) {
  31375. item.update(newOptions, false);
  31376. if (oneToOne) {
  31377. item.touched = true;
  31378. }
  31379. }
  31380. // If oneToOne and no matching item is found, add one
  31381. if (!item && oneToOne && chart.collectionsWithInit[coll]) {
  31382. chart.collectionsWithInit[coll][0].apply(chart,
  31383. // [newOptions, ...extraArguments, redraw=false]
  31384. [
  31385. newOptions
  31386. ].concat(
  31387. // Not all initializers require extra args
  31388. chart.collectionsWithInit[coll][1] || []).concat([
  31389. false
  31390. ])).touched = true;
  31391. }
  31392. });
  31393. // Add items for removal
  31394. if (oneToOne) {
  31395. chart[coll].forEach(function (item) {
  31396. if (!item.touched && !item.options.isInternal) {
  31397. itemsForRemoval.push(item);
  31398. }
  31399. else {
  31400. delete item.touched;
  31401. }
  31402. });
  31403. }
  31404. }
  31405. });
  31406. itemsForRemoval.forEach(function (item) {
  31407. if (item.chart) { // #9097, avoid removing twice
  31408. item.remove(false);
  31409. }
  31410. });
  31411. if (updateAllAxes) {
  31412. chart.axes.forEach(function (axis) {
  31413. axis.update({}, false);
  31414. });
  31415. }
  31416. // Certain options require the whole series structure to be thrown away
  31417. // and rebuilt
  31418. if (updateAllSeries) {
  31419. chart.getSeriesOrderByLinks().forEach(function (series) {
  31420. // Avoid removed navigator series
  31421. if (series.chart) {
  31422. series.update({}, false);
  31423. }
  31424. }, this);
  31425. }
  31426. // Update size. Redraw is forced.
  31427. newWidth = optionsChart && optionsChart.width;
  31428. newHeight = optionsChart && optionsChart.height;
  31429. if (isString(newHeight)) {
  31430. newHeight = relativeLength(newHeight, newWidth || chart.chartWidth);
  31431. }
  31432. if (
  31433. // In this case, run chart.setSize with newWidth and newHeight which
  31434. // are undefined, only for reflowing chart elements because margin
  31435. // or spacing has been set (#8190)
  31436. runSetSize ||
  31437. // In this case, the size is actually set
  31438. (isNumber(newWidth) && newWidth !== chart.chartWidth) ||
  31439. (isNumber(newHeight) && newHeight !== chart.chartHeight)) {
  31440. chart.setSize(newWidth, newHeight, animation);
  31441. }
  31442. else if (pick(redraw, true)) {
  31443. chart.redraw(animation);
  31444. }
  31445. fireEvent(chart, 'afterUpdate', {
  31446. options: options,
  31447. redraw: redraw,
  31448. animation: animation
  31449. });
  31450. };
  31451. /**
  31452. * Shortcut to set the subtitle options. This can also be done from {@link
  31453. * Chart#update} or {@link Chart#setTitle}.
  31454. *
  31455. * @function Highcharts.Chart#setSubtitle
  31456. *
  31457. * @param {Highcharts.SubtitleOptions} options
  31458. * New subtitle options. The subtitle text itself is set by the
  31459. * `options.text` property.
  31460. */
  31461. Chart.prototype.setSubtitle = function (options, redraw) {
  31462. this.applyDescription('subtitle', options);
  31463. this.layOutTitles(redraw);
  31464. };
  31465. /**
  31466. * Set the caption options. This can also be done from {@link
  31467. * Chart#update}.
  31468. *
  31469. * @function Highcharts.Chart#setCaption
  31470. *
  31471. * @param {Highcharts.CaptionOptions} options
  31472. * New caption options. The caption text itself is set by the
  31473. * `options.text` property.
  31474. */
  31475. Chart.prototype.setCaption = function (options, redraw) {
  31476. this.applyDescription('caption', options);
  31477. this.layOutTitles(redraw);
  31478. };
  31479. /**
  31480. * Display the zoom button, so users can reset zoom to the default view
  31481. * settings.
  31482. *
  31483. * @function Highcharts.Chart#showResetZoom
  31484. *
  31485. * @fires Highcharts.Chart#event:afterShowResetZoom
  31486. * @fires Highcharts.Chart#event:beforeShowResetZoom
  31487. */
  31488. Chart.prototype.showResetZoom = function () {
  31489. var chart = this,
  31490. lang = defaultOptions.lang,
  31491. btnOptions = chart.options.chart.resetZoomButton,
  31492. theme = btnOptions.theme,
  31493. states = theme.states,
  31494. alignTo = (btnOptions.relativeTo === 'chart' ||
  31495. btnOptions.relativeTo === 'spaceBox' ?
  31496. null :
  31497. this.scrollablePlotBox || 'plotBox');
  31498. /**
  31499. * @private
  31500. */
  31501. function zoomOut() {
  31502. chart.zoomOut();
  31503. }
  31504. fireEvent(this, 'beforeShowResetZoom', null, function () {
  31505. chart.resetZoomButton = chart.renderer
  31506. .button(lang.resetZoom, null, null, zoomOut, theme, states && states.hover)
  31507. .attr({
  31508. align: btnOptions.position.align,
  31509. title: lang.resetZoomTitle
  31510. })
  31511. .addClass('highcharts-reset-zoom')
  31512. .add()
  31513. .align(btnOptions.position, false, alignTo);
  31514. });
  31515. fireEvent(this, 'afterShowResetZoom');
  31516. };
  31517. /**
  31518. * Zoom the chart out after a user has zoomed in. See also
  31519. * [Axis.setExtremes](/class-reference/Highcharts.Axis#setExtremes).
  31520. *
  31521. * @function Highcharts.Chart#zoomOut
  31522. *
  31523. * @fires Highcharts.Chart#event:selection
  31524. */
  31525. Chart.prototype.zoomOut = function () {
  31526. fireEvent(this, 'selection', { resetSelection: true }, this.zoom);
  31527. };
  31528. /**
  31529. * Zoom into a given portion of the chart given by axis coordinates.
  31530. *
  31531. * @private
  31532. * @function Highcharts.Chart#zoom
  31533. * @param {Highcharts.SelectEventObject} event
  31534. */
  31535. Chart.prototype.zoom = function (event) {
  31536. var chart = this,
  31537. hasZoomed,
  31538. pointer = chart.pointer,
  31539. displayButton = false,
  31540. mouseDownPos = chart.inverted ? pointer.mouseDownX : pointer.mouseDownY,
  31541. resetZoomButton;
  31542. // If zoom is called with no arguments, reset the axes
  31543. if (!event || event.resetSelection) {
  31544. chart.axes.forEach(function (axis) {
  31545. hasZoomed = axis.zoom();
  31546. });
  31547. pointer.initiated = false; // #6804
  31548. }
  31549. else { // else, zoom in on all axes
  31550. event.xAxis.concat(event.yAxis).forEach(function (axisData) {
  31551. var axis = axisData.axis,
  31552. axisStartPos = chart.inverted ? axis.left : axis.top,
  31553. axisEndPos = chart.inverted ?
  31554. axisStartPos + axis.width : axisStartPos + axis.height,
  31555. isXAxis = axis.isXAxis,
  31556. isWithinPane = false;
  31557. // Check if zoomed area is within the pane (#1289).
  31558. // In case of multiple panes only one pane should be zoomed.
  31559. if ((!isXAxis &&
  31560. mouseDownPos >= axisStartPos &&
  31561. mouseDownPos <= axisEndPos) ||
  31562. isXAxis ||
  31563. !defined(mouseDownPos)) {
  31564. isWithinPane = true;
  31565. }
  31566. // don't zoom more than minRange
  31567. if (pointer[isXAxis ? 'zoomX' : 'zoomY'] && isWithinPane) {
  31568. hasZoomed = axis.zoom(axisData.min, axisData.max);
  31569. if (axis.displayBtn) {
  31570. displayButton = true;
  31571. }
  31572. }
  31573. });
  31574. }
  31575. // Show or hide the Reset zoom button
  31576. resetZoomButton = chart.resetZoomButton;
  31577. if (displayButton && !resetZoomButton) {
  31578. chart.showResetZoom();
  31579. }
  31580. else if (!displayButton && isObject(resetZoomButton)) {
  31581. chart.resetZoomButton = resetZoomButton.destroy();
  31582. }
  31583. // Redraw
  31584. if (hasZoomed) {
  31585. chart.redraw(pick(chart.options.chart.animation, event && event.animation, chart.pointCount < 100));
  31586. }
  31587. };
  31588. /**
  31589. * Pan the chart by dragging the mouse across the pane. This function is
  31590. * called on mouse move, and the distance to pan is computed from chartX
  31591. * compared to the first chartX position in the dragging operation.
  31592. *
  31593. * @private
  31594. * @function Highcharts.Chart#pan
  31595. * @param {Highcharts.PointerEventObject} e
  31596. * @param {string} panning
  31597. */
  31598. Chart.prototype.pan = function (e, panning) {
  31599. var chart = this,
  31600. hoverPoints = chart.hoverPoints,
  31601. panningOptions,
  31602. chartOptions = chart.options.chart,
  31603. hasMapNavigation = chart.options.mapNavigation &&
  31604. chart.options.mapNavigation.enabled,
  31605. doRedraw,
  31606. type;
  31607. if (typeof panning === 'object') {
  31608. panningOptions = panning;
  31609. }
  31610. else {
  31611. panningOptions = {
  31612. enabled: panning,
  31613. type: 'x'
  31614. };
  31615. }
  31616. if (chartOptions && chartOptions.panning) {
  31617. chartOptions.panning = panningOptions;
  31618. }
  31619. type = panningOptions.type;
  31620. fireEvent(this, 'pan', { originalEvent: e }, function () {
  31621. // remove active points for shared tooltip
  31622. if (hoverPoints) {
  31623. hoverPoints.forEach(function (point) {
  31624. point.setState();
  31625. });
  31626. }
  31627. // panning axis mapping
  31628. var xy = [1]; // x
  31629. if (type === 'xy') {
  31630. xy = [1, 0];
  31631. }
  31632. else if (type === 'y') {
  31633. xy = [0];
  31634. }
  31635. xy.forEach(function (isX) {
  31636. var axis = chart[isX ? 'xAxis' : 'yAxis'][0], horiz = axis.horiz, mousePos = e[horiz ? 'chartX' : 'chartY'], mouseDown = horiz ? 'mouseDownX' : 'mouseDownY', startPos = chart[mouseDown], halfPointRange = (axis.pointRange || 0) / 2, pointRangeDirection = (axis.reversed && !chart.inverted) ||
  31637. (!axis.reversed && chart.inverted) ?
  31638. -1 :
  31639. 1, extremes = axis.getExtremes(), panMin = axis.toValue(startPos - mousePos, true) +
  31640. halfPointRange * pointRangeDirection, panMax = axis.toValue(startPos + axis.len - mousePos, true) -
  31641. halfPointRange * pointRangeDirection, flipped = panMax < panMin, newMin = flipped ? panMax : panMin, newMax = flipped ? panMin : panMax, hasVerticalPanning = axis.hasVerticalPanning(), paddedMin, paddedMax, spill, panningState = axis.panningState;
  31642. // General calculations of panning state.
  31643. // This is related to using vertical panning. (#11315).
  31644. if (hasVerticalPanning &&
  31645. !isX && (!panningState || panningState.isDirty)) {
  31646. axis.series.forEach(function (series) {
  31647. var processedData = series.getProcessedData(true),
  31648. dataExtremes = series.getExtremes(processedData.yData,
  31649. true);
  31650. if (!panningState) {
  31651. panningState = {
  31652. startMin: Number.MAX_VALUE,
  31653. startMax: -Number.MAX_VALUE
  31654. };
  31655. }
  31656. if (isNumber(dataExtremes.dataMin) &&
  31657. isNumber(dataExtremes.dataMax)) {
  31658. panningState.startMin = Math.min(pick(series.options.threshold, Infinity), dataExtremes.dataMin, panningState.startMin);
  31659. panningState.startMax = Math.max(pick(series.options.threshold, -Infinity), dataExtremes.dataMax, panningState.startMax);
  31660. }
  31661. });
  31662. }
  31663. paddedMin = Math.min(pick(panningState === null || panningState === void 0 ? void 0 : panningState.startMin, extremes.dataMin), halfPointRange ?
  31664. extremes.min :
  31665. axis.toValue(axis.toPixels(extremes.min) -
  31666. axis.minPixelPadding));
  31667. paddedMax = Math.max(pick(panningState === null || panningState === void 0 ? void 0 : panningState.startMax, extremes.dataMax), halfPointRange ?
  31668. extremes.max :
  31669. axis.toValue(axis.toPixels(extremes.max) +
  31670. axis.minPixelPadding));
  31671. axis.panningState = panningState;
  31672. // It is not necessary to calculate extremes on ordinal axis,
  31673. // because they are already calculated, so we don't want to
  31674. // override them.
  31675. if (!axis.isOrdinal) {
  31676. // If the new range spills over, either to the min or max,
  31677. // adjust the new range.
  31678. spill = paddedMin - newMin;
  31679. if (spill > 0) {
  31680. newMax += spill;
  31681. newMin = paddedMin;
  31682. }
  31683. spill = newMax - paddedMax;
  31684. if (spill > 0) {
  31685. newMax = paddedMax;
  31686. newMin -= spill;
  31687. }
  31688. // Set new extremes if they are actually new
  31689. if (axis.series.length &&
  31690. newMin !== extremes.min &&
  31691. newMax !== extremes.max &&
  31692. newMin >= paddedMin &&
  31693. newMax <= paddedMax) {
  31694. axis.setExtremes(newMin, newMax, false, false, { trigger: 'pan' });
  31695. if (!chart.resetZoomButton &&
  31696. !hasMapNavigation &&
  31697. // Show reset zoom button only when both newMin and
  31698. // newMax values are between padded axis range.
  31699. newMin !== paddedMin &&
  31700. newMax !== paddedMax &&
  31701. type.match('y')) {
  31702. chart.showResetZoom();
  31703. axis.displayBtn = false;
  31704. }
  31705. doRedraw = true;
  31706. }
  31707. // set new reference for next run:
  31708. chart[mouseDown] = mousePos;
  31709. }
  31710. });
  31711. if (doRedraw) {
  31712. chart.redraw(false);
  31713. }
  31714. css(chart.container, { cursor: 'move' });
  31715. });
  31716. };
  31717. return Chart;
  31718. }());
  31719. extend(Chart.prototype, {
  31720. // Hook for adding callbacks in modules
  31721. callbacks: [],
  31722. /**
  31723. * These collections (arrays) implement `Chart.addSomethig` method used in
  31724. * chart.update() to create new object in the collection. Equivalent for
  31725. * deleting is resolved by simple `Somethig.remove()`.
  31726. *
  31727. * Note: We need to define these references after initializers are bound to
  31728. * chart's prototype.
  31729. */
  31730. collectionsWithInit: {
  31731. // collectionName: [ initializingMethod, [extraArguments] ]
  31732. xAxis: [Chart.prototype.addAxis, [true]],
  31733. yAxis: [Chart.prototype.addAxis, [false]],
  31734. series: [Chart.prototype.addSeries]
  31735. },
  31736. /**
  31737. * These collections (arrays) implement update() methods with support for
  31738. * one-to-one option.
  31739. */
  31740. collectionsWithUpdate: [
  31741. 'xAxis',
  31742. 'yAxis',
  31743. 'zAxis',
  31744. 'series'
  31745. ],
  31746. /**
  31747. * These properties cause isDirtyBox to be set to true when updating. Can be
  31748. * extended from plugins.
  31749. */
  31750. propsRequireDirtyBox: [
  31751. 'backgroundColor',
  31752. 'borderColor',
  31753. 'borderWidth',
  31754. 'borderRadius',
  31755. 'plotBackgroundColor',
  31756. 'plotBackgroundImage',
  31757. 'plotBorderColor',
  31758. 'plotBorderWidth',
  31759. 'plotShadow',
  31760. 'shadow'
  31761. ],
  31762. /**
  31763. * These properties require a full reflow of chart elements, best
  31764. * implemented through running `Chart.setSize` internally (#8190).
  31765. * @type {Array}
  31766. */
  31767. propsRequireReflow: [
  31768. 'margin',
  31769. 'marginTop',
  31770. 'marginRight',
  31771. 'marginBottom',
  31772. 'marginLeft',
  31773. 'spacing',
  31774. 'spacingTop',
  31775. 'spacingRight',
  31776. 'spacingBottom',
  31777. 'spacingLeft'
  31778. ],
  31779. /**
  31780. * These properties cause all series to be updated when updating. Can be
  31781. * extended from plugins.
  31782. */
  31783. propsRequireUpdateSeries: [
  31784. 'chart.inverted',
  31785. 'chart.polar',
  31786. 'chart.ignoreHiddenSeries',
  31787. 'chart.type',
  31788. 'colors',
  31789. 'plotOptions',
  31790. 'time',
  31791. 'tooltip'
  31792. ]
  31793. });
  31794. /**
  31795. * Factory function for basic charts.
  31796. *
  31797. * @example
  31798. * // Render a chart in to div#container
  31799. * var chart = Highcharts.chart('container', {
  31800. * title: {
  31801. * text: 'My chart'
  31802. * },
  31803. * series: [{
  31804. * data: [1, 3, 2, 4]
  31805. * }]
  31806. * });
  31807. *
  31808. * @function Highcharts.chart
  31809. *
  31810. * @param {string|Highcharts.HTMLDOMElement} [renderTo]
  31811. * The DOM element to render to, or its id.
  31812. *
  31813. * @param {Highcharts.Options} options
  31814. * The chart options structure.
  31815. *
  31816. * @param {Highcharts.ChartCallbackFunction} [callback]
  31817. * Function to run when the chart has loaded and and all external images
  31818. * are loaded. Defining a
  31819. * [chart.events.load](https://api.highcharts.com/highcharts/chart.events.load)
  31820. * handler is equivalent.
  31821. *
  31822. * @return {Highcharts.Chart}
  31823. * Returns the Chart object.
  31824. */
  31825. function chart(a, b, c) {
  31826. return new Chart(a, b, c);
  31827. }
  31828. H.chart = chart;
  31829. H.Chart = Chart;
  31830. /* *
  31831. *
  31832. * Export
  31833. *
  31834. * */
  31835. /* *
  31836. *
  31837. * API Declarations
  31838. *
  31839. * */
  31840. /**
  31841. * Callback for chart constructors.
  31842. *
  31843. * @callback Highcharts.ChartCallbackFunction
  31844. *
  31845. * @param {Highcharts.Chart} chart
  31846. * Created chart.
  31847. */
  31848. /**
  31849. * Format a number and return a string based on input settings.
  31850. *
  31851. * @callback Highcharts.NumberFormatterCallbackFunction
  31852. *
  31853. * @param {number} number
  31854. * The input number to format.
  31855. *
  31856. * @param {number} decimals
  31857. * The amount of decimals. A value of -1 preserves the amount in the
  31858. * input number.
  31859. *
  31860. * @param {string} [decimalPoint]
  31861. * The decimal point, defaults to the one given in the lang options, or
  31862. * a dot.
  31863. *
  31864. * @param {string} [thousandsSep]
  31865. * The thousands separator, defaults to the one given in the lang
  31866. * options, or a space character.
  31867. *
  31868. * @return {string} The formatted number.
  31869. */
  31870. /**
  31871. * The chart title. The title has an `update` method that allows modifying the
  31872. * options directly or indirectly via `chart.update`.
  31873. *
  31874. * @interface Highcharts.TitleObject
  31875. * @extends Highcharts.SVGElement
  31876. */ /**
  31877. * Modify options for the title.
  31878. *
  31879. * @function Highcharts.TitleObject#update
  31880. *
  31881. * @param {Highcharts.TitleOptions} titleOptions
  31882. * Options to modify.
  31883. *
  31884. * @param {boolean} [redraw=true]
  31885. * Whether to redraw the chart after the title is altered. If doing more
  31886. * operations on the chart, it is a good idea to set redraw to false and
  31887. * call {@link Chart#redraw} after.
  31888. */
  31889. /**
  31890. * The chart subtitle. The subtitle has an `update` method that
  31891. * allows modifying the options directly or indirectly via
  31892. * `chart.update`.
  31893. *
  31894. * @interface Highcharts.SubtitleObject
  31895. * @extends Highcharts.SVGElement
  31896. */ /**
  31897. * Modify options for the subtitle.
  31898. *
  31899. * @function Highcharts.SubtitleObject#update
  31900. *
  31901. * @param {Highcharts.SubtitleOptions} subtitleOptions
  31902. * Options to modify.
  31903. *
  31904. * @param {boolean} [redraw=true]
  31905. * Whether to redraw the chart after the subtitle is altered. If doing
  31906. * more operations on the chart, it is a good idea to set redraw to false
  31907. * and call {@link Chart#redraw} after.
  31908. */
  31909. /**
  31910. * The chart caption. The caption has an `update` method that
  31911. * allows modifying the options directly or indirectly via
  31912. * `chart.update`.
  31913. *
  31914. * @interface Highcharts.CaptionObject
  31915. * @extends Highcharts.SVGElement
  31916. */ /**
  31917. * Modify options for the caption.
  31918. *
  31919. * @function Highcharts.CaptionObject#update
  31920. *
  31921. * @param {Highcharts.CaptionOptions} captionOptions
  31922. * Options to modify.
  31923. *
  31924. * @param {boolean} [redraw=true]
  31925. * Whether to redraw the chart after the caption is altered. If doing
  31926. * more operations on the chart, it is a good idea to set redraw to false
  31927. * and call {@link Chart#redraw} after.
  31928. */
  31929. ''; // include doclets above in transpilat
  31930. return Chart;
  31931. });
  31932. _registerModule(_modules, 'Mixins/LegendSymbol.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
  31933. /* *
  31934. *
  31935. * (c) 2010-2021 Torstein Honsi
  31936. *
  31937. * License: www.highcharts.com/license
  31938. *
  31939. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  31940. *
  31941. * */
  31942. var merge = U.merge,
  31943. pick = U.pick;
  31944. /* eslint-disable valid-jsdoc */
  31945. /**
  31946. * Legend symbol mixin.
  31947. *
  31948. * @private
  31949. * @mixin Highcharts.LegendSymbolMixin
  31950. */
  31951. var LegendSymbolMixin = H.LegendSymbolMixin = {
  31952. /**
  31953. * Get the series' symbol in the legend
  31954. *
  31955. * @private
  31956. * @function Highcharts.LegendSymbolMixin.drawRectangle
  31957. *
  31958. * @param {Highcharts.Legend} legend
  31959. * The legend object
  31960. *
  31961. * @param {Highcharts.Point|Highcharts.Series} item
  31962. * The series (this) or point
  31963. */
  31964. drawRectangle: function (legend,
  31965. item) {
  31966. var options = legend.options,
  31967. symbolHeight = legend.symbolHeight,
  31968. square = options.squareSymbol,
  31969. symbolWidth = square ? symbolHeight : legend.symbolWidth;
  31970. item.legendSymbol = this.chart.renderer.rect(square ? (legend.symbolWidth - symbolHeight) / 2 : 0, legend.baseline - symbolHeight + 1, // #3988
  31971. symbolWidth, symbolHeight, pick(legend.options.symbolRadius, symbolHeight / 2))
  31972. .addClass('highcharts-point')
  31973. .attr({
  31974. zIndex: 3
  31975. }).add(item.legendGroup);
  31976. },
  31977. /**
  31978. * Get the series' symbol in the legend. This method should be overridable
  31979. * to create custom symbols through
  31980. * Highcharts.seriesTypes[type].prototype.drawLegendSymbols.
  31981. *
  31982. * @private
  31983. * @function Highcharts.LegendSymbolMixin.drawLineMarker
  31984. *
  31985. * @param {Highcharts.Legend} legend
  31986. * The legend object.
  31987. */
  31988. drawLineMarker: function (legend) {
  31989. var options = this.options,
  31990. markerOptions = options.marker,
  31991. radius,
  31992. legendSymbol,
  31993. symbolWidth = legend.symbolWidth,
  31994. symbolHeight = legend.symbolHeight,
  31995. generalRadius = symbolHeight / 2,
  31996. renderer = this.chart.renderer,
  31997. legendItemGroup = this.legendGroup,
  31998. verticalCenter = legend.baseline -
  31999. Math.round(legend.fontMetrics.b * 0.3),
  32000. attr = {};
  32001. // Draw the line
  32002. if (!this.chart.styledMode) {
  32003. attr = {
  32004. 'stroke-width': options.lineWidth || 0
  32005. };
  32006. if (options.dashStyle) {
  32007. attr.dashstyle = options.dashStyle;
  32008. }
  32009. }
  32010. this.legendLine = renderer
  32011. .path([
  32012. ['M', 0, verticalCenter],
  32013. ['L', symbolWidth, verticalCenter]
  32014. ])
  32015. .addClass('highcharts-graph')
  32016. .attr(attr)
  32017. .add(legendItemGroup);
  32018. // Draw the marker
  32019. if (markerOptions && markerOptions.enabled !== false && symbolWidth) {
  32020. // Do not allow the marker to be larger than the symbolHeight
  32021. radius = Math.min(pick(markerOptions.radius, generalRadius), generalRadius);
  32022. // Restrict symbol markers size
  32023. if (this.symbol.indexOf('url') === 0) {
  32024. markerOptions = merge(markerOptions, {
  32025. width: symbolHeight,
  32026. height: symbolHeight
  32027. });
  32028. radius = 0;
  32029. }
  32030. this.legendSymbol = legendSymbol = renderer.symbol(this.symbol, (symbolWidth / 2) - radius, verticalCenter - radius, 2 * radius, 2 * radius, markerOptions)
  32031. .addClass('highcharts-point')
  32032. .add(legendItemGroup);
  32033. legendSymbol.isMarker = true;
  32034. }
  32035. }
  32036. };
  32037. return LegendSymbolMixin;
  32038. });
  32039. _registerModule(_modules, 'Core/Series/Series.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Globals.js'], _modules['Mixins/LegendSymbol.js'], _modules['Core/Options.js'], _modules['Core/Color/Palette.js'], _modules['Core/Series/Point.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Utilities.js']], function (A, H, LegendSymbolMixin, O, palette, Point, SeriesRegistry, SVGElement, U) {
  32040. /* *
  32041. *
  32042. * (c) 2010-2021 Torstein Honsi
  32043. *
  32044. * License: www.highcharts.com/license
  32045. *
  32046. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  32047. *
  32048. * */
  32049. var animObject = A.animObject,
  32050. setAnimation = A.setAnimation;
  32051. var hasTouch = H.hasTouch,
  32052. svg = H.svg,
  32053. win = H.win;
  32054. var defaultOptions = O.defaultOptions;
  32055. var seriesTypes = SeriesRegistry.seriesTypes;
  32056. var addEvent = U.addEvent,
  32057. arrayMax = U.arrayMax,
  32058. arrayMin = U.arrayMin,
  32059. clamp = U.clamp,
  32060. cleanRecursively = U.cleanRecursively,
  32061. correctFloat = U.correctFloat,
  32062. defined = U.defined,
  32063. erase = U.erase,
  32064. error = U.error,
  32065. extend = U.extend,
  32066. find = U.find,
  32067. fireEvent = U.fireEvent,
  32068. getNestedProperty = U.getNestedProperty,
  32069. isArray = U.isArray,
  32070. isFunction = U.isFunction,
  32071. isNumber = U.isNumber,
  32072. isString = U.isString,
  32073. merge = U.merge,
  32074. objectEach = U.objectEach,
  32075. pick = U.pick,
  32076. removeEvent = U.removeEvent,
  32077. splat = U.splat,
  32078. syncTimeout = U.syncTimeout;
  32079. /* *
  32080. *
  32081. * Class
  32082. *
  32083. * */
  32084. /**
  32085. * This is the base series prototype that all other series types inherit from.
  32086. * A new series is initialized either through the
  32087. * [series](https://api.highcharts.com/highcharts/series)
  32088. * option structure, or after the chart is initialized, through
  32089. * {@link Highcharts.Chart#addSeries}.
  32090. *
  32091. * The object can be accessed in a number of ways. All series and point event
  32092. * handlers give a reference to the `series` object. The chart object has a
  32093. * {@link Highcharts.Chart#series|series} property that is a collection of all
  32094. * the chart's series. The point objects and axis objects also have the same
  32095. * reference.
  32096. *
  32097. * Another way to reference the series programmatically is by `id`. Add an id
  32098. * in the series configuration options, and get the series object by
  32099. * {@link Highcharts.Chart#get}.
  32100. *
  32101. * Configuration options for the series are given in three levels. Options for
  32102. * all series in a chart are given in the
  32103. * [plotOptions.series](https://api.highcharts.com/highcharts/plotOptions.series)
  32104. * object. Then options for all series of a specific type
  32105. * are given in the plotOptions of that type, for example `plotOptions.line`.
  32106. * Next, options for one single series are given in the series array, or as
  32107. * arguments to `chart.addSeries`.
  32108. *
  32109. * The data in the series is stored in various arrays.
  32110. *
  32111. * - First, `series.options.data` contains all the original config options for
  32112. * each point whether added by options or methods like `series.addPoint`.
  32113. *
  32114. * - Next, `series.data` contains those values converted to points, but in case
  32115. * the series data length exceeds the `cropThreshold`, or if the data is
  32116. * grouped, `series.data` doesn't contain all the points. It only contains the
  32117. * points that have been created on demand.
  32118. *
  32119. * - Then there's `series.points` that contains all currently visible point
  32120. * objects. In case of cropping, the cropped-away points are not part of this
  32121. * array. The `series.points` array starts at `series.cropStart` compared to
  32122. * `series.data` and `series.options.data`. If however the series data is
  32123. * grouped, these can't be correlated one to one.
  32124. *
  32125. * - `series.xData` and `series.processedXData` contain clean x values,
  32126. * equivalent to `series.data` and `series.points`.
  32127. *
  32128. * - `series.yData` and `series.processedYData` contain clean y values,
  32129. * equivalent to `series.data` and `series.points`.
  32130. *
  32131. * @class
  32132. * @name Highcharts.Series
  32133. *
  32134. * @param {Highcharts.Chart} chart
  32135. * The chart instance.
  32136. *
  32137. * @param {Highcharts.SeriesOptionsType|object} options
  32138. * The series options.
  32139. */
  32140. var Series = /** @class */ (function () {
  32141. function Series() {
  32142. /* *
  32143. *
  32144. * Static Functions
  32145. *
  32146. * */
  32147. this._i = void 0;
  32148. this.chart = void 0;
  32149. this.data = void 0;
  32150. this.eventOptions = void 0;
  32151. this.eventsToUnbind = void 0;
  32152. this.index = void 0;
  32153. this.linkedSeries = void 0;
  32154. this.options = void 0;
  32155. this.points = void 0;
  32156. this.processedXData = void 0;
  32157. this.processedYData = void 0;
  32158. this.tooltipOptions = void 0;
  32159. this.userOptions = void 0;
  32160. this.xAxis = void 0;
  32161. this.yAxis = void 0;
  32162. this.zones = void 0;
  32163. /** eslint-enable valid-jsdoc */
  32164. }
  32165. /* *
  32166. *
  32167. * Functions
  32168. *
  32169. * */
  32170. /* eslint-disable valid-jsdoc */
  32171. Series.prototype.init = function (chart, options) {
  32172. fireEvent(this, 'init', { options: options });
  32173. var series = this,
  32174. events,
  32175. chartSeries = chart.series,
  32176. lastSeries;
  32177. // A lookup over those events that are added by _options_ (not
  32178. // programmatically). These are updated through Series.update()
  32179. // (#10861).
  32180. this.eventOptions = this.eventOptions || {};
  32181. // The 'eventsToUnbind' property moved from prototype into the
  32182. // Series init to avoid reference to the same array between
  32183. // the different series and charts. #12959, #13937
  32184. this.eventsToUnbind = [];
  32185. /**
  32186. * Read only. The chart that the series belongs to.
  32187. *
  32188. * @name Highcharts.Series#chart
  32189. * @type {Highcharts.Chart}
  32190. */
  32191. series.chart = chart;
  32192. /**
  32193. * Read only. The series' type, like "line", "area", "column" etc.
  32194. * The type in the series options anc can be altered using
  32195. * {@link Series#update}.
  32196. *
  32197. * @name Highcharts.Series#type
  32198. * @type {string}
  32199. */
  32200. /**
  32201. * Read only. The series' current options. To update, use
  32202. * {@link Series#update}.
  32203. *
  32204. * @name Highcharts.Series#options
  32205. * @type {Highcharts.SeriesOptionsType}
  32206. */
  32207. series.options = options = series.setOptions(options);
  32208. series.linkedSeries = [];
  32209. // bind the axes
  32210. series.bindAxes();
  32211. // set some variables
  32212. extend(series, {
  32213. /**
  32214. * The series name as given in the options. Defaults to
  32215. * "Series {n}".
  32216. *
  32217. * @name Highcharts.Series#name
  32218. * @type {string}
  32219. */
  32220. name: options.name,
  32221. state: '',
  32222. /**
  32223. * Read only. The series' visibility state as set by {@link
  32224. * Series#show}, {@link Series#hide}, or in the initial
  32225. * configuration.
  32226. *
  32227. * @name Highcharts.Series#visible
  32228. * @type {boolean}
  32229. */
  32230. visible: options.visible !== false,
  32231. /**
  32232. * Read only. The series' selected state as set by {@link
  32233. * Highcharts.Series#select}.
  32234. *
  32235. * @name Highcharts.Series#selected
  32236. * @type {boolean}
  32237. */
  32238. selected: options.selected === true // false by default
  32239. });
  32240. // Register event listeners
  32241. events = options.events;
  32242. objectEach(events, function (event, eventType) {
  32243. if (isFunction(event)) {
  32244. // If event does not exist, or is changed by Series.update
  32245. if (series.eventOptions[eventType] !== event) {
  32246. // Remove existing if set by option
  32247. if (isFunction(series.eventOptions[eventType])) {
  32248. removeEvent(series, eventType, series.eventOptions[eventType]);
  32249. }
  32250. series.eventOptions[eventType] = event;
  32251. addEvent(series, eventType, event);
  32252. }
  32253. }
  32254. });
  32255. if ((events && events.click) ||
  32256. (options.point &&
  32257. options.point.events &&
  32258. options.point.events.click) ||
  32259. options.allowPointSelect) {
  32260. chart.runTrackerClick = true;
  32261. }
  32262. series.getColor();
  32263. series.getSymbol();
  32264. // Initialize the parallel data arrays
  32265. series.parallelArrays.forEach(function (key) {
  32266. if (!series[key + 'Data']) {
  32267. series[key + 'Data'] = [];
  32268. }
  32269. });
  32270. // Mark cartesian
  32271. if (series.isCartesian) {
  32272. chart.hasCartesianSeries = true;
  32273. }
  32274. // Get the index and register the series in the chart. The index is
  32275. // one more than the current latest series index (#5960).
  32276. if (chartSeries.length) {
  32277. lastSeries = chartSeries[chartSeries.length - 1];
  32278. }
  32279. series._i = pick(lastSeries && lastSeries._i, -1) + 1;
  32280. series.opacity = series.options.opacity;
  32281. // Insert the series and re-order all series above the insertion
  32282. // point.
  32283. chart.orderSeries(this.insert(chartSeries));
  32284. // Set options for series with sorting and set data later.
  32285. if (options.dataSorting && options.dataSorting.enabled) {
  32286. series.setDataSortingOptions();
  32287. }
  32288. else if (!series.points && !series.data) {
  32289. series.setData(options.data, false);
  32290. }
  32291. fireEvent(this, 'afterInit');
  32292. };
  32293. /**
  32294. * Check whether the series item is itself or inherits from a certain
  32295. * series type.
  32296. *
  32297. * @function Highcharts.Series#is
  32298. * @param {string} type The type of series to check for, can be either
  32299. * featured or custom series types. For example `column`, `pie`,
  32300. * `ohlc` etc.
  32301. *
  32302. * @return {boolean}
  32303. * True if this item is or inherits from the given type.
  32304. */
  32305. Series.prototype.is = function (type) {
  32306. return seriesTypes[type] && this instanceof seriesTypes[type];
  32307. };
  32308. /**
  32309. * Insert the series in a collection with other series, either the chart
  32310. * series or yAxis series, in the correct order according to the index
  32311. * option. Used internally when adding series.
  32312. *
  32313. * @private
  32314. * @function Highcharts.Series#insert
  32315. * @param {Array<Highcharts.Series>} collection
  32316. * A collection of series, like `chart.series` or `xAxis.series`.
  32317. * @return {number}
  32318. * The index of the series in the collection.
  32319. */
  32320. Series.prototype.insert = function (collection) {
  32321. var indexOption = this.options.index,
  32322. i;
  32323. // Insert by index option
  32324. if (isNumber(indexOption)) {
  32325. i = collection.length;
  32326. while (i--) {
  32327. // Loop down until the interted element has higher index
  32328. if (indexOption >=
  32329. pick(collection[i].options.index, collection[i]._i)) {
  32330. collection.splice(i + 1, 0, this);
  32331. break;
  32332. }
  32333. }
  32334. if (i === -1) {
  32335. collection.unshift(this);
  32336. }
  32337. i = i + 1;
  32338. // Or just push it to the end
  32339. }
  32340. else {
  32341. collection.push(this);
  32342. }
  32343. return pick(i, collection.length - 1);
  32344. };
  32345. /**
  32346. * Set the xAxis and yAxis properties of cartesian series, and register
  32347. * the series in the `axis.series` array.
  32348. *
  32349. * @private
  32350. * @function Highcharts.Series#bindAxes
  32351. */
  32352. Series.prototype.bindAxes = function () {
  32353. var series = this,
  32354. seriesOptions = series.options,
  32355. chart = series.chart,
  32356. axisOptions;
  32357. fireEvent(this, 'bindAxes', null, function () {
  32358. // repeat for xAxis and yAxis
  32359. (series.axisTypes || []).forEach(function (AXIS) {
  32360. // loop through the chart's axis objects
  32361. chart[AXIS].forEach(function (axis) {
  32362. axisOptions = axis.options;
  32363. // apply if the series xAxis or yAxis option mathches
  32364. // the number of the axis, or if undefined, use the
  32365. // first axis
  32366. if (seriesOptions[AXIS] ===
  32367. axisOptions.index ||
  32368. (typeof seriesOptions[AXIS] !==
  32369. 'undefined' &&
  32370. seriesOptions[AXIS] === axisOptions.id) ||
  32371. (typeof seriesOptions[AXIS] ===
  32372. 'undefined' &&
  32373. axisOptions.index === 0)) {
  32374. // register this series in the axis.series lookup
  32375. series.insert(axis.series);
  32376. // set this series.xAxis or series.yAxis reference
  32377. /**
  32378. * Read only. The unique xAxis object associated
  32379. * with the series.
  32380. *
  32381. * @name Highcharts.Series#xAxis
  32382. * @type {Highcharts.Axis}
  32383. */
  32384. /**
  32385. * Read only. The unique yAxis object associated
  32386. * with the series.
  32387. *
  32388. * @name Highcharts.Series#yAxis
  32389. * @type {Highcharts.Axis}
  32390. */
  32391. series[AXIS] = axis;
  32392. // mark dirty for redraw
  32393. axis.isDirty = true;
  32394. }
  32395. });
  32396. // The series needs an X and an Y axis
  32397. if (!series[AXIS] &&
  32398. series.optionalAxis !== AXIS) {
  32399. error(18, true, chart);
  32400. }
  32401. });
  32402. });
  32403. fireEvent(this, 'afterBindAxes');
  32404. };
  32405. /**
  32406. * For simple series types like line and column, the data values are
  32407. * held in arrays like xData and yData for quick lookup to find extremes
  32408. * and more. For multidimensional series like bubble and map, this can
  32409. * be extended with arrays like zData and valueData by adding to the
  32410. * `series.parallelArrays` array.
  32411. *
  32412. * @private
  32413. * @function Highcharts.Series#updateParallelArrays
  32414. */
  32415. Series.prototype.updateParallelArrays = function (point, i) {
  32416. var series = point.series,
  32417. args = arguments,
  32418. fn = isNumber(i) ?
  32419. // Insert the value in the given position
  32420. function (key) {
  32421. var val = key === 'y' && series.toYData ?
  32422. series.toYData(point) :
  32423. point[key];
  32424. series[key + 'Data'][i] = val;
  32425. } :
  32426. // Apply the method specified in i with the following
  32427. // arguments as arguments
  32428. function (key) {
  32429. Array.prototype[i].apply(series[key + 'Data'], Array.prototype.slice.call(args, 2));
  32430. };
  32431. series.parallelArrays.forEach(fn);
  32432. };
  32433. /**
  32434. * Define hasData functions for series. These return true if there
  32435. * are data points on this series within the plot area.
  32436. *
  32437. * @private
  32438. * @function Highcharts.Series#hasData
  32439. * @return {boolean}
  32440. */
  32441. Series.prototype.hasData = function () {
  32442. return ((this.visible &&
  32443. typeof this.dataMax !== 'undefined' &&
  32444. typeof this.dataMin !== 'undefined') || ( // #3703
  32445. this.visible &&
  32446. this.yData &&
  32447. this.yData.length > 0) // #9758
  32448. );
  32449. };
  32450. /**
  32451. * Return an auto incremented x value based on the pointStart and
  32452. * pointInterval options. This is only used if an x value is not given
  32453. * for the point that calls autoIncrement.
  32454. *
  32455. * @private
  32456. * @function Highcharts.Series#autoIncrement
  32457. * @return {number}
  32458. */
  32459. Series.prototype.autoIncrement = function () {
  32460. var options = this.options,
  32461. xIncrement = this.xIncrement,
  32462. date,
  32463. pointInterval,
  32464. pointIntervalUnit = options.pointIntervalUnit,
  32465. time = this.chart.time;
  32466. xIncrement = pick(xIncrement, options.pointStart, 0);
  32467. this.pointInterval = pointInterval = pick(this.pointInterval, options.pointInterval, 1);
  32468. // Added code for pointInterval strings
  32469. if (pointIntervalUnit) {
  32470. date = new time.Date(xIncrement);
  32471. if (pointIntervalUnit === 'day') {
  32472. time.set('Date', date, time.get('Date', date) + pointInterval);
  32473. }
  32474. else if (pointIntervalUnit === 'month') {
  32475. time.set('Month', date, time.get('Month', date) + pointInterval);
  32476. }
  32477. else if (pointIntervalUnit === 'year') {
  32478. time.set('FullYear', date, time.get('FullYear', date) + pointInterval);
  32479. }
  32480. pointInterval = date.getTime() - xIncrement;
  32481. }
  32482. this.xIncrement = xIncrement + pointInterval;
  32483. return xIncrement;
  32484. };
  32485. /**
  32486. * Internal function to set properties for series if data sorting is
  32487. * enabled.
  32488. *
  32489. * @private
  32490. * @function Highcharts.Series#setDataSortingOptions
  32491. */
  32492. Series.prototype.setDataSortingOptions = function () {
  32493. var options = this.options;
  32494. extend(this, {
  32495. requireSorting: false,
  32496. sorted: false,
  32497. enabledDataSorting: true,
  32498. allowDG: false
  32499. });
  32500. // To allow unsorted data for column series.
  32501. if (!defined(options.pointRange)) {
  32502. options.pointRange = 1;
  32503. }
  32504. };
  32505. /**
  32506. * Set the series options by merging from the options tree. Called
  32507. * internally on initializing and updating series. This function will
  32508. * not redraw the series. For API usage, use {@link Series#update}.
  32509. * @private
  32510. * @function Highcharts.Series#setOptions
  32511. *
  32512. * @param {Highcharts.SeriesOptionsType} itemOptions
  32513. * The series options.
  32514. *
  32515. * @return {Highcharts.SeriesOptionsType}
  32516. *
  32517. * @fires Highcharts.Series#event:afterSetOptions
  32518. */
  32519. Series.prototype.setOptions = function (itemOptions) {
  32520. var chart = this.chart,
  32521. chartOptions = chart.options,
  32522. plotOptions = chartOptions.plotOptions,
  32523. userOptions = chart.userOptions || {},
  32524. seriesUserOptions = merge(itemOptions),
  32525. options,
  32526. zones,
  32527. zone,
  32528. styledMode = chart.styledMode,
  32529. e = {
  32530. plotOptions: plotOptions,
  32531. userOptions: seriesUserOptions
  32532. };
  32533. fireEvent(this, 'setOptions', e);
  32534. // These may be modified by the event
  32535. var typeOptions = e.plotOptions[this.type],
  32536. userPlotOptions = (userOptions.plotOptions || {});
  32537. // use copy to prevent undetected changes (#9762)
  32538. /**
  32539. * Contains series options by the user without defaults.
  32540. * @name Highcharts.Series#userOptions
  32541. * @type {Highcharts.SeriesOptionsType}
  32542. */
  32543. this.userOptions = e.userOptions;
  32544. options = merge(typeOptions, plotOptions.series,
  32545. // #3881, chart instance plotOptions[type] should trump
  32546. // plotOptions.series
  32547. userOptions.plotOptions &&
  32548. userOptions.plotOptions[this.type], seriesUserOptions);
  32549. // The tooltip options are merged between global and series specific
  32550. // options. Importance order asscendingly:
  32551. // globals: (1)tooltip, (2)plotOptions.series,
  32552. // (3)plotOptions[this.type]
  32553. // init userOptions with possible later updates: 4-6 like 1-3 and
  32554. // (7)this series options
  32555. this.tooltipOptions = merge(defaultOptions.tooltip, // 1
  32556. defaultOptions.plotOptions.series &&
  32557. defaultOptions.plotOptions.series.tooltip, // 2
  32558. defaultOptions.plotOptions[this.type].tooltip, // 3
  32559. chartOptions.tooltip.userOptions, // 4
  32560. plotOptions.series &&
  32561. plotOptions.series.tooltip, // 5
  32562. plotOptions[this.type].tooltip, // 6
  32563. seriesUserOptions.tooltip // 7
  32564. );
  32565. // When shared tooltip, stickyTracking is true by default,
  32566. // unless user says otherwise.
  32567. this.stickyTracking = pick(seriesUserOptions.stickyTracking, userPlotOptions[this.type] &&
  32568. userPlotOptions[this.type].stickyTracking, userPlotOptions.series && userPlotOptions.series.stickyTracking, (this.tooltipOptions.shared && !this.noSharedTooltip ?
  32569. true :
  32570. options.stickyTracking));
  32571. // Delete marker object if not allowed (#1125)
  32572. if (typeOptions.marker === null) {
  32573. delete options.marker;
  32574. }
  32575. // Handle color zones
  32576. this.zoneAxis = options.zoneAxis;
  32577. zones = this.zones = (options.zones || []).slice();
  32578. if ((options.negativeColor || options.negativeFillColor) &&
  32579. !options.zones) {
  32580. zone = {
  32581. value: options[this.zoneAxis + 'Threshold'] ||
  32582. options.threshold ||
  32583. 0,
  32584. className: 'highcharts-negative'
  32585. };
  32586. if (!styledMode) {
  32587. zone.color = options.negativeColor;
  32588. zone.fillColor = options.negativeFillColor;
  32589. }
  32590. zones.push(zone);
  32591. }
  32592. if (zones.length) { // Push one extra zone for the rest
  32593. if (defined(zones[zones.length - 1].value)) {
  32594. zones.push(styledMode ? {} : {
  32595. color: this.color,
  32596. fillColor: this.fillColor
  32597. });
  32598. }
  32599. }
  32600. fireEvent(this, 'afterSetOptions', { options: options });
  32601. return options;
  32602. };
  32603. /**
  32604. * Return series name in "Series {Number}" format or the one defined by
  32605. * a user. This method can be simply overridden as series name format
  32606. * can vary (e.g. technical indicators).
  32607. *
  32608. * @function Highcharts.Series#getName
  32609. *
  32610. * @return {string}
  32611. * The series name.
  32612. */
  32613. Series.prototype.getName = function () {
  32614. // #4119
  32615. return pick(this.options.name, 'Series ' + (this.index + 1));
  32616. };
  32617. /**
  32618. * @private
  32619. * @function Highcharts.Series#getCyclic
  32620. */
  32621. Series.prototype.getCyclic = function (prop, value, defaults) {
  32622. var i, chart = this.chart, userOptions = this.userOptions, indexName = prop + 'Index', counterName = prop + 'Counter', len = defaults ? defaults.length : pick(chart.options.chart[prop + 'Count'], chart[prop + 'Count']), setting;
  32623. if (!value) {
  32624. // Pick up either the colorIndex option, or the _colorIndex
  32625. // after Series.update()
  32626. setting = pick(userOptions[indexName], userOptions['_' + indexName]);
  32627. if (defined(setting)) { // after Series.update()
  32628. i = setting;
  32629. }
  32630. else {
  32631. // #6138
  32632. if (!chart.series.length) {
  32633. chart[counterName] = 0;
  32634. }
  32635. userOptions['_' + indexName] = i =
  32636. chart[counterName] % len;
  32637. chart[counterName] += 1;
  32638. }
  32639. if (defaults) {
  32640. value = defaults[i];
  32641. }
  32642. }
  32643. // Set the colorIndex
  32644. if (typeof i !== 'undefined') {
  32645. this[indexName] = i;
  32646. }
  32647. this[prop] = value;
  32648. };
  32649. /**
  32650. * Get the series' color based on either the options or pulled from
  32651. * global options.
  32652. *
  32653. * @private
  32654. * @function Highcharts.Series#getColor
  32655. */
  32656. Series.prototype.getColor = function () {
  32657. if (this.chart.styledMode) {
  32658. this.getCyclic('color');
  32659. }
  32660. else if (this.options.colorByPoint) {
  32661. // #4359, selected slice got series.color even when colorByPoint
  32662. // was set.
  32663. this.options.color = null;
  32664. }
  32665. else {
  32666. this.getCyclic('color', this.options.color ||
  32667. defaultOptions.plotOptions[this.type].color, this.chart.options.colors);
  32668. }
  32669. };
  32670. /**
  32671. * Get all points' instances created for this series.
  32672. *
  32673. * @private
  32674. * @function Highcharts.Series#getPointsCollection
  32675. * @return {Array<Highcharts.Point>}
  32676. */
  32677. Series.prototype.getPointsCollection = function () {
  32678. return (this.hasGroupedData ? this.points : this.data) || [];
  32679. };
  32680. /**
  32681. * Get the series' symbol based on either the options or pulled from
  32682. * global options.
  32683. *
  32684. * @private
  32685. * @function Highcharts.Series#getSymbol
  32686. * @return {void}
  32687. */
  32688. Series.prototype.getSymbol = function () {
  32689. var seriesMarkerOption = this.options.marker;
  32690. this.getCyclic('symbol', seriesMarkerOption.symbol, this.chart.options.symbols);
  32691. };
  32692. /**
  32693. * Finds the index of an existing point that matches the given point
  32694. * options.
  32695. *
  32696. * @private
  32697. * @function Highcharts.Series#findPointIndex
  32698. * @param {Highcharts.PointOptionsObject} optionsObject
  32699. * The options of the point.
  32700. * @param {number} fromIndex
  32701. * The index to start searching from, used for optimizing
  32702. * series with required sorting.
  32703. * @returns {number|undefined}
  32704. * Returns the index of a matching point, or undefined if no
  32705. * match is found.
  32706. */
  32707. Series.prototype.findPointIndex = function (optionsObject, fromIndex) {
  32708. var id = optionsObject.id,
  32709. x = optionsObject.x,
  32710. oldData = this.points,
  32711. matchingPoint,
  32712. matchedById,
  32713. pointIndex,
  32714. matchKey,
  32715. dataSorting = this.options.dataSorting;
  32716. if (id) {
  32717. matchingPoint = this.chart.get(id);
  32718. }
  32719. else if (this.linkedParent || this.enabledDataSorting) {
  32720. matchKey = (dataSorting && dataSorting.matchByName) ?
  32721. 'name' : 'index';
  32722. matchingPoint = find(oldData, function (oldPoint) {
  32723. return !oldPoint.touched && oldPoint[matchKey] ===
  32724. optionsObject[matchKey];
  32725. });
  32726. // Add unmatched point as a new point
  32727. if (!matchingPoint) {
  32728. return void 0;
  32729. }
  32730. }
  32731. if (matchingPoint) {
  32732. pointIndex = matchingPoint && matchingPoint.index;
  32733. if (typeof pointIndex !== 'undefined') {
  32734. matchedById = true;
  32735. }
  32736. }
  32737. // Search for the same X in the existing data set
  32738. if (typeof pointIndex === 'undefined' && isNumber(x)) {
  32739. pointIndex = this.xData.indexOf(x, fromIndex);
  32740. }
  32741. // Reduce pointIndex if data is cropped
  32742. if (pointIndex !== -1 &&
  32743. typeof pointIndex !== 'undefined' &&
  32744. this.cropped) {
  32745. pointIndex = (pointIndex >= this.cropStart) ?
  32746. pointIndex - this.cropStart : pointIndex;
  32747. }
  32748. if (!matchedById &&
  32749. oldData[pointIndex] && oldData[pointIndex].touched) {
  32750. pointIndex = void 0;
  32751. }
  32752. return pointIndex;
  32753. };
  32754. /**
  32755. * Internal function called from setData. If the point count is the same
  32756. * as is was, or if there are overlapping X values, just run
  32757. * Point.update which is cheaper, allows animation, and keeps references
  32758. * to points. This also allows adding or removing points if the X-es
  32759. * don't match.
  32760. *
  32761. * @private
  32762. * @function Highcharts.Series#updateData
  32763. */
  32764. Series.prototype.updateData = function (data, animation) {
  32765. var options = this.options,
  32766. dataSorting = options.dataSorting,
  32767. oldData = this.points,
  32768. pointsToAdd = [],
  32769. hasUpdatedByKey,
  32770. i,
  32771. point,
  32772. lastIndex,
  32773. requireSorting = this.requireSorting,
  32774. equalLength = data.length === oldData.length,
  32775. succeeded = true;
  32776. this.xIncrement = null;
  32777. // Iterate the new data
  32778. data.forEach(function (pointOptions, i) {
  32779. var id,
  32780. x,
  32781. pointIndex,
  32782. optionsObject = (defined(pointOptions) &&
  32783. this.pointClass.prototype.optionsToObject.call({ series: this },
  32784. pointOptions)) || {};
  32785. // Get the x of the new data point
  32786. x = optionsObject.x;
  32787. id = optionsObject.id;
  32788. if (id || isNumber(x)) {
  32789. pointIndex = this.findPointIndex(optionsObject, lastIndex);
  32790. // Matching X not found
  32791. // or used already due to ununique x values (#8995),
  32792. // add point (but later)
  32793. if (pointIndex === -1 ||
  32794. typeof pointIndex === 'undefined') {
  32795. pointsToAdd.push(pointOptions);
  32796. // Matching X found, update
  32797. }
  32798. else if (oldData[pointIndex] &&
  32799. pointOptions !== options.data[pointIndex]) {
  32800. oldData[pointIndex].update(pointOptions, false, null, false);
  32801. // Mark it touched, below we will remove all points that
  32802. // are not touched.
  32803. oldData[pointIndex].touched = true;
  32804. // Speed optimize by only searching after last known
  32805. // index. Performs ~20% bettor on large data sets.
  32806. if (requireSorting) {
  32807. lastIndex = pointIndex + 1;
  32808. }
  32809. // Point exists, no changes, don't remove it
  32810. }
  32811. else if (oldData[pointIndex]) {
  32812. oldData[pointIndex].touched = true;
  32813. }
  32814. // If the length is equal and some of the nodes had a
  32815. // match in the same position, we don't want to remove
  32816. // non-matches.
  32817. if (!equalLength ||
  32818. i !== pointIndex ||
  32819. (dataSorting && dataSorting.enabled) ||
  32820. this.hasDerivedData) {
  32821. hasUpdatedByKey = true;
  32822. }
  32823. }
  32824. else {
  32825. // Gather all points that are not matched
  32826. pointsToAdd.push(pointOptions);
  32827. }
  32828. }, this);
  32829. // Remove points that don't exist in the updated data set
  32830. if (hasUpdatedByKey) {
  32831. i = oldData.length;
  32832. while (i--) {
  32833. point = oldData[i];
  32834. if (point && !point.touched && point.remove) {
  32835. point.remove(false, animation);
  32836. }
  32837. }
  32838. // If we did not find keys (ids or x-values), and the length is the
  32839. // same, update one-to-one
  32840. }
  32841. else if (equalLength && (!dataSorting || !dataSorting.enabled)) {
  32842. data.forEach(function (point, i) {
  32843. // .update doesn't exist on a linked, hidden series (#3709)
  32844. // (#10187)
  32845. if (oldData[i].update && point !== oldData[i].y) {
  32846. oldData[i].update(point, false, null, false);
  32847. }
  32848. });
  32849. // Don't add new points since those configs are used above
  32850. pointsToAdd.length = 0;
  32851. // Did not succeed in updating data
  32852. }
  32853. else {
  32854. succeeded = false;
  32855. }
  32856. oldData.forEach(function (point) {
  32857. if (point) {
  32858. point.touched = false;
  32859. }
  32860. });
  32861. if (!succeeded) {
  32862. return false;
  32863. }
  32864. // Add new points
  32865. pointsToAdd.forEach(function (point) {
  32866. this.addPoint(point, false, null, null, false);
  32867. }, this);
  32868. if (this.xIncrement === null &&
  32869. this.xData &&
  32870. this.xData.length) {
  32871. this.xIncrement = arrayMax(this.xData);
  32872. this.autoIncrement();
  32873. }
  32874. return true;
  32875. };
  32876. /**
  32877. * Apply a new set of data to the series and optionally redraw it. The
  32878. * new data array is passed by reference (except in case of
  32879. * `updatePoints`), and may later be mutated when updating the chart
  32880. * data.
  32881. *
  32882. * Note the difference in behaviour when setting the same amount of
  32883. * points, or a different amount of points, as handled by the
  32884. * `updatePoints` parameter.
  32885. *
  32886. * @sample highcharts/members/series-setdata/
  32887. * Set new data from a button
  32888. * @sample highcharts/members/series-setdata-pie/
  32889. * Set data in a pie
  32890. * @sample stock/members/series-setdata/
  32891. * Set new data in Highstock
  32892. * @sample maps/members/series-setdata/
  32893. * Set new data in Highmaps
  32894. *
  32895. * @function Highcharts.Series#setData
  32896. *
  32897. * @param {Array<Highcharts.PointOptionsType>} data
  32898. * Takes an array of data in the same format as described under
  32899. * `series.{type}.data` for the given series type, for example a
  32900. * line series would take data in the form described under
  32901. * [series.line.data](https://api.highcharts.com/highcharts/series.line.data).
  32902. *
  32903. * @param {boolean} [redraw=true]
  32904. * Whether to redraw the chart after the series is altered. If
  32905. * doing more operations on the chart, it is a good idea to set
  32906. * redraw to false and call {@link Chart#redraw} after.
  32907. *
  32908. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
  32909. * When the updated data is the same length as the existing data,
  32910. * points will be updated by default, and animation visualizes
  32911. * how the points are changed. Set false to disable animation, or
  32912. * a configuration object to set duration or easing.
  32913. *
  32914. * @param {boolean} [updatePoints=true]
  32915. * When this is true, points will be updated instead of replaced
  32916. * whenever possible. This occurs a) when the updated data is the
  32917. * same length as the existing data, b) when points are matched
  32918. * by their id's, or c) when points can be matched by X values.
  32919. * This allows updating with animation and performs better. In
  32920. * this case, the original array is not passed by reference. Set
  32921. * `false` to prevent.
  32922. */
  32923. Series.prototype.setData = function (data, redraw, animation, updatePoints) {
  32924. var series = this,
  32925. oldData = series.points,
  32926. oldDataLength = (oldData && oldData.length) || 0,
  32927. dataLength,
  32928. options = series.options,
  32929. chart = series.chart,
  32930. dataSorting = options.dataSorting,
  32931. firstPoint = null,
  32932. xAxis = series.xAxis,
  32933. i,
  32934. turboThreshold = options.turboThreshold,
  32935. pt,
  32936. xData = this.xData,
  32937. yData = this.yData,
  32938. pointArrayMap = series.pointArrayMap,
  32939. valueCount = pointArrayMap && pointArrayMap.length,
  32940. keys = options.keys,
  32941. indexOfX = 0,
  32942. indexOfY = 1,
  32943. updatedData;
  32944. data = data || [];
  32945. dataLength = data.length;
  32946. redraw = pick(redraw, true);
  32947. if (dataSorting && dataSorting.enabled) {
  32948. data = this.sortData(data);
  32949. }
  32950. // First try to run Point.update which is cheaper, allows animation,
  32951. // and keeps references to points.
  32952. if (updatePoints !== false &&
  32953. dataLength &&
  32954. oldDataLength &&
  32955. !series.cropped &&
  32956. !series.hasGroupedData &&
  32957. series.visible &&
  32958. // Soft updating has no benefit in boost, and causes JS error
  32959. // (#8355)
  32960. !series.isSeriesBoosting) {
  32961. updatedData = this.updateData(data, animation);
  32962. }
  32963. if (!updatedData) {
  32964. // Reset properties
  32965. series.xIncrement = null;
  32966. series.colorCounter = 0; // for series with colorByPoint (#1547)
  32967. // Update parallel arrays
  32968. this.parallelArrays.forEach(function (key) {
  32969. series[key + 'Data'].length = 0;
  32970. });
  32971. // In turbo mode, only one- or twodimensional arrays of numbers
  32972. // are allowed. The first value is tested, and we assume that
  32973. // all the rest are defined the same way. Although the 'for'
  32974. // loops are similar, they are repeated inside each if-else
  32975. // conditional for max performance.
  32976. if (turboThreshold && dataLength > turboThreshold) {
  32977. firstPoint = series.getFirstValidPoint(data);
  32978. if (isNumber(firstPoint)) { // assume all points are numbers
  32979. for (i = 0; i < dataLength; i++) {
  32980. xData[i] = this.autoIncrement();
  32981. yData[i] = data[i];
  32982. }
  32983. // Assume all points are arrays when first point is
  32984. }
  32985. else if (isArray(firstPoint)) {
  32986. if (valueCount) { // [x, low, high] or [x, o, h, l, c]
  32987. for (i = 0; i < dataLength; i++) {
  32988. pt = data[i];
  32989. xData[i] = pt[0];
  32990. yData[i] =
  32991. pt.slice(1, valueCount + 1);
  32992. }
  32993. }
  32994. else { // [x, y]
  32995. if (keys) {
  32996. indexOfX = keys.indexOf('x');
  32997. indexOfY = keys.indexOf('y');
  32998. indexOfX = indexOfX >= 0 ? indexOfX : 0;
  32999. indexOfY = indexOfY >= 0 ? indexOfY : 1;
  33000. }
  33001. for (i = 0; i < dataLength; i++) {
  33002. pt = data[i];
  33003. xData[i] = pt[indexOfX];
  33004. yData[i] = pt[indexOfY];
  33005. }
  33006. }
  33007. }
  33008. else {
  33009. // Highcharts expects configs to be numbers or arrays in
  33010. // turbo mode
  33011. error(12, false, chart);
  33012. }
  33013. }
  33014. else {
  33015. for (i = 0; i < dataLength; i++) {
  33016. // stray commas in oldIE:
  33017. if (typeof data[i] !== 'undefined') {
  33018. pt = { series: series };
  33019. series.pointClass.prototype.applyOptions.apply(pt, [data[i]]);
  33020. series.updateParallelArrays(pt, i);
  33021. }
  33022. }
  33023. }
  33024. // Forgetting to cast strings to numbers is a common caveat when
  33025. // handling CSV or JSON
  33026. if (yData && isString(yData[0])) {
  33027. error(14, true, chart);
  33028. }
  33029. series.data = [];
  33030. series.options.data = series.userOptions.data = data;
  33031. // destroy old points
  33032. i = oldDataLength;
  33033. while (i--) {
  33034. if (oldData[i] && oldData[i].destroy) {
  33035. oldData[i].destroy();
  33036. }
  33037. }
  33038. // reset minRange (#878)
  33039. if (xAxis) {
  33040. xAxis.minRange = xAxis.userMinRange;
  33041. }
  33042. // redraw
  33043. series.isDirty = chart.isDirtyBox = true;
  33044. series.isDirtyData = !!oldData;
  33045. animation = false;
  33046. }
  33047. // Typically for pie series, points need to be processed and
  33048. // generated prior to rendering the legend
  33049. if (options.legendType === 'point') {
  33050. this.processData();
  33051. this.generatePoints();
  33052. }
  33053. if (redraw) {
  33054. chart.redraw(animation);
  33055. }
  33056. };
  33057. /**
  33058. * Internal function to sort series data
  33059. *
  33060. * @private
  33061. * @function Highcharts.Series#sortData
  33062. *
  33063. * @param {Array<Highcharts.PointOptionsType>} data
  33064. * Force data grouping.
  33065. *
  33066. * @return {Array<Highcharts.PointOptionsObject>}
  33067. */
  33068. Series.prototype.sortData = function (data) {
  33069. var series = this,
  33070. options = series.options,
  33071. dataSorting = options.dataSorting,
  33072. sortKey = dataSorting.sortKey || 'y',
  33073. sortedData,
  33074. getPointOptionsObject = function (series,
  33075. pointOptions) {
  33076. return (defined(pointOptions) &&
  33077. series.pointClass.prototype.optionsToObject.call({
  33078. series: series
  33079. },
  33080. pointOptions)) || {};
  33081. };
  33082. data.forEach(function (pointOptions, i) {
  33083. data[i] = getPointOptionsObject(series, pointOptions);
  33084. data[i].index = i;
  33085. }, this);
  33086. // Sorting
  33087. sortedData = data.concat().sort(function (a, b) {
  33088. var aValue = getNestedProperty(sortKey,
  33089. a);
  33090. var bValue = getNestedProperty(sortKey,
  33091. b);
  33092. return bValue < aValue ? -1 : bValue > aValue ? 1 : 0;
  33093. });
  33094. // Set x value depending on the position in the array
  33095. sortedData.forEach(function (point, i) {
  33096. point.x = i;
  33097. }, this);
  33098. // Set the same x for linked series points if they don't have their
  33099. // own sorting
  33100. if (series.linkedSeries) {
  33101. series.linkedSeries.forEach(function (linkedSeries) {
  33102. var options = linkedSeries.options,
  33103. seriesData = options.data;
  33104. if ((!options.dataSorting ||
  33105. !options.dataSorting.enabled) &&
  33106. seriesData) {
  33107. seriesData.forEach(function (pointOptions, i) {
  33108. seriesData[i] = getPointOptionsObject(linkedSeries, pointOptions);
  33109. if (data[i]) {
  33110. seriesData[i].x = data[i].x;
  33111. seriesData[i].index = i;
  33112. }
  33113. });
  33114. linkedSeries.setData(seriesData, false);
  33115. }
  33116. });
  33117. }
  33118. return data;
  33119. };
  33120. /**
  33121. * Internal function to process the data by cropping away unused data
  33122. * points if the series is longer than the crop threshold. This saves
  33123. * computing time for large series.
  33124. *
  33125. * @private
  33126. * @function Highcharts.Series#getProcessedData
  33127. * @param {boolean} [forceExtremesFromAll]
  33128. * Force getting extremes of a total series data range.
  33129. * @return {Highcharts.SeriesProcessedDataObject}
  33130. */
  33131. Series.prototype.getProcessedData = function (forceExtremesFromAll) {
  33132. var series = this,
  33133. // copied during slice operation:
  33134. processedXData = series.xData,
  33135. processedYData = series.yData,
  33136. dataLength = processedXData.length,
  33137. croppedData,
  33138. cropStart = 0,
  33139. cropped,
  33140. distance,
  33141. closestPointRange,
  33142. xAxis = series.xAxis,
  33143. i, // loop variable
  33144. options = series.options,
  33145. cropThreshold = options.cropThreshold,
  33146. getExtremesFromAll = forceExtremesFromAll ||
  33147. series.getExtremesFromAll ||
  33148. options.getExtremesFromAll, // #4599
  33149. isCartesian = series.isCartesian,
  33150. xExtremes,
  33151. val2lin = xAxis && xAxis.val2lin,
  33152. isLog = !!(xAxis && xAxis.logarithmic),
  33153. throwOnUnsorted = series.requireSorting,
  33154. min,
  33155. max;
  33156. if (xAxis) {
  33157. // corrected for log axis (#3053)
  33158. xExtremes = xAxis.getExtremes();
  33159. min = xExtremes.min;
  33160. max = xExtremes.max;
  33161. }
  33162. // optionally filter out points outside the plot area
  33163. if (isCartesian &&
  33164. series.sorted &&
  33165. !getExtremesFromAll &&
  33166. (!cropThreshold ||
  33167. dataLength > cropThreshold ||
  33168. series.forceCrop)) {
  33169. // it's outside current extremes
  33170. if (processedXData[dataLength - 1] < min ||
  33171. processedXData[0] > max) {
  33172. processedXData = [];
  33173. processedYData = [];
  33174. // only crop if it's actually spilling out
  33175. }
  33176. else if (series.yData && (processedXData[0] < min ||
  33177. processedXData[dataLength - 1] > max)) {
  33178. croppedData = this.cropData(series.xData, series.yData, min, max);
  33179. processedXData = croppedData.xData;
  33180. processedYData = croppedData.yData;
  33181. cropStart = croppedData.start;
  33182. cropped = true;
  33183. }
  33184. }
  33185. // Find the closest distance between processed points
  33186. i = processedXData.length || 1;
  33187. while (--i) {
  33188. distance = (isLog ?
  33189. (val2lin(processedXData[i]) -
  33190. val2lin(processedXData[i - 1])) :
  33191. (processedXData[i] -
  33192. processedXData[i - 1]));
  33193. if (distance > 0 &&
  33194. (typeof closestPointRange === 'undefined' ||
  33195. distance < closestPointRange)) {
  33196. closestPointRange = distance;
  33197. // Unsorted data is not supported by the line tooltip, as well
  33198. // as data grouping and navigation in Stock charts (#725) and
  33199. // width calculation of columns (#1900)
  33200. }
  33201. else if (distance < 0 && throwOnUnsorted) {
  33202. error(15, false, series.chart);
  33203. throwOnUnsorted = false; // Only once
  33204. }
  33205. }
  33206. return {
  33207. xData: processedXData,
  33208. yData: processedYData,
  33209. cropped: cropped,
  33210. cropStart: cropStart,
  33211. closestPointRange: closestPointRange
  33212. };
  33213. };
  33214. /**
  33215. * Internal function to apply processed data.
  33216. * In Highstock, this function is extended to provide data grouping.
  33217. *
  33218. * @private
  33219. * @function Highcharts.Series#processData
  33220. * @param {boolean} [force]
  33221. * Force data grouping.
  33222. * @return {boolean|undefined}
  33223. */
  33224. Series.prototype.processData = function (force) {
  33225. var series = this,
  33226. xAxis = series.xAxis,
  33227. processedData;
  33228. // If the series data or axes haven't changed, don't go through
  33229. // this. Return false to pass the message on to override methods
  33230. // like in data grouping.
  33231. if (series.isCartesian &&
  33232. !series.isDirty &&
  33233. !xAxis.isDirty &&
  33234. !series.yAxis.isDirty &&
  33235. !force) {
  33236. return false;
  33237. }
  33238. processedData = series.getProcessedData();
  33239. // Record the properties
  33240. series.cropped = processedData.cropped; // undefined or true
  33241. series.cropStart = processedData.cropStart;
  33242. series.processedXData = processedData.xData;
  33243. series.processedYData = processedData.yData;
  33244. series.closestPointRange = series.basePointRange = processedData.closestPointRange;
  33245. };
  33246. /**
  33247. * Iterate over xData and crop values between min and max. Returns
  33248. * object containing crop start/end cropped xData with corresponding
  33249. * part of yData, dataMin and dataMax within the cropped range.
  33250. *
  33251. * @private
  33252. * @function Highcharts.Series#cropData
  33253. * @param {Array<number>} xData
  33254. * @param {Array<number>} yData
  33255. * @param {number} min
  33256. * @param {number} max
  33257. * @param {number} [cropShoulder]
  33258. * @return {Highcharts.SeriesCropDataObject}
  33259. */
  33260. Series.prototype.cropData = function (xData, yData, min, max, cropShoulder) {
  33261. var dataLength = xData.length,
  33262. cropStart = 0,
  33263. cropEnd = dataLength,
  33264. i,
  33265. j;
  33266. // line-type series need one point outside
  33267. cropShoulder = pick(cropShoulder, this.cropShoulder);
  33268. // iterate up to find slice start
  33269. for (i = 0; i < dataLength; i++) {
  33270. if (xData[i] >= min) {
  33271. cropStart = Math.max(0, i - cropShoulder);
  33272. break;
  33273. }
  33274. }
  33275. // proceed to find slice end
  33276. for (j = i; j < dataLength; j++) {
  33277. if (xData[j] > max) {
  33278. cropEnd = j + cropShoulder;
  33279. break;
  33280. }
  33281. }
  33282. return {
  33283. xData: xData.slice(cropStart, cropEnd),
  33284. yData: yData.slice(cropStart, cropEnd),
  33285. start: cropStart,
  33286. end: cropEnd
  33287. };
  33288. };
  33289. /**
  33290. * Generate the data point after the data has been processed by cropping
  33291. * away unused points and optionally grouped in Highcharts Stock.
  33292. *
  33293. * @private
  33294. * @function Highcharts.Series#generatePoints
  33295. */
  33296. Series.prototype.generatePoints = function () {
  33297. var series = this,
  33298. options = series.options,
  33299. dataOptions = options.data,
  33300. data = series.data,
  33301. dataLength,
  33302. processedXData = series.processedXData,
  33303. processedYData = series.processedYData,
  33304. PointClass = series.pointClass,
  33305. processedDataLength = processedXData.length,
  33306. cropStart = series.cropStart || 0,
  33307. cursor,
  33308. hasGroupedData = series.hasGroupedData,
  33309. keys = options.keys,
  33310. point,
  33311. points = [],
  33312. i;
  33313. if (!data && !hasGroupedData) {
  33314. var arr = [];
  33315. arr.length = dataOptions.length;
  33316. data = series.data = arr;
  33317. }
  33318. if (keys && hasGroupedData) {
  33319. // grouped data has already applied keys (#6590)
  33320. series.options.keys = false;
  33321. }
  33322. for (i = 0; i < processedDataLength; i++) {
  33323. cursor = cropStart + i;
  33324. if (!hasGroupedData) {
  33325. point = data[cursor];
  33326. // #970:
  33327. if (!point &&
  33328. typeof dataOptions[cursor] !== 'undefined') {
  33329. data[cursor] = point = (new PointClass()).init(series, dataOptions[cursor], processedXData[i]);
  33330. }
  33331. }
  33332. else {
  33333. // splat the y data in case of ohlc data array
  33334. point = (new PointClass()).init(series, [processedXData[i]].concat(splat(processedYData[i])));
  33335. /**
  33336. * Highstock only. If a point object is created by data
  33337. * grouping, it doesn't reflect actual points in the raw
  33338. * data. In this case, the `dataGroup` property holds
  33339. * information that points back to the raw data.
  33340. *
  33341. * - `dataGroup.start` is the index of the first raw data
  33342. * point in the group.
  33343. *
  33344. * - `dataGroup.length` is the amount of points in the
  33345. * group.
  33346. *
  33347. * @product highstock
  33348. *
  33349. * @name Highcharts.Point#dataGroup
  33350. * @type {Highcharts.DataGroupingInfoObject|undefined}
  33351. */
  33352. point.dataGroup = series.groupMap[i];
  33353. if (point.dataGroup.options) {
  33354. point.options = point.dataGroup.options;
  33355. extend(point, point.dataGroup.options);
  33356. // Collision of props and options (#9770)
  33357. delete point.dataLabels;
  33358. }
  33359. }
  33360. if (point) { // #6279
  33361. /**
  33362. * Contains the point's index in the `Series.points` array.
  33363. *
  33364. * @name Highcharts.Point#index
  33365. * @type {number}
  33366. * @readonly
  33367. */
  33368. point.index = cursor; // For faster access in Point.update
  33369. points[i] = point;
  33370. }
  33371. }
  33372. // restore keys options (#6590)
  33373. series.options.keys = keys;
  33374. // Hide cropped-away points - this only runs when the number of
  33375. // points is above cropThreshold, or when swithching view from
  33376. // non-grouped data to grouped data (#637)
  33377. if (data &&
  33378. (processedDataLength !== (dataLength = data.length) ||
  33379. hasGroupedData)) {
  33380. for (i = 0; i < dataLength; i++) {
  33381. // when has grouped data, clear all points
  33382. if (i === cropStart && !hasGroupedData) {
  33383. i += processedDataLength;
  33384. }
  33385. if (data[i]) {
  33386. data[i].destroyElements();
  33387. data[i].plotX = void 0; // #1003
  33388. }
  33389. }
  33390. }
  33391. /**
  33392. * Read only. An array containing those values converted to points.
  33393. * In case the series data length exceeds the `cropThreshold`, or if
  33394. * the data is grouped, `series.data` doesn't contain all the
  33395. * points. Also, in case a series is hidden, the `data` array may be
  33396. * empty. To access raw values, `series.options.data` will always be
  33397. * up to date. `Series.data` only contains the points that have been
  33398. * created on demand. To modify the data, use
  33399. * {@link Highcharts.Series#setData} or
  33400. * {@link Highcharts.Point#update}.
  33401. *
  33402. * @see Series.points
  33403. *
  33404. * @name Highcharts.Series#data
  33405. * @type {Array<Highcharts.Point>}
  33406. */
  33407. series.data = data;
  33408. /**
  33409. * An array containing all currently visible point objects. In case
  33410. * of cropping, the cropped-away points are not part of this array.
  33411. * The `series.points` array starts at `series.cropStart` compared
  33412. * to `series.data` and `series.options.data`. If however the series
  33413. * data is grouped, these can't be correlated one to one. To modify
  33414. * the data, use {@link Highcharts.Series#setData} or
  33415. * {@link Highcharts.Point#update}.
  33416. *
  33417. * @name Highcharts.Series#points
  33418. * @type {Array<Highcharts.Point>}
  33419. */
  33420. series.points = points;
  33421. fireEvent(this, 'afterGeneratePoints');
  33422. };
  33423. /**
  33424. * Get current X extremes for the visible data.
  33425. *
  33426. * @private
  33427. * @function Highcharts.Series#getXExtremes
  33428. *
  33429. * @param {Array<number>} xData
  33430. * The data to inspect. Defaults to the current data within the visible
  33431. * range.
  33432. *
  33433. * @return {Highcharts.RangeObject}
  33434. */
  33435. Series.prototype.getXExtremes = function (xData) {
  33436. return {
  33437. min: arrayMin(xData),
  33438. max: arrayMax(xData)
  33439. };
  33440. };
  33441. /**
  33442. * Calculate Y extremes for the visible data. The result is returned
  33443. * as an object with `dataMin` and `dataMax` properties.
  33444. *
  33445. * @private
  33446. * @function Highcharts.Series#getExtremes
  33447. *
  33448. * @param {Array<number>} [yData]
  33449. * The data to inspect. Defaults to the current data within the visible
  33450. * range.
  33451. * @param {boolean} [forceExtremesFromAll]
  33452. * Force getting extremes of a total series data range.
  33453. *
  33454. * @return {Highcharts.DataExtremesObject}
  33455. */
  33456. Series.prototype.getExtremes = function (yData, forceExtremesFromAll) {
  33457. var xAxis = this.xAxis,
  33458. yAxis = this.yAxis,
  33459. xData = this.processedXData || this.xData,
  33460. yDataLength,
  33461. activeYData = [],
  33462. activeCounter = 0,
  33463. // #2117, need to compensate for log X axis
  33464. xExtremes,
  33465. xMin = 0,
  33466. xMax = 0,
  33467. validValue,
  33468. withinRange,
  33469. // Handle X outside the viewed area. This does not work with
  33470. // non-sorted data like scatter (#7639).
  33471. shoulder = this.requireSorting ? this.cropShoulder : 0,
  33472. positiveValuesOnly = yAxis ? yAxis.positiveValuesOnly : false,
  33473. x,
  33474. y,
  33475. i,
  33476. j;
  33477. yData = yData || this.stackedYData || this.processedYData || [];
  33478. yDataLength = yData.length;
  33479. if (xAxis) {
  33480. xExtremes = xAxis.getExtremes();
  33481. xMin = xExtremes.min;
  33482. xMax = xExtremes.max;
  33483. }
  33484. for (i = 0; i < yDataLength; i++) {
  33485. x = xData[i];
  33486. y = yData[i];
  33487. // For points within the visible range, including the first
  33488. // point outside the visible range (#7061), consider y extremes.
  33489. validValue = ((isNumber(y) || isArray(y)) &&
  33490. ((y.length || y > 0) || !positiveValuesOnly));
  33491. withinRange = (forceExtremesFromAll ||
  33492. this.getExtremesFromAll ||
  33493. this.options.getExtremesFromAll ||
  33494. this.cropped ||
  33495. !xAxis || // for colorAxis support
  33496. ((xData[i + shoulder] || x) >= xMin &&
  33497. (xData[i - shoulder] || x) <= xMax));
  33498. if (validValue && withinRange) {
  33499. j = y.length;
  33500. if (j) { // array, like ohlc or range data
  33501. while (j--) {
  33502. if (isNumber(y[j])) { // #7380, #11513
  33503. activeYData[activeCounter++] = y[j];
  33504. }
  33505. }
  33506. }
  33507. else {
  33508. activeYData[activeCounter++] = y;
  33509. }
  33510. }
  33511. }
  33512. var dataExtremes = {
  33513. dataMin: arrayMin(activeYData),
  33514. dataMax: arrayMax(activeYData)
  33515. };
  33516. fireEvent(this, 'afterGetExtremes', { dataExtremes: dataExtremes });
  33517. return dataExtremes;
  33518. };
  33519. /**
  33520. * Set the current data extremes as `dataMin` and `dataMax` on the
  33521. * Series item. Use this only when the series properties should be
  33522. * updated.
  33523. *
  33524. * @private
  33525. * @function Highcharts.Series#applyExtremes
  33526. */
  33527. Series.prototype.applyExtremes = function () {
  33528. var dataExtremes = this.getExtremes();
  33529. /**
  33530. * Contains the minimum value of the series' data point. Some series
  33531. * types like `networkgraph` do not support this property as they
  33532. * lack a `y`-value.
  33533. * @name Highcharts.Series#dataMin
  33534. * @type {number|undefined}
  33535. * @readonly
  33536. */
  33537. this.dataMin = dataExtremes.dataMin;
  33538. /**
  33539. * Contains the maximum value of the series' data point. Some series
  33540. * types like `networkgraph` do not support this property as they
  33541. * lack a `y`-value.
  33542. * @name Highcharts.Series#dataMax
  33543. * @type {number|undefined}
  33544. * @readonly
  33545. */
  33546. this.dataMax = dataExtremes.dataMax;
  33547. return dataExtremes;
  33548. };
  33549. /**
  33550. * Find and return the first non null point in the data
  33551. *
  33552. * @private
  33553. * @function Highcharts.Series.getFirstValidPoint
  33554. *
  33555. * @param {Array<Highcharts.PointOptionsType>} data
  33556. * Array of options for points
  33557. *
  33558. * @return {Highcharts.PointOptionsType}
  33559. */
  33560. Series.prototype.getFirstValidPoint = function (data) {
  33561. var firstPoint = null,
  33562. dataLength = data.length,
  33563. i = 0;
  33564. while (firstPoint === null && i < dataLength) {
  33565. firstPoint = data[i];
  33566. i++;
  33567. }
  33568. return firstPoint;
  33569. };
  33570. /**
  33571. * Translate data points from raw data values to chart specific
  33572. * positioning data needed later in the `drawPoints` and `drawGraph`
  33573. * functions. This function can be overridden in plugins and custom
  33574. * series type implementations.
  33575. *
  33576. * @function Highcharts.Series#translate
  33577. *
  33578. * @fires Highcharts.Series#events:translate
  33579. */
  33580. Series.prototype.translate = function () {
  33581. if (!this.processedXData) { // hidden series
  33582. this.processData();
  33583. }
  33584. this.generatePoints();
  33585. var series = this,
  33586. options = series.options,
  33587. stacking = options.stacking,
  33588. xAxis = series.xAxis,
  33589. categories = xAxis.categories,
  33590. enabledDataSorting = series.enabledDataSorting,
  33591. yAxis = series.yAxis,
  33592. points = series.points,
  33593. dataLength = points.length,
  33594. hasModifyValue = !!series.modifyValue,
  33595. i,
  33596. pointPlacement = series.pointPlacementToXValue(), // #7860
  33597. dynamicallyPlaced = Boolean(pointPlacement),
  33598. threshold = options.threshold,
  33599. stackThreshold = options.startFromThreshold ? threshold : 0,
  33600. plotX,
  33601. lastPlotX,
  33602. stackIndicator,
  33603. zoneAxis = this.zoneAxis || 'y',
  33604. closestPointRangePx = Number.MAX_VALUE;
  33605. /**
  33606. * Plotted coordinates need to be within a limited range. Drawing
  33607. * too far outside the viewport causes various rendering issues
  33608. * (#3201, #3923, #7555).
  33609. * @private
  33610. */
  33611. function limitedRange(val) {
  33612. return clamp(val, -1e5, 1e5);
  33613. }
  33614. // Translate each point
  33615. for (i = 0; i < dataLength; i++) {
  33616. var point = points[i],
  33617. xValue = point.x,
  33618. yValue = point.y,
  33619. yBottom = point.low,
  33620. stack = stacking && yAxis.stacking && yAxis.stacking.stacks[(series.negStacks &&
  33621. yValue <
  33622. (stackThreshold ? 0 : threshold) ?
  33623. '-' :
  33624. '') + series.stackKey],
  33625. pointStack,
  33626. stackValues;
  33627. if (yAxis.positiveValuesOnly && !yAxis.validatePositiveValue(yValue) ||
  33628. xAxis.positiveValuesOnly && !xAxis.validatePositiveValue(xValue)) {
  33629. point.isNull = true;
  33630. }
  33631. // Get the plotX translation
  33632. point.plotX = plotX = correctFloat(// #5236
  33633. limitedRange(xAxis.translate(// #3923
  33634. xValue, 0, 0, 0, 1, pointPlacement, this.type === 'flags')) // #3923
  33635. );
  33636. // Calculate the bottom y value for stacked series
  33637. if (stacking &&
  33638. series.visible &&
  33639. stack &&
  33640. stack[xValue]) {
  33641. stackIndicator = series.getStackIndicator(stackIndicator, xValue, series.index);
  33642. if (!point.isNull) {
  33643. pointStack = stack[xValue];
  33644. stackValues =
  33645. pointStack.points[stackIndicator.key];
  33646. }
  33647. }
  33648. if (isArray(stackValues)) {
  33649. yBottom = stackValues[0];
  33650. yValue = stackValues[1];
  33651. if (yBottom === stackThreshold &&
  33652. stackIndicator.key ===
  33653. stack[xValue].base) {
  33654. yBottom = pick((isNumber(threshold) && threshold), yAxis.min);
  33655. }
  33656. // #1200, #1232
  33657. if (yAxis.positiveValuesOnly && yBottom <= 0) {
  33658. yBottom = null;
  33659. }
  33660. point.total = point.stackTotal = pointStack.total;
  33661. point.percentage =
  33662. pointStack.total &&
  33663. (point.y / pointStack.total * 100);
  33664. point.stackY = yValue;
  33665. // Place the stack label
  33666. // in case of variwide series (where widths of points are
  33667. // different in most cases), stack labels are positioned
  33668. // wrongly, so the call of the setOffset is omited here and
  33669. // labels are correctly positioned later, at the end of the
  33670. // variwide's translate function (#10962)
  33671. if (!series.irregularWidths) {
  33672. pointStack.setOffset(series.pointXOffset || 0, series.barW || 0);
  33673. }
  33674. }
  33675. // Set translated yBottom or remove it
  33676. point.yBottom = defined(yBottom) ?
  33677. limitedRange(yAxis.translate(yBottom, 0, 1, 0, 1)) :
  33678. null;
  33679. // general hook, used for Highstock compare mode
  33680. if (hasModifyValue) {
  33681. yValue = series.modifyValue(yValue, point);
  33682. }
  33683. // Set the the plotY value, reset it for redraws
  33684. // #3201
  33685. point.plotY = void 0;
  33686. if (isNumber(yValue)) {
  33687. var translated = yAxis.translate(yValue,
  33688. false,
  33689. true,
  33690. false,
  33691. true);
  33692. if (typeof translated !== 'undefined') {
  33693. point.plotY = limitedRange(translated);
  33694. }
  33695. }
  33696. point.isInside = this.isPointInside(point);
  33697. // Set client related positions for mouse tracking
  33698. point.clientX = dynamicallyPlaced ?
  33699. correctFloat(xAxis.translate(xValue, 0, 0, 0, 1, pointPlacement)) :
  33700. plotX; // #1514, #5383, #5518
  33701. // Negative points. For bubble charts, this means negative z
  33702. // values (#9728)
  33703. point.negative = point[zoneAxis] < (options[zoneAxis + 'Threshold'] ||
  33704. threshold ||
  33705. 0);
  33706. // some API data
  33707. point.category = (categories &&
  33708. typeof categories[point.x] !== 'undefined' ?
  33709. categories[point.x] :
  33710. point.x);
  33711. // Determine auto enabling of markers (#3635, #5099)
  33712. if (!point.isNull && point.visible !== false) {
  33713. if (typeof lastPlotX !== 'undefined') {
  33714. closestPointRangePx = Math.min(closestPointRangePx, Math.abs(plotX - lastPlotX));
  33715. }
  33716. lastPlotX = plotX;
  33717. }
  33718. // Find point zone
  33719. point.zone = (this.zones.length && point.getZone());
  33720. // Animate new points with data sorting
  33721. if (!point.graphic && series.group && enabledDataSorting) {
  33722. point.isNew = true;
  33723. }
  33724. }
  33725. series.closestPointRangePx = closestPointRangePx;
  33726. fireEvent(this, 'afterTranslate');
  33727. };
  33728. /**
  33729. * Return the series points with null points filtered out.
  33730. *
  33731. * @function Highcharts.Series#getValidPoints
  33732. *
  33733. * @param {Array<Highcharts.Point>} [points]
  33734. * The points to inspect, defaults to {@link Series.points}.
  33735. *
  33736. * @param {boolean} [insideOnly=false]
  33737. * Whether to inspect only the points that are inside the visible view.
  33738. *
  33739. * @param {boolean} [allowNull=false]
  33740. * Whether to allow null points to pass as valid points.
  33741. *
  33742. * @return {Array<Highcharts.Point>}
  33743. * The valid points.
  33744. */
  33745. Series.prototype.getValidPoints = function (points, insideOnly, allowNull) {
  33746. var chart = this.chart;
  33747. // #3916, #5029, #5085
  33748. return (points || this.points || []).filter(function (point) {
  33749. if (insideOnly && !chart.isInsidePlot(point.plotX, point.plotY, chart.inverted)) {
  33750. return false;
  33751. }
  33752. return point.visible !== false &&
  33753. (allowNull || !point.isNull);
  33754. });
  33755. };
  33756. /**
  33757. * Get the clipping for the series. Could be called for a series to
  33758. * initiate animating the clip or to set the final clip (only width
  33759. * and x).
  33760. *
  33761. * @private
  33762. * @function Highcharts.Series#getClip
  33763. *
  33764. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
  33765. * Initialize the animation.
  33766. *
  33767. * @param {boolean} [finalBox]
  33768. * Final size for the clip - end state for the animation.
  33769. *
  33770. * @return {Highcharts.Dictionary<number>}
  33771. */
  33772. Series.prototype.getClipBox = function (animation, finalBox) {
  33773. var series = this,
  33774. options = series.options,
  33775. chart = series.chart,
  33776. inverted = chart.inverted,
  33777. xAxis = series.xAxis,
  33778. yAxis = xAxis && series.yAxis,
  33779. clipBox,
  33780. scrollablePlotAreaOptions = chart.options.chart.scrollablePlotArea || {};
  33781. if (animation && options.clip === false && yAxis) {
  33782. // support for not clipped series animation (#10450)
  33783. clipBox = inverted ? {
  33784. y: -chart.chartWidth + yAxis.len + yAxis.pos,
  33785. height: chart.chartWidth,
  33786. width: chart.chartHeight,
  33787. x: -chart.chartHeight + xAxis.len + xAxis.pos
  33788. } : {
  33789. y: -yAxis.pos,
  33790. height: chart.chartHeight,
  33791. width: chart.chartWidth,
  33792. x: -xAxis.pos
  33793. };
  33794. // x and width will be changed later when setting for animation
  33795. // initial state in Series.setClip
  33796. }
  33797. else {
  33798. clipBox = series.clipBox || chart.clipBox;
  33799. if (finalBox) {
  33800. clipBox.width = chart.plotSizeX;
  33801. clipBox.x = (chart.scrollablePixelsX || 0) *
  33802. (scrollablePlotAreaOptions.scrollPositionX || 0);
  33803. }
  33804. }
  33805. return !finalBox ? clipBox : {
  33806. width: clipBox.width,
  33807. x: clipBox.x
  33808. };
  33809. };
  33810. /**
  33811. * Set the clipping for the series. For animated series it is called
  33812. * twice, first to initiate animating the clip then the second time
  33813. * without the animation to set the final clip.
  33814. *
  33815. * @private
  33816. * @function Highcharts.Series#setClip
  33817. */
  33818. Series.prototype.setClip = function (animation) {
  33819. var chart = this.chart, options = this.options, renderer = chart.renderer, inverted = chart.inverted, seriesClipBox = this.clipBox, clipBox = this.getClipBox(animation), sharedClipKey = this.sharedClipKey ||
  33820. [
  33821. '_sharedClip',
  33822. animation && animation.duration,
  33823. animation && animation.easing,
  33824. animation && animation.defer,
  33825. clipBox.height,
  33826. options.xAxis,
  33827. options.yAxis
  33828. ].join(','), // #4526
  33829. clipRect = chart[sharedClipKey], markerClipRect = chart[sharedClipKey + 'm'];
  33830. if (animation) {
  33831. clipBox.width = 0;
  33832. if (inverted) {
  33833. clipBox.x = chart.plotHeight +
  33834. (options.clip !== false ? 0 : chart.plotTop);
  33835. }
  33836. }
  33837. // If a clipping rectangle with the same properties is currently
  33838. // present in the chart, use that.
  33839. if (!clipRect) {
  33840. // When animation is set, prepare the initial positions
  33841. if (animation) {
  33842. chart[sharedClipKey + 'm'] = markerClipRect =
  33843. renderer.clipRect(
  33844. // include the width of the first marker
  33845. inverted ? chart.plotSizeX + 99 : -99, inverted ? -chart.plotLeft : -chart.plotTop, 99, inverted ? chart.chartWidth : chart.chartHeight);
  33846. }
  33847. chart[sharedClipKey] = clipRect = renderer.clipRect(clipBox);
  33848. // Create hashmap for series indexes
  33849. clipRect.count = { length: 0 };
  33850. // When the series is rendered again before starting animating, in
  33851. // compliance to a responsive rule
  33852. }
  33853. else if (!chart.hasLoaded) {
  33854. clipRect.attr(clipBox);
  33855. }
  33856. if (animation) {
  33857. if (!clipRect.count[this.index]) {
  33858. clipRect.count[this.index] = true;
  33859. clipRect.count.length += 1;
  33860. }
  33861. }
  33862. if (options.clip !== false || animation) {
  33863. this.group.clip(animation || seriesClipBox ? clipRect : chart.clipRect);
  33864. this.markerGroup.clip(markerClipRect);
  33865. this.sharedClipKey = sharedClipKey;
  33866. }
  33867. // Remove the shared clipping rectangle when all series are shown
  33868. if (!animation) {
  33869. if (clipRect.count[this.index]) {
  33870. delete clipRect.count[this.index];
  33871. clipRect.count.length -= 1;
  33872. }
  33873. if (clipRect.count.length === 0 &&
  33874. sharedClipKey &&
  33875. chart[sharedClipKey]) {
  33876. if (!seriesClipBox) {
  33877. chart[sharedClipKey] =
  33878. chart[sharedClipKey].destroy();
  33879. }
  33880. if (chart[sharedClipKey + 'm']) {
  33881. chart[sharedClipKey + 'm'] =
  33882. chart[sharedClipKey + 'm'].destroy();
  33883. }
  33884. }
  33885. }
  33886. };
  33887. /**
  33888. * Animate in the series. Called internally twice. First with the `init`
  33889. * parameter set to true, which sets up the initial state of the
  33890. * animation. Then when ready, it is called with the `init` parameter
  33891. * undefined, in order to perform the actual animation. After the
  33892. * second run, the function is removed.
  33893. *
  33894. * @function Highcharts.Series#animate
  33895. *
  33896. * @param {boolean} [init]
  33897. * Initialize the animation.
  33898. */
  33899. Series.prototype.animate = function (init) {
  33900. var series = this,
  33901. chart = series.chart,
  33902. animation = animObject(series.options.animation),
  33903. clipRect,
  33904. sharedClipKey,
  33905. finalBox;
  33906. // Initialize the animation. Set up the clipping rectangle.
  33907. if (init) {
  33908. series.setClip(animation);
  33909. // Run the animation
  33910. }
  33911. else {
  33912. sharedClipKey = this.sharedClipKey;
  33913. clipRect = chart[sharedClipKey];
  33914. finalBox = series.getClipBox(animation, true);
  33915. if (clipRect) {
  33916. clipRect.animate(finalBox, animation);
  33917. }
  33918. if (chart[sharedClipKey + 'm']) {
  33919. chart[sharedClipKey + 'm'].animate({
  33920. width: finalBox.width + 99,
  33921. x: finalBox.x - (chart.inverted ? 0 : 99)
  33922. }, animation);
  33923. }
  33924. }
  33925. };
  33926. /**
  33927. * This runs after animation to land on the final plot clipping.
  33928. *
  33929. * @private
  33930. * @function Highcharts.Series#afterAnimate
  33931. *
  33932. * @fires Highcharts.Series#event:afterAnimate
  33933. */
  33934. Series.prototype.afterAnimate = function () {
  33935. this.setClip();
  33936. fireEvent(this, 'afterAnimate');
  33937. this.finishedAnimating = true;
  33938. };
  33939. /**
  33940. * Draw the markers for line-like series types, and columns or other
  33941. * graphical representation for {@link Point} objects for other series
  33942. * types. The resulting element is typically stored as
  33943. * {@link Point.graphic}, and is created on the first call and updated
  33944. * and moved on subsequent calls.
  33945. *
  33946. * @function Highcharts.Series#drawPoints
  33947. */
  33948. Series.prototype.drawPoints = function () {
  33949. var series = this,
  33950. points = series.points,
  33951. chart = series.chart,
  33952. i,
  33953. point,
  33954. graphic,
  33955. verb,
  33956. options = series.options,
  33957. seriesMarkerOptions = options.marker,
  33958. pointMarkerOptions,
  33959. hasPointMarker,
  33960. markerGroup = (series[series.specialGroup] ||
  33961. series.markerGroup),
  33962. xAxis = series.xAxis,
  33963. markerAttribs,
  33964. globallyEnabled = pick(seriesMarkerOptions.enabled, !xAxis || xAxis.isRadial ? true : null,
  33965. // Use larger or equal as radius is null in bubbles (#6321)
  33966. series.closestPointRangePx >= (seriesMarkerOptions.enabledThreshold *
  33967. seriesMarkerOptions.radius));
  33968. if (seriesMarkerOptions.enabled !== false ||
  33969. series._hasPointMarkers) {
  33970. for (i = 0; i < points.length; i++) {
  33971. point = points[i];
  33972. graphic = point.graphic;
  33973. verb = graphic ? 'animate' : 'attr';
  33974. pointMarkerOptions = point.marker || {};
  33975. hasPointMarker = !!point.marker;
  33976. var shouldDrawMarker = ((globallyEnabled &&
  33977. typeof pointMarkerOptions.enabled === 'undefined') || pointMarkerOptions.enabled) && !point.isNull && point.visible !== false;
  33978. // only draw the point if y is defined
  33979. if (shouldDrawMarker) {
  33980. // Shortcuts
  33981. var symbol = pick(pointMarkerOptions.symbol,
  33982. series.symbol);
  33983. markerAttribs = series.markerAttribs(point, (point.selected && 'select'));
  33984. // Set starting position for point sliding animation.
  33985. if (series.enabledDataSorting) {
  33986. point.startXPos = xAxis.reversed ?
  33987. -markerAttribs.width :
  33988. xAxis.width;
  33989. }
  33990. var isInside = point.isInside !== false;
  33991. if (graphic) { // update
  33992. // Since the marker group isn't clipped, each
  33993. // individual marker must be toggled
  33994. graphic[isInside ? 'show' : 'hide'](isInside)
  33995. .animate(markerAttribs);
  33996. }
  33997. else if (isInside &&
  33998. (markerAttribs.width > 0 || point.hasImage)) {
  33999. /**
  34000. * The graphic representation of the point.
  34001. * Typically this is a simple shape, like a `rect`
  34002. * for column charts or `path` for line markers, but
  34003. * for some complex series types like boxplot or 3D
  34004. * charts, the graphic may be a `g` element
  34005. * containing other shapes. The graphic is generated
  34006. * the first time {@link Series#drawPoints} runs,
  34007. * and updated and moved on subsequent runs.
  34008. *
  34009. * @name Point#graphic
  34010. * @type {SVGElement}
  34011. */
  34012. point.graphic = graphic = chart.renderer
  34013. .symbol(symbol, markerAttribs.x, markerAttribs.y, markerAttribs.width, markerAttribs.height, hasPointMarker ?
  34014. pointMarkerOptions :
  34015. seriesMarkerOptions)
  34016. .add(markerGroup);
  34017. // Sliding animation for new points
  34018. if (series.enabledDataSorting &&
  34019. chart.hasRendered) {
  34020. graphic.attr({
  34021. x: point.startXPos
  34022. });
  34023. verb = 'animate';
  34024. }
  34025. }
  34026. if (graphic && verb === 'animate') { // update
  34027. // Since the marker group isn't clipped, each
  34028. // individual marker must be toggled
  34029. graphic[isInside ? 'show' : 'hide'](isInside)
  34030. .animate(markerAttribs);
  34031. }
  34032. // Presentational attributes
  34033. if (graphic && !chart.styledMode) {
  34034. graphic[verb](series.pointAttribs(point, (point.selected && 'select')));
  34035. }
  34036. if (graphic) {
  34037. graphic.addClass(point.getClassName(), true);
  34038. }
  34039. }
  34040. else if (graphic) {
  34041. point.graphic = graphic.destroy(); // #1269
  34042. }
  34043. }
  34044. }
  34045. };
  34046. /**
  34047. * Get non-presentational attributes for a point. Used internally for
  34048. * both styled mode and classic. Can be overridden for different series
  34049. * types.
  34050. *
  34051. * @see Series#pointAttribs
  34052. *
  34053. * @function Highcharts.Series#markerAttribs
  34054. *
  34055. * @param {Highcharts.Point} point
  34056. * The Point to inspect.
  34057. *
  34058. * @param {string} [state]
  34059. * The state, can be either `hover`, `select` or undefined.
  34060. *
  34061. * @return {Highcharts.SVGAttributes}
  34062. * A hash containing those attributes that are not settable from CSS.
  34063. */
  34064. Series.prototype.markerAttribs = function (point, state) {
  34065. var seriesOptions = this.options,
  34066. seriesMarkerOptions = seriesOptions.marker,
  34067. seriesStateOptions,
  34068. pointMarkerOptions = point.marker || {},
  34069. symbol = (pointMarkerOptions.symbol ||
  34070. seriesMarkerOptions.symbol),
  34071. pointStateOptions,
  34072. radius = pick(pointMarkerOptions.radius,
  34073. seriesMarkerOptions.radius),
  34074. attribs;
  34075. // Handle hover and select states
  34076. if (state) {
  34077. seriesStateOptions = seriesMarkerOptions.states[state];
  34078. pointStateOptions = pointMarkerOptions.states &&
  34079. pointMarkerOptions.states[state];
  34080. radius = pick(pointStateOptions && pointStateOptions.radius, seriesStateOptions && seriesStateOptions.radius, radius + (seriesStateOptions && seriesStateOptions.radiusPlus ||
  34081. 0));
  34082. }
  34083. point.hasImage = symbol && symbol.indexOf('url') === 0;
  34084. if (point.hasImage) {
  34085. radius = 0; // and subsequently width and height is not set
  34086. }
  34087. attribs = {
  34088. // Math.floor for #1843:
  34089. x: seriesOptions.crisp ?
  34090. Math.floor(point.plotX) - radius :
  34091. point.plotX - radius,
  34092. y: point.plotY - radius
  34093. };
  34094. if (radius) {
  34095. attribs.width = attribs.height = 2 * radius;
  34096. }
  34097. return attribs;
  34098. };
  34099. /**
  34100. * Internal function to get presentational attributes for each point.
  34101. * Unlike {@link Series#markerAttribs}, this function should return
  34102. * those attributes that can also be set in CSS. In styled mode,
  34103. * `pointAttribs` won't be called.
  34104. *
  34105. * @private
  34106. * @function Highcharts.Series#pointAttribs
  34107. *
  34108. * @param {Highcharts.Point} [point]
  34109. * The point instance to inspect.
  34110. *
  34111. * @param {string} [state]
  34112. * The point state, can be either `hover`, `select` or 'normal'. If
  34113. * undefined, normal state is assumed.
  34114. *
  34115. * @return {Highcharts.SVGAttributes}
  34116. * The presentational attributes to be set on the point.
  34117. */
  34118. Series.prototype.pointAttribs = function (point, state) {
  34119. var seriesMarkerOptions = this.options.marker,
  34120. seriesStateOptions,
  34121. pointOptions = point && point.options,
  34122. pointMarkerOptions = ((pointOptions && pointOptions.marker) || {}),
  34123. pointStateOptions,
  34124. color = this.color,
  34125. pointColorOption = pointOptions && pointOptions.color,
  34126. pointColor = point && point.color,
  34127. strokeWidth = pick(pointMarkerOptions.lineWidth,
  34128. seriesMarkerOptions.lineWidth),
  34129. zoneColor = point && point.zone && point.zone.color,
  34130. fill,
  34131. stroke,
  34132. opacity = 1;
  34133. color = (pointColorOption ||
  34134. zoneColor ||
  34135. pointColor ||
  34136. color);
  34137. fill = (pointMarkerOptions.fillColor ||
  34138. seriesMarkerOptions.fillColor ||
  34139. color);
  34140. stroke = (pointMarkerOptions.lineColor ||
  34141. seriesMarkerOptions.lineColor ||
  34142. color);
  34143. // Handle hover and select states
  34144. state = state || 'normal';
  34145. if (state) {
  34146. seriesStateOptions = seriesMarkerOptions.states[state];
  34147. pointStateOptions = (pointMarkerOptions.states &&
  34148. pointMarkerOptions.states[state]) || {};
  34149. strokeWidth = pick(pointStateOptions.lineWidth, seriesStateOptions.lineWidth, strokeWidth + pick(pointStateOptions.lineWidthPlus, seriesStateOptions.lineWidthPlus, 0));
  34150. fill = (pointStateOptions.fillColor ||
  34151. seriesStateOptions.fillColor ||
  34152. fill);
  34153. stroke = (pointStateOptions.lineColor ||
  34154. seriesStateOptions.lineColor ||
  34155. stroke);
  34156. opacity = pick(pointStateOptions.opacity, seriesStateOptions.opacity, opacity);
  34157. }
  34158. return {
  34159. 'stroke': stroke,
  34160. 'stroke-width': strokeWidth,
  34161. 'fill': fill,
  34162. 'opacity': opacity
  34163. };
  34164. };
  34165. /**
  34166. * Clear DOM objects and free up memory.
  34167. *
  34168. * @private
  34169. * @function Highcharts.Series#destroy
  34170. *
  34171. * @fires Highcharts.Series#event:destroy
  34172. */
  34173. Series.prototype.destroy = function (keepEventsForUpdate) {
  34174. var series = this,
  34175. chart = series.chart,
  34176. issue134 = /AppleWebKit\/533/.test(win.navigator.userAgent),
  34177. destroy,
  34178. i,
  34179. data = series.data || [],
  34180. point,
  34181. axis;
  34182. // add event hook
  34183. fireEvent(series, 'destroy');
  34184. // remove events
  34185. this.removeEvents(keepEventsForUpdate);
  34186. // erase from axes
  34187. (series.axisTypes || []).forEach(function (AXIS) {
  34188. axis = series[AXIS];
  34189. if (axis && axis.series) {
  34190. erase(axis.series, series);
  34191. axis.isDirty = axis.forceRedraw = true;
  34192. }
  34193. });
  34194. // remove legend items
  34195. if (series.legendItem) {
  34196. series.chart.legend.destroyItem(series);
  34197. }
  34198. // destroy all points with their elements
  34199. i = data.length;
  34200. while (i--) {
  34201. point = data[i];
  34202. if (point && point.destroy) {
  34203. point.destroy();
  34204. }
  34205. }
  34206. series.points = null;
  34207. // Clear the animation timeout if we are destroying the series
  34208. // during initial animation
  34209. U.clearTimeout(series.animationTimeout);
  34210. // Destroy all SVGElements associated to the series
  34211. objectEach(series, function (val, prop) {
  34212. // Survive provides a hook for not destroying
  34213. if (val instanceof SVGElement && !val.survive) {
  34214. // issue 134 workaround
  34215. destroy = issue134 && prop === 'group' ?
  34216. 'hide' :
  34217. 'destroy';
  34218. val[destroy]();
  34219. }
  34220. });
  34221. // remove from hoverSeries
  34222. if (chart.hoverSeries === series) {
  34223. chart.hoverSeries = null;
  34224. }
  34225. erase(chart.series, series);
  34226. chart.orderSeries();
  34227. // clear all members
  34228. objectEach(series, function (val, prop) {
  34229. if (!keepEventsForUpdate || prop !== 'hcEvents') {
  34230. delete series[prop];
  34231. }
  34232. });
  34233. };
  34234. /**
  34235. * Clip the graphs into zones for colors and styling.
  34236. *
  34237. * @private
  34238. * @function Highcharts.Series#applyZones
  34239. */
  34240. Series.prototype.applyZones = function () {
  34241. var series = this,
  34242. chart = this.chart,
  34243. renderer = chart.renderer,
  34244. zones = this.zones,
  34245. translatedFrom,
  34246. translatedTo,
  34247. clips = (this.clips || []),
  34248. clipAttr,
  34249. graph = this.graph,
  34250. area = this.area,
  34251. chartSizeMax = Math.max(chart.chartWidth,
  34252. chart.chartHeight),
  34253. axis = this[(this.zoneAxis || 'y') + 'Axis'],
  34254. extremes,
  34255. reversed,
  34256. inverted = chart.inverted,
  34257. horiz,
  34258. pxRange,
  34259. pxPosMin,
  34260. pxPosMax,
  34261. ignoreZones = false,
  34262. zoneArea,
  34263. zoneGraph;
  34264. if (zones.length &&
  34265. (graph || area) &&
  34266. axis &&
  34267. typeof axis.min !== 'undefined') {
  34268. reversed = axis.reversed;
  34269. horiz = axis.horiz;
  34270. // The use of the Color Threshold assumes there are no gaps
  34271. // so it is safe to hide the original graph and area
  34272. // unless it is not waterfall series, then use showLine property
  34273. // to set lines between columns to be visible (#7862)
  34274. if (graph && !this.showLine) {
  34275. graph.hide();
  34276. }
  34277. if (area) {
  34278. area.hide();
  34279. }
  34280. // Create the clips
  34281. extremes = axis.getExtremes();
  34282. zones.forEach(function (threshold, i) {
  34283. translatedFrom = reversed ?
  34284. (horiz ? chart.plotWidth : 0) :
  34285. (horiz ? 0 : (axis.toPixels(extremes.min) || 0));
  34286. translatedFrom = clamp(pick(translatedTo, translatedFrom), 0, chartSizeMax);
  34287. translatedTo = clamp(Math.round(axis.toPixels(pick(threshold.value, extremes.max), true) || 0), 0, chartSizeMax);
  34288. if (ignoreZones) {
  34289. translatedFrom = translatedTo =
  34290. axis.toPixels(extremes.max);
  34291. }
  34292. pxRange = Math.abs(translatedFrom - translatedTo);
  34293. pxPosMin = Math.min(translatedFrom, translatedTo);
  34294. pxPosMax = Math.max(translatedFrom, translatedTo);
  34295. if (axis.isXAxis) {
  34296. clipAttr = {
  34297. x: inverted ? pxPosMax : pxPosMin,
  34298. y: 0,
  34299. width: pxRange,
  34300. height: chartSizeMax
  34301. };
  34302. if (!horiz) {
  34303. clipAttr.x = chart.plotHeight - clipAttr.x;
  34304. }
  34305. }
  34306. else {
  34307. clipAttr = {
  34308. x: 0,
  34309. y: inverted ? pxPosMax : pxPosMin,
  34310. width: chartSizeMax,
  34311. height: pxRange
  34312. };
  34313. if (horiz) {
  34314. clipAttr.y = chart.plotWidth - clipAttr.y;
  34315. }
  34316. }
  34317. // VML SUPPPORT
  34318. if (inverted && renderer.isVML) {
  34319. if (axis.isXAxis) {
  34320. clipAttr = {
  34321. x: 0,
  34322. y: reversed ? pxPosMin : pxPosMax,
  34323. height: clipAttr.width,
  34324. width: chart.chartWidth
  34325. };
  34326. }
  34327. else {
  34328. clipAttr = {
  34329. x: (clipAttr.y -
  34330. chart.plotLeft -
  34331. chart.spacingBox.x),
  34332. y: 0,
  34333. width: clipAttr.height,
  34334. height: chart.chartHeight
  34335. };
  34336. }
  34337. }
  34338. // END OF VML SUPPORT
  34339. if (clips[i]) {
  34340. clips[i].animate(clipAttr);
  34341. }
  34342. else {
  34343. clips[i] = renderer.clipRect(clipAttr);
  34344. }
  34345. // when no data, graph zone is not applied and after setData
  34346. // clip was ignored. As a result, it should be applied each
  34347. // time.
  34348. zoneArea = series['zone-area-' + i];
  34349. zoneGraph = series['zone-graph-' + i];
  34350. if (graph && zoneGraph) {
  34351. zoneGraph.clip(clips[i]);
  34352. }
  34353. if (area && zoneArea) {
  34354. zoneArea.clip(clips[i]);
  34355. }
  34356. // if this zone extends out of the axis, ignore the others
  34357. ignoreZones = threshold.value > extremes.max;
  34358. // Clear translatedTo for indicators
  34359. if (series.resetZones && translatedTo === 0) {
  34360. translatedTo = void 0;
  34361. }
  34362. });
  34363. this.clips = clips;
  34364. }
  34365. else if (series.visible) {
  34366. // If zones were removed, restore graph and area
  34367. if (graph) {
  34368. graph.show(true);
  34369. }
  34370. if (area) {
  34371. area.show(true);
  34372. }
  34373. }
  34374. };
  34375. /**
  34376. * Initialize and perform group inversion on series.group and
  34377. * series.markerGroup.
  34378. *
  34379. * @private
  34380. * @function Highcharts.Series#invertGroups
  34381. */
  34382. Series.prototype.invertGroups = function (inverted) {
  34383. var series = this,
  34384. chart = series.chart;
  34385. /**
  34386. * @private
  34387. */
  34388. function setInvert() {
  34389. ['group', 'markerGroup'].forEach(function (groupName) {
  34390. if (series[groupName]) {
  34391. // VML/HTML needs explicit attributes for flipping
  34392. if (chart.renderer.isVML) {
  34393. series[groupName].attr({
  34394. width: series.yAxis.len,
  34395. height: series.xAxis.len
  34396. });
  34397. }
  34398. series[groupName].width = series.yAxis.len;
  34399. series[groupName].height = series.xAxis.len;
  34400. // If inverted polar, don't invert series group
  34401. series[groupName].invert(series.isRadialSeries ? false : inverted);
  34402. }
  34403. });
  34404. }
  34405. // Pie, go away (#1736)
  34406. if (!series.xAxis) {
  34407. return;
  34408. }
  34409. // A fixed size is needed for inversion to work
  34410. series.eventsToUnbind.push(addEvent(chart, 'resize', setInvert));
  34411. // Do it now
  34412. setInvert();
  34413. // On subsequent render and redraw, just do setInvert without
  34414. // setting up events again
  34415. series.invertGroups = setInvert;
  34416. };
  34417. /**
  34418. * General abstraction for creating plot groups like series.group,
  34419. * series.dataLabelsGroup and series.markerGroup. On subsequent calls,
  34420. * the group will only be adjusted to the updated plot size.
  34421. *
  34422. * @private
  34423. * @function Highcharts.Series#plotGroup
  34424. */
  34425. Series.prototype.plotGroup = function (prop, name, visibility, zIndex, parent) {
  34426. var group = this[prop],
  34427. isNew = !group,
  34428. attrs = {
  34429. visibility: visibility,
  34430. zIndex: zIndex || 0.1 // IE8 and pointer logic use this
  34431. };
  34432. // Avoid setting undefined opacity, or in styled mode
  34433. if (typeof this.opacity !== 'undefined' &&
  34434. !this.chart.styledMode && this.state !== 'inactive' // #13719
  34435. ) {
  34436. attrs.opacity = this.opacity;
  34437. }
  34438. // Generate it on first call
  34439. if (isNew) {
  34440. this[prop] = group = this.chart.renderer
  34441. .g()
  34442. .add(parent);
  34443. }
  34444. // Add the class names, and replace existing ones as response to
  34445. // Series.update (#6660)
  34446. group.addClass(('highcharts-' + name +
  34447. ' highcharts-series-' + this.index +
  34448. ' highcharts-' + this.type + '-series ' +
  34449. (defined(this.colorIndex) ?
  34450. 'highcharts-color-' + this.colorIndex + ' ' :
  34451. '') +
  34452. (this.options.className || '') +
  34453. (group.hasClass('highcharts-tracker') ?
  34454. ' highcharts-tracker' :
  34455. '')), true);
  34456. // Place it on first and subsequent (redraw) calls
  34457. group.attr(attrs)[isNew ? 'attr' : 'animate'](this.getPlotBox());
  34458. return group;
  34459. };
  34460. /**
  34461. * Get the translation and scale for the plot area of this series.
  34462. *
  34463. * @function Highcharts.Series#getPlotBox
  34464. *
  34465. * @return {Highcharts.SeriesPlotBoxObject}
  34466. */
  34467. Series.prototype.getPlotBox = function () {
  34468. var chart = this.chart,
  34469. xAxis = this.xAxis,
  34470. yAxis = this.yAxis;
  34471. // Swap axes for inverted (#2339)
  34472. if (chart.inverted) {
  34473. xAxis = yAxis;
  34474. yAxis = this.xAxis;
  34475. }
  34476. return {
  34477. translateX: xAxis ? xAxis.left : chart.plotLeft,
  34478. translateY: yAxis ? yAxis.top : chart.plotTop,
  34479. scaleX: 1,
  34480. scaleY: 1
  34481. };
  34482. };
  34483. /**
  34484. * Removes the event handlers attached previously with addEvents.
  34485. * @private
  34486. * @function Highcharts.Series#removeEvents
  34487. */
  34488. Series.prototype.removeEvents = function (keepEventsForUpdate) {
  34489. var series = this;
  34490. if (!keepEventsForUpdate) {
  34491. // remove all events
  34492. removeEvent(series);
  34493. }
  34494. if (series.eventsToUnbind.length) {
  34495. // remove only internal events for proper update
  34496. // #12355 - solves problem with multiple destroy events
  34497. series.eventsToUnbind.forEach(function (unbind) {
  34498. unbind();
  34499. });
  34500. series.eventsToUnbind.length = 0;
  34501. }
  34502. };
  34503. /**
  34504. * Render the graph and markers. Called internally when first rendering
  34505. * and later when redrawing the chart. This function can be extended in
  34506. * plugins, but normally shouldn't be called directly.
  34507. *
  34508. * @function Highcharts.Series#render
  34509. *
  34510. * @fires Highcharts.Series#event:afterRender
  34511. */
  34512. Series.prototype.render = function () {
  34513. var series = this,
  34514. chart = series.chart,
  34515. group,
  34516. options = series.options,
  34517. animOptions = animObject(options.animation),
  34518. // Animation doesn't work in IE8 quirks when the group div is
  34519. // hidden, and looks bad in other oldIE
  34520. animDuration = (!series.finishedAnimating &&
  34521. chart.renderer.isSVG &&
  34522. animOptions.duration),
  34523. visibility = series.visible ? 'inherit' : 'hidden', // #2597
  34524. zIndex = options.zIndex,
  34525. hasRendered = series.hasRendered,
  34526. chartSeriesGroup = chart.seriesGroup,
  34527. inverted = chart.inverted;
  34528. fireEvent(this, 'render');
  34529. // the group
  34530. group = series.plotGroup('group', 'series', visibility, zIndex, chartSeriesGroup);
  34531. series.markerGroup = series.plotGroup('markerGroup', 'markers', visibility, zIndex, chartSeriesGroup);
  34532. // initiate the animation
  34533. if (animDuration && series.animate) {
  34534. series.animate(true);
  34535. }
  34536. // SVGRenderer needs to know this before drawing elements (#1089,
  34537. // #1795)
  34538. group.inverted = pick(series.invertible, series.isCartesian) ?
  34539. inverted : false;
  34540. // Draw the graph if any
  34541. if (series.drawGraph) {
  34542. series.drawGraph();
  34543. series.applyZones();
  34544. }
  34545. // Draw the points
  34546. if (series.visible) {
  34547. series.drawPoints();
  34548. }
  34549. /* series.points.forEach(function (point) {
  34550. if (point.redraw) {
  34551. point.redraw();
  34552. }
  34553. }); */
  34554. // Draw the data labels
  34555. if (series.drawDataLabels) {
  34556. series.drawDataLabels();
  34557. }
  34558. // In pie charts, slices are added to the DOM, but actual rendering
  34559. // is postponed until labels reserved their space
  34560. if (series.redrawPoints) {
  34561. series.redrawPoints();
  34562. }
  34563. // draw the mouse tracking area
  34564. if (series.drawTracker &&
  34565. series.options.enableMouseTracking !== false) {
  34566. series.drawTracker();
  34567. }
  34568. // Handle inverted series and tracker groups
  34569. series.invertGroups(inverted);
  34570. // Initial clipping, must be defined after inverting groups for VML.
  34571. // Applies to columns etc. (#3839).
  34572. if (options.clip !== false &&
  34573. !series.sharedClipKey &&
  34574. !hasRendered) {
  34575. group.clip(chart.clipRect);
  34576. }
  34577. // Run the animation
  34578. if (animDuration && series.animate) {
  34579. series.animate();
  34580. }
  34581. // Call the afterAnimate function on animation complete (but don't
  34582. // overwrite the animation.complete option which should be available
  34583. // to the user).
  34584. if (!hasRendered) {
  34585. // Additional time if defer is defined before afterAnimate
  34586. // will be triggered
  34587. if (animDuration && animOptions.defer) {
  34588. animDuration += animOptions.defer;
  34589. }
  34590. series.animationTimeout = syncTimeout(function () {
  34591. series.afterAnimate();
  34592. }, animDuration || 0);
  34593. }
  34594. // Means data is in accordance with what you see
  34595. series.isDirty = false;
  34596. // (See #322) series.isDirty = series.isDirtyData = false; // means
  34597. // data is in accordance with what you see
  34598. series.hasRendered = true;
  34599. fireEvent(series, 'afterRender');
  34600. };
  34601. /**
  34602. * Redraw the series. This function is called internally from
  34603. * `chart.redraw` and normally shouldn't be called directly.
  34604. * @private
  34605. * @function Highcharts.Series#redraw
  34606. */
  34607. Series.prototype.redraw = function () {
  34608. var series = this,
  34609. chart = series.chart,
  34610. // cache it here as it is set to false in render, but used after
  34611. wasDirty = series.isDirty || series.isDirtyData,
  34612. group = series.group,
  34613. xAxis = series.xAxis,
  34614. yAxis = series.yAxis;
  34615. // reposition on resize
  34616. if (group) {
  34617. if (chart.inverted) {
  34618. group.attr({
  34619. width: chart.plotWidth,
  34620. height: chart.plotHeight
  34621. });
  34622. }
  34623. group.animate({
  34624. translateX: pick(xAxis && xAxis.left, chart.plotLeft),
  34625. translateY: pick(yAxis && yAxis.top, chart.plotTop)
  34626. });
  34627. }
  34628. series.translate();
  34629. series.render();
  34630. if (wasDirty) { // #3868, #3945
  34631. delete this.kdTree;
  34632. }
  34633. };
  34634. /**
  34635. * @private
  34636. * @function Highcharts.Series#searchPoint
  34637. */
  34638. Series.prototype.searchPoint = function (e, compareX) {
  34639. var series = this,
  34640. xAxis = series.xAxis,
  34641. yAxis = series.yAxis,
  34642. inverted = series.chart.inverted;
  34643. return this.searchKDTree({
  34644. clientX: inverted ?
  34645. xAxis.len - e.chartY + xAxis.pos :
  34646. e.chartX - xAxis.pos,
  34647. plotY: inverted ?
  34648. yAxis.len - e.chartX + yAxis.pos :
  34649. e.chartY - yAxis.pos
  34650. }, compareX, e);
  34651. };
  34652. /**
  34653. * Build the k-d-tree that is used by mouse and touch interaction to get
  34654. * the closest point. Line-like series typically have a one-dimensional
  34655. * tree where points are searched along the X axis, while scatter-like
  34656. * series typically search in two dimensions, X and Y.
  34657. *
  34658. * @private
  34659. * @function Highcharts.Series#buildKDTree
  34660. */
  34661. Series.prototype.buildKDTree = function (e) {
  34662. // Prevent multiple k-d-trees from being built simultaneously
  34663. // (#6235)
  34664. this.buildingKdTree = true;
  34665. var series = this,
  34666. dimensions = series.options.findNearestPointBy
  34667. .indexOf('y') > -1 ? 2 : 1;
  34668. /**
  34669. * Internal function
  34670. * @private
  34671. */
  34672. function _kdtree(points, depth, dimensions) {
  34673. var axis,
  34674. median,
  34675. length = points && points.length;
  34676. if (length) {
  34677. // alternate between the axis
  34678. axis = series.kdAxisArray[depth % dimensions];
  34679. // sort point array
  34680. points.sort(function (a, b) {
  34681. return a[axis] - b[axis];
  34682. });
  34683. median = Math.floor(length / 2);
  34684. // build and return nod
  34685. return {
  34686. point: points[median],
  34687. left: _kdtree(points.slice(0, median), depth + 1, dimensions),
  34688. right: _kdtree(points.slice(median + 1), depth + 1, dimensions)
  34689. };
  34690. }
  34691. }
  34692. /**
  34693. * Start the recursive build process with a clone of the points
  34694. * array and null points filtered out. (#3873)
  34695. * @private
  34696. */
  34697. function startRecursive() {
  34698. series.kdTree = _kdtree(series.getValidPoints(null,
  34699. // For line-type series restrict to plot area, but
  34700. // column-type series not (#3916, #4511)
  34701. !series.directTouch), dimensions, dimensions);
  34702. series.buildingKdTree = false;
  34703. }
  34704. delete series.kdTree;
  34705. // For testing tooltips, don't build async. Also if touchstart, we
  34706. // may be dealing with click events on mobile, so don't delay
  34707. // (#6817).
  34708. syncTimeout(startRecursive, series.options.kdNow || (e && e.type === 'touchstart') ? 0 : 1);
  34709. };
  34710. /**
  34711. * @private
  34712. * @function Highcharts.Series#searchKDTree
  34713. */
  34714. Series.prototype.searchKDTree = function (point, compareX, e) {
  34715. var series = this,
  34716. kdX = this.kdAxisArray[0],
  34717. kdY = this.kdAxisArray[1],
  34718. kdComparer = compareX ? 'distX' : 'dist',
  34719. kdDimensions = series.options.findNearestPointBy
  34720. .indexOf('y') > -1 ? 2 : 1;
  34721. /**
  34722. * Set the one and two dimensional distance on the point object.
  34723. * @private
  34724. */
  34725. function setDistance(p1, p2) {
  34726. var x = (defined(p1[kdX]) &&
  34727. defined(p2[kdX])) ?
  34728. Math.pow(p1[kdX] - p2[kdX], 2) :
  34729. null,
  34730. y = (defined(p1[kdY]) &&
  34731. defined(p2[kdY])) ?
  34732. Math.pow(p1[kdY] - p2[kdY], 2) :
  34733. null,
  34734. r = (x || 0) + (y || 0);
  34735. p2.dist = defined(r) ? Math.sqrt(r) : Number.MAX_VALUE;
  34736. p2.distX = defined(x) ? Math.sqrt(x) : Number.MAX_VALUE;
  34737. }
  34738. /**
  34739. * @private
  34740. */
  34741. function _search(search, tree, depth, dimensions) {
  34742. var point = tree.point,
  34743. axis = series.kdAxisArray[depth % dimensions],
  34744. tdist,
  34745. sideA,
  34746. sideB,
  34747. ret = point,
  34748. nPoint1,
  34749. nPoint2;
  34750. setDistance(search, point);
  34751. // Pick side based on distance to splitting point
  34752. tdist = search[axis] - point[axis];
  34753. sideA = tdist < 0 ? 'left' : 'right';
  34754. sideB = tdist < 0 ? 'right' : 'left';
  34755. // End of tree
  34756. if (tree[sideA]) {
  34757. nPoint1 = _search(search, tree[sideA], depth + 1, dimensions);
  34758. ret = (nPoint1[kdComparer] <
  34759. ret[kdComparer] ?
  34760. nPoint1 :
  34761. point);
  34762. }
  34763. if (tree[sideB]) {
  34764. // compare distance to current best to splitting point to
  34765. // decide wether to check side B or not
  34766. if (Math.sqrt(tdist * tdist) < ret[kdComparer]) {
  34767. nPoint2 = _search(search, tree[sideB], depth + 1, dimensions);
  34768. ret = (nPoint2[kdComparer] <
  34769. ret[kdComparer] ?
  34770. nPoint2 :
  34771. ret);
  34772. }
  34773. }
  34774. return ret;
  34775. }
  34776. if (!this.kdTree && !this.buildingKdTree) {
  34777. this.buildKDTree(e);
  34778. }
  34779. if (this.kdTree) {
  34780. return _search(point, this.kdTree, kdDimensions, kdDimensions);
  34781. }
  34782. };
  34783. /**
  34784. * @private
  34785. * @function Highcharts.Series#pointPlacementToXValue
  34786. */
  34787. Series.prototype.pointPlacementToXValue = function () {
  34788. var _a = this,
  34789. _b = _a.options,
  34790. pointPlacement = _b.pointPlacement,
  34791. pointRange = _b.pointRange,
  34792. axis = _a.xAxis;
  34793. var factor = pointPlacement;
  34794. // Point placement is relative to each series pointRange (#5889)
  34795. if (factor === 'between') {
  34796. factor = axis.reversed ? -0.5 : 0.5; // #11955
  34797. }
  34798. return isNumber(factor) ?
  34799. factor * (pointRange || axis.pointRange) :
  34800. 0;
  34801. };
  34802. /**
  34803. * @private
  34804. * @function Highcharts.Series#isPointInside
  34805. */
  34806. Series.prototype.isPointInside = function (point) {
  34807. var isInside = typeof point.plotY !== 'undefined' &&
  34808. typeof point.plotX !== 'undefined' &&
  34809. point.plotY >= 0 &&
  34810. point.plotY <= this.yAxis.len && // #3519
  34811. point.plotX >= 0 &&
  34812. point.plotX <= this.xAxis.len;
  34813. return isInside;
  34814. };
  34815. /**
  34816. * Draw the tracker object that sits above all data labels and markers to
  34817. * track mouse events on the graph or points. For the line type charts
  34818. * the tracker uses the same graphPath, but with a greater stroke width
  34819. * for better control.
  34820. * @private
  34821. */
  34822. Series.prototype.drawTracker = function () {
  34823. var series = this,
  34824. options = series.options,
  34825. trackByArea = options.trackByArea,
  34826. trackerPath = [].concat(trackByArea ?
  34827. series.areaPath :
  34828. series.graphPath),
  34829. // trackerPathLength = trackerPath.length,
  34830. chart = series.chart,
  34831. pointer = chart.pointer,
  34832. renderer = chart.renderer,
  34833. snap = chart.options.tooltip.snap,
  34834. tracker = series.tracker,
  34835. i,
  34836. onMouseOver = function (e) {
  34837. if (chart.hoverSeries !== series) {
  34838. series.onMouseOver();
  34839. }
  34840. },
  34841. /*
  34842. * Empirical lowest possible opacities for TRACKER_FILL for an
  34843. * element to stay invisible but clickable
  34844. * IE6: 0.002
  34845. * IE7: 0.002
  34846. * IE8: 0.002
  34847. * IE9: 0.00000000001 (unlimited)
  34848. * IE10: 0.0001 (exporting only)
  34849. * FF: 0.00000000001 (unlimited)
  34850. * Chrome: 0.000001
  34851. * Safari: 0.000001
  34852. * Opera: 0.00000000001 (unlimited)
  34853. */
  34854. TRACKER_FILL = 'rgba(192,192,192,' + (svg ? 0.0001 : 0.002) + ')';
  34855. // Draw the tracker
  34856. if (tracker) {
  34857. tracker.attr({ d: trackerPath });
  34858. }
  34859. else if (series.graph) { // create
  34860. series.tracker = renderer.path(trackerPath)
  34861. .attr({
  34862. visibility: series.visible ? 'visible' : 'hidden',
  34863. zIndex: 2
  34864. })
  34865. .addClass(trackByArea ?
  34866. 'highcharts-tracker-area' :
  34867. 'highcharts-tracker-line')
  34868. .add(series.group);
  34869. if (!chart.styledMode) {
  34870. series.tracker.attr({
  34871. 'stroke-linecap': 'round',
  34872. 'stroke-linejoin': 'round',
  34873. stroke: TRACKER_FILL,
  34874. fill: trackByArea ? TRACKER_FILL : 'none',
  34875. 'stroke-width': series.graph.strokeWidth() +
  34876. (trackByArea ? 0 : 2 * snap)
  34877. });
  34878. }
  34879. // The tracker is added to the series group, which is clipped, but
  34880. // is covered by the marker group. So the marker group also needs to
  34881. // capture events.
  34882. [series.tracker, series.markerGroup].forEach(function (tracker) {
  34883. tracker.addClass('highcharts-tracker')
  34884. .on('mouseover', onMouseOver)
  34885. .on('mouseout', function (e) {
  34886. pointer.onTrackerMouseOut(e);
  34887. });
  34888. if (options.cursor && !chart.styledMode) {
  34889. tracker.css({ cursor: options.cursor });
  34890. }
  34891. if (hasTouch) {
  34892. tracker.on('touchstart', onMouseOver);
  34893. }
  34894. });
  34895. }
  34896. fireEvent(this, 'afterDrawTracker');
  34897. };
  34898. /**
  34899. * Add a point to the series after render time. The point can be added at
  34900. * the end, or by giving it an X value, to the start or in the middle of the
  34901. * series.
  34902. *
  34903. * @sample highcharts/members/series-addpoint-append/
  34904. * Append point
  34905. * @sample highcharts/members/series-addpoint-append-and-shift/
  34906. * Append and shift
  34907. * @sample highcharts/members/series-addpoint-x-and-y/
  34908. * Both X and Y values given
  34909. * @sample highcharts/members/series-addpoint-pie/
  34910. * Append pie slice
  34911. * @sample stock/members/series-addpoint/
  34912. * Append 100 points in Highstock
  34913. * @sample stock/members/series-addpoint-shift/
  34914. * Append and shift in Highstock
  34915. * @sample maps/members/series-addpoint/
  34916. * Add a point in Highmaps
  34917. *
  34918. * @function Highcharts.Series#addPoint
  34919. *
  34920. * @param {Highcharts.PointOptionsType} options
  34921. * The point options. If options is a single number, a point with
  34922. * that y value is appended to the series. If it is an array, it will
  34923. * be interpreted as x and y values respectively. If it is an
  34924. * object, advanced options as outlined under `series.data` are
  34925. * applied.
  34926. *
  34927. * @param {boolean} [redraw=true]
  34928. * Whether to redraw the chart after the point is added. When adding
  34929. * more than one point, it is highly recommended that the redraw
  34930. * option be set to false, and instead {@link Chart#redraw} is
  34931. * explicitly called after the adding of points is finished.
  34932. * Otherwise, the chart will redraw after adding each point.
  34933. *
  34934. * @param {boolean} [shift=false]
  34935. * If true, a point is shifted off the start of the series as one is
  34936. * appended to the end.
  34937. *
  34938. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
  34939. * Whether to apply animation, and optionally animation
  34940. * configuration.
  34941. *
  34942. * @param {boolean} [withEvent=true]
  34943. * Used internally, whether to fire the series `addPoint` event.
  34944. *
  34945. * @fires Highcharts.Series#event:addPoint
  34946. */
  34947. Series.prototype.addPoint = function (options, redraw, shift, animation, withEvent) {
  34948. var series = this,
  34949. seriesOptions = series.options,
  34950. data = series.data,
  34951. chart = series.chart,
  34952. xAxis = series.xAxis,
  34953. names = xAxis && xAxis.hasNames && xAxis.names,
  34954. dataOptions = seriesOptions.data,
  34955. point,
  34956. xData = series.xData,
  34957. isInTheMiddle,
  34958. i,
  34959. x;
  34960. // Optional redraw, defaults to true
  34961. redraw = pick(redraw, true);
  34962. // Get options and push the point to xData, yData and series.options. In
  34963. // series.generatePoints the Point instance will be created on demand
  34964. // and pushed to the series.data array.
  34965. point = { series: series };
  34966. series.pointClass.prototype.applyOptions.apply(point, [options]);
  34967. x = point.x;
  34968. // Get the insertion point
  34969. i = xData.length;
  34970. if (series.requireSorting && x < xData[i - 1]) {
  34971. isInTheMiddle = true;
  34972. while (i && xData[i - 1] > x) {
  34973. i--;
  34974. }
  34975. }
  34976. // Insert undefined item
  34977. series.updateParallelArrays(point, 'splice', i, 0, 0);
  34978. // Update it
  34979. series.updateParallelArrays(point, i);
  34980. if (names && point.name) {
  34981. names[x] = point.name;
  34982. }
  34983. dataOptions.splice(i, 0, options);
  34984. if (isInTheMiddle) {
  34985. series.data.splice(i, 0, null);
  34986. series.processData();
  34987. }
  34988. // Generate points to be added to the legend (#1329)
  34989. if (seriesOptions.legendType === 'point') {
  34990. series.generatePoints();
  34991. }
  34992. // Shift the first point off the parallel arrays
  34993. if (shift) {
  34994. if (data[0] && data[0].remove) {
  34995. data[0].remove(false);
  34996. }
  34997. else {
  34998. data.shift();
  34999. series.updateParallelArrays(point, 'shift');
  35000. dataOptions.shift();
  35001. }
  35002. }
  35003. // Fire event
  35004. if (withEvent !== false) {
  35005. fireEvent(series, 'addPoint', { point: point });
  35006. }
  35007. // redraw
  35008. series.isDirty = true;
  35009. series.isDirtyData = true;
  35010. if (redraw) {
  35011. chart.redraw(animation); // Animation is set anyway on redraw, #5665
  35012. }
  35013. };
  35014. /**
  35015. * Remove a point from the series. Unlike the
  35016. * {@link Highcharts.Point#remove} method, this can also be done on a point
  35017. * that is not instanciated because it is outside the view or subject to
  35018. * Highstock data grouping.
  35019. *
  35020. * @sample highcharts/members/series-removepoint/
  35021. * Remove cropped point
  35022. *
  35023. * @function Highcharts.Series#removePoint
  35024. *
  35025. * @param {number} i
  35026. * The index of the point in the {@link Highcharts.Series.data|data}
  35027. * array.
  35028. *
  35029. * @param {boolean} [redraw=true]
  35030. * Whether to redraw the chart after the point is added. When
  35031. * removing more than one point, it is highly recommended that the
  35032. * `redraw` option be set to `false`, and instead {@link
  35033. * Highcharts.Chart#redraw} is explicitly called after the adding of
  35034. * points is finished.
  35035. *
  35036. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
  35037. * Whether and optionally how the series should be animated.
  35038. *
  35039. * @fires Highcharts.Point#event:remove
  35040. */
  35041. Series.prototype.removePoint = function (i, redraw, animation) {
  35042. var series = this,
  35043. data = series.data,
  35044. point = data[i],
  35045. points = series.points,
  35046. chart = series.chart,
  35047. remove = function () {
  35048. if (points && points.length === data.length) { // #4935
  35049. points.splice(i, 1);
  35050. }
  35051. data.splice(i, 1);
  35052. series.options.data.splice(i, 1);
  35053. series.updateParallelArrays(point || { series: series }, 'splice', i, 1);
  35054. if (point) {
  35055. point.destroy();
  35056. }
  35057. // redraw
  35058. series.isDirty = true;
  35059. series.isDirtyData = true;
  35060. if (redraw) {
  35061. chart.redraw();
  35062. }
  35063. };
  35064. setAnimation(animation, chart);
  35065. redraw = pick(redraw, true);
  35066. // Fire the event with a default handler of removing the point
  35067. if (point) {
  35068. point.firePointEvent('remove', null, remove);
  35069. }
  35070. else {
  35071. remove();
  35072. }
  35073. };
  35074. /**
  35075. * Remove a series and optionally redraw the chart.
  35076. *
  35077. * @sample highcharts/members/series-remove/
  35078. * Remove first series from a button
  35079. *
  35080. * @function Highcharts.Series#remove
  35081. *
  35082. * @param {boolean} [redraw=true]
  35083. * Whether to redraw the chart or wait for an explicit call to
  35084. * {@link Highcharts.Chart#redraw}.
  35085. *
  35086. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
  35087. * Whether to apply animation, and optionally animation
  35088. * configuration.
  35089. *
  35090. * @param {boolean} [withEvent=true]
  35091. * Used internally, whether to fire the series `remove` event.
  35092. *
  35093. * @fires Highcharts.Series#event:remove
  35094. */
  35095. Series.prototype.remove = function (redraw, animation, withEvent, keepEvents) {
  35096. var series = this,
  35097. chart = series.chart;
  35098. /**
  35099. * @private
  35100. */
  35101. function remove() {
  35102. // Destroy elements
  35103. series.destroy(keepEvents);
  35104. // Redraw
  35105. chart.isDirtyLegend = chart.isDirtyBox = true;
  35106. chart.linkSeries();
  35107. if (pick(redraw, true)) {
  35108. chart.redraw(animation);
  35109. }
  35110. }
  35111. // Fire the event with a default handler of removing the point
  35112. if (withEvent !== false) {
  35113. fireEvent(series, 'remove', null, remove);
  35114. }
  35115. else {
  35116. remove();
  35117. }
  35118. };
  35119. /**
  35120. * Update the series with a new set of options. For a clean and precise
  35121. * handling of new options, all methods and elements from the series are
  35122. * removed, and it is initialized from scratch. Therefore, this method is
  35123. * more performance expensive than some other utility methods like {@link
  35124. * Series#setData} or {@link Series#setVisible}.
  35125. *
  35126. * Note that `Series.update` may mutate the passed `data` options.
  35127. *
  35128. * @sample highcharts/members/series-update/
  35129. * Updating series options
  35130. * @sample maps/members/series-update/
  35131. * Update series options in Highmaps
  35132. *
  35133. * @function Highcharts.Series#update
  35134. *
  35135. * @param {Highcharts.SeriesOptionsType} options
  35136. * New options that will be merged with the series' existing options.
  35137. *
  35138. * @param {boolean} [redraw=true]
  35139. * Whether to redraw the chart after the series is altered. If doing
  35140. * more operations on the chart, it is a good idea to set redraw to
  35141. * false and call {@link Chart#redraw} after.
  35142. *
  35143. * @fires Highcharts.Series#event:update
  35144. * @fires Highcharts.Series#event:afterUpdate
  35145. */
  35146. Series.prototype.update = function (options, redraw) {
  35147. options = cleanRecursively(options, this.userOptions);
  35148. fireEvent(this, 'update', { options: options });
  35149. var series = this,
  35150. chart = series.chart,
  35151. // must use user options when changing type because series.options
  35152. // is merged in with type specific plotOptions
  35153. oldOptions = series.userOptions,
  35154. seriesOptions,
  35155. initialType = series.initialType || series.type,
  35156. plotOptions = chart.options.plotOptions,
  35157. newType = (options.type ||
  35158. oldOptions.type ||
  35159. chart.options.chart.type),
  35160. keepPoints = !(
  35161. // Indicators, histograms etc recalculate the data. It should be
  35162. // possible to omit this.
  35163. this.hasDerivedData ||
  35164. // New type requires new point classes
  35165. (newType && newType !== this.type) ||
  35166. // New options affecting how the data points are built
  35167. typeof options.pointStart !== 'undefined' ||
  35168. typeof options.pointInterval !== 'undefined' ||
  35169. // Changes to data grouping requires new points in new group
  35170. series.hasOptionChanged('dataGrouping') ||
  35171. series.hasOptionChanged('pointStart') ||
  35172. series.hasOptionChanged('pointInterval') ||
  35173. series.hasOptionChanged('pointIntervalUnit') ||
  35174. series.hasOptionChanged('keys')),
  35175. initialSeriesProto = seriesTypes[initialType].prototype,
  35176. n,
  35177. groups = [
  35178. 'group',
  35179. 'markerGroup',
  35180. 'dataLabelsGroup',
  35181. 'transformGroup'
  35182. ],
  35183. preserve = [
  35184. 'eventOptions',
  35185. 'navigatorSeries',
  35186. 'baseSeries'
  35187. ],
  35188. // Animation must be enabled when calling update before the initial
  35189. // animation has first run. This happens when calling update
  35190. // directly after chart initialization, or when applying responsive
  35191. // rules (#6912).
  35192. animation = series.finishedAnimating && { animation: false },
  35193. kinds = {};
  35194. if (keepPoints) {
  35195. preserve.push('data', 'isDirtyData', 'points', 'processedXData', 'processedYData', 'xIncrement', 'cropped', '_hasPointMarkers', '_hasPointLabels',
  35196. // Networkgraph (#14397)
  35197. 'nodes', 'layout',
  35198. // Map specific, consider moving it to series-specific preserve-
  35199. // properties (#10617)
  35200. 'mapMap', 'mapData', 'minY', 'maxY', 'minX', 'maxX');
  35201. if (options.visible !== false) {
  35202. preserve.push('area', 'graph');
  35203. }
  35204. series.parallelArrays.forEach(function (key) {
  35205. preserve.push(key + 'Data');
  35206. });
  35207. if (options.data) {
  35208. // setData uses dataSorting options so we need to update them
  35209. // earlier
  35210. if (options.dataSorting) {
  35211. extend(series.options.dataSorting, options.dataSorting);
  35212. }
  35213. this.setData(options.data, false);
  35214. }
  35215. }
  35216. // Do the merge, with some forced options
  35217. options = merge(oldOptions, animation, {
  35218. // When oldOptions.index is null it should't be cleared.
  35219. // Otherwise navigator series will have wrong indexes (#10193).
  35220. index: typeof oldOptions.index === 'undefined' ?
  35221. series.index : oldOptions.index,
  35222. pointStart: pick(
  35223. // when updating from blank (#7933)
  35224. plotOptions && plotOptions.series && plotOptions.series.pointStart, oldOptions.pointStart,
  35225. // when updating after addPoint
  35226. series.xData[0])
  35227. }, (!keepPoints && { data: series.options.data }), options);
  35228. // Merge does not merge arrays, but replaces them. Since points were
  35229. // updated, `series.options.data` has correct merged options, use it:
  35230. if (keepPoints && options.data) {
  35231. options.data = series.options.data;
  35232. }
  35233. // Make sure preserved properties are not destroyed (#3094)
  35234. preserve = groups.concat(preserve);
  35235. preserve.forEach(function (prop) {
  35236. preserve[prop] = series[prop];
  35237. delete series[prop];
  35238. });
  35239. if (seriesTypes[newType || initialType]) {
  35240. var casting = newType !== series.type;
  35241. // Destroy the series and delete all properties, it will be
  35242. // reinserted within the `init` call below
  35243. series.remove(false, false, false, true);
  35244. if (casting) {
  35245. // Modern browsers including IE11
  35246. if (Object.setPrototypeOf) {
  35247. Object.setPrototypeOf(series, seriesTypes[newType || initialType].prototype);
  35248. // Legacy (IE < 11)
  35249. }
  35250. else {
  35251. var ownEvents = Object.hasOwnProperty.call(series, 'hcEvents') &&
  35252. series.hcEvents;
  35253. for (n in initialSeriesProto) { // eslint-disable-line guard-for-in
  35254. series[n] = void 0;
  35255. }
  35256. // Reinsert all methods and properties from the new type
  35257. // prototype (#2270, #3719).
  35258. extend(series, seriesTypes[newType || initialType].prototype);
  35259. // The events are tied to the prototype chain, don't copy if
  35260. // they're not the series' own
  35261. if (ownEvents) {
  35262. series.hcEvents = ownEvents;
  35263. }
  35264. else {
  35265. delete series.hcEvents;
  35266. }
  35267. }
  35268. }
  35269. }
  35270. else {
  35271. error(17, true, chart, { missingModuleFor: (newType || initialType) });
  35272. }
  35273. // Re-register groups (#3094) and other preserved properties
  35274. preserve.forEach(function (prop) {
  35275. series[prop] = preserve[prop];
  35276. });
  35277. series.init(chart, options);
  35278. // Remove particular elements of the points. Check `series.options`
  35279. // because we need to consider the options being set on plotOptions as
  35280. // well.
  35281. if (keepPoints && this.points) {
  35282. seriesOptions = series.options;
  35283. // What kind of elements to destroy
  35284. if (seriesOptions.visible === false) {
  35285. kinds.graphic = 1;
  35286. kinds.dataLabel = 1;
  35287. }
  35288. else if (!series._hasPointLabels) {
  35289. var marker = seriesOptions.marker,
  35290. dataLabels = seriesOptions.dataLabels;
  35291. if (marker && (marker.enabled === false ||
  35292. 'symbol' in marker // #10870
  35293. )) {
  35294. kinds.graphic = 1;
  35295. }
  35296. if (dataLabels &&
  35297. dataLabels.enabled === false) {
  35298. kinds.dataLabel = 1;
  35299. }
  35300. }
  35301. this.points.forEach(function (point) {
  35302. if (point && point.series) {
  35303. point.resolveColor();
  35304. // Destroy elements in order to recreate based on updated
  35305. // series options.
  35306. if (Object.keys(kinds).length) {
  35307. point.destroyElements(kinds);
  35308. }
  35309. if (seriesOptions.showInLegend === false &&
  35310. point.legendItem) {
  35311. chart.legend.destroyItem(point);
  35312. }
  35313. }
  35314. }, this);
  35315. }
  35316. series.initialType = initialType;
  35317. chart.linkSeries(); // Links are lost in series.remove (#3028)
  35318. fireEvent(this, 'afterUpdate');
  35319. if (pick(redraw, true)) {
  35320. chart.redraw(keepPoints ? void 0 : false);
  35321. }
  35322. };
  35323. /**
  35324. * Used from within series.update
  35325. * @private
  35326. */
  35327. Series.prototype.setName = function (name) {
  35328. this.name = this.options.name = this.userOptions.name = name;
  35329. this.chart.isDirtyLegend = true;
  35330. };
  35331. /**
  35332. * Check if the option has changed.
  35333. * @private
  35334. */
  35335. Series.prototype.hasOptionChanged = function (optionName) {
  35336. var chart = this.chart,
  35337. option = this.options[optionName],
  35338. plotOptions = chart.options.plotOptions,
  35339. oldOption = this.userOptions[optionName];
  35340. if (oldOption) {
  35341. return option !== oldOption;
  35342. }
  35343. return option !==
  35344. pick(plotOptions && plotOptions[this.type] && plotOptions[this.type][optionName], plotOptions && plotOptions.series && plotOptions.series[optionName], option);
  35345. };
  35346. /**
  35347. * Runs on mouse over the series graphical items.
  35348. *
  35349. * @function Highcharts.Series#onMouseOver
  35350. * @fires Highcharts.Series#event:mouseOver
  35351. */
  35352. Series.prototype.onMouseOver = function () {
  35353. var series = this,
  35354. chart = series.chart,
  35355. hoverSeries = chart.hoverSeries,
  35356. pointer = chart.pointer;
  35357. pointer.setHoverChartIndex();
  35358. // set normal state to previous series
  35359. if (hoverSeries && hoverSeries !== series) {
  35360. hoverSeries.onMouseOut();
  35361. }
  35362. // trigger the event, but to save processing time,
  35363. // only if defined
  35364. if (series.options.events.mouseOver) {
  35365. fireEvent(series, 'mouseOver');
  35366. }
  35367. // hover this
  35368. series.setState('hover');
  35369. /**
  35370. * Contains the original hovered series.
  35371. *
  35372. * @name Highcharts.Chart#hoverSeries
  35373. * @type {Highcharts.Series|null}
  35374. */
  35375. chart.hoverSeries = series;
  35376. };
  35377. /**
  35378. * Runs on mouse out of the series graphical items.
  35379. *
  35380. * @function Highcharts.Series#onMouseOut
  35381. *
  35382. * @fires Highcharts.Series#event:mouseOut
  35383. */
  35384. Series.prototype.onMouseOut = function () {
  35385. // trigger the event only if listeners exist
  35386. var series = this,
  35387. options = series.options,
  35388. chart = series.chart,
  35389. tooltip = chart.tooltip,
  35390. hoverPoint = chart.hoverPoint;
  35391. // #182, set to null before the mouseOut event fires
  35392. chart.hoverSeries = null;
  35393. // trigger mouse out on the point, which must be in this series
  35394. if (hoverPoint) {
  35395. hoverPoint.onMouseOut();
  35396. }
  35397. // fire the mouse out event
  35398. if (series && options.events.mouseOut) {
  35399. fireEvent(series, 'mouseOut');
  35400. }
  35401. // hide the tooltip
  35402. if (tooltip &&
  35403. !series.stickyTracking &&
  35404. (!tooltip.shared || series.noSharedTooltip)) {
  35405. tooltip.hide();
  35406. }
  35407. // Reset all inactive states
  35408. chart.series.forEach(function (s) {
  35409. s.setState('', true);
  35410. });
  35411. };
  35412. /**
  35413. * Set the state of the series. Called internally on mouse interaction
  35414. * operations, but it can also be called directly to visually
  35415. * highlight a series.
  35416. *
  35417. * @function Highcharts.Series#setState
  35418. *
  35419. * @param {Highcharts.SeriesStateValue|""} [state]
  35420. * The new state, can be either `'hover'`, `'inactive'`, `'select'`,
  35421. * or `''` (an empty string), `'normal'` or `undefined` to set to
  35422. * normal state.
  35423. * @param {boolean} [inherit]
  35424. * Determines if state should be inherited by points too.
  35425. */
  35426. Series.prototype.setState = function (state, inherit) {
  35427. var series = this,
  35428. options = series.options,
  35429. graph = series.graph,
  35430. inactiveOtherPoints = options.inactiveOtherPoints,
  35431. stateOptions = options.states,
  35432. lineWidth = options.lineWidth,
  35433. opacity = options.opacity,
  35434. // By default a quick animation to hover/inactive,
  35435. // slower to un-hover
  35436. stateAnimation = pick((stateOptions[state || 'normal'] &&
  35437. stateOptions[state || 'normal'].animation),
  35438. series.chart.options.chart.animation),
  35439. attribs,
  35440. i = 0;
  35441. state = state || '';
  35442. if (series.state !== state) {
  35443. // Toggle class names
  35444. [
  35445. series.group,
  35446. series.markerGroup,
  35447. series.dataLabelsGroup
  35448. ].forEach(function (group) {
  35449. if (group) {
  35450. // Old state
  35451. if (series.state) {
  35452. group.removeClass('highcharts-series-' + series.state);
  35453. }
  35454. // New state
  35455. if (state) {
  35456. group.addClass('highcharts-series-' + state);
  35457. }
  35458. }
  35459. });
  35460. series.state = state;
  35461. if (!series.chart.styledMode) {
  35462. if (stateOptions[state] &&
  35463. stateOptions[state].enabled === false) {
  35464. return;
  35465. }
  35466. if (state) {
  35467. lineWidth = (stateOptions[state].lineWidth ||
  35468. lineWidth + (stateOptions[state].lineWidthPlus || 0)); // #4035
  35469. opacity = pick(stateOptions[state].opacity, opacity);
  35470. }
  35471. if (graph && !graph.dashstyle) {
  35472. attribs = {
  35473. 'stroke-width': lineWidth
  35474. };
  35475. // Animate the graph stroke-width.
  35476. graph.animate(attribs, stateAnimation);
  35477. while (series['zone-graph-' + i]) {
  35478. series['zone-graph-' + i].animate(attribs, stateAnimation);
  35479. i = i + 1;
  35480. }
  35481. }
  35482. // For some types (pie, networkgraph, sankey) opacity is
  35483. // resolved on a point level
  35484. if (!inactiveOtherPoints) {
  35485. [
  35486. series.group,
  35487. series.markerGroup,
  35488. series.dataLabelsGroup,
  35489. series.labelBySeries
  35490. ].forEach(function (group) {
  35491. if (group) {
  35492. group.animate({
  35493. opacity: opacity
  35494. }, stateAnimation);
  35495. }
  35496. });
  35497. }
  35498. }
  35499. }
  35500. // Don't loop over points on a series that doesn't apply inactive state
  35501. // to siblings markers (e.g. line, column)
  35502. if (inherit && inactiveOtherPoints && series.points) {
  35503. series.setAllPointsToState(state || void 0);
  35504. }
  35505. };
  35506. /**
  35507. * Set the state for all points in the series.
  35508. *
  35509. * @function Highcharts.Series#setAllPointsToState
  35510. *
  35511. * @private
  35512. *
  35513. * @param {string} [state]
  35514. * Can be either `hover` or undefined to set to normal state.
  35515. */
  35516. Series.prototype.setAllPointsToState = function (state) {
  35517. this.points.forEach(function (point) {
  35518. if (point.setState) {
  35519. point.setState(state);
  35520. }
  35521. });
  35522. };
  35523. /**
  35524. * Show or hide the series.
  35525. *
  35526. * @function Highcharts.Series#setVisible
  35527. *
  35528. * @param {boolean} [visible]
  35529. * True to show the series, false to hide. If undefined, the visibility is
  35530. * toggled.
  35531. *
  35532. * @param {boolean} [redraw=true]
  35533. * Whether to redraw the chart after the series is altered. If doing more
  35534. * operations on the chart, it is a good idea to set redraw to false and
  35535. * call {@link Chart#redraw|chart.redraw()} after.
  35536. *
  35537. * @fires Highcharts.Series#event:hide
  35538. * @fires Highcharts.Series#event:show
  35539. */
  35540. Series.prototype.setVisible = function (vis, redraw) {
  35541. var series = this,
  35542. chart = series.chart,
  35543. legendItem = series.legendItem,
  35544. showOrHide,
  35545. ignoreHiddenSeries = chart.options.chart.ignoreHiddenSeries,
  35546. oldVisibility = series.visible;
  35547. // if called without an argument, toggle visibility
  35548. series.visible =
  35549. vis =
  35550. series.options.visible =
  35551. series.userOptions.visible =
  35552. typeof vis === 'undefined' ? !oldVisibility : vis; // #5618
  35553. showOrHide = vis ? 'show' : 'hide';
  35554. // show or hide elements
  35555. [
  35556. 'group',
  35557. 'dataLabelsGroup',
  35558. 'markerGroup',
  35559. 'tracker',
  35560. 'tt'
  35561. ].forEach(function (key) {
  35562. if (series[key]) {
  35563. series[key][showOrHide]();
  35564. }
  35565. });
  35566. // hide tooltip (#1361)
  35567. if (chart.hoverSeries === series ||
  35568. (chart.hoverPoint && chart.hoverPoint.series) === series) {
  35569. series.onMouseOut();
  35570. }
  35571. if (legendItem) {
  35572. chart.legend.colorizeItem(series, vis);
  35573. }
  35574. // rescale or adapt to resized chart
  35575. series.isDirty = true;
  35576. // in a stack, all other series are affected
  35577. if (series.options.stacking) {
  35578. chart.series.forEach(function (otherSeries) {
  35579. if (otherSeries.options.stacking && otherSeries.visible) {
  35580. otherSeries.isDirty = true;
  35581. }
  35582. });
  35583. }
  35584. // show or hide linked series
  35585. series.linkedSeries.forEach(function (otherSeries) {
  35586. otherSeries.setVisible(vis, false);
  35587. });
  35588. if (ignoreHiddenSeries) {
  35589. chart.isDirtyBox = true;
  35590. }
  35591. fireEvent(series, showOrHide);
  35592. if (redraw !== false) {
  35593. chart.redraw();
  35594. }
  35595. };
  35596. /**
  35597. * Show the series if hidden.
  35598. *
  35599. * @sample highcharts/members/series-hide/
  35600. * Toggle visibility from a button
  35601. *
  35602. * @function Highcharts.Series#show
  35603. * @fires Highcharts.Series#event:show
  35604. */
  35605. Series.prototype.show = function () {
  35606. this.setVisible(true);
  35607. };
  35608. /**
  35609. * Hide the series if visible. If the
  35610. * [chart.ignoreHiddenSeries](https://api.highcharts.com/highcharts/chart.ignoreHiddenSeries)
  35611. * option is true, the chart is redrawn without this series.
  35612. *
  35613. * @sample highcharts/members/series-hide/
  35614. * Toggle visibility from a button
  35615. *
  35616. * @function Highcharts.Series#hide
  35617. * @fires Highcharts.Series#event:hide
  35618. */
  35619. Series.prototype.hide = function () {
  35620. this.setVisible(false);
  35621. };
  35622. /**
  35623. * Select or unselect the series. This means its
  35624. * {@link Highcharts.Series.selected|selected}
  35625. * property is set, the checkbox in the legend is toggled and when selected,
  35626. * the series is returned by the {@link Highcharts.Chart#getSelectedSeries}
  35627. * function.
  35628. *
  35629. * @sample highcharts/members/series-select/
  35630. * Select a series from a button
  35631. *
  35632. * @function Highcharts.Series#select
  35633. *
  35634. * @param {boolean} [selected]
  35635. * True to select the series, false to unselect. If undefined, the selection
  35636. * state is toggled.
  35637. *
  35638. * @fires Highcharts.Series#event:select
  35639. * @fires Highcharts.Series#event:unselect
  35640. */
  35641. Series.prototype.select = function (selected) {
  35642. var series = this;
  35643. series.selected =
  35644. selected =
  35645. this.options.selected = (typeof selected === 'undefined' ?
  35646. !series.selected :
  35647. selected);
  35648. if (series.checkbox) {
  35649. series.checkbox.checked = selected;
  35650. }
  35651. fireEvent(series, selected ? 'select' : 'unselect');
  35652. };
  35653. /**
  35654. * General options for all series types.
  35655. *
  35656. * @optionparent plotOptions.series
  35657. */
  35658. Series.defaultOptions = {
  35659. // base series options
  35660. /**
  35661. * The SVG value used for the `stroke-linecap` and `stroke-linejoin`
  35662. * of a line graph. Round means that lines are rounded in the ends and
  35663. * bends.
  35664. *
  35665. * @type {Highcharts.SeriesLinecapValue}
  35666. * @default round
  35667. * @since 3.0.7
  35668. * @apioption plotOptions.line.linecap
  35669. */
  35670. /**
  35671. * Pixel width of the graph line.
  35672. *
  35673. * @see In styled mode, the line stroke-width can be set with the
  35674. * `.highcharts-graph` class name.
  35675. *
  35676. * @sample {highcharts} highcharts/plotoptions/series-linewidth-general/
  35677. * On all series
  35678. * @sample {highcharts} highcharts/plotoptions/series-linewidth-specific/
  35679. * On one single series
  35680. *
  35681. * @product highcharts highstock
  35682. *
  35683. * @private
  35684. */
  35685. lineWidth: 2,
  35686. /**
  35687. * For some series, there is a limit that shuts down initial animation
  35688. * by default when the total number of points in the chart is too high.
  35689. * For example, for a column chart and its derivatives, animation does
  35690. * not run if there is more than 250 points totally. To disable this
  35691. * cap, set `animationLimit` to `Infinity`.
  35692. *
  35693. * @type {number}
  35694. * @apioption plotOptions.series.animationLimit
  35695. */
  35696. /**
  35697. * Allow this series' points to be selected by clicking on the graphic
  35698. * (columns, point markers, pie slices, map areas etc).
  35699. *
  35700. * The selected points can be handled by point select and unselect
  35701. * events, or collectively by the [getSelectedPoints
  35702. * ](/class-reference/Highcharts.Chart#getSelectedPoints) function.
  35703. *
  35704. * And alternative way of selecting points is through dragging.
  35705. *
  35706. * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-line/
  35707. * Line
  35708. * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-column/
  35709. * Column
  35710. * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-pie/
  35711. * Pie
  35712. * @sample {highcharts} highcharts/chart/events-selection-points/
  35713. * Select a range of points through a drag selection
  35714. * @sample {highmaps} maps/plotoptions/series-allowpointselect/
  35715. * Map area
  35716. * @sample {highmaps} maps/plotoptions/mapbubble-allowpointselect/
  35717. * Map bubble
  35718. *
  35719. * @since 1.2.0
  35720. *
  35721. * @private
  35722. */
  35723. allowPointSelect: false,
  35724. /**
  35725. * When true, each point or column edge is rounded to its nearest pixel
  35726. * in order to render sharp on screen. In some cases, when there are a
  35727. * lot of densely packed columns, this leads to visible difference
  35728. * in column widths or distance between columns. In these cases,
  35729. * setting `crisp` to `false` may look better, even though each column
  35730. * is rendered blurry.
  35731. *
  35732. * @sample {highcharts} highcharts/plotoptions/column-crisp-false/
  35733. * Crisp is false
  35734. *
  35735. * @since 5.0.10
  35736. * @product highcharts highstock gantt
  35737. *
  35738. * @private
  35739. */
  35740. crisp: true,
  35741. /**
  35742. * If true, a checkbox is displayed next to the legend item to allow
  35743. * selecting the series. The state of the checkbox is determined by
  35744. * the `selected` option.
  35745. *
  35746. * @productdesc {highmaps}
  35747. * Note that if a `colorAxis` is defined, the color axis is represented
  35748. * in the legend, not the series.
  35749. *
  35750. * @sample {highcharts} highcharts/plotoptions/series-showcheckbox-true/
  35751. * Show select box
  35752. *
  35753. * @since 1.2.0
  35754. *
  35755. * @private
  35756. */
  35757. showCheckbox: false,
  35758. /**
  35759. * Enable or disable the initial animation when a series is displayed.
  35760. * The animation can also be set as a configuration object. Please
  35761. * note that this option only applies to the initial animation of the
  35762. * series itself. For other animations, see [chart.animation](
  35763. * #chart.animation) and the animation parameter under the API methods.
  35764. * The following properties are supported:
  35765. *
  35766. * - `defer`: The animation delay time in milliseconds.
  35767. *
  35768. * - `duration`: The duration of the animation in milliseconds.
  35769. *
  35770. * - `easing`: Can be a string reference to an easing function set on
  35771. * the `Math` object or a function. See the _Custom easing function_
  35772. * demo below.
  35773. *
  35774. * Due to poor performance, animation is disabled in old IE browsers
  35775. * for several chart types.
  35776. *
  35777. * @sample {highcharts} highcharts/plotoptions/series-animation-disabled/
  35778. * Animation disabled
  35779. * @sample {highcharts} highcharts/plotoptions/series-animation-slower/
  35780. * Slower animation
  35781. * @sample {highcharts} highcharts/plotoptions/series-animation-easing/
  35782. * Custom easing function
  35783. * @sample {highstock} stock/plotoptions/animation-slower/
  35784. * Slower animation
  35785. * @sample {highstock} stock/plotoptions/animation-easing/
  35786. * Custom easing function
  35787. * @sample {highmaps} maps/plotoptions/series-animation-true/
  35788. * Animation enabled on map series
  35789. * @sample {highmaps} maps/plotoptions/mapbubble-animation-false/
  35790. * Disabled on mapbubble series
  35791. *
  35792. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  35793. * @default {highcharts} true
  35794. * @default {highstock} true
  35795. * @default {highmaps} false
  35796. *
  35797. * @private
  35798. */
  35799. animation: {
  35800. /** @internal */
  35801. duration: 1000
  35802. },
  35803. /**
  35804. * @default 0
  35805. * @type {number}
  35806. * @since 8.2.0
  35807. * @apioption plotOptions.series.animation.defer
  35808. */
  35809. /**
  35810. * An additional class name to apply to the series' graphical elements.
  35811. * This option does not replace default class names of the graphical
  35812. * element.
  35813. *
  35814. * @type {string}
  35815. * @since 5.0.0
  35816. * @apioption plotOptions.series.className
  35817. */
  35818. /**
  35819. * Disable this option to allow series rendering in the whole plotting
  35820. * area.
  35821. *
  35822. * **Note:** Clipping should be always enabled when
  35823. * [chart.zoomType](#chart.zoomType) is set
  35824. *
  35825. * @sample {highcharts} highcharts/plotoptions/series-clip/
  35826. * Disabled clipping
  35827. *
  35828. * @default true
  35829. * @type {boolean}
  35830. * @since 3.0.0
  35831. * @apioption plotOptions.series.clip
  35832. */
  35833. /**
  35834. * The main color of the series. In line type series it applies to the
  35835. * line and the point markers unless otherwise specified. In bar type
  35836. * series it applies to the bars unless a color is specified per point.
  35837. * The default value is pulled from the `options.colors` array.
  35838. *
  35839. * In styled mode, the color can be defined by the
  35840. * [colorIndex](#plotOptions.series.colorIndex) option. Also, the series
  35841. * color can be set with the `.highcharts-series`,
  35842. * `.highcharts-color-{n}`, `.highcharts-{type}-series` or
  35843. * `.highcharts-series-{n}` class, or individual classes given by the
  35844. * `className` option.
  35845. *
  35846. * @productdesc {highmaps}
  35847. * In maps, the series color is rarely used, as most choropleth maps use
  35848. * the color to denote the value of each point. The series color can
  35849. * however be used in a map with multiple series holding categorized
  35850. * data.
  35851. *
  35852. * @sample {highcharts} highcharts/plotoptions/series-color-general/
  35853. * General plot option
  35854. * @sample {highcharts} highcharts/plotoptions/series-color-specific/
  35855. * One specific series
  35856. * @sample {highcharts} highcharts/plotoptions/series-color-area/
  35857. * Area color
  35858. * @sample {highcharts} highcharts/series/infographic/
  35859. * Pattern fill
  35860. * @sample {highmaps} maps/demo/category-map/
  35861. * Category map by multiple series
  35862. *
  35863. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  35864. * @apioption plotOptions.series.color
  35865. */
  35866. /**
  35867. * Styled mode only. A specific color index to use for the series, so
  35868. * its graphic representations are given the class name
  35869. * `highcharts-color-{n}`.
  35870. *
  35871. * @type {number}
  35872. * @since 5.0.0
  35873. * @apioption plotOptions.series.colorIndex
  35874. */
  35875. /**
  35876. * Whether to connect a graph line across null points, or render a gap
  35877. * between the two points on either side of the null.
  35878. *
  35879. * @sample {highcharts} highcharts/plotoptions/series-connectnulls-false/
  35880. * False by default
  35881. * @sample {highcharts} highcharts/plotoptions/series-connectnulls-true/
  35882. * True
  35883. *
  35884. * @type {boolean}
  35885. * @default false
  35886. * @product highcharts highstock
  35887. * @apioption plotOptions.series.connectNulls
  35888. */
  35889. /**
  35890. * You can set the cursor to "pointer" if you have click events attached
  35891. * to the series, to signal to the user that the points and lines can
  35892. * be clicked.
  35893. *
  35894. * In styled mode, the series cursor can be set with the same classes
  35895. * as listed under [series.color](#plotOptions.series.color).
  35896. *
  35897. * @sample {highcharts} highcharts/plotoptions/series-cursor-line/
  35898. * On line graph
  35899. * @sample {highcharts} highcharts/plotoptions/series-cursor-column/
  35900. * On columns
  35901. * @sample {highcharts} highcharts/plotoptions/series-cursor-scatter/
  35902. * On scatter markers
  35903. * @sample {highstock} stock/plotoptions/cursor/
  35904. * Pointer on a line graph
  35905. * @sample {highmaps} maps/plotoptions/series-allowpointselect/
  35906. * Map area
  35907. * @sample {highmaps} maps/plotoptions/mapbubble-allowpointselect/
  35908. * Map bubble
  35909. *
  35910. * @type {string|Highcharts.CursorValue}
  35911. * @apioption plotOptions.series.cursor
  35912. */
  35913. /**
  35914. * A reserved subspace to store options and values for customized
  35915. * functionality. Here you can add additional data for your own event
  35916. * callbacks and formatter callbacks.
  35917. *
  35918. * @sample {highcharts} highcharts/point/custom/
  35919. * Point and series with custom data
  35920. *
  35921. * @type {Highcharts.Dictionary<*>}
  35922. * @apioption plotOptions.series.custom
  35923. */
  35924. /**
  35925. * Name of the dash style to use for the graph, or for some series types
  35926. * the outline of each shape.
  35927. *
  35928. * In styled mode, the
  35929. * [stroke dash-array](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/series-dashstyle/)
  35930. * can be set with the same classes as listed under
  35931. * [series.color](#plotOptions.series.color).
  35932. *
  35933. * @sample {highcharts} highcharts/plotoptions/series-dashstyle-all/
  35934. * Possible values demonstrated
  35935. * @sample {highcharts} highcharts/plotoptions/series-dashstyle/
  35936. * Chart suitable for printing in black and white
  35937. * @sample {highstock} highcharts/plotoptions/series-dashstyle-all/
  35938. * Possible values demonstrated
  35939. * @sample {highmaps} highcharts/plotoptions/series-dashstyle-all/
  35940. * Possible values demonstrated
  35941. * @sample {highmaps} maps/plotoptions/series-dashstyle/
  35942. * Dotted borders on a map
  35943. *
  35944. * @type {Highcharts.DashStyleValue}
  35945. * @default Solid
  35946. * @since 2.1
  35947. * @apioption plotOptions.series.dashStyle
  35948. */
  35949. /**
  35950. * A description of the series to add to the screen reader information
  35951. * about the series.
  35952. *
  35953. * @type {string}
  35954. * @since 5.0.0
  35955. * @requires modules/accessibility
  35956. * @apioption plotOptions.series.description
  35957. */
  35958. /**
  35959. * Options for the series data sorting.
  35960. *
  35961. * @type {Highcharts.DataSortingOptionsObject}
  35962. * @since 8.0.0
  35963. * @product highcharts highstock
  35964. * @apioption plotOptions.series.dataSorting
  35965. */
  35966. /**
  35967. * Enable or disable data sorting for the series. Use [xAxis.reversed](
  35968. * #xAxis.reversed) to change the sorting order.
  35969. *
  35970. * @sample {highcharts} highcharts/datasorting/animation/
  35971. * Data sorting in scatter-3d
  35972. * @sample {highcharts} highcharts/datasorting/labels-animation/
  35973. * Axis labels animation
  35974. * @sample {highcharts} highcharts/datasorting/dependent-sorting/
  35975. * Dependent series sorting
  35976. * @sample {highcharts} highcharts/datasorting/independent-sorting/
  35977. * Independent series sorting
  35978. *
  35979. * @type {boolean}
  35980. * @since 8.0.0
  35981. * @apioption plotOptions.series.dataSorting.enabled
  35982. */
  35983. /**
  35984. * Whether to allow matching points by name in an update. If this option
  35985. * is disabled, points will be matched by order.
  35986. *
  35987. * @sample {highcharts} highcharts/datasorting/match-by-name/
  35988. * Enabled match by name
  35989. *
  35990. * @type {boolean}
  35991. * @since 8.0.0
  35992. * @apioption plotOptions.series.dataSorting.matchByName
  35993. */
  35994. /**
  35995. * Determines what data value should be used to sort by.
  35996. *
  35997. * @sample {highcharts} highcharts/datasorting/sort-key/
  35998. * Sort key as `z` value
  35999. *
  36000. * @type {string}
  36001. * @since 8.0.0
  36002. * @default y
  36003. * @apioption plotOptions.series.dataSorting.sortKey
  36004. */
  36005. /**
  36006. * Enable or disable the mouse tracking for a specific series. This
  36007. * includes point tooltips and click events on graphs and points. For
  36008. * large datasets it improves performance.
  36009. *
  36010. * @sample {highcharts} highcharts/plotoptions/series-enablemousetracking-false/
  36011. * No mouse tracking
  36012. * @sample {highmaps} maps/plotoptions/series-enablemousetracking-false/
  36013. * No mouse tracking
  36014. *
  36015. * @type {boolean}
  36016. * @default true
  36017. * @apioption plotOptions.series.enableMouseTracking
  36018. */
  36019. /**
  36020. * Whether to use the Y extremes of the total chart width or only the
  36021. * zoomed area when zooming in on parts of the X axis. By default, the
  36022. * Y axis adjusts to the min and max of the visible data. Cartesian
  36023. * series only.
  36024. *
  36025. * @type {boolean}
  36026. * @default false
  36027. * @since 4.1.6
  36028. * @product highcharts highstock gantt
  36029. * @apioption plotOptions.series.getExtremesFromAll
  36030. */
  36031. /**
  36032. * An array specifying which option maps to which key in the data point
  36033. * array. This makes it convenient to work with unstructured data arrays
  36034. * from different sources.
  36035. *
  36036. * @see [series.data](#series.line.data)
  36037. *
  36038. * @sample {highcharts|highstock} highcharts/series/data-keys/
  36039. * An extended data array with keys
  36040. * @sample {highcharts|highstock} highcharts/series/data-nested-keys/
  36041. * Nested keys used to access object properties
  36042. *
  36043. * @type {Array<string>}
  36044. * @since 4.1.6
  36045. * @apioption plotOptions.series.keys
  36046. */
  36047. /**
  36048. * The line cap used for line ends and line joins on the graph.
  36049. *
  36050. * @type {Highcharts.SeriesLinecapValue}
  36051. * @default round
  36052. * @product highcharts highstock
  36053. * @apioption plotOptions.series.linecap
  36054. */
  36055. /**
  36056. * The [id](#series.id) of another series to link to. Additionally,
  36057. * the value can be ":previous" to link to the previous series. When
  36058. * two series are linked, only the first one appears in the legend.
  36059. * Toggling the visibility of this also toggles the linked series.
  36060. *
  36061. * If master series uses data sorting and linked series does not have
  36062. * its own sorting definition, the linked series will be sorted in the
  36063. * same order as the master one.
  36064. *
  36065. * @sample {highcharts|highstock} highcharts/demo/arearange-line/
  36066. * Linked series
  36067. *
  36068. * @type {string}
  36069. * @since 3.0
  36070. * @product highcharts highstock gantt
  36071. * @apioption plotOptions.series.linkedTo
  36072. */
  36073. /**
  36074. * Options for the corresponding navigator series if `showInNavigator`
  36075. * is `true` for this series. Available options are the same as any
  36076. * series, documented at [plotOptions](#plotOptions.series) and
  36077. * [series](#series).
  36078. *
  36079. * These options are merged with options in [navigator.series](
  36080. * #navigator.series), and will take precedence if the same option is
  36081. * defined both places.
  36082. *
  36083. * @see [navigator.series](#navigator.series)
  36084. *
  36085. * @type {Highcharts.PlotSeriesOptions}
  36086. * @since 5.0.0
  36087. * @product highstock
  36088. * @apioption plotOptions.series.navigatorOptions
  36089. */
  36090. /**
  36091. * The color for the parts of the graph or points that are below the
  36092. * [threshold](#plotOptions.series.threshold). Note that `zones` takes
  36093. * precedence over the negative color. Using `negativeColor` is
  36094. * equivalent to applying a zone with value of 0.
  36095. *
  36096. * @see In styled mode, a negative color is applied by setting this option
  36097. * to `true` combined with the `.highcharts-negative` class name.
  36098. *
  36099. * @sample {highcharts} highcharts/plotoptions/series-negative-color/
  36100. * Spline, area and column
  36101. * @sample {highcharts} highcharts/plotoptions/arearange-negativecolor/
  36102. * Arearange
  36103. * @sample {highcharts} highcharts/css/series-negative-color/
  36104. * Styled mode
  36105. * @sample {highstock} highcharts/plotoptions/series-negative-color/
  36106. * Spline, area and column
  36107. * @sample {highstock} highcharts/plotoptions/arearange-negativecolor/
  36108. * Arearange
  36109. * @sample {highmaps} highcharts/plotoptions/series-negative-color/
  36110. * Spline, area and column
  36111. * @sample {highmaps} highcharts/plotoptions/arearange-negativecolor/
  36112. * Arearange
  36113. *
  36114. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  36115. * @since 3.0
  36116. * @apioption plotOptions.series.negativeColor
  36117. */
  36118. /**
  36119. * Same as
  36120. * [accessibility.pointDescriptionFormatter](#accessibility.pointDescriptionFormatter),
  36121. * but for an individual series. Overrides the chart wide configuration.
  36122. *
  36123. * @type {Function}
  36124. * @since 5.0.12
  36125. * @apioption plotOptions.series.pointDescriptionFormatter
  36126. */
  36127. /**
  36128. * If no x values are given for the points in a series, `pointInterval`
  36129. * defines the interval of the x values. For example, if a series
  36130. * contains one value every decade starting from year 0, set
  36131. * `pointInterval` to `10`. In true `datetime` axes, the `pointInterval`
  36132. * is set in milliseconds.
  36133. *
  36134. * It can be also be combined with `pointIntervalUnit` to draw irregular
  36135. * time intervals.
  36136. *
  36137. * Please note that this options applies to the _series data_, not the
  36138. * interval of the axis ticks, which is independent.
  36139. *
  36140. * @sample {highcharts} highcharts/plotoptions/series-pointstart-datetime/
  36141. * Datetime X axis
  36142. * @sample {highstock} stock/plotoptions/pointinterval-pointstart/
  36143. * Using pointStart and pointInterval
  36144. *
  36145. * @type {number}
  36146. * @default 1
  36147. * @product highcharts highstock gantt
  36148. * @apioption plotOptions.series.pointInterval
  36149. */
  36150. /**
  36151. * On datetime series, this allows for setting the
  36152. * [pointInterval](#plotOptions.series.pointInterval) to irregular time
  36153. * units, `day`, `month` and `year`. A day is usually the same as 24
  36154. * hours, but `pointIntervalUnit` also takes the DST crossover into
  36155. * consideration when dealing with local time. Combine this option with
  36156. * `pointInterval` to draw weeks, quarters, 6 months, 10 years etc.
  36157. *
  36158. * Please note that this options applies to the _series data_, not the
  36159. * interval of the axis ticks, which is independent.
  36160. *
  36161. * @sample {highcharts} highcharts/plotoptions/series-pointintervalunit/
  36162. * One point a month
  36163. * @sample {highstock} highcharts/plotoptions/series-pointintervalunit/
  36164. * One point a month
  36165. *
  36166. * @type {string}
  36167. * @since 4.1.0
  36168. * @product highcharts highstock gantt
  36169. * @validvalue ["day", "month", "year"]
  36170. * @apioption plotOptions.series.pointIntervalUnit
  36171. */
  36172. /**
  36173. * Possible values: `"on"`, `"between"`, `number`.
  36174. *
  36175. * In a column chart, when pointPlacement is `"on"`, the point will not
  36176. * create any padding of the X axis. In a polar column chart this means
  36177. * that the first column points directly north. If the pointPlacement is
  36178. * `"between"`, the columns will be laid out between ticks. This is
  36179. * useful for example for visualising an amount between two points in
  36180. * time or in a certain sector of a polar chart.
  36181. *
  36182. * Since Highcharts 3.0.2, the point placement can also be numeric,
  36183. * where 0 is on the axis value, -0.5 is between this value and the
  36184. * previous, and 0.5 is between this value and the next. Unlike the
  36185. * textual options, numeric point placement options won't affect axis
  36186. * padding.
  36187. *
  36188. * Note that pointPlacement needs a [pointRange](
  36189. * #plotOptions.series.pointRange) to work. For column series this is
  36190. * computed, but for line-type series it needs to be set.
  36191. *
  36192. * For the `xrange` series type and gantt charts, if the Y axis is a
  36193. * category axis, the `pointPlacement` applies to the Y axis rather than
  36194. * the (typically datetime) X axis.
  36195. *
  36196. * Defaults to `undefined` in cartesian charts, `"between"` in polar
  36197. * charts.
  36198. *
  36199. * @see [xAxis.tickmarkPlacement](#xAxis.tickmarkPlacement)
  36200. *
  36201. * @sample {highcharts|highstock} highcharts/plotoptions/series-pointplacement-between/
  36202. * Between in a column chart
  36203. * @sample {highcharts|highstock} highcharts/plotoptions/series-pointplacement-numeric/
  36204. * Numeric placement for custom layout
  36205. * @sample {highcharts|highstock} maps/plotoptions/heatmap-pointplacement/
  36206. * Placement in heatmap
  36207. *
  36208. * @type {string|number}
  36209. * @since 2.3.0
  36210. * @product highcharts highstock gantt
  36211. * @apioption plotOptions.series.pointPlacement
  36212. */
  36213. /**
  36214. * If no x values are given for the points in a series, pointStart
  36215. * defines on what value to start. For example, if a series contains one
  36216. * yearly value starting from 1945, set pointStart to 1945.
  36217. *
  36218. * @sample {highcharts} highcharts/plotoptions/series-pointstart-linear/
  36219. * Linear
  36220. * @sample {highcharts} highcharts/plotoptions/series-pointstart-datetime/
  36221. * Datetime
  36222. * @sample {highstock} stock/plotoptions/pointinterval-pointstart/
  36223. * Using pointStart and pointInterval
  36224. *
  36225. * @type {number}
  36226. * @default 0
  36227. * @product highcharts highstock gantt
  36228. * @apioption plotOptions.series.pointStart
  36229. */
  36230. /**
  36231. * Whether to select the series initially. If `showCheckbox` is true,
  36232. * the checkbox next to the series name in the legend will be checked
  36233. * for a selected series.
  36234. *
  36235. * @sample {highcharts} highcharts/plotoptions/series-selected/
  36236. * One out of two series selected
  36237. *
  36238. * @type {boolean}
  36239. * @default false
  36240. * @since 1.2.0
  36241. * @apioption plotOptions.series.selected
  36242. */
  36243. /**
  36244. * Whether to apply a drop shadow to the graph line. Since 2.3 the
  36245. * shadow can be an object configuration containing `color`, `offsetX`,
  36246. * `offsetY`, `opacity` and `width`.
  36247. *
  36248. * @sample {highcharts} highcharts/plotoptions/series-shadow/
  36249. * Shadow enabled
  36250. *
  36251. * @type {boolean|Highcharts.ShadowOptionsObject}
  36252. * @default false
  36253. * @apioption plotOptions.series.shadow
  36254. */
  36255. /**
  36256. * Whether to display this particular series or series type in the
  36257. * legend. Standalone series are shown in legend by default, and linked
  36258. * series are not. Since v7.2.0 it is possible to show series that use
  36259. * colorAxis by setting this option to `true`.
  36260. *
  36261. * @sample {highcharts} highcharts/plotoptions/series-showinlegend/
  36262. * One series in the legend, one hidden
  36263. *
  36264. * @type {boolean}
  36265. * @apioption plotOptions.series.showInLegend
  36266. */
  36267. /**
  36268. * Whether or not to show the series in the navigator. Takes precedence
  36269. * over [navigator.baseSeries](#navigator.baseSeries) if defined.
  36270. *
  36271. * @type {boolean}
  36272. * @since 5.0.0
  36273. * @product highstock
  36274. * @apioption plotOptions.series.showInNavigator
  36275. */
  36276. /**
  36277. * If set to `true`, the accessibility module will skip past the points
  36278. * in this series for keyboard navigation.
  36279. *
  36280. * @type {boolean}
  36281. * @since 5.0.12
  36282. * @apioption plotOptions.series.skipKeyboardNavigation
  36283. */
  36284. /**
  36285. * Whether to stack the values of each series on top of each other.
  36286. * Possible values are `undefined` to disable, `"normal"` to stack by
  36287. * value or `"percent"`.
  36288. *
  36289. * When stacking is enabled, data must be sorted
  36290. * in ascending X order.
  36291. *
  36292. * Some stacking options are related to specific series types. In the
  36293. * streamgraph series type, the stacking option is set to `"stream"`.
  36294. * The second one is `"overlap"`, which only applies to waterfall
  36295. * series.
  36296. *
  36297. * @see [yAxis.reversedStacks](#yAxis.reversedStacks)
  36298. *
  36299. * @sample {highcharts} highcharts/plotoptions/series-stacking-line/
  36300. * Line
  36301. * @sample {highcharts} highcharts/plotoptions/series-stacking-column/
  36302. * Column
  36303. * @sample {highcharts} highcharts/plotoptions/series-stacking-bar/
  36304. * Bar
  36305. * @sample {highcharts} highcharts/plotoptions/series-stacking-area/
  36306. * Area
  36307. * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-line/
  36308. * Line
  36309. * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-column/
  36310. * Column
  36311. * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-bar/
  36312. * Bar
  36313. * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-area/
  36314. * Area
  36315. * @sample {highcharts} highcharts/plotoptions/series-waterfall-with-normal-stacking
  36316. * Waterfall with normal stacking
  36317. * @sample {highcharts} highcharts/plotoptions/series-waterfall-with-overlap-stacking
  36318. * Waterfall with overlap stacking
  36319. * @sample {highstock} stock/plotoptions/stacking/
  36320. * Area
  36321. *
  36322. * @type {string}
  36323. * @product highcharts highstock
  36324. * @validvalue ["normal", "overlap", "percent", "stream"]
  36325. * @apioption plotOptions.series.stacking
  36326. */
  36327. /**
  36328. * Whether to apply steps to the line. Possible values are `left`,
  36329. * `center` and `right`.
  36330. *
  36331. * @sample {highcharts} highcharts/plotoptions/line-step/
  36332. * Different step line options
  36333. * @sample {highcharts} highcharts/plotoptions/area-step/
  36334. * Stepped, stacked area
  36335. * @sample {highstock} stock/plotoptions/line-step/
  36336. * Step line
  36337. *
  36338. * @type {string}
  36339. * @since 1.2.5
  36340. * @product highcharts highstock
  36341. * @validvalue ["left", "center", "right"]
  36342. * @apioption plotOptions.series.step
  36343. */
  36344. /**
  36345. * The threshold, also called zero level or base level. For line type
  36346. * series this is only used in conjunction with
  36347. * [negativeColor](#plotOptions.series.negativeColor).
  36348. *
  36349. * @see [softThreshold](#plotOptions.series.softThreshold).
  36350. *
  36351. * @type {number|null}
  36352. * @default 0
  36353. * @since 3.0
  36354. * @product highcharts highstock
  36355. * @apioption plotOptions.series.threshold
  36356. */
  36357. /**
  36358. * Set the initial visibility of the series.
  36359. *
  36360. * @sample {highcharts} highcharts/plotoptions/series-visible/
  36361. * Two series, one hidden and one visible
  36362. * @sample {highstock} stock/plotoptions/series-visibility/
  36363. * Hidden series
  36364. *
  36365. * @type {boolean}
  36366. * @default true
  36367. * @apioption plotOptions.series.visible
  36368. */
  36369. /**
  36370. * Defines the Axis on which the zones are applied.
  36371. *
  36372. * @see [zones](#plotOptions.series.zones)
  36373. *
  36374. * @sample {highcharts} highcharts/series/color-zones-zoneaxis-x/
  36375. * Zones on the X-Axis
  36376. * @sample {highstock} highcharts/series/color-zones-zoneaxis-x/
  36377. * Zones on the X-Axis
  36378. *
  36379. * @type {string}
  36380. * @default y
  36381. * @since 4.1.0
  36382. * @product highcharts highstock
  36383. * @apioption plotOptions.series.zoneAxis
  36384. */
  36385. /**
  36386. * General event handlers for the series items. These event hooks can
  36387. * also be attached to the series at run time using the
  36388. * `Highcharts.addEvent` function.
  36389. *
  36390. * @declare Highcharts.SeriesEventsOptionsObject
  36391. *
  36392. * @private
  36393. */
  36394. events: {},
  36395. /**
  36396. * Fires after the series has finished its initial animation, or in case
  36397. * animation is disabled, immediately as the series is displayed.
  36398. *
  36399. * @sample {highcharts} highcharts/plotoptions/series-events-afteranimate/
  36400. * Show label after animate
  36401. * @sample {highstock} highcharts/plotoptions/series-events-afteranimate/
  36402. * Show label after animate
  36403. *
  36404. * @type {Highcharts.SeriesAfterAnimateCallbackFunction}
  36405. * @since 4.0
  36406. * @product highcharts highstock gantt
  36407. * @context Highcharts.Series
  36408. * @apioption plotOptions.series.events.afterAnimate
  36409. */
  36410. /**
  36411. * Fires when the checkbox next to the series' name in the legend is
  36412. * clicked. One parameter, `event`, is passed to the function. The state
  36413. * of the checkbox is found by `event.checked`. The checked item is
  36414. * found by `event.item`. Return `false` to prevent the default action
  36415. * which is to toggle the select state of the series.
  36416. *
  36417. * @sample {highcharts} highcharts/plotoptions/series-events-checkboxclick/
  36418. * Alert checkbox status
  36419. *
  36420. * @type {Highcharts.SeriesCheckboxClickCallbackFunction}
  36421. * @since 1.2.0
  36422. * @context Highcharts.Series
  36423. * @apioption plotOptions.series.events.checkboxClick
  36424. */
  36425. /**
  36426. * Fires when the series is clicked. One parameter, `event`, is passed
  36427. * to the function, containing common event information. Additionally,
  36428. * `event.point` holds a pointer to the nearest point on the graph.
  36429. *
  36430. * @sample {highcharts} highcharts/plotoptions/series-events-click/
  36431. * Alert click info
  36432. * @sample {highstock} stock/plotoptions/series-events-click/
  36433. * Alert click info
  36434. * @sample {highmaps} maps/plotoptions/series-events-click/
  36435. * Display click info in subtitle
  36436. *
  36437. * @type {Highcharts.SeriesClickCallbackFunction}
  36438. * @context Highcharts.Series
  36439. * @apioption plotOptions.series.events.click
  36440. */
  36441. /**
  36442. * Fires when the series is hidden after chart generation time, either
  36443. * by clicking the legend item or by calling `.hide()`.
  36444. *
  36445. * @sample {highcharts} highcharts/plotoptions/series-events-hide/
  36446. * Alert when the series is hidden by clicking the legend item
  36447. *
  36448. * @type {Highcharts.SeriesHideCallbackFunction}
  36449. * @since 1.2.0
  36450. * @context Highcharts.Series
  36451. * @apioption plotOptions.series.events.hide
  36452. */
  36453. /**
  36454. * Fires when the legend item belonging to the series is clicked. One
  36455. * parameter, `event`, is passed to the function. The default action
  36456. * is to toggle the visibility of the series. This can be prevented
  36457. * by returning `false` or calling `event.preventDefault()`.
  36458. *
  36459. * @sample {highcharts} highcharts/plotoptions/series-events-legenditemclick/
  36460. * Confirm hiding and showing
  36461. *
  36462. * @type {Highcharts.SeriesLegendItemClickCallbackFunction}
  36463. * @context Highcharts.Series
  36464. * @apioption plotOptions.series.events.legendItemClick
  36465. */
  36466. /**
  36467. * Fires when the mouse leaves the graph. One parameter, `event`, is
  36468. * passed to the function, containing common event information. If the
  36469. * [stickyTracking](#plotOptions.series) option is true, `mouseOut`
  36470. * doesn't happen before the mouse enters another graph or leaves the
  36471. * plot area.
  36472. *
  36473. * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-sticky/
  36474. * With sticky tracking by default
  36475. * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-no-sticky/
  36476. * Without sticky tracking
  36477. *
  36478. * @type {Highcharts.SeriesMouseOutCallbackFunction}
  36479. * @context Highcharts.Series
  36480. * @apioption plotOptions.series.events.mouseOut
  36481. */
  36482. /**
  36483. * Fires when the mouse enters the graph. One parameter, `event`, is
  36484. * passed to the function, containing common event information.
  36485. *
  36486. * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-sticky/
  36487. * With sticky tracking by default
  36488. * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-no-sticky/
  36489. * Without sticky tracking
  36490. *
  36491. * @type {Highcharts.SeriesMouseOverCallbackFunction}
  36492. * @context Highcharts.Series
  36493. * @apioption plotOptions.series.events.mouseOver
  36494. */
  36495. /**
  36496. * Fires when the series is shown after chart generation time, either
  36497. * by clicking the legend item or by calling `.show()`.
  36498. *
  36499. * @sample {highcharts} highcharts/plotoptions/series-events-show/
  36500. * Alert when the series is shown by clicking the legend item.
  36501. *
  36502. * @type {Highcharts.SeriesShowCallbackFunction}
  36503. * @since 1.2.0
  36504. * @context Highcharts.Series
  36505. * @apioption plotOptions.series.events.show
  36506. */
  36507. /**
  36508. * Options for the point markers of line-like series. Properties like
  36509. * `fillColor`, `lineColor` and `lineWidth` define the visual appearance
  36510. * of the markers. Other series types, like column series, don't have
  36511. * markers, but have visual options on the series level instead.
  36512. *
  36513. * In styled mode, the markers can be styled with the
  36514. * `.highcharts-point`, `.highcharts-point-hover` and
  36515. * `.highcharts-point-select` class names.
  36516. *
  36517. * @declare Highcharts.PointMarkerOptionsObject
  36518. *
  36519. * @private
  36520. */
  36521. marker: {
  36522. /**
  36523. * Enable or disable the point marker. If `undefined`, the markers
  36524. * are hidden when the data is dense, and shown for more widespread
  36525. * data points.
  36526. *
  36527. * @sample {highcharts} highcharts/plotoptions/series-marker-enabled/
  36528. * Disabled markers
  36529. * @sample {highcharts} highcharts/plotoptions/series-marker-enabled-false/
  36530. * Disabled in normal state but enabled on hover
  36531. * @sample {highstock} stock/plotoptions/series-marker/
  36532. * Enabled markers
  36533. *
  36534. * @type {boolean}
  36535. * @default {highcharts} undefined
  36536. * @default {highstock} false
  36537. * @apioption plotOptions.series.marker.enabled
  36538. */
  36539. /**
  36540. * The threshold for how dense the point markers should be before
  36541. * they are hidden, given that `enabled` is not defined. The number
  36542. * indicates the horizontal distance between the two closest points
  36543. * in the series, as multiples of the `marker.radius`. In other
  36544. * words, the default value of 2 means points are hidden if
  36545. * overlapping horizontally.
  36546. *
  36547. * @sample highcharts/plotoptions/series-marker-enabledthreshold
  36548. * A higher threshold
  36549. *
  36550. * @since 6.0.5
  36551. */
  36552. enabledThreshold: 2,
  36553. /**
  36554. * The fill color of the point marker. When `undefined`, the series'
  36555. * or point's color is used.
  36556. *
  36557. * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/
  36558. * White fill
  36559. *
  36560. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  36561. * @apioption plotOptions.series.marker.fillColor
  36562. */
  36563. /**
  36564. * Image markers only. Set the image width explicitly. When using
  36565. * this option, a `width` must also be set.
  36566. *
  36567. * @sample {highcharts} highcharts/plotoptions/series-marker-width-height/
  36568. * Fixed width and height
  36569. * @sample {highstock} highcharts/plotoptions/series-marker-width-height/
  36570. * Fixed width and height
  36571. *
  36572. * @type {number}
  36573. * @since 4.0.4
  36574. * @apioption plotOptions.series.marker.height
  36575. */
  36576. /**
  36577. * The color of the point marker's outline. When `undefined`, the
  36578. * series' or point's color is used.
  36579. *
  36580. * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/
  36581. * Inherit from series color (undefined)
  36582. *
  36583. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  36584. */
  36585. lineColor: palette.backgroundColor,
  36586. /**
  36587. * The width of the point marker's outline.
  36588. *
  36589. * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/
  36590. * 2px blue marker
  36591. */
  36592. lineWidth: 0,
  36593. /**
  36594. * The radius of the point marker.
  36595. *
  36596. * @sample {highcharts} highcharts/plotoptions/series-marker-radius/
  36597. * Bigger markers
  36598. *
  36599. * @default {highstock} 2
  36600. */
  36601. radius: 4,
  36602. /**
  36603. * A predefined shape or symbol for the marker. When undefined, the
  36604. * symbol is pulled from options.symbols. Other possible values are
  36605. * `'circle'`, `'square'`,`'diamond'`, `'triangle'` and
  36606. * `'triangle-down'`.
  36607. *
  36608. * Additionally, the URL to a graphic can be given on this form:
  36609. * `'url(graphic.png)'`. Note that for the image to be applied to
  36610. * exported charts, its URL needs to be accessible by the export
  36611. * server.
  36612. *
  36613. * Custom callbacks for symbol path generation can also be added to
  36614. * `Highcharts.SVGRenderer.prototype.symbols`. The callback is then
  36615. * used by its method name, as shown in the demo.
  36616. *
  36617. * @sample {highcharts} highcharts/plotoptions/series-marker-symbol/
  36618. * Predefined, graphic and custom markers
  36619. * @sample {highstock} highcharts/plotoptions/series-marker-symbol/
  36620. * Predefined, graphic and custom markers
  36621. *
  36622. * @type {string}
  36623. * @apioption plotOptions.series.marker.symbol
  36624. */
  36625. /**
  36626. * Image markers only. Set the image width explicitly. When using
  36627. * this option, a `height` must also be set.
  36628. *
  36629. * @sample {highcharts} highcharts/plotoptions/series-marker-width-height/
  36630. * Fixed width and height
  36631. * @sample {highstock} highcharts/plotoptions/series-marker-width-height/
  36632. * Fixed width and height
  36633. *
  36634. * @type {number}
  36635. * @since 4.0.4
  36636. * @apioption plotOptions.series.marker.width
  36637. */
  36638. /**
  36639. * States for a single point marker.
  36640. *
  36641. * @declare Highcharts.PointStatesOptionsObject
  36642. */
  36643. states: {
  36644. /**
  36645. * The normal state of a single point marker. Currently only
  36646. * used for setting animation when returning to normal state
  36647. * from hover.
  36648. *
  36649. * @declare Highcharts.PointStatesNormalOptionsObject
  36650. */
  36651. normal: {
  36652. /**
  36653. * Animation when returning to normal state after hovering.
  36654. *
  36655. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  36656. */
  36657. animation: true
  36658. },
  36659. /**
  36660. * The hover state for a single point marker.
  36661. *
  36662. * @declare Highcharts.PointStatesHoverOptionsObject
  36663. */
  36664. hover: {
  36665. /**
  36666. * Animation when hovering over the marker.
  36667. *
  36668. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  36669. */
  36670. animation: {
  36671. /** @internal */
  36672. duration: 50
  36673. },
  36674. /**
  36675. * Enable or disable the point marker.
  36676. *
  36677. * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-enabled/
  36678. * Disabled hover state
  36679. */
  36680. enabled: true,
  36681. /**
  36682. * The fill color of the marker in hover state. When
  36683. * `undefined`, the series' or point's fillColor for normal
  36684. * state is used.
  36685. *
  36686. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  36687. * @apioption plotOptions.series.marker.states.hover.fillColor
  36688. */
  36689. /**
  36690. * The color of the point marker's outline. When
  36691. * `undefined`, the series' or point's lineColor for normal
  36692. * state is used.
  36693. *
  36694. * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-linecolor/
  36695. * White fill color, black line color
  36696. *
  36697. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  36698. * @apioption plotOptions.series.marker.states.hover.lineColor
  36699. */
  36700. /**
  36701. * The width of the point marker's outline. When
  36702. * `undefined`, the series' or point's lineWidth for normal
  36703. * state is used.
  36704. *
  36705. * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-linewidth/
  36706. * 3px line width
  36707. *
  36708. * @type {number}
  36709. * @apioption plotOptions.series.marker.states.hover.lineWidth
  36710. */
  36711. /**
  36712. * The radius of the point marker. In hover state, it
  36713. * defaults to the normal state's radius + 2 as per the
  36714. * [radiusPlus](#plotOptions.series.marker.states.hover.radiusPlus)
  36715. * option.
  36716. *
  36717. * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-radius/
  36718. * 10px radius
  36719. *
  36720. * @type {number}
  36721. * @apioption plotOptions.series.marker.states.hover.radius
  36722. */
  36723. /**
  36724. * The number of pixels to increase the radius of the
  36725. * hovered point.
  36726. *
  36727. * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/
  36728. * 5 pixels greater radius on hover
  36729. * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/
  36730. * 5 pixels greater radius on hover
  36731. *
  36732. * @since 4.0.3
  36733. */
  36734. radiusPlus: 2,
  36735. /**
  36736. * The additional line width for a hovered point.
  36737. *
  36738. * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/
  36739. * 2 pixels wider on hover
  36740. * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/
  36741. * 2 pixels wider on hover
  36742. *
  36743. * @since 4.0.3
  36744. */
  36745. lineWidthPlus: 1
  36746. },
  36747. /**
  36748. * The appearance of the point marker when selected. In order to
  36749. * allow a point to be selected, set the
  36750. * `series.allowPointSelect` option to true.
  36751. *
  36752. * @declare Highcharts.PointStatesSelectOptionsObject
  36753. */
  36754. select: {
  36755. /**
  36756. * Enable or disable visible feedback for selection.
  36757. *
  36758. * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-enabled/
  36759. * Disabled select state
  36760. *
  36761. * @type {boolean}
  36762. * @default true
  36763. * @apioption plotOptions.series.marker.states.select.enabled
  36764. */
  36765. /**
  36766. * The radius of the point marker. In hover state, it
  36767. * defaults to the normal state's radius + 2.
  36768. *
  36769. * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-radius/
  36770. * 10px radius for selected points
  36771. *
  36772. * @type {number}
  36773. * @apioption plotOptions.series.marker.states.select.radius
  36774. */
  36775. /**
  36776. * The fill color of the point marker.
  36777. *
  36778. * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-fillcolor/
  36779. * Solid red discs for selected points
  36780. *
  36781. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  36782. */
  36783. fillColor: palette.neutralColor20,
  36784. /**
  36785. * The color of the point marker's outline. When
  36786. * `undefined`, the series' or point's color is used.
  36787. *
  36788. * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-linecolor/
  36789. * Red line color for selected points
  36790. *
  36791. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  36792. */
  36793. lineColor: palette.neutralColor100,
  36794. /**
  36795. * The width of the point marker's outline.
  36796. *
  36797. * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-linewidth/
  36798. * 3px line width for selected points
  36799. */
  36800. lineWidth: 2
  36801. }
  36802. }
  36803. },
  36804. /**
  36805. * Properties for each single point.
  36806. *
  36807. * @declare Highcharts.PlotSeriesPointOptions
  36808. *
  36809. * @private
  36810. */
  36811. point: {
  36812. /**
  36813. * Fires when a point is clicked. One parameter, `event`, is passed
  36814. * to the function, containing common event information.
  36815. *
  36816. * If the `series.allowPointSelect` option is true, the default
  36817. * action for the point's click event is to toggle the point's
  36818. * select state. Returning `false` cancels this action.
  36819. *
  36820. * @sample {highcharts} highcharts/plotoptions/series-point-events-click/
  36821. * Click marker to alert values
  36822. * @sample {highcharts} highcharts/plotoptions/series-point-events-click-column/
  36823. * Click column
  36824. * @sample {highcharts} highcharts/plotoptions/series-point-events-click-url/
  36825. * Go to URL
  36826. * @sample {highmaps} maps/plotoptions/series-point-events-click/
  36827. * Click marker to display values
  36828. * @sample {highmaps} maps/plotoptions/series-point-events-click-url/
  36829. * Go to URL
  36830. *
  36831. * @type {Highcharts.PointClickCallbackFunction}
  36832. * @context Highcharts.Point
  36833. * @apioption plotOptions.series.point.events.click
  36834. */
  36835. /**
  36836. * Fires when the mouse leaves the area close to the point. One
  36837. * parameter, `event`, is passed to the function, containing common
  36838. * event information.
  36839. *
  36840. * @sample {highcharts} highcharts/plotoptions/series-point-events-mouseover/
  36841. * Show values in the chart's corner on mouse over
  36842. *
  36843. * @type {Highcharts.PointMouseOutCallbackFunction}
  36844. * @context Highcharts.Point
  36845. * @apioption plotOptions.series.point.events.mouseOut
  36846. */
  36847. /**
  36848. * Fires when the mouse enters the area close to the point. One
  36849. * parameter, `event`, is passed to the function, containing common
  36850. * event information.
  36851. *
  36852. * @sample {highcharts} highcharts/plotoptions/series-point-events-mouseover/
  36853. * Show values in the chart's corner on mouse over
  36854. *
  36855. * @type {Highcharts.PointMouseOverCallbackFunction}
  36856. * @context Highcharts.Point
  36857. * @apioption plotOptions.series.point.events.mouseOver
  36858. */
  36859. /**
  36860. * Fires when the point is removed using the `.remove()` method. One
  36861. * parameter, `event`, is passed to the function. Returning `false`
  36862. * cancels the operation.
  36863. *
  36864. * @sample {highcharts} highcharts/plotoptions/series-point-events-remove/
  36865. * Remove point and confirm
  36866. *
  36867. * @type {Highcharts.PointRemoveCallbackFunction}
  36868. * @since 1.2.0
  36869. * @context Highcharts.Point
  36870. * @apioption plotOptions.series.point.events.remove
  36871. */
  36872. /**
  36873. * Fires when the point is selected either programmatically or
  36874. * following a click on the point. One parameter, `event`, is passed
  36875. * to the function. Returning `false` cancels the operation.
  36876. *
  36877. * @sample {highcharts} highcharts/plotoptions/series-point-events-select/
  36878. * Report the last selected point
  36879. * @sample {highmaps} maps/plotoptions/series-allowpointselect/
  36880. * Report select and unselect
  36881. *
  36882. * @type {Highcharts.PointSelectCallbackFunction}
  36883. * @since 1.2.0
  36884. * @context Highcharts.Point
  36885. * @apioption plotOptions.series.point.events.select
  36886. */
  36887. /**
  36888. * Fires when the point is unselected either programmatically or
  36889. * following a click on the point. One parameter, `event`, is passed
  36890. * to the function.
  36891. * Returning `false` cancels the operation.
  36892. *
  36893. * @sample {highcharts} highcharts/plotoptions/series-point-events-unselect/
  36894. * Report the last unselected point
  36895. * @sample {highmaps} maps/plotoptions/series-allowpointselect/
  36896. * Report select and unselect
  36897. *
  36898. * @type {Highcharts.PointUnselectCallbackFunction}
  36899. * @since 1.2.0
  36900. * @context Highcharts.Point
  36901. * @apioption plotOptions.series.point.events.unselect
  36902. */
  36903. /**
  36904. * Fires when the point is updated programmatically through the
  36905. * `.update()` method. One parameter, `event`, is passed to the
  36906. * function. The new point options can be accessed through
  36907. * `event.options`. Returning `false` cancels the operation.
  36908. *
  36909. * @sample {highcharts} highcharts/plotoptions/series-point-events-update/
  36910. * Confirm point updating
  36911. *
  36912. * @type {Highcharts.PointUpdateCallbackFunction}
  36913. * @since 1.2.0
  36914. * @context Highcharts.Point
  36915. * @apioption plotOptions.series.point.events.update
  36916. */
  36917. /**
  36918. * Events for each single point.
  36919. *
  36920. * @declare Highcharts.PointEventsOptionsObject
  36921. */
  36922. events: {}
  36923. },
  36924. /**
  36925. * Options for the series data labels, appearing next to each data
  36926. * point.
  36927. *
  36928. * Since v6.2.0, multiple data labels can be applied to each single
  36929. * point by defining them as an array of configs.
  36930. *
  36931. * In styled mode, the data labels can be styled with the
  36932. * `.highcharts-data-label-box` and `.highcharts-data-label` class names
  36933. * ([see example](https://www.highcharts.com/samples/highcharts/css/series-datalabels)).
  36934. *
  36935. * @sample {highcharts} highcharts/plotoptions/series-datalabels-enabled
  36936. * Data labels enabled
  36937. * @sample {highcharts} highcharts/plotoptions/series-datalabels-multiple
  36938. * Multiple data labels on a bar series
  36939. * @sample {highcharts} highcharts/css/series-datalabels
  36940. * Style mode example
  36941. *
  36942. * @type {*|Array<*>}
  36943. * @product highcharts highstock highmaps gantt
  36944. *
  36945. * @private
  36946. */
  36947. dataLabels: {
  36948. /**
  36949. * Enable or disable the initial animation when a series is
  36950. * displayed for the `dataLabels`. The animation can also be set as
  36951. * a configuration object. Please note that this option only
  36952. * applies to the initial animation.
  36953. * For other animations, see [chart.animation](#chart.animation)
  36954. * and the animation parameter under the API methods.
  36955. * The following properties are supported:
  36956. *
  36957. * - `defer`: The animation delay time in milliseconds.
  36958. *
  36959. * @sample {highcharts} highcharts/plotoptions/animation-defer/
  36960. * Animation defer settings
  36961. *
  36962. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  36963. * @since 8.2.0
  36964. * @apioption plotOptions.series.dataLabels.animation
  36965. */
  36966. animation: {},
  36967. /**
  36968. * The animation delay time in milliseconds.
  36969. * Set to `0` renders dataLabel immediately.
  36970. * As `undefined` inherits defer time from the [series.animation.defer](#plotOptions.series.animation.defer).
  36971. *
  36972. * @type {number}
  36973. * @since 8.2.0
  36974. * @apioption plotOptions.series.dataLabels.animation.defer
  36975. */
  36976. /**
  36977. * The alignment of the data label compared to the point. If
  36978. * `right`, the right side of the label should be touching the
  36979. * point. For points with an extent, like columns, the alignments
  36980. * also dictates how to align it inside the box, as given with the
  36981. * [inside](#plotOptions.column.dataLabels.inside)
  36982. * option. Can be one of `left`, `center` or `right`.
  36983. *
  36984. * @sample {highcharts} highcharts/plotoptions/series-datalabels-align-left/
  36985. * Left aligned
  36986. * @sample {highcharts} highcharts/plotoptions/bar-datalabels-align-inside-bar/
  36987. * Data labels inside the bar
  36988. *
  36989. * @type {Highcharts.AlignValue|null}
  36990. */
  36991. align: 'center',
  36992. /**
  36993. * Whether to allow data labels to overlap. To make the labels less
  36994. * sensitive for overlapping, the
  36995. * [dataLabels.padding](#plotOptions.series.dataLabels.padding)
  36996. * can be set to 0.
  36997. *
  36998. * @sample {highcharts} highcharts/plotoptions/series-datalabels-allowoverlap-false/
  36999. * Don't allow overlap
  37000. *
  37001. * @type {boolean}
  37002. * @default false
  37003. * @since 4.1.0
  37004. * @apioption plotOptions.series.dataLabels.allowOverlap
  37005. */
  37006. /**
  37007. * The background color or gradient for the data label.
  37008. *
  37009. * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
  37010. * Data labels box options
  37011. * @sample {highmaps} maps/plotoptions/series-datalabels-box/
  37012. * Data labels box options
  37013. *
  37014. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  37015. * @since 2.2.1
  37016. * @apioption plotOptions.series.dataLabels.backgroundColor
  37017. */
  37018. /**
  37019. * The border color for the data label. Defaults to `undefined`.
  37020. *
  37021. * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
  37022. * Data labels box options
  37023. *
  37024. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  37025. * @since 2.2.1
  37026. * @apioption plotOptions.series.dataLabels.borderColor
  37027. */
  37028. /**
  37029. * The border radius in pixels for the data label.
  37030. *
  37031. * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
  37032. * Data labels box options
  37033. * @sample {highmaps} maps/plotoptions/series-datalabels-box/
  37034. * Data labels box options
  37035. *
  37036. * @type {number}
  37037. * @default 0
  37038. * @since 2.2.1
  37039. * @apioption plotOptions.series.dataLabels.borderRadius
  37040. */
  37041. /**
  37042. * The border width in pixels for the data label.
  37043. *
  37044. * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
  37045. * Data labels box options
  37046. *
  37047. * @type {number}
  37048. * @default 0
  37049. * @since 2.2.1
  37050. * @apioption plotOptions.series.dataLabels.borderWidth
  37051. */
  37052. /**
  37053. * A class name for the data label. Particularly in styled mode,
  37054. * this can be used to give each series' or point's data label
  37055. * unique styling. In addition to this option, a default color class
  37056. * name is added so that we can give the labels a contrast text
  37057. * shadow.
  37058. *
  37059. * @sample {highcharts} highcharts/css/data-label-contrast/
  37060. * Contrast text shadow
  37061. * @sample {highcharts} highcharts/css/series-datalabels/
  37062. * Styling by CSS
  37063. *
  37064. * @type {string}
  37065. * @since 5.0.0
  37066. * @apioption plotOptions.series.dataLabels.className
  37067. */
  37068. /**
  37069. * The text color for the data labels. Defaults to `undefined`. For
  37070. * certain series types, like column or map, the data labels can be
  37071. * drawn inside the points. In this case the data label will be
  37072. * drawn with maximum contrast by default. Additionally, it will be
  37073. * given a `text-outline` style with the opposite color, to further
  37074. * increase the contrast. This can be overridden by setting the
  37075. * `text-outline` style to `none` in the `dataLabels.style` option.
  37076. *
  37077. * @sample {highcharts} highcharts/plotoptions/series-datalabels-color/
  37078. * Red data labels
  37079. * @sample {highmaps} maps/demo/color-axis/
  37080. * White data labels
  37081. *
  37082. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  37083. * @apioption plotOptions.series.dataLabels.color
  37084. */
  37085. /**
  37086. * Whether to hide data labels that are outside the plot area. By
  37087. * default, the data label is moved inside the plot area according
  37088. * to the
  37089. * [overflow](#plotOptions.series.dataLabels.overflow)
  37090. * option.
  37091. *
  37092. * @type {boolean}
  37093. * @default true
  37094. * @since 2.3.3
  37095. * @apioption plotOptions.series.dataLabels.crop
  37096. */
  37097. /**
  37098. * Whether to defer displaying the data labels until the initial
  37099. * series animation has finished. Setting to `false` renders the
  37100. * data label immediately. If set to `true` inherits the defer
  37101. * time set in [plotOptions.series.animation](#plotOptions.series.animation).
  37102. *
  37103. * @sample highcharts/plotoptions/animation-defer
  37104. * Set defer time
  37105. *
  37106. * @since 4.0.0
  37107. * @product highcharts highstock gantt
  37108. */
  37109. defer: true,
  37110. /**
  37111. * Enable or disable the data labels.
  37112. *
  37113. * @sample {highcharts} highcharts/plotoptions/series-datalabels-enabled/
  37114. * Data labels enabled
  37115. * @sample {highmaps} maps/demo/color-axis/
  37116. * Data labels enabled
  37117. *
  37118. * @type {boolean}
  37119. * @default false
  37120. * @apioption plotOptions.series.dataLabels.enabled
  37121. */
  37122. /**
  37123. * A declarative filter to control of which data labels to display.
  37124. * The declarative filter is designed for use when callback
  37125. * functions are not available, like when the chart options require
  37126. * a pure JSON structure or for use with graphical editors. For
  37127. * programmatic control, use the `formatter` instead, and return
  37128. * `undefined` to disable a single data label.
  37129. *
  37130. * @example
  37131. * filter: {
  37132. * property: 'percentage',
  37133. * operator: '>',
  37134. * value: 4
  37135. * }
  37136. *
  37137. * @sample {highcharts} highcharts/demo/pie-monochrome
  37138. * Data labels filtered by percentage
  37139. *
  37140. * @declare Highcharts.DataLabelsFilterOptionsObject
  37141. * @since 6.0.3
  37142. * @apioption plotOptions.series.dataLabels.filter
  37143. */
  37144. /**
  37145. * The operator to compare by. Can be one of `>`, `<`, `>=`, `<=`,
  37146. * `==`, and `===`.
  37147. *
  37148. * @type {string}
  37149. * @validvalue [">", "<", ">=", "<=", "==", "==="]
  37150. * @apioption plotOptions.series.dataLabels.filter.operator
  37151. */
  37152. /**
  37153. * The point property to filter by. Point options are passed
  37154. * directly to properties, additionally there are `y` value,
  37155. * `percentage` and others listed under {@link Highcharts.Point}
  37156. * members.
  37157. *
  37158. * @type {string}
  37159. * @apioption plotOptions.series.dataLabels.filter.property
  37160. */
  37161. /**
  37162. * The value to compare against.
  37163. *
  37164. * @type {number}
  37165. * @apioption plotOptions.series.dataLabels.filter.value
  37166. */
  37167. /**
  37168. * A
  37169. * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
  37170. * for the data label. Available variables are the same as for
  37171. * `formatter`.
  37172. *
  37173. * @sample {highcharts} highcharts/plotoptions/series-datalabels-format/
  37174. * Add a unit
  37175. * @sample {highmaps} maps/plotoptions/series-datalabels-format/
  37176. * Formatted value in the data label
  37177. *
  37178. * @type {string}
  37179. * @default y
  37180. * @default point.value
  37181. * @since 3.0
  37182. * @apioption plotOptions.series.dataLabels.format
  37183. */
  37184. // eslint-disable-next-line valid-jsdoc
  37185. /**
  37186. * Callback JavaScript function to format the data label. Note that
  37187. * if a `format` is defined, the format takes precedence and the
  37188. * formatter is ignored.
  37189. *
  37190. * @sample {highmaps} maps/plotoptions/series-datalabels-format/
  37191. * Formatted value
  37192. *
  37193. * @type {Highcharts.DataLabelsFormatterCallbackFunction}
  37194. */
  37195. formatter: function () {
  37196. var numberFormatter = this.series.chart.numberFormatter;
  37197. return typeof this.y !== 'number' ? '' : numberFormatter(this.y, -1);
  37198. },
  37199. /**
  37200. * For points with an extent, like columns or map areas, whether to
  37201. * align the data label inside the box or to the actual value point.
  37202. * Defaults to `false` in most cases, `true` in stacked columns.
  37203. *
  37204. * @type {boolean}
  37205. * @since 3.0
  37206. * @apioption plotOptions.series.dataLabels.inside
  37207. */
  37208. /**
  37209. * Format for points with the value of null. Works analogously to
  37210. * [format](#plotOptions.series.dataLabels.format). `nullFormat` can
  37211. * be applied only to series which support displaying null points.
  37212. *
  37213. * @sample {highcharts} highcharts/plotoptions/series-datalabels-format/
  37214. * Format data label and tooltip for null point.
  37215. *
  37216. * @type {boolean|string}
  37217. * @since 7.1.0
  37218. * @apioption plotOptions.series.dataLabels.nullFormat
  37219. */
  37220. /**
  37221. * Callback JavaScript function that defines formatting for points
  37222. * with the value of null. Works analogously to
  37223. * [formatter](#plotOptions.series.dataLabels.formatter).
  37224. * `nullPointFormatter` can be applied only to series which support
  37225. * displaying null points.
  37226. *
  37227. * @sample {highcharts} highcharts/plotoptions/series-datalabels-format/
  37228. * Format data label and tooltip for null point.
  37229. *
  37230. * @type {Highcharts.DataLabelsFormatterCallbackFunction}
  37231. * @since 7.1.0
  37232. * @apioption plotOptions.series.dataLabels.nullFormatter
  37233. */
  37234. /**
  37235. * How to handle data labels that flow outside the plot area. The
  37236. * default is `"justify"`, which aligns them inside the plot area.
  37237. * For columns and bars, this means it will be moved inside the bar.
  37238. * To display data labels outside the plot area, set `crop` to
  37239. * `false` and `overflow` to `"allow"`.
  37240. *
  37241. * @type {Highcharts.DataLabelsOverflowValue}
  37242. * @default justify
  37243. * @since 3.0.6
  37244. * @apioption plotOptions.series.dataLabels.overflow
  37245. */
  37246. /**
  37247. * When either the `borderWidth` or the `backgroundColor` is set,
  37248. * this is the padding within the box.
  37249. *
  37250. * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
  37251. * Data labels box options
  37252. * @sample {highmaps} maps/plotoptions/series-datalabels-box/
  37253. * Data labels box options
  37254. *
  37255. * @since 2.2.1
  37256. */
  37257. padding: 5,
  37258. /**
  37259. * Aligns data labels relative to points. If `center` alignment is
  37260. * not possible, it defaults to `right`.
  37261. *
  37262. * @type {Highcharts.AlignValue}
  37263. * @default center
  37264. * @apioption plotOptions.series.dataLabels.position
  37265. */
  37266. /**
  37267. * Text rotation in degrees. Note that due to a more complex
  37268. * structure, backgrounds, borders and padding will be lost on a
  37269. * rotated data label.
  37270. *
  37271. * @sample {highcharts} highcharts/plotoptions/series-datalabels-rotation/
  37272. * Vertical labels
  37273. *
  37274. * @type {number}
  37275. * @default 0
  37276. * @apioption plotOptions.series.dataLabels.rotation
  37277. */
  37278. /**
  37279. * The shadow of the box. Works best with `borderWidth` or
  37280. * `backgroundColor`. Since 2.3 the shadow can be an object
  37281. * configuration containing `color`, `offsetX`, `offsetY`, `opacity`
  37282. * and `width`.
  37283. *
  37284. * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
  37285. * Data labels box options
  37286. *
  37287. * @type {boolean|Highcharts.ShadowOptionsObject}
  37288. * @default false
  37289. * @since 2.2.1
  37290. * @apioption plotOptions.series.dataLabels.shadow
  37291. */
  37292. /**
  37293. * The name of a symbol to use for the border around the label.
  37294. * Symbols are predefined functions on the Renderer object.
  37295. *
  37296. * @sample {highcharts} highcharts/plotoptions/series-datalabels-shape/
  37297. * A callout for annotations
  37298. *
  37299. * @type {string}
  37300. * @default square
  37301. * @since 4.1.2
  37302. * @apioption plotOptions.series.dataLabels.shape
  37303. */
  37304. /**
  37305. * Styles for the label. The default `color` setting is
  37306. * `"contrast"`, which is a pseudo color that Highcharts picks up
  37307. * and applies the maximum contrast to the underlying point item,
  37308. * for example the bar in a bar chart.
  37309. *
  37310. * The `textOutline` is a pseudo property that applies an outline of
  37311. * the given width with the given color, which by default is the
  37312. * maximum contrast to the text. So a bright text color will result
  37313. * in a black text outline for maximum readability on a mixed
  37314. * background. In some cases, especially with grayscale text, the
  37315. * text outline doesn't work well, in which cases it can be disabled
  37316. * by setting it to `"none"`. When `useHTML` is true, the
  37317. * `textOutline` will not be picked up. In this, case, the same
  37318. * effect can be acheived through the `text-shadow` CSS property.
  37319. *
  37320. * For some series types, where each point has an extent, like for
  37321. * example tree maps, the data label may overflow the point. There
  37322. * are two strategies for handling overflow. By default, the text
  37323. * will wrap to multiple lines. The other strategy is to set
  37324. * `style.textOverflow` to `ellipsis`, which will keep the text on
  37325. * one line plus it will break inside long words.
  37326. *
  37327. * @sample {highcharts} highcharts/plotoptions/series-datalabels-style/
  37328. * Bold labels
  37329. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-overflow/
  37330. * Long labels truncated with an ellipsis in a pie
  37331. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-overflow-wrap/
  37332. * Long labels are wrapped in a pie
  37333. * @sample {highmaps} maps/demo/color-axis/
  37334. * Bold labels
  37335. *
  37336. * @type {Highcharts.CSSObject}
  37337. * @since 4.1.0
  37338. * @apioption plotOptions.series.dataLabels.style
  37339. */
  37340. style: {
  37341. /** @internal */
  37342. fontSize: '11px',
  37343. /** @internal */
  37344. fontWeight: 'bold',
  37345. /** @internal */
  37346. color: 'contrast',
  37347. /** @internal */
  37348. textOutline: '1px contrast'
  37349. },
  37350. /**
  37351. * Options for a label text which should follow marker's shape.
  37352. * Border and background are disabled for a label that follows a
  37353. * path.
  37354. *
  37355. * **Note:** Only SVG-based renderer supports this option. Setting
  37356. * `useHTML` to true will disable this option.
  37357. *
  37358. * @declare Highcharts.DataLabelsTextPathOptionsObject
  37359. * @since 7.1.0
  37360. * @apioption plotOptions.series.dataLabels.textPath
  37361. */
  37362. /**
  37363. * Presentation attributes for the text path.
  37364. *
  37365. * @type {Highcharts.SVGAttributes}
  37366. * @since 7.1.0
  37367. * @apioption plotOptions.series.dataLabels.textPath.attributes
  37368. */
  37369. /**
  37370. * Enable or disable `textPath` option for link's or marker's data
  37371. * labels.
  37372. *
  37373. * @type {boolean}
  37374. * @since 7.1.0
  37375. * @apioption plotOptions.series.dataLabels.textPath.enabled
  37376. */
  37377. /**
  37378. * Whether to
  37379. * [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  37380. * to render the labels.
  37381. *
  37382. * @type {boolean}
  37383. * @default false
  37384. * @apioption plotOptions.series.dataLabels.useHTML
  37385. */
  37386. /**
  37387. * The vertical alignment of a data label. Can be one of `top`,
  37388. * `middle` or `bottom`. The default value depends on the data, for
  37389. * instance in a column chart, the label is above positive values
  37390. * and below negative values.
  37391. *
  37392. * @type {Highcharts.VerticalAlignValue|null}
  37393. * @since 2.3.3
  37394. */
  37395. verticalAlign: 'bottom',
  37396. /**
  37397. * The x position offset of the label relative to the point in
  37398. * pixels.
  37399. *
  37400. * @sample {highcharts} highcharts/plotoptions/series-datalabels-rotation/
  37401. * Vertical and positioned
  37402. * @sample {highcharts} highcharts/plotoptions/bar-datalabels-align-inside-bar/
  37403. * Data labels inside the bar
  37404. */
  37405. x: 0,
  37406. /**
  37407. * The Z index of the data labels. The default Z index puts it above
  37408. * the series. Use a Z index of 2 to display it behind the series.
  37409. *
  37410. * @type {number}
  37411. * @default 6
  37412. * @since 2.3.5
  37413. * @apioption plotOptions.series.dataLabels.z
  37414. */
  37415. /**
  37416. * The y position offset of the label relative to the point in
  37417. * pixels.
  37418. *
  37419. * @sample {highcharts} highcharts/plotoptions/series-datalabels-rotation/
  37420. * Vertical and positioned
  37421. */
  37422. y: 0
  37423. },
  37424. /**
  37425. * When the series contains less points than the crop threshold, all
  37426. * points are drawn, even if the points fall outside the visible plot
  37427. * area at the current zoom. The advantage of drawing all points
  37428. * (including markers and columns), is that animation is performed on
  37429. * updates. On the other hand, when the series contains more points than
  37430. * the crop threshold, the series data is cropped to only contain points
  37431. * that fall within the plot area. The advantage of cropping away
  37432. * invisible points is to increase performance on large series.
  37433. *
  37434. * @since 2.2
  37435. * @product highcharts highstock
  37436. *
  37437. * @private
  37438. */
  37439. cropThreshold: 300,
  37440. /**
  37441. * Opacity of a series parts: line, fill (e.g. area) and dataLabels.
  37442. *
  37443. * @see [states.inactive.opacity](#plotOptions.series.states.inactive.opacity)
  37444. *
  37445. * @since 7.1.0
  37446. *
  37447. * @private
  37448. */
  37449. opacity: 1,
  37450. /**
  37451. * The width of each point on the x axis. For example in a column chart
  37452. * with one value each day, the pointRange would be 1 day (= 24 * 3600
  37453. * * 1000 milliseconds). This is normally computed automatically, but
  37454. * this option can be used to override the automatic value.
  37455. *
  37456. * @product highstock
  37457. *
  37458. * @private
  37459. */
  37460. pointRange: 0,
  37461. /**
  37462. * When this is true, the series will not cause the Y axis to cross
  37463. * the zero plane (or [threshold](#plotOptions.series.threshold) option)
  37464. * unless the data actually crosses the plane.
  37465. *
  37466. * For example, if `softThreshold` is `false`, a series of 0, 1, 2,
  37467. * 3 will make the Y axis show negative values according to the
  37468. * `minPadding` option. If `softThreshold` is `true`, the Y axis starts
  37469. * at 0.
  37470. *
  37471. * @since 4.1.9
  37472. * @product highcharts highstock
  37473. *
  37474. * @private
  37475. */
  37476. softThreshold: true,
  37477. /**
  37478. * @declare Highcharts.SeriesStatesOptionsObject
  37479. *
  37480. * @private
  37481. */
  37482. states: {
  37483. /**
  37484. * The normal state of a series, or for point items in column, pie
  37485. * and similar series. Currently only used for setting animation
  37486. * when returning to normal state from hover.
  37487. *
  37488. * @declare Highcharts.SeriesStatesNormalOptionsObject
  37489. */
  37490. normal: {
  37491. /**
  37492. * Animation when returning to normal state after hovering.
  37493. *
  37494. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  37495. */
  37496. animation: true
  37497. },
  37498. /**
  37499. * Options for the hovered series. These settings override the
  37500. * normal state options when a series is moused over or touched.
  37501. *
  37502. * @declare Highcharts.SeriesStatesHoverOptionsObject
  37503. */
  37504. hover: {
  37505. /**
  37506. * Enable separate styles for the hovered series to visualize
  37507. * that the user hovers either the series itself or the legend.
  37508. *
  37509. * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled/
  37510. * Line
  37511. * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled-column/
  37512. * Column
  37513. * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled-pie/
  37514. * Pie
  37515. *
  37516. * @type {boolean}
  37517. * @default true
  37518. * @since 1.2
  37519. * @apioption plotOptions.series.states.hover.enabled
  37520. */
  37521. /**
  37522. * Animation setting for hovering the graph in line-type series.
  37523. *
  37524. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  37525. * @since 5.0.8
  37526. * @product highcharts highstock
  37527. */
  37528. animation: {
  37529. /**
  37530. * The duration of the hover animation in milliseconds. By
  37531. * default the hover state animates quickly in, and slowly
  37532. * back to normal.
  37533. *
  37534. * @internal
  37535. */
  37536. duration: 50
  37537. },
  37538. /**
  37539. * Pixel width of the graph line. By default this property is
  37540. * undefined, and the `lineWidthPlus` property dictates how much
  37541. * to increase the linewidth from normal state.
  37542. *
  37543. * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidth/
  37544. * 5px line on hover
  37545. *
  37546. * @type {number}
  37547. * @product highcharts highstock
  37548. * @apioption plotOptions.series.states.hover.lineWidth
  37549. */
  37550. /**
  37551. * The additional line width for the graph of a hovered series.
  37552. *
  37553. * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/
  37554. * 5 pixels wider
  37555. * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/
  37556. * 5 pixels wider
  37557. *
  37558. * @since 4.0.3
  37559. * @product highcharts highstock
  37560. */
  37561. lineWidthPlus: 1,
  37562. /**
  37563. * In Highcharts 1.0, the appearance of all markers belonging
  37564. * to the hovered series. For settings on the hover state of the
  37565. * individual point, see
  37566. * [marker.states.hover](#plotOptions.series.marker.states.hover).
  37567. *
  37568. * @deprecated
  37569. *
  37570. * @extends plotOptions.series.marker
  37571. * @excluding states
  37572. * @product highcharts highstock
  37573. */
  37574. marker: {
  37575. // lineWidth: base + 1,
  37576. // radius: base + 1
  37577. },
  37578. /**
  37579. * Options for the halo appearing around the hovered point in
  37580. * line-type series as well as outside the hovered slice in pie
  37581. * charts. By default the halo is filled by the current point or
  37582. * series color with an opacity of 0.25\. The halo can be
  37583. * disabled by setting the `halo` option to `null`.
  37584. *
  37585. * In styled mode, the halo is styled with the
  37586. * `.highcharts-halo` class, with colors inherited from
  37587. * `.highcharts-color-{n}`.
  37588. *
  37589. * @sample {highcharts} highcharts/plotoptions/halo/
  37590. * Halo options
  37591. * @sample {highstock} highcharts/plotoptions/halo/
  37592. * Halo options
  37593. *
  37594. * @declare Highcharts.SeriesStatesHoverHaloOptionsObject
  37595. * @type {null|*}
  37596. * @since 4.0
  37597. * @product highcharts highstock
  37598. */
  37599. halo: {
  37600. /**
  37601. * A collection of SVG attributes to override the appearance
  37602. * of the halo, for example `fill`, `stroke` and
  37603. * `stroke-width`.
  37604. *
  37605. * @type {Highcharts.SVGAttributes}
  37606. * @since 4.0
  37607. * @product highcharts highstock
  37608. * @apioption plotOptions.series.states.hover.halo.attributes
  37609. */
  37610. /**
  37611. * The pixel size of the halo. For point markers this is the
  37612. * radius of the halo. For pie slices it is the width of the
  37613. * halo outside the slice. For bubbles it defaults to 5 and
  37614. * is the width of the halo outside the bubble.
  37615. *
  37616. * @since 4.0
  37617. * @product highcharts highstock
  37618. */
  37619. size: 10,
  37620. /**
  37621. * Opacity for the halo unless a specific fill is overridden
  37622. * using the `attributes` setting. Note that Highcharts is
  37623. * only able to apply opacity to colors of hex or rgb(a)
  37624. * formats.
  37625. *
  37626. * @since 4.0
  37627. * @product highcharts highstock
  37628. */
  37629. opacity: 0.25
  37630. }
  37631. },
  37632. /**
  37633. * Specific options for point in selected states, after being
  37634. * selected by
  37635. * [allowPointSelect](#plotOptions.series.allowPointSelect)
  37636. * or programmatically.
  37637. *
  37638. * @sample maps/plotoptions/series-allowpointselect/
  37639. * Allow point select demo
  37640. *
  37641. * @declare Highcharts.SeriesStatesSelectOptionsObject
  37642. * @extends plotOptions.series.states.hover
  37643. * @excluding brightness
  37644. */
  37645. select: {
  37646. animation: {
  37647. /** @internal */
  37648. duration: 0
  37649. }
  37650. },
  37651. /**
  37652. * The opposite state of a hover for series.
  37653. *
  37654. * @sample highcharts/plotoptions/series-states-inactive-disabled
  37655. * Disabled inactive state
  37656. *
  37657. * @declare Highcharts.SeriesStatesInactiveOptionsObject
  37658. */
  37659. inactive: {
  37660. /**
  37661. * Enable or disable the inactive state for a series
  37662. *
  37663. * @sample highcharts/plotoptions/series-states-inactive-disabled
  37664. * Disabled inactive state
  37665. *
  37666. * @type {boolean}
  37667. * @default true
  37668. * @apioption plotOptions.series.states.inactive.enabled
  37669. */
  37670. /**
  37671. * The animation for entering the inactive state.
  37672. *
  37673. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  37674. */
  37675. animation: {
  37676. /** @internal */
  37677. duration: 50
  37678. },
  37679. /**
  37680. * Opacity of series elements (dataLabels, line, area).
  37681. *
  37682. * @type {number}
  37683. */
  37684. opacity: 0.2
  37685. }
  37686. },
  37687. /**
  37688. * Sticky tracking of mouse events. When true, the `mouseOut` event on a
  37689. * series isn't triggered until the mouse moves over another series, or
  37690. * out of the plot area. When false, the `mouseOut` event on a series is
  37691. * triggered when the mouse leaves the area around the series' graph or
  37692. * markers. This also implies the tooltip when not shared. When
  37693. * `stickyTracking` is false and `tooltip.shared` is false, the tooltip
  37694. * will be hidden when moving the mouse between series. Defaults to true
  37695. * for line and area type series, but to false for columns, pies etc.
  37696. *
  37697. * **Note:** The boost module will force this option because of
  37698. * technical limitations.
  37699. *
  37700. * @sample {highcharts} highcharts/plotoptions/series-stickytracking-true/
  37701. * True by default
  37702. * @sample {highcharts} highcharts/plotoptions/series-stickytracking-false/
  37703. * False
  37704. *
  37705. * @default {highcharts} true
  37706. * @default {highstock} true
  37707. * @default {highmaps} false
  37708. * @since 2.0
  37709. *
  37710. * @private
  37711. */
  37712. stickyTracking: true,
  37713. /**
  37714. * A configuration object for the tooltip rendering of each single
  37715. * series. Properties are inherited from [tooltip](#tooltip), but only
  37716. * the following properties can be defined on a series level.
  37717. *
  37718. * @declare Highcharts.SeriesTooltipOptionsObject
  37719. * @since 2.3
  37720. * @extends tooltip
  37721. * @excluding animation, backgroundColor, borderColor, borderRadius,
  37722. * borderWidth, className, crosshairs, enabled, formatter,
  37723. * headerShape, hideDelay, outside, padding, positioner,
  37724. * shadow, shape, shared, snap, split, stickOnContact,
  37725. * style, useHTML
  37726. * @apioption plotOptions.series.tooltip
  37727. */
  37728. /**
  37729. * When a series contains a data array that is longer than this, only
  37730. * one dimensional arrays of numbers, or two dimensional arrays with
  37731. * x and y values are allowed. Also, only the first point is tested,
  37732. * and the rest are assumed to be the same format. This saves expensive
  37733. * data checking and indexing in long series. Set it to `0` disable.
  37734. *
  37735. * Note:
  37736. * In boost mode turbo threshold is forced. Only array of numbers or
  37737. * two dimensional arrays are allowed.
  37738. *
  37739. * @since 2.2
  37740. * @product highcharts highstock gantt
  37741. *
  37742. * @private
  37743. */
  37744. turboThreshold: 1000,
  37745. /**
  37746. * An array defining zones within a series. Zones can be applied to the
  37747. * X axis, Y axis or Z axis for bubbles, according to the `zoneAxis`
  37748. * option. The zone definitions have to be in ascending order regarding
  37749. * to the value.
  37750. *
  37751. * In styled mode, the color zones are styled with the
  37752. * `.highcharts-zone-{n}` class, or custom classed from the `className`
  37753. * option
  37754. * ([view live demo](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/color-zones/)).
  37755. *
  37756. * @see [zoneAxis](#plotOptions.series.zoneAxis)
  37757. *
  37758. * @sample {highcharts} highcharts/series/color-zones-simple/
  37759. * Color zones
  37760. * @sample {highstock} highcharts/series/color-zones-simple/
  37761. * Color zones
  37762. *
  37763. * @declare Highcharts.SeriesZonesOptionsObject
  37764. * @type {Array<*>}
  37765. * @since 4.1.0
  37766. * @product highcharts highstock
  37767. * @apioption plotOptions.series.zones
  37768. */
  37769. /**
  37770. * Styled mode only. A custom class name for the zone.
  37771. *
  37772. * @sample highcharts/css/color-zones/
  37773. * Zones styled by class name
  37774. *
  37775. * @type {string}
  37776. * @since 5.0.0
  37777. * @apioption plotOptions.series.zones.className
  37778. */
  37779. /**
  37780. * Defines the color of the series.
  37781. *
  37782. * @see [series color](#plotOptions.series.color)
  37783. *
  37784. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  37785. * @since 4.1.0
  37786. * @product highcharts highstock
  37787. * @apioption plotOptions.series.zones.color
  37788. */
  37789. /**
  37790. * A name for the dash style to use for the graph.
  37791. *
  37792. * @see [plotOptions.series.dashStyle](#plotOptions.series.dashStyle)
  37793. *
  37794. * @sample {highcharts|highstock} highcharts/series/color-zones-dashstyle-dot/
  37795. * Dashed line indicates prognosis
  37796. *
  37797. * @type {Highcharts.DashStyleValue}
  37798. * @since 4.1.0
  37799. * @product highcharts highstock
  37800. * @apioption plotOptions.series.zones.dashStyle
  37801. */
  37802. /**
  37803. * Defines the fill color for the series (in area type series)
  37804. *
  37805. * @see [fillColor](#plotOptions.area.fillColor)
  37806. *
  37807. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  37808. * @since 4.1.0
  37809. * @product highcharts highstock
  37810. * @apioption plotOptions.series.zones.fillColor
  37811. */
  37812. /**
  37813. * The value up to where the zone extends, if undefined the zones
  37814. * stretches to the last value in the series.
  37815. *
  37816. * @type {number}
  37817. * @since 4.1.0
  37818. * @product highcharts highstock
  37819. * @apioption plotOptions.series.zones.value
  37820. */
  37821. /**
  37822. * When using dual or multiple color axes, this number defines which
  37823. * colorAxis the particular series is connected to. It refers to
  37824. * either the
  37825. * {@link #colorAxis.id|axis id}
  37826. * or the index of the axis in the colorAxis array, with 0 being the
  37827. * first. Set this option to false to prevent a series from connecting
  37828. * to the default color axis.
  37829. *
  37830. * Since v7.2.0 the option can also be an axis id or an axis index
  37831. * instead of a boolean flag.
  37832. *
  37833. * @sample highcharts/coloraxis/coloraxis-with-pie/
  37834. * Color axis with pie series
  37835. * @sample highcharts/coloraxis/multiple-coloraxis/
  37836. * Multiple color axis
  37837. *
  37838. * @type {number|string|boolean}
  37839. * @default 0
  37840. * @product highcharts highstock highmaps
  37841. * @apioption plotOptions.series.colorAxis
  37842. */
  37843. /**
  37844. * Determines what data value should be used to calculate point color
  37845. * if `colorAxis` is used. Requires to set `min` and `max` if some
  37846. * custom point property is used or if approximation for data grouping
  37847. * is set to `'sum'`.
  37848. *
  37849. * @sample highcharts/coloraxis/custom-color-key/
  37850. * Custom color key
  37851. * @sample highcharts/coloraxis/changed-default-color-key/
  37852. * Changed default color key
  37853. *
  37854. * @type {string}
  37855. * @default y
  37856. * @since 7.2.0
  37857. * @product highcharts highstock highmaps
  37858. * @apioption plotOptions.series.colorKey
  37859. */
  37860. /**
  37861. * Determines whether the series should look for the nearest point
  37862. * in both dimensions or just the x-dimension when hovering the series.
  37863. * Defaults to `'xy'` for scatter series and `'x'` for most other
  37864. * series. If the data has duplicate x-values, it is recommended to
  37865. * set this to `'xy'` to allow hovering over all points.
  37866. *
  37867. * Applies only to series types using nearest neighbor search (not
  37868. * direct hover) for tooltip.
  37869. *
  37870. * @sample {highcharts} highcharts/series/findnearestpointby/
  37871. * Different hover behaviors
  37872. * @sample {highstock} highcharts/series/findnearestpointby/
  37873. * Different hover behaviors
  37874. * @sample {highmaps} highcharts/series/findnearestpointby/
  37875. * Different hover behaviors
  37876. *
  37877. * @since 5.0.10
  37878. * @validvalue ["x", "xy"]
  37879. *
  37880. * @private
  37881. */
  37882. findNearestPointBy: 'x'
  37883. };
  37884. return Series;
  37885. }());
  37886. extend(Series.prototype, {
  37887. axisTypes: ['xAxis', 'yAxis'],
  37888. coll: 'series',
  37889. colorCounter: 0,
  37890. cropShoulder: 1,
  37891. directTouch: false,
  37892. drawLegendSymbol: LegendSymbolMixin.drawLineMarker,
  37893. isCartesian: true,
  37894. kdAxisArray: ['clientX', 'plotY'],
  37895. // each point's x and y values are stored in this.xData and this.yData:
  37896. parallelArrays: ['x', 'y'],
  37897. pointClass: Point,
  37898. requireSorting: true,
  37899. // requires the data to be sorted:
  37900. sorted: true
  37901. });
  37902. /* *
  37903. *
  37904. * Registry
  37905. *
  37906. * */
  37907. SeriesRegistry.series = Series;
  37908. /* *
  37909. *
  37910. * Default Export
  37911. *
  37912. * */
  37913. /* *
  37914. *
  37915. * API Declarations
  37916. *
  37917. * */
  37918. /**
  37919. * This is a placeholder type of the possible series options for
  37920. * [Highcharts](../highcharts/series), [Highstock](../highstock/series),
  37921. * [Highmaps](../highmaps/series), and [Gantt](../gantt/series).
  37922. *
  37923. * In TypeScript is this dynamically generated to reference all possible types
  37924. * of series options.
  37925. *
  37926. * @ignore-declaration
  37927. * @typedef {Highcharts.SeriesOptions|Highcharts.Dictionary<*>} Highcharts.SeriesOptionsType
  37928. */
  37929. /**
  37930. * Options for `dataSorting`.
  37931. *
  37932. * @interface Highcharts.DataSortingOptionsObject
  37933. * @since 8.0.0
  37934. */ /**
  37935. * Enable or disable data sorting for the series.
  37936. * @name Highcharts.DataSortingOptionsObject#enabled
  37937. * @type {boolean|undefined}
  37938. */ /**
  37939. * Whether to allow matching points by name in an update.
  37940. * @name Highcharts.DataSortingOptionsObject#matchByName
  37941. * @type {boolean|undefined}
  37942. */ /**
  37943. * Determines what data value should be used to sort by.
  37944. * @name Highcharts.DataSortingOptionsObject#sortKey
  37945. * @type {string|undefined}
  37946. */
  37947. /**
  37948. * Function callback when a series has been animated.
  37949. *
  37950. * @callback Highcharts.SeriesAfterAnimateCallbackFunction
  37951. *
  37952. * @param {Highcharts.Series} this
  37953. * The series where the event occured.
  37954. *
  37955. * @param {Highcharts.SeriesAfterAnimateEventObject} event
  37956. * Event arguments.
  37957. */
  37958. /**
  37959. * Event information regarding completed animation of a series.
  37960. *
  37961. * @interface Highcharts.SeriesAfterAnimateEventObject
  37962. */ /**
  37963. * Animated series.
  37964. * @name Highcharts.SeriesAfterAnimateEventObject#target
  37965. * @type {Highcharts.Series}
  37966. */ /**
  37967. * Event type.
  37968. * @name Highcharts.SeriesAfterAnimateEventObject#type
  37969. * @type {"afterAnimate"}
  37970. */
  37971. /**
  37972. * Function callback when the checkbox next to the series' name in the legend is
  37973. * clicked.
  37974. *
  37975. * @callback Highcharts.SeriesCheckboxClickCallbackFunction
  37976. *
  37977. * @param {Highcharts.Series} this
  37978. * The series where the event occured.
  37979. *
  37980. * @param {Highcharts.SeriesCheckboxClickEventObject} event
  37981. * Event arguments.
  37982. */
  37983. /**
  37984. * Event information regarding check of a series box.
  37985. *
  37986. * @interface Highcharts.SeriesCheckboxClickEventObject
  37987. */ /**
  37988. * Whether the box has been checked.
  37989. * @name Highcharts.SeriesCheckboxClickEventObject#checked
  37990. * @type {boolean}
  37991. */ /**
  37992. * Related series.
  37993. * @name Highcharts.SeriesCheckboxClickEventObject#item
  37994. * @type {Highcharts.Series}
  37995. */ /**
  37996. * Related series.
  37997. * @name Highcharts.SeriesCheckboxClickEventObject#target
  37998. * @type {Highcharts.Series}
  37999. */ /**
  38000. * Event type.
  38001. * @name Highcharts.SeriesCheckboxClickEventObject#type
  38002. * @type {"checkboxClick"}
  38003. */
  38004. /**
  38005. * Function callback when a series is clicked. Return false to cancel toogle
  38006. * actions.
  38007. *
  38008. * @callback Highcharts.SeriesClickCallbackFunction
  38009. *
  38010. * @param {Highcharts.Series} this
  38011. * The series where the event occured.
  38012. *
  38013. * @param {Highcharts.SeriesClickEventObject} event
  38014. * Event arguments.
  38015. */
  38016. /**
  38017. * Common information for a click event on a series.
  38018. *
  38019. * @interface Highcharts.SeriesClickEventObject
  38020. * @extends global.Event
  38021. */ /**
  38022. * Nearest point on the graph.
  38023. * @name Highcharts.SeriesClickEventObject#point
  38024. * @type {Highcharts.Point}
  38025. */
  38026. /**
  38027. * Gets fired when the series is hidden after chart generation time, either by
  38028. * clicking the legend item or by calling `.hide()`.
  38029. *
  38030. * @callback Highcharts.SeriesHideCallbackFunction
  38031. *
  38032. * @param {Highcharts.Series} this
  38033. * The series where the event occured.
  38034. *
  38035. * @param {global.Event} event
  38036. * The event that occured.
  38037. */
  38038. /**
  38039. * The SVG value used for the `stroke-linecap` and `stroke-linejoin` of a line
  38040. * graph.
  38041. *
  38042. * @typedef {"butt"|"round"|"square"|string} Highcharts.SeriesLinecapValue
  38043. */
  38044. /**
  38045. * Gets fired when the legend item belonging to the series is clicked. The
  38046. * default action is to toggle the visibility of the series. This can be
  38047. * prevented by returning `false` or calling `event.preventDefault()`.
  38048. *
  38049. * @callback Highcharts.SeriesLegendItemClickCallbackFunction
  38050. *
  38051. * @param {Highcharts.Series} this
  38052. * The series where the event occured.
  38053. *
  38054. * @param {Highcharts.SeriesLegendItemClickEventObject} event
  38055. * The event that occured.
  38056. */
  38057. /**
  38058. * Information about the event.
  38059. *
  38060. * @interface Highcharts.SeriesLegendItemClickEventObject
  38061. */ /**
  38062. * Related browser event.
  38063. * @name Highcharts.SeriesLegendItemClickEventObject#browserEvent
  38064. * @type {global.PointerEvent}
  38065. */ /**
  38066. * Prevent the default action of toggle the visibility of the series.
  38067. * @name Highcharts.SeriesLegendItemClickEventObject#preventDefault
  38068. * @type {Function}
  38069. */ /**
  38070. * Related series.
  38071. * @name Highcharts.SeriesCheckboxClickEventObject#target
  38072. * @type {Highcharts.Series}
  38073. */ /**
  38074. * Event type.
  38075. * @name Highcharts.SeriesCheckboxClickEventObject#type
  38076. * @type {"checkboxClick"}
  38077. */
  38078. /**
  38079. * Gets fired when the mouse leaves the graph.
  38080. *
  38081. * @callback Highcharts.SeriesMouseOutCallbackFunction
  38082. *
  38083. * @param {Highcharts.Series} this
  38084. * Series where the event occured.
  38085. *
  38086. * @param {global.PointerEvent} event
  38087. * Event that occured.
  38088. */
  38089. /**
  38090. * Gets fired when the mouse enters the graph.
  38091. *
  38092. * @callback Highcharts.SeriesMouseOverCallbackFunction
  38093. *
  38094. * @param {Highcharts.Series} this
  38095. * Series where the event occured.
  38096. *
  38097. * @param {global.PointerEvent} event
  38098. * Event that occured.
  38099. */
  38100. /**
  38101. * Translation and scale for the plot area of a series.
  38102. *
  38103. * @interface Highcharts.SeriesPlotBoxObject
  38104. */ /**
  38105. * @name Highcharts.SeriesPlotBoxObject#scaleX
  38106. * @type {number}
  38107. */ /**
  38108. * @name Highcharts.SeriesPlotBoxObject#scaleY
  38109. * @type {number}
  38110. */ /**
  38111. * @name Highcharts.SeriesPlotBoxObject#translateX
  38112. * @type {number}
  38113. */ /**
  38114. * @name Highcharts.SeriesPlotBoxObject#translateY
  38115. * @type {number}
  38116. */
  38117. /**
  38118. * Gets fired when the series is shown after chart generation time, either by
  38119. * clicking the legend item or by calling `.show()`.
  38120. *
  38121. * @callback Highcharts.SeriesShowCallbackFunction
  38122. *
  38123. * @param {Highcharts.Series} this
  38124. * Series where the event occured.
  38125. *
  38126. * @param {global.Event} event
  38127. * Event that occured.
  38128. */
  38129. /**
  38130. * Possible key values for the series state options.
  38131. *
  38132. * @typedef {"hover"|"inactive"|"normal"|"select"} Highcharts.SeriesStateValue
  38133. */
  38134. ''; // detach doclets above
  38135. /* *
  38136. *
  38137. * API Options
  38138. *
  38139. * */
  38140. /**
  38141. * Series options for specific data and the data itself. In TypeScript you
  38142. * have to cast the series options to specific series types, to get all
  38143. * possible options for a series.
  38144. *
  38145. * @example
  38146. * // TypeScript example
  38147. * Highcharts.chart('container', {
  38148. * series: [{
  38149. * color: '#06C',
  38150. * data: [[0, 1], [2, 3]]
  38151. * } as Highcharts.SeriesLineOptions ]
  38152. * });
  38153. *
  38154. * @type {Array<*>}
  38155. * @apioption series
  38156. */
  38157. /**
  38158. * An id for the series. This can be used after render time to get a pointer
  38159. * to the series object through `chart.get()`.
  38160. *
  38161. * @sample {highcharts} highcharts/plotoptions/series-id/
  38162. * Get series by id
  38163. *
  38164. * @type {string}
  38165. * @since 1.2.0
  38166. * @apioption series.id
  38167. */
  38168. /**
  38169. * The index of the series in the chart, affecting the internal index in the
  38170. * `chart.series` array, the visible Z index as well as the order in the
  38171. * legend.
  38172. *
  38173. * @type {number}
  38174. * @since 2.3.0
  38175. * @apioption series.index
  38176. */
  38177. /**
  38178. * The sequential index of the series in the legend.
  38179. *
  38180. * @see [legend.reversed](#legend.reversed),
  38181. * [yAxis.reversedStacks](#yAxis.reversedStacks)
  38182. *
  38183. * @sample {highcharts|highstock} highcharts/series/legendindex/
  38184. * Legend in opposite order
  38185. *
  38186. * @type {number}
  38187. * @apioption series.legendIndex
  38188. */
  38189. /**
  38190. * The name of the series as shown in the legend, tooltip etc.
  38191. *
  38192. * @sample {highcharts} highcharts/series/name/
  38193. * Series name
  38194. * @sample {highmaps} maps/demo/category-map/
  38195. * Series name
  38196. *
  38197. * @type {string}
  38198. * @apioption series.name
  38199. */
  38200. /**
  38201. * This option allows grouping series in a stacked chart. The stack option
  38202. * can be a string or anything else, as long as the grouped series' stack
  38203. * options match each other after conversion into a string.
  38204. *
  38205. * @sample {highcharts} highcharts/series/stack/
  38206. * Stacked and grouped columns
  38207. *
  38208. * @type {number|string}
  38209. * @since 2.1
  38210. * @product highcharts highstock
  38211. * @apioption series.stack
  38212. */
  38213. /**
  38214. * The type of series, for example `line` or `column`. By default, the
  38215. * series type is inherited from [chart.type](#chart.type), so unless the
  38216. * chart is a combination of series types, there is no need to set it on the
  38217. * series level.
  38218. *
  38219. * @sample {highcharts} highcharts/series/type/
  38220. * Line and column in the same chart
  38221. * @sample highcharts/series/type-dynamic/
  38222. * Dynamic types with button selector
  38223. * @sample {highmaps} maps/demo/mapline-mappoint/
  38224. * Multiple types in the same map
  38225. *
  38226. * @type {string}
  38227. * @apioption series.type
  38228. */
  38229. /**
  38230. * When using dual or multiple x axes, this number defines which xAxis the
  38231. * particular series is connected to. It refers to either the
  38232. * {@link #xAxis.id|axis id}
  38233. * or the index of the axis in the xAxis array, with 0 being the first.
  38234. *
  38235. * @type {number|string}
  38236. * @default 0
  38237. * @product highcharts highstock
  38238. * @apioption series.xAxis
  38239. */
  38240. /**
  38241. * When using dual or multiple y axes, this number defines which yAxis the
  38242. * particular series is connected to. It refers to either the
  38243. * {@link #yAxis.id|axis id}
  38244. * or the index of the axis in the yAxis array, with 0 being the first.
  38245. *
  38246. * @sample {highcharts} highcharts/series/yaxis/
  38247. * Apply the column series to the secondary Y axis
  38248. *
  38249. * @type {number|string}
  38250. * @default 0
  38251. * @product highcharts highstock
  38252. * @apioption series.yAxis
  38253. */
  38254. /**
  38255. * Define the visual z index of the series.
  38256. *
  38257. * @sample {highcharts} highcharts/plotoptions/series-zindex-default/
  38258. * With no z index, the series defined last are on top
  38259. * @sample {highcharts} highcharts/plotoptions/series-zindex/
  38260. * With a z index, the series with the highest z index is on top
  38261. * @sample {highstock} highcharts/plotoptions/series-zindex-default/
  38262. * With no z index, the series defined last are on top
  38263. * @sample {highstock} highcharts/plotoptions/series-zindex/
  38264. * With a z index, the series with the highest z index is on top
  38265. *
  38266. * @type {number}
  38267. * @product highcharts highstock
  38268. * @apioption series.zIndex
  38269. */
  38270. ''; // include precedent doclets in transpilat
  38271. return Series;
  38272. });
  38273. _registerModule(_modules, 'Extensions/ScrollablePlotArea.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Axis/Axis.js'], _modules['Core/Chart/Chart.js'], _modules['Core/Series/Series.js'], _modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (A, Axis, Chart, Series, H, U) {
  38274. /* *
  38275. *
  38276. * (c) 2010-2021 Torstein Honsi
  38277. *
  38278. * License: www.highcharts.com/license
  38279. *
  38280. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  38281. *
  38282. * Highcharts feature to make the Y axis stay fixed when scrolling the chart
  38283. * horizontally on mobile devices. Supports left and right side axes.
  38284. */
  38285. /*
  38286. WIP on vertical scrollable plot area (#9378). To do:
  38287. - Bottom axis positioning
  38288. - Test with Gantt
  38289. - Look for size optimizing the code
  38290. - API and demos
  38291. */
  38292. var stop = A.stop;
  38293. var addEvent = U.addEvent,
  38294. createElement = U.createElement,
  38295. merge = U.merge,
  38296. pick = U.pick;
  38297. /**
  38298. * Options for a scrollable plot area. This feature provides a minimum size for
  38299. * the plot area of the chart. If the size gets smaller than this, typically
  38300. * on mobile devices, a native browser scrollbar is presented. This scrollbar
  38301. * provides smooth scrolling for the contents of the plot area, whereas the
  38302. * title, legend and unaffected axes are fixed.
  38303. *
  38304. * Since v7.1.2, a scrollable plot area can be defined for either horizontal or
  38305. * vertical scrolling, depending on whether the `minWidth` or `minHeight`
  38306. * option is set.
  38307. *
  38308. * @sample highcharts/chart/scrollable-plotarea
  38309. * Scrollable plot area
  38310. * @sample highcharts/chart/scrollable-plotarea-vertical
  38311. * Vertically scrollable plot area
  38312. * @sample {gantt} highcharts/chart/scrollable-plotarea-vertical
  38313. * Gantt chart with vertically scrollable plot area
  38314. *
  38315. * @since 6.1.0
  38316. * @product highcharts gantt
  38317. * @apioption chart.scrollablePlotArea
  38318. */
  38319. /**
  38320. * The minimum height for the plot area. If it gets smaller than this, the plot
  38321. * area will become scrollable.
  38322. *
  38323. * @type {number}
  38324. * @apioption chart.scrollablePlotArea.minHeight
  38325. */
  38326. /**
  38327. * The minimum width for the plot area. If it gets smaller than this, the plot
  38328. * area will become scrollable.
  38329. *
  38330. * @type {number}
  38331. * @apioption chart.scrollablePlotArea.minWidth
  38332. */
  38333. /**
  38334. * The initial scrolling position of the scrollable plot area. Ranges from 0 to
  38335. * 1, where 0 aligns the plot area to the left and 1 aligns it to the right.
  38336. * Typically we would use 1 if the chart has right aligned Y axes.
  38337. *
  38338. * @type {number}
  38339. * @apioption chart.scrollablePlotArea.scrollPositionX
  38340. */
  38341. /**
  38342. * The initial scrolling position of the scrollable plot area. Ranges from 0 to
  38343. * 1, where 0 aligns the plot area to the top and 1 aligns it to the bottom.
  38344. *
  38345. * @type {number}
  38346. * @apioption chart.scrollablePlotArea.scrollPositionY
  38347. */
  38348. /**
  38349. * The opacity of mask applied on one of the sides of the plot
  38350. * area.
  38351. *
  38352. * @sample {highcharts} highcharts/chart/scrollable-plotarea-opacity
  38353. * Disabled opacity for the mask
  38354. *
  38355. * @type {number}
  38356. * @default 0.85
  38357. * @since 7.1.1
  38358. * @apioption chart.scrollablePlotArea.opacity
  38359. */
  38360. ''; // detach API doclets
  38361. /* eslint-disable no-invalid-this, valid-jsdoc */
  38362. addEvent(Chart, 'afterSetChartSize', function (e) {
  38363. var scrollablePlotArea = this.options.chart.scrollablePlotArea,
  38364. scrollableMinWidth = scrollablePlotArea && scrollablePlotArea.minWidth,
  38365. scrollableMinHeight = scrollablePlotArea && scrollablePlotArea.minHeight,
  38366. scrollablePixelsX,
  38367. scrollablePixelsY,
  38368. corrections;
  38369. if (!this.renderer.forExport) {
  38370. // The amount of pixels to scroll, the difference between chart
  38371. // width and scrollable width
  38372. if (scrollableMinWidth) {
  38373. this.scrollablePixelsX = scrollablePixelsX = Math.max(0, scrollableMinWidth - this.chartWidth);
  38374. if (scrollablePixelsX) {
  38375. this.scrollablePlotBox = merge(this.plotBox);
  38376. this.plotWidth += scrollablePixelsX;
  38377. if (this.inverted) {
  38378. this.clipBox.height += scrollablePixelsX;
  38379. this.plotBox.height += scrollablePixelsX;
  38380. }
  38381. else {
  38382. this.clipBox.width += scrollablePixelsX;
  38383. this.plotBox.width += scrollablePixelsX;
  38384. }
  38385. corrections = {
  38386. // Corrections for right side
  38387. 1: { name: 'right', value: scrollablePixelsX }
  38388. };
  38389. }
  38390. // Currently we can only do either X or Y
  38391. }
  38392. else if (scrollableMinHeight) {
  38393. this.scrollablePixelsY = scrollablePixelsY = Math.max(0, scrollableMinHeight - this.chartHeight);
  38394. if (scrollablePixelsY) {
  38395. this.scrollablePlotBox = merge(this.plotBox);
  38396. this.plotHeight += scrollablePixelsY;
  38397. if (this.inverted) {
  38398. this.clipBox.width += scrollablePixelsY;
  38399. this.plotBox.width += scrollablePixelsY;
  38400. }
  38401. else {
  38402. this.clipBox.height += scrollablePixelsY;
  38403. this.plotBox.height += scrollablePixelsY;
  38404. }
  38405. corrections = {
  38406. 2: { name: 'bottom', value: scrollablePixelsY }
  38407. };
  38408. }
  38409. }
  38410. if (corrections && !e.skipAxes) {
  38411. this.axes.forEach(function (axis) {
  38412. // For right and bottom axes, only fix the plot line length
  38413. if (corrections[axis.side]) {
  38414. // Get the plot lines right in getPlotLinePath,
  38415. // temporarily set it to the adjusted plot width.
  38416. axis.getPlotLinePath = function () {
  38417. var marginName = corrections[axis.side].name,
  38418. correctionValue = corrections[axis.side].value,
  38419. // axis.right or axis.bottom
  38420. margin = this[marginName],
  38421. path;
  38422. // Temporarily adjust
  38423. this[marginName] = margin - correctionValue;
  38424. path = H.Axis.prototype.getPlotLinePath.apply(this, arguments);
  38425. // Reset
  38426. this[marginName] = margin;
  38427. return path;
  38428. };
  38429. }
  38430. else {
  38431. // Apply the corrected plotWidth
  38432. axis.setAxisSize();
  38433. axis.setAxisTranslation();
  38434. }
  38435. });
  38436. }
  38437. }
  38438. });
  38439. addEvent(Chart, 'render', function () {
  38440. if (this.scrollablePixelsX || this.scrollablePixelsY) {
  38441. if (this.setUpScrolling) {
  38442. this.setUpScrolling();
  38443. }
  38444. this.applyFixed();
  38445. }
  38446. else if (this.fixedDiv) { // Has been in scrollable mode
  38447. this.applyFixed();
  38448. }
  38449. });
  38450. /**
  38451. * @private
  38452. * @function Highcharts.Chart#setUpScrolling
  38453. * @return {void}
  38454. */
  38455. Chart.prototype.setUpScrolling = function () {
  38456. var _this = this;
  38457. var attribs = {
  38458. WebkitOverflowScrolling: 'touch',
  38459. overflowX: 'hidden',
  38460. overflowY: 'hidden'
  38461. };
  38462. if (this.scrollablePixelsX) {
  38463. attribs.overflowX = 'auto';
  38464. }
  38465. if (this.scrollablePixelsY) {
  38466. attribs.overflowY = 'auto';
  38467. }
  38468. // Insert a container with position relative
  38469. // that scrolling and fixed container renders to (#10555)
  38470. this.scrollingParent = createElement('div', {
  38471. className: 'highcharts-scrolling-parent'
  38472. }, {
  38473. position: 'relative'
  38474. }, this.renderTo);
  38475. // Add the necessary divs to provide scrolling
  38476. this.scrollingContainer = createElement('div', {
  38477. 'className': 'highcharts-scrolling'
  38478. }, attribs, this.scrollingParent);
  38479. // On scroll, reset the chart position because it applies to the scrolled
  38480. // container
  38481. addEvent(this.scrollingContainer, 'scroll', function () {
  38482. if (_this.pointer) {
  38483. delete _this.pointer.chartPosition;
  38484. }
  38485. });
  38486. this.innerContainer = createElement('div', {
  38487. 'className': 'highcharts-inner-container'
  38488. }, null, this.scrollingContainer);
  38489. // Now move the container inside
  38490. this.innerContainer.appendChild(this.container);
  38491. // Don't run again
  38492. this.setUpScrolling = null;
  38493. };
  38494. /**
  38495. * These elements are moved over to the fixed renderer and stay fixed when the
  38496. * user scrolls the chart
  38497. * @private
  38498. */
  38499. Chart.prototype.moveFixedElements = function () {
  38500. var container = this.container,
  38501. fixedRenderer = this.fixedRenderer,
  38502. fixedSelectors = [
  38503. '.highcharts-contextbutton',
  38504. '.highcharts-credits',
  38505. '.highcharts-legend',
  38506. '.highcharts-legend-checkbox',
  38507. '.highcharts-navigator-series',
  38508. '.highcharts-navigator-xaxis',
  38509. '.highcharts-navigator-yaxis',
  38510. '.highcharts-navigator',
  38511. '.highcharts-reset-zoom',
  38512. '.highcharts-scrollbar',
  38513. '.highcharts-subtitle',
  38514. '.highcharts-title'
  38515. ],
  38516. axisClass;
  38517. if (this.scrollablePixelsX && !this.inverted) {
  38518. axisClass = '.highcharts-yaxis';
  38519. }
  38520. else if (this.scrollablePixelsX && this.inverted) {
  38521. axisClass = '.highcharts-xaxis';
  38522. }
  38523. else if (this.scrollablePixelsY && !this.inverted) {
  38524. axisClass = '.highcharts-xaxis';
  38525. }
  38526. else if (this.scrollablePixelsY && this.inverted) {
  38527. axisClass = '.highcharts-yaxis';
  38528. }
  38529. if (axisClass) {
  38530. fixedSelectors.push(axisClass + ":not(.highcharts-radial-axis)", axisClass + "-labels:not(.highcharts-radial-axis-labels)");
  38531. }
  38532. fixedSelectors.forEach(function (className) {
  38533. [].forEach.call(container.querySelectorAll(className), function (elem) {
  38534. (elem.namespaceURI === fixedRenderer.SVG_NS ?
  38535. fixedRenderer.box :
  38536. fixedRenderer.box.parentNode).appendChild(elem);
  38537. elem.style.pointerEvents = 'auto';
  38538. });
  38539. });
  38540. };
  38541. /**
  38542. * @private
  38543. * @function Highcharts.Chart#applyFixed
  38544. * @return {void}
  38545. */
  38546. Chart.prototype.applyFixed = function () {
  38547. var _this = this;
  38548. var _a,
  38549. _b,
  38550. _c;
  38551. var fixedRenderer,
  38552. scrollableWidth,
  38553. scrollableHeight,
  38554. firstTime = !this.fixedDiv,
  38555. chartOptions = this.options.chart,
  38556. scrollableOptions = chartOptions.scrollablePlotArea;
  38557. // First render
  38558. if (firstTime) {
  38559. this.fixedDiv = createElement('div', {
  38560. className: 'highcharts-fixed'
  38561. }, {
  38562. position: 'absolute',
  38563. overflow: 'hidden',
  38564. pointerEvents: 'none',
  38565. zIndex: (((_a = chartOptions.style) === null || _a === void 0 ? void 0 : _a.zIndex) || 0) + 2,
  38566. top: 0
  38567. }, null, true);
  38568. (_b = this.scrollingContainer) === null || _b === void 0 ? void 0 : _b.parentNode.insertBefore(this.fixedDiv, this.scrollingContainer);
  38569. this.renderTo.style.overflow = 'visible';
  38570. this.fixedRenderer = fixedRenderer = new H.Renderer(this.fixedDiv, this.chartWidth, this.chartHeight, (_c = this.options.chart) === null || _c === void 0 ? void 0 : _c.style);
  38571. // Mask
  38572. this.scrollableMask = fixedRenderer
  38573. .path()
  38574. .attr({
  38575. fill: this.options.chart.backgroundColor || '#fff',
  38576. 'fill-opacity': pick(scrollableOptions.opacity, 0.85),
  38577. zIndex: -1
  38578. })
  38579. .addClass('highcharts-scrollable-mask')
  38580. .add();
  38581. addEvent(this, 'afterShowResetZoom', this.moveFixedElements);
  38582. addEvent(this, 'afterLayOutTitles', this.moveFixedElements);
  38583. addEvent(Axis, 'afterInit', function () {
  38584. _this.scrollableDirty = true;
  38585. });
  38586. addEvent(Series, 'show', function () {
  38587. _this.scrollableDirty = true;
  38588. });
  38589. }
  38590. else {
  38591. // Set the size of the fixed renderer to the visible width
  38592. this.fixedRenderer.setSize(this.chartWidth, this.chartHeight);
  38593. }
  38594. if (this.scrollableDirty || firstTime) {
  38595. this.scrollableDirty = false;
  38596. this.moveFixedElements();
  38597. }
  38598. // Increase the size of the scrollable renderer and background
  38599. scrollableWidth = this.chartWidth + (this.scrollablePixelsX || 0);
  38600. scrollableHeight = this.chartHeight + (this.scrollablePixelsY || 0);
  38601. stop(this.container);
  38602. this.container.style.width = scrollableWidth + 'px';
  38603. this.container.style.height = scrollableHeight + 'px';
  38604. this.renderer.boxWrapper.attr({
  38605. width: scrollableWidth,
  38606. height: scrollableHeight,
  38607. viewBox: [0, 0, scrollableWidth, scrollableHeight].join(' ')
  38608. });
  38609. this.chartBackground.attr({
  38610. width: scrollableWidth,
  38611. height: scrollableHeight
  38612. });
  38613. this.scrollingContainer.style.height = this.chartHeight + 'px';
  38614. // Set scroll position
  38615. if (firstTime) {
  38616. if (scrollableOptions.scrollPositionX) {
  38617. this.scrollingContainer.scrollLeft =
  38618. this.scrollablePixelsX *
  38619. scrollableOptions.scrollPositionX;
  38620. }
  38621. if (scrollableOptions.scrollPositionY) {
  38622. this.scrollingContainer.scrollTop =
  38623. this.scrollablePixelsY *
  38624. scrollableOptions.scrollPositionY;
  38625. }
  38626. }
  38627. // Mask behind the left and right side
  38628. var axisOffset = this.axisOffset,
  38629. maskTop = this.plotTop - axisOffset[0] - 1,
  38630. maskLeft = this.plotLeft - axisOffset[3] - 1,
  38631. maskBottom = this.plotTop + this.plotHeight + axisOffset[2] + 1,
  38632. maskRight = this.plotLeft + this.plotWidth + axisOffset[1] + 1,
  38633. maskPlotRight = this.plotLeft + this.plotWidth -
  38634. (this.scrollablePixelsX || 0),
  38635. maskPlotBottom = this.plotTop + this.plotHeight -
  38636. (this.scrollablePixelsY || 0),
  38637. d;
  38638. if (this.scrollablePixelsX) {
  38639. d = [
  38640. // Left side
  38641. ['M', 0, maskTop],
  38642. ['L', this.plotLeft - 1, maskTop],
  38643. ['L', this.plotLeft - 1, maskBottom],
  38644. ['L', 0, maskBottom],
  38645. ['Z'],
  38646. // Right side
  38647. ['M', maskPlotRight, maskTop],
  38648. ['L', this.chartWidth, maskTop],
  38649. ['L', this.chartWidth, maskBottom],
  38650. ['L', maskPlotRight, maskBottom],
  38651. ['Z']
  38652. ];
  38653. }
  38654. else if (this.scrollablePixelsY) {
  38655. d = [
  38656. // Top side
  38657. ['M', maskLeft, 0],
  38658. ['L', maskLeft, this.plotTop - 1],
  38659. ['L', maskRight, this.plotTop - 1],
  38660. ['L', maskRight, 0],
  38661. ['Z'],
  38662. // Bottom side
  38663. ['M', maskLeft, maskPlotBottom],
  38664. ['L', maskLeft, this.chartHeight],
  38665. ['L', maskRight, this.chartHeight],
  38666. ['L', maskRight, maskPlotBottom],
  38667. ['Z']
  38668. ];
  38669. }
  38670. else {
  38671. d = [['M', 0, 0]];
  38672. }
  38673. if (this.redrawTrigger !== 'adjustHeight') {
  38674. this.scrollableMask.attr({ d: d });
  38675. }
  38676. };
  38677. });
  38678. _registerModule(_modules, 'Core/Axis/StackingAxis.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Utilities.js']], function (A, U) {
  38679. /* *
  38680. *
  38681. * (c) 2010-2021 Torstein Honsi
  38682. *
  38683. * License: www.highcharts.com/license
  38684. *
  38685. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  38686. *
  38687. * */
  38688. var getDeferredAnimation = A.getDeferredAnimation;
  38689. var addEvent = U.addEvent,
  38690. destroyObjectProperties = U.destroyObjectProperties,
  38691. fireEvent = U.fireEvent,
  38692. objectEach = U.objectEach,
  38693. pick = U.pick;
  38694. /* eslint-disable valid-jsdoc */
  38695. /**
  38696. * Adds stacking support to axes.
  38697. * @private
  38698. * @class
  38699. */
  38700. var StackingAxisAdditions = /** @class */ (function () {
  38701. /* *
  38702. *
  38703. * Constructors
  38704. *
  38705. * */
  38706. function StackingAxisAdditions(axis) {
  38707. this.oldStacks = {};
  38708. this.stacks = {};
  38709. this.stacksTouched = 0;
  38710. this.axis = axis;
  38711. }
  38712. /* *
  38713. *
  38714. * Functions
  38715. *
  38716. * */
  38717. /**
  38718. * Build the stacks from top down
  38719. * @private
  38720. */
  38721. StackingAxisAdditions.prototype.buildStacks = function () {
  38722. var stacking = this;
  38723. var axis = stacking.axis;
  38724. var axisSeries = axis.series;
  38725. var reversedStacks = pick(axis.options.reversedStacks,
  38726. true);
  38727. var len = axisSeries.length;
  38728. var actualSeries,
  38729. i;
  38730. if (!axis.isXAxis) {
  38731. stacking.usePercentage = false;
  38732. i = len;
  38733. while (i--) {
  38734. actualSeries = axisSeries[reversedStacks ? i : len - i - 1];
  38735. actualSeries.setStackedPoints();
  38736. actualSeries.setGroupedPoints();
  38737. }
  38738. // Loop up again to compute percent and stream stack
  38739. for (i = 0; i < len; i++) {
  38740. axisSeries[i].modifyStacks();
  38741. }
  38742. fireEvent(axis, 'afterBuildStacks');
  38743. }
  38744. };
  38745. /**
  38746. * @private
  38747. */
  38748. StackingAxisAdditions.prototype.cleanStacks = function () {
  38749. var stacking = this;
  38750. var axis = stacking.axis;
  38751. var stacks;
  38752. if (!axis.isXAxis) {
  38753. if (stacking.oldStacks) {
  38754. stacks = stacking.stacks = stacking.oldStacks;
  38755. }
  38756. // reset stacks
  38757. objectEach(stacks, function (type) {
  38758. objectEach(type, function (stack) {
  38759. stack.cumulative = stack.total;
  38760. });
  38761. });
  38762. }
  38763. };
  38764. /**
  38765. * Set all the stacks to initial states and destroy unused ones.
  38766. * @private
  38767. */
  38768. StackingAxisAdditions.prototype.resetStacks = function () {
  38769. var stacking = this;
  38770. var axis = stacking.axis;
  38771. var stacks = stacking.stacks;
  38772. if (!axis.isXAxis) {
  38773. objectEach(stacks, function (type) {
  38774. objectEach(type, function (stack, key) {
  38775. // Clean up memory after point deletion (#1044, #4320)
  38776. if (stack.touched < stacking.stacksTouched) {
  38777. stack.destroy();
  38778. delete type[key];
  38779. // Reset stacks
  38780. }
  38781. else {
  38782. stack.total = null;
  38783. stack.cumulative = null;
  38784. }
  38785. });
  38786. });
  38787. }
  38788. };
  38789. /**
  38790. * @private
  38791. */
  38792. StackingAxisAdditions.prototype.renderStackTotals = function () {
  38793. var stacking = this;
  38794. var axis = stacking.axis;
  38795. var chart = axis.chart;
  38796. var renderer = chart.renderer;
  38797. var stacks = stacking.stacks;
  38798. var stackLabelsAnim = axis.options.stackLabels.animation;
  38799. var animationConfig = getDeferredAnimation(chart,
  38800. stackLabelsAnim);
  38801. var stackTotalGroup = stacking.stackTotalGroup = (stacking.stackTotalGroup ||
  38802. renderer
  38803. .g('stack-labels')
  38804. .attr({
  38805. visibility: 'visible',
  38806. zIndex: 6,
  38807. opacity: 0
  38808. })
  38809. .add());
  38810. // plotLeft/Top will change when y axis gets wider so we need to
  38811. // translate the stackTotalGroup at every render call. See bug #506
  38812. // and #516
  38813. stackTotalGroup.translate(chart.plotLeft, chart.plotTop);
  38814. // Render each stack total
  38815. objectEach(stacks, function (type) {
  38816. objectEach(type, function (stack) {
  38817. stack.render(stackTotalGroup);
  38818. });
  38819. });
  38820. stackTotalGroup.animate({
  38821. opacity: 1
  38822. }, animationConfig);
  38823. };
  38824. return StackingAxisAdditions;
  38825. }());
  38826. /**
  38827. * Axis with stacking support.
  38828. * @private
  38829. * @class
  38830. */
  38831. var StackingAxis = /** @class */ (function () {
  38832. function StackingAxis() {
  38833. }
  38834. /* *
  38835. *
  38836. * Static Functions
  38837. *
  38838. * */
  38839. /**
  38840. * Extends axis with stacking support.
  38841. * @private
  38842. */
  38843. StackingAxis.compose = function (AxisClass) {
  38844. var axisProto = AxisClass.prototype;
  38845. addEvent(AxisClass, 'init', StackingAxis.onInit);
  38846. addEvent(AxisClass, 'destroy', StackingAxis.onDestroy);
  38847. };
  38848. /**
  38849. * @private
  38850. */
  38851. StackingAxis.onDestroy = function () {
  38852. var stacking = this.stacking;
  38853. if (!stacking) {
  38854. return;
  38855. }
  38856. var stacks = stacking.stacks;
  38857. // Destroy each stack total
  38858. objectEach(stacks, function (stack, stackKey) {
  38859. destroyObjectProperties(stack);
  38860. stacks[stackKey] = null;
  38861. });
  38862. if (stacking &&
  38863. stacking.stackTotalGroup) {
  38864. stacking.stackTotalGroup.destroy();
  38865. }
  38866. };
  38867. /**
  38868. * @private
  38869. */
  38870. StackingAxis.onInit = function () {
  38871. var axis = this;
  38872. if (!axis.stacking) {
  38873. axis.stacking = new StackingAxisAdditions(axis);
  38874. }
  38875. };
  38876. return StackingAxis;
  38877. }());
  38878. return StackingAxis;
  38879. });
  38880. _registerModule(_modules, 'Extensions/Stacking.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Chart/Chart.js'], _modules['Core/Globals.js'], _modules['Core/Series/Series.js'], _modules['Core/Axis/StackingAxis.js'], _modules['Core/Utilities.js']], function (Axis, Chart, H, Series, StackingAxis, U) {
  38881. /* *
  38882. *
  38883. * (c) 2010-2021 Torstein Honsi
  38884. *
  38885. * License: www.highcharts.com/license
  38886. *
  38887. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  38888. *
  38889. * */
  38890. var correctFloat = U.correctFloat,
  38891. defined = U.defined,
  38892. destroyObjectProperties = U.destroyObjectProperties,
  38893. format = U.format,
  38894. isArray = U.isArray,
  38895. isNumber = U.isNumber,
  38896. pick = U.pick;
  38897. /**
  38898. * Stack of data points
  38899. *
  38900. * @product highcharts
  38901. *
  38902. * @interface Highcharts.StackItemObject
  38903. */ /**
  38904. * Alignment settings
  38905. * @name Highcharts.StackItemObject#alignOptions
  38906. * @type {Highcharts.AlignObject}
  38907. */ /**
  38908. * Related axis
  38909. * @name Highcharts.StackItemObject#axis
  38910. * @type {Highcharts.Axis}
  38911. */ /**
  38912. * Cumulative value of the stacked data points
  38913. * @name Highcharts.StackItemObject#cumulative
  38914. * @type {number}
  38915. */ /**
  38916. * True if on the negative side
  38917. * @name Highcharts.StackItemObject#isNegative
  38918. * @type {boolean}
  38919. */ /**
  38920. * Related SVG element
  38921. * @name Highcharts.StackItemObject#label
  38922. * @type {Highcharts.SVGElement}
  38923. */ /**
  38924. * Related stack options
  38925. * @name Highcharts.StackItemObject#options
  38926. * @type {Highcharts.YAxisStackLabelsOptions}
  38927. */ /**
  38928. * Total value of the stacked data points
  38929. * @name Highcharts.StackItemObject#total
  38930. * @type {number}
  38931. */ /**
  38932. * Shared x value of the stack
  38933. * @name Highcharts.StackItemObject#x
  38934. * @type {number}
  38935. */
  38936. ''; // detached doclets above
  38937. /* eslint-disable no-invalid-this, valid-jsdoc */
  38938. /**
  38939. * The class for stacks. Each stack, on a specific X value and either negative
  38940. * or positive, has its own stack item.
  38941. *
  38942. * @private
  38943. * @class
  38944. * @name Highcharts.StackItem
  38945. * @param {Highcharts.Axis} axis
  38946. * @param {Highcharts.YAxisStackLabelsOptions} options
  38947. * @param {boolean} isNegative
  38948. * @param {number} x
  38949. * @param {Highcharts.OptionsStackingValue} [stackOption]
  38950. */
  38951. var StackItem = /** @class */ (function () {
  38952. function StackItem(axis, options, isNegative, x, stackOption) {
  38953. var inverted = axis.chart.inverted;
  38954. this.axis = axis;
  38955. // Tells if the stack is negative
  38956. this.isNegative = isNegative;
  38957. // Save the options to be able to style the label
  38958. this.options = options = options || {};
  38959. // Save the x value to be able to position the label later
  38960. this.x = x;
  38961. // Initialize total value
  38962. this.total = null;
  38963. // This will keep each points' extremes stored by series.index and point
  38964. // index
  38965. this.points = {};
  38966. this.hasValidPoints = false;
  38967. // Save the stack option on the series configuration object,
  38968. // and whether to treat it as percent
  38969. this.stack = stackOption;
  38970. this.leftCliff = 0;
  38971. this.rightCliff = 0;
  38972. // The align options and text align varies on whether the stack is
  38973. // negative and if the chart is inverted or not.
  38974. // First test the user supplied value, then use the dynamic.
  38975. this.alignOptions = {
  38976. align: options.align ||
  38977. (inverted ? (isNegative ? 'left' : 'right') : 'center'),
  38978. verticalAlign: options.verticalAlign ||
  38979. (inverted ? 'middle' : (isNegative ? 'bottom' : 'top')),
  38980. y: options.y,
  38981. x: options.x
  38982. };
  38983. this.textAlign = options.textAlign ||
  38984. (inverted ? (isNegative ? 'right' : 'left') : 'center');
  38985. }
  38986. /**
  38987. * @private
  38988. * @function Highcharts.StackItem#destroy
  38989. */
  38990. StackItem.prototype.destroy = function () {
  38991. destroyObjectProperties(this, this.axis);
  38992. };
  38993. /**
  38994. * Renders the stack total label and adds it to the stack label group.
  38995. *
  38996. * @private
  38997. * @function Highcharts.StackItem#render
  38998. * @param {Highcharts.SVGElement} group
  38999. */
  39000. StackItem.prototype.render = function (group) {
  39001. var chart = this.axis.chart,
  39002. options = this.options,
  39003. formatOption = options.format,
  39004. attr = {},
  39005. str = formatOption ? // format the text in the label
  39006. format(formatOption,
  39007. this,
  39008. chart) :
  39009. options.formatter.call(this);
  39010. // Change the text to reflect the new total and set visibility to hidden
  39011. // in case the serie is hidden
  39012. if (this.label) {
  39013. this.label.attr({ text: str, visibility: 'hidden' });
  39014. }
  39015. else {
  39016. // Create new label
  39017. this.label = chart.renderer
  39018. .label(str, null, null, options.shape, null, null, options.useHTML, false, 'stack-labels');
  39019. attr = {
  39020. r: options.borderRadius || 0,
  39021. text: str,
  39022. rotation: options.rotation,
  39023. padding: pick(options.padding, 5),
  39024. visibility: 'hidden' // hidden until setOffset is called
  39025. };
  39026. if (!chart.styledMode) {
  39027. attr.fill = options.backgroundColor;
  39028. attr.stroke = options.borderColor;
  39029. attr['stroke-width'] = options.borderWidth;
  39030. this.label.css(options.style);
  39031. }
  39032. this.label.attr(attr);
  39033. if (!this.label.added) {
  39034. this.label.add(group); // add to the labels-group
  39035. }
  39036. }
  39037. // Rank it higher than data labels (#8742)
  39038. this.label.labelrank = chart.plotSizeY;
  39039. };
  39040. /**
  39041. * Sets the offset that the stack has from the x value and repositions the
  39042. * label.
  39043. *
  39044. * @private
  39045. * @function Highcarts.StackItem#setOffset
  39046. * @param {number} xOffset
  39047. * @param {number} xWidth
  39048. * @param {number} [boxBottom]
  39049. * @param {number} [boxTop]
  39050. * @param {number} [defaultX]
  39051. */
  39052. StackItem.prototype.setOffset = function (xOffset, xWidth, boxBottom, boxTop, defaultX) {
  39053. var stackItem = this,
  39054. axis = stackItem.axis,
  39055. chart = axis.chart,
  39056. // stack value translated mapped to chart coordinates
  39057. y = axis.translate(axis.stacking.usePercentage ?
  39058. 100 :
  39059. (boxTop ?
  39060. boxTop :
  39061. stackItem.total), 0, 0, 0, 1),
  39062. yZero = axis.translate(boxBottom ? boxBottom : 0), // stack origin
  39063. // stack height:
  39064. h = defined(y) && Math.abs(y - yZero),
  39065. // x position:
  39066. x = pick(defaultX,
  39067. chart.xAxis[0].translate(stackItem.x)) +
  39068. xOffset,
  39069. stackBox = defined(y) && stackItem.getStackBox(chart,
  39070. stackItem,
  39071. x,
  39072. y,
  39073. xWidth,
  39074. h,
  39075. axis),
  39076. label = stackItem.label,
  39077. isNegative = stackItem.isNegative,
  39078. isJustify = pick(stackItem.options.overflow, 'justify') === 'justify',
  39079. textAlign = stackItem.textAlign,
  39080. visible;
  39081. if (label && stackBox) {
  39082. var bBox = label.getBBox(),
  39083. padding = label.padding,
  39084. boxOffsetX,
  39085. boxOffsetY;
  39086. if (textAlign === 'left') {
  39087. boxOffsetX = chart.inverted ? -padding : padding;
  39088. }
  39089. else if (textAlign === 'right') {
  39090. boxOffsetX = bBox.width;
  39091. }
  39092. else {
  39093. if (chart.inverted && textAlign === 'center') {
  39094. boxOffsetX = bBox.width / 2;
  39095. }
  39096. else {
  39097. boxOffsetX = chart.inverted ?
  39098. (isNegative ? bBox.width + padding : -padding) : bBox.width / 2;
  39099. }
  39100. }
  39101. boxOffsetY = chart.inverted ?
  39102. bBox.height / 2 : (isNegative ? -padding : bBox.height);
  39103. // Reset alignOptions property after justify #12337
  39104. stackItem.alignOptions.x = pick(stackItem.options.x, 0);
  39105. stackItem.alignOptions.y = pick(stackItem.options.y, 0);
  39106. // Set the stackBox position
  39107. stackBox.x -= boxOffsetX;
  39108. stackBox.y -= boxOffsetY;
  39109. // Align the label to the box
  39110. label.align(stackItem.alignOptions, null, stackBox);
  39111. // Check if label is inside the plotArea #12294
  39112. if (chart.isInsidePlot(label.alignAttr.x + boxOffsetX - stackItem.alignOptions.x, label.alignAttr.y + boxOffsetY - stackItem.alignOptions.y)) {
  39113. label.show();
  39114. }
  39115. else {
  39116. // Move label away to avoid the overlapping issues
  39117. label.alignAttr.y = -9999;
  39118. isJustify = false;
  39119. }
  39120. if (isJustify) {
  39121. // Justify stackLabel into the stackBox
  39122. Series.prototype.justifyDataLabel.call(this.axis, label, stackItem.alignOptions, label.alignAttr, bBox, stackBox);
  39123. }
  39124. label.attr({
  39125. x: label.alignAttr.x,
  39126. y: label.alignAttr.y
  39127. });
  39128. if (pick(!isJustify && stackItem.options.crop, true)) {
  39129. visible =
  39130. isNumber(label.x) &&
  39131. isNumber(label.y) &&
  39132. chart.isInsidePlot(label.x - padding + label.width, label.y) &&
  39133. chart.isInsidePlot(label.x + padding, label.y);
  39134. if (!visible) {
  39135. label.hide();
  39136. }
  39137. }
  39138. }
  39139. };
  39140. /**
  39141. * @private
  39142. * @function Highcharts.StackItem#getStackBox
  39143. *
  39144. * @param {Highcharts.Chart} chart
  39145. *
  39146. * @param {Highcharts.StackItem} stackItem
  39147. *
  39148. * @param {number} x
  39149. *
  39150. * @param {number} y
  39151. *
  39152. * @param {number} xWidth
  39153. *
  39154. * @param {number} h
  39155. *
  39156. * @param {Highcharts.Axis} axis
  39157. *
  39158. * @return {Highcharts.BBoxObject}
  39159. */
  39160. StackItem.prototype.getStackBox = function (chart, stackItem, x, y, xWidth, h, axis) {
  39161. var reversed = stackItem.axis.reversed,
  39162. inverted = chart.inverted,
  39163. axisPos = axis.height + axis.pos -
  39164. (inverted ? chart.plotLeft : chart.plotTop),
  39165. neg = (stackItem.isNegative && !reversed) ||
  39166. (!stackItem.isNegative && reversed); // #4056
  39167. return {
  39168. x: inverted ? (neg ? y - axis.right : y - h + axis.pos - chart.plotLeft) :
  39169. x + chart.xAxis[0].transB - chart.plotLeft,
  39170. y: inverted ?
  39171. axis.height - x - xWidth :
  39172. (neg ?
  39173. (axisPos - y - h) :
  39174. axisPos - y),
  39175. width: inverted ? h : xWidth,
  39176. height: inverted ? xWidth : h
  39177. };
  39178. };
  39179. return StackItem;
  39180. }());
  39181. /**
  39182. * Generate stacks for each series and calculate stacks total values
  39183. *
  39184. * @private
  39185. * @function Highcharts.Chart#getStacks
  39186. */
  39187. Chart.prototype.getStacks = function () {
  39188. var chart = this,
  39189. inverted = chart.inverted;
  39190. // reset stacks for each yAxis
  39191. chart.yAxis.forEach(function (axis) {
  39192. if (axis.stacking && axis.stacking.stacks && axis.hasVisibleSeries) {
  39193. axis.stacking.oldStacks = axis.stacking.stacks;
  39194. }
  39195. });
  39196. chart.series.forEach(function (series) {
  39197. var xAxisOptions = series.xAxis && series.xAxis.options || {};
  39198. if (series.options.stacking &&
  39199. (series.visible === true ||
  39200. chart.options.chart.ignoreHiddenSeries === false)) {
  39201. series.stackKey = [
  39202. series.type,
  39203. pick(series.options.stack, ''),
  39204. inverted ? xAxisOptions.top : xAxisOptions.left,
  39205. inverted ? xAxisOptions.height : xAxisOptions.width
  39206. ].join(',');
  39207. }
  39208. });
  39209. };
  39210. // Stacking methods defined on the Axis prototype
  39211. StackingAxis.compose(Axis);
  39212. // Stacking methods defined for Series prototype
  39213. /**
  39214. * Set grouped points in a stack-like object. When `centerInCategory` is true,
  39215. * and `stacking` is not enabled, we need a pseudo (horizontal) stack in order
  39216. * to handle grouping of points within the same category.
  39217. *
  39218. * @private
  39219. * @function Highcharts.Series#setStackedPoints
  39220. * @return {void}
  39221. */
  39222. Series.prototype.setGroupedPoints = function () {
  39223. if (this.options.centerInCategory &&
  39224. (this.is('column') || this.is('columnrange')) &&
  39225. // With stacking enabled, we already have stacks that we can compute
  39226. // from
  39227. !this.options.stacking &&
  39228. // With only one series, we don't need to consider centerInCategory
  39229. this.chart.series.length > 1) {
  39230. Series.prototype.setStackedPoints.call(this, 'group');
  39231. }
  39232. };
  39233. /**
  39234. * Adds series' points value to corresponding stack
  39235. *
  39236. * @private
  39237. * @function Highcharts.Series#setStackedPoints
  39238. */
  39239. Series.prototype.setStackedPoints = function (stackingParam) {
  39240. var stacking = stackingParam || this.options.stacking;
  39241. if (!stacking ||
  39242. (this.visible !== true &&
  39243. this.chart.options.chart.ignoreHiddenSeries !== false)) {
  39244. return;
  39245. }
  39246. var series = this, xData = series.processedXData, yData = series.processedYData, stackedYData = [], yDataLength = yData.length, seriesOptions = series.options, threshold = seriesOptions.threshold, stackThreshold = pick(seriesOptions.startFromThreshold && threshold, 0), stackOption = seriesOptions.stack, stackKey = stackingParam ? series.type + "," + stacking : series.stackKey, negKey = '-' + stackKey, negStacks = series.negStacks, yAxis = series.yAxis, stacks = yAxis.stacking.stacks, oldStacks = yAxis.stacking.oldStacks, stackIndicator, isNegative, stack, other, key, pointKey, i, x, y;
  39247. yAxis.stacking.stacksTouched += 1;
  39248. // loop over the non-null y values and read them into a local array
  39249. for (i = 0; i < yDataLength; i++) {
  39250. x = xData[i];
  39251. y = yData[i];
  39252. stackIndicator = series.getStackIndicator(stackIndicator, x, series.index);
  39253. pointKey = stackIndicator.key;
  39254. // Read stacked values into a stack based on the x value,
  39255. // the sign of y and the stack key. Stacking is also handled for null
  39256. // values (#739)
  39257. isNegative = negStacks && y < (stackThreshold ? 0 : threshold);
  39258. key = isNegative ? negKey : stackKey;
  39259. // Create empty object for this stack if it doesn't exist yet
  39260. if (!stacks[key]) {
  39261. stacks[key] =
  39262. {};
  39263. }
  39264. // Initialize StackItem for this x
  39265. if (!stacks[key][x]) {
  39266. if (oldStacks[key] &&
  39267. oldStacks[key][x]) {
  39268. stacks[key][x] = oldStacks[key][x];
  39269. stacks[key][x].total = null;
  39270. }
  39271. else {
  39272. stacks[key][x] = new StackItem(yAxis, yAxis.options.stackLabels, isNegative, x, stackOption);
  39273. }
  39274. }
  39275. // If the StackItem doesn't exist, create it first
  39276. stack = stacks[key][x];
  39277. if (y !== null) {
  39278. stack.points[pointKey] = stack.points[series.index] =
  39279. [pick(stack.cumulative, stackThreshold)];
  39280. // Record the base of the stack
  39281. if (!defined(stack.cumulative)) {
  39282. stack.base = pointKey;
  39283. }
  39284. stack.touched = yAxis.stacking.stacksTouched;
  39285. // In area charts, if there are multiple points on the same X value,
  39286. // let the area fill the full span of those points
  39287. if (stackIndicator.index > 0 && series.singleStacks === false) {
  39288. stack.points[pointKey][0] =
  39289. stack.points[series.index + ',' + x + ',0'][0];
  39290. }
  39291. // When updating to null, reset the point stack (#7493)
  39292. }
  39293. else {
  39294. stack.points[pointKey] = stack.points[series.index] =
  39295. null;
  39296. }
  39297. // Add value to the stack total
  39298. if (stacking === 'percent') {
  39299. // Percent stacked column, totals are the same for the positive and
  39300. // negative stacks
  39301. other = isNegative ? stackKey : negKey;
  39302. if (negStacks && stacks[other] && stacks[other][x]) {
  39303. other = stacks[other][x];
  39304. stack.total = other.total =
  39305. Math.max(other.total, stack.total) +
  39306. Math.abs(y) ||
  39307. 0;
  39308. // Percent stacked areas
  39309. }
  39310. else {
  39311. stack.total =
  39312. correctFloat(stack.total + (Math.abs(y) || 0));
  39313. }
  39314. }
  39315. else if (stacking === 'group') {
  39316. if (isArray(y)) {
  39317. y = y[0];
  39318. }
  39319. // In this stack, the total is the number of valid points
  39320. if (y !== null) {
  39321. stack.total = (stack.total || 0) + 1;
  39322. }
  39323. }
  39324. else {
  39325. stack.total = correctFloat(stack.total + (y || 0));
  39326. }
  39327. if (stacking === 'group') {
  39328. // This point's index within the stack, pushed to stack.points[1]
  39329. stack.cumulative = (stack.total || 1) - 1;
  39330. }
  39331. else {
  39332. stack.cumulative =
  39333. pick(stack.cumulative, stackThreshold) + (y || 0);
  39334. }
  39335. if (y !== null) {
  39336. stack.points[pointKey].push(stack.cumulative);
  39337. stackedYData[i] = stack.cumulative;
  39338. stack.hasValidPoints = true;
  39339. }
  39340. }
  39341. if (stacking === 'percent') {
  39342. yAxis.stacking.usePercentage = true;
  39343. }
  39344. if (stacking !== 'group') {
  39345. this.stackedYData = stackedYData; // To be used in getExtremes
  39346. }
  39347. // Reset old stacks
  39348. yAxis.stacking.oldStacks = {};
  39349. };
  39350. /**
  39351. * Iterate over all stacks and compute the absolute values to percent
  39352. *
  39353. * @private
  39354. * @function Highcharts.Series#modifyStacks
  39355. */
  39356. Series.prototype.modifyStacks = function () {
  39357. var series = this,
  39358. yAxis = series.yAxis,
  39359. stackKey = series.stackKey,
  39360. stacks = yAxis.stacking.stacks,
  39361. processedXData = series.processedXData,
  39362. stackIndicator,
  39363. stacking = series.options.stacking;
  39364. if (series[stacking + 'Stacker']) { // Modifier function exists
  39365. [stackKey, '-' + stackKey].forEach(function (key) {
  39366. var i = processedXData.length,
  39367. x,
  39368. stack,
  39369. pointExtremes;
  39370. while (i--) {
  39371. x = processedXData[i];
  39372. stackIndicator = series.getStackIndicator(stackIndicator, x, series.index, key);
  39373. stack = stacks[key] && stacks[key][x];
  39374. pointExtremes =
  39375. stack && stack.points[stackIndicator.key];
  39376. if (pointExtremes) {
  39377. series[stacking + 'Stacker'](pointExtremes, stack, i);
  39378. }
  39379. }
  39380. });
  39381. }
  39382. };
  39383. /**
  39384. * Modifier function for percent stacks. Blows up the stack to 100%.
  39385. *
  39386. * @private
  39387. * @function Highcharts.Series#percentStacker
  39388. */
  39389. Series.prototype.percentStacker = function (pointExtremes, stack, i) {
  39390. var totalFactor = stack.total ? 100 / stack.total : 0;
  39391. // Y bottom value
  39392. pointExtremes[0] = correctFloat(pointExtremes[0] * totalFactor);
  39393. // Y value
  39394. pointExtremes[1] = correctFloat(pointExtremes[1] * totalFactor);
  39395. this.stackedYData[i] = pointExtremes[1];
  39396. };
  39397. /**
  39398. * Get stack indicator, according to it's x-value, to determine points with the
  39399. * same x-value
  39400. *
  39401. * @private
  39402. * @function Highcharts.Series#getStackIndicator
  39403. * @param {Highcharts.StackItemIndicatorObject|undefined} stackIndicator
  39404. * @param {number} x
  39405. * @param {number} index
  39406. * @param {string} [key]
  39407. * @return {Highcharts.StackItemIndicatorObject}
  39408. */
  39409. Series.prototype.getStackIndicator = function (stackIndicator, x, index, key) {
  39410. // Update stack indicator, when:
  39411. // first point in a stack || x changed || stack type (negative vs positive)
  39412. // changed:
  39413. if (!defined(stackIndicator) ||
  39414. stackIndicator.x !== x ||
  39415. (key && stackIndicator.key !== key)) {
  39416. stackIndicator = {
  39417. x: x,
  39418. index: 0,
  39419. key: key
  39420. };
  39421. }
  39422. else {
  39423. (stackIndicator).index++;
  39424. }
  39425. stackIndicator.key =
  39426. [index, x, stackIndicator.index].join(',');
  39427. return stackIndicator;
  39428. };
  39429. H.StackItem = StackItem;
  39430. return H.StackItem;
  39431. });
  39432. _registerModule(_modules, 'Series/Line/LineSeries.js', [_modules['Core/Color/Palette.js'], _modules['Core/Series/Series.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (palette, Series, SeriesRegistry, U) {
  39433. /* *
  39434. *
  39435. * (c) 2010-2021 Torstein Honsi
  39436. *
  39437. * License: www.highcharts.com/license
  39438. *
  39439. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  39440. *
  39441. * */
  39442. var __extends = (this && this.__extends) || (function () {
  39443. var extendStatics = function (d,
  39444. b) {
  39445. extendStatics = Object.setPrototypeOf ||
  39446. ({ __proto__: [] } instanceof Array && function (d,
  39447. b) { d.__proto__ = b; }) ||
  39448. function (d,
  39449. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  39450. return extendStatics(d, b);
  39451. };
  39452. return function (d, b) {
  39453. extendStatics(d, b);
  39454. function __() { this.constructor = d; }
  39455. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  39456. };
  39457. })();
  39458. var defined = U.defined,
  39459. merge = U.merge;
  39460. /* *
  39461. *
  39462. * Class
  39463. *
  39464. * */
  39465. /**
  39466. * The line series is the base type and is therefor the series base prototype.
  39467. *
  39468. * @private
  39469. */
  39470. var LineSeries = /** @class */ (function (_super) {
  39471. __extends(LineSeries, _super);
  39472. function LineSeries() {
  39473. /* *
  39474. *
  39475. * Static Functions
  39476. *
  39477. * */
  39478. var _this = _super !== null && _super.apply(this,
  39479. arguments) || this;
  39480. /* *
  39481. *
  39482. * Properties
  39483. *
  39484. * */
  39485. _this.data = void 0;
  39486. _this.options = void 0;
  39487. _this.points = void 0;
  39488. return _this;
  39489. }
  39490. /* *
  39491. *
  39492. * Functions
  39493. *
  39494. * */
  39495. /**
  39496. * Draw the graph. Called internally when rendering line-like series
  39497. * types. The first time it generates the `series.graph` item and
  39498. * optionally other series-wide items like `series.area` for area
  39499. * charts. On subsequent calls these items are updated with new
  39500. * positions and attributes.
  39501. *
  39502. * @function Highcharts.Series#drawGraph
  39503. */
  39504. LineSeries.prototype.drawGraph = function () {
  39505. var series = this,
  39506. options = this.options,
  39507. graphPath = (this.gappedPath || this.getGraphPath).call(this),
  39508. styledMode = this.chart.styledMode,
  39509. props = [[
  39510. 'graph',
  39511. 'highcharts-graph'
  39512. ]];
  39513. // Presentational properties
  39514. if (!styledMode) {
  39515. props[0].push((options.lineColor ||
  39516. this.color ||
  39517. palette.neutralColor20 // when colorByPoint = true
  39518. ), options.dashStyle);
  39519. }
  39520. props = series.getZonesGraphs(props);
  39521. // Draw the graph
  39522. props.forEach(function (prop, i) {
  39523. var graphKey = prop[0],
  39524. graph = series[graphKey],
  39525. verb = graph ? 'animate' : 'attr',
  39526. attribs;
  39527. if (graph) {
  39528. graph.endX = series.preventGraphAnimation ?
  39529. null :
  39530. graphPath.xMap;
  39531. graph.animate({ d: graphPath });
  39532. }
  39533. else if (graphPath.length) { // #1487
  39534. /**
  39535. * SVG element of area-based charts. Can be used for styling
  39536. * purposes. If zones are configured, this element will be
  39537. * hidden and replaced by multiple zone areas, accessible
  39538. * via `series['zone-area-x']` (where x is a number,
  39539. * starting with 0).
  39540. *
  39541. * @name Highcharts.Series#area
  39542. * @type {Highcharts.SVGElement|undefined}
  39543. */
  39544. /**
  39545. * SVG element of line-based charts. Can be used for styling
  39546. * purposes. If zones are configured, this element will be
  39547. * hidden and replaced by multiple zone lines, accessible
  39548. * via `series['zone-graph-x']` (where x is a number,
  39549. * starting with 0).
  39550. *
  39551. * @name Highcharts.Series#graph
  39552. * @type {Highcharts.SVGElement|undefined}
  39553. */
  39554. series[graphKey] = graph = series.chart.renderer
  39555. .path(graphPath)
  39556. .addClass(prop[1])
  39557. .attr({ zIndex: 1 }) // #1069
  39558. .add(series.group);
  39559. }
  39560. if (graph && !styledMode) {
  39561. attribs = {
  39562. 'stroke': prop[2],
  39563. 'stroke-width': options.lineWidth,
  39564. // Polygon series use filled graph
  39565. 'fill': (series.fillGraph && series.color) || 'none'
  39566. };
  39567. if (prop[3]) {
  39568. attribs.dashstyle = prop[3];
  39569. }
  39570. else if (options.linecap !== 'square') {
  39571. attribs['stroke-linecap'] =
  39572. attribs['stroke-linejoin'] = 'round';
  39573. }
  39574. graph[verb](attribs)
  39575. // Add shadow to normal series (0) or to first
  39576. // zone (1) #3932
  39577. .shadow((i < 2) && options.shadow);
  39578. }
  39579. // Helpers for animation
  39580. if (graph) {
  39581. graph.startX = graphPath.xMap;
  39582. graph.isArea = graphPath.isArea; // For arearange animation
  39583. }
  39584. });
  39585. };
  39586. // eslint-disable-next-line valid-jsdoc
  39587. /**
  39588. * Get the graph path.
  39589. *
  39590. * @private
  39591. */
  39592. LineSeries.prototype.getGraphPath = function (points, nullsAsZeroes, connectCliffs) {
  39593. var series = this,
  39594. options = series.options,
  39595. step = options.step,
  39596. reversed,
  39597. graphPath = [],
  39598. xMap = [],
  39599. gap;
  39600. points = points || series.points;
  39601. // Bottom of a stack is reversed
  39602. reversed = points.reversed;
  39603. if (reversed) {
  39604. points.reverse();
  39605. }
  39606. // Reverse the steps (#5004)
  39607. step = {
  39608. right: 1,
  39609. center: 2
  39610. }[step] || (step && 3);
  39611. if (step && reversed) {
  39612. step = 4 - step;
  39613. }
  39614. // Remove invalid points, especially in spline (#5015)
  39615. points = this.getValidPoints(points, false, !(options.connectNulls && !nullsAsZeroes && !connectCliffs));
  39616. // Build the line
  39617. points.forEach(function (point, i) {
  39618. var plotX = point.plotX,
  39619. plotY = point.plotY,
  39620. lastPoint = points[i - 1],
  39621. // the path to this point from the previous
  39622. pathToPoint;
  39623. if ((point.leftCliff || (lastPoint && lastPoint.rightCliff)) &&
  39624. !connectCliffs) {
  39625. gap = true; // ... and continue
  39626. }
  39627. // Line series, nullsAsZeroes is not handled
  39628. if (point.isNull && !defined(nullsAsZeroes) && i > 0) {
  39629. gap = !options.connectNulls;
  39630. // Area series, nullsAsZeroes is set
  39631. }
  39632. else if (point.isNull && !nullsAsZeroes) {
  39633. gap = true;
  39634. }
  39635. else {
  39636. if (i === 0 || gap) {
  39637. pathToPoint = [[
  39638. 'M',
  39639. point.plotX,
  39640. point.plotY
  39641. ]];
  39642. // Generate the spline as defined in the SplineSeries object
  39643. }
  39644. else if (series.getPointSpline) {
  39645. pathToPoint = [series.getPointSpline(points, point, i)];
  39646. }
  39647. else if (step) {
  39648. if (step === 1) { // right
  39649. pathToPoint = [[
  39650. 'L',
  39651. lastPoint.plotX,
  39652. plotY
  39653. ]];
  39654. }
  39655. else if (step === 2) { // center
  39656. pathToPoint = [[
  39657. 'L',
  39658. (lastPoint.plotX + plotX) / 2,
  39659. lastPoint.plotY
  39660. ], [
  39661. 'L',
  39662. (lastPoint.plotX + plotX) / 2,
  39663. plotY
  39664. ]];
  39665. }
  39666. else {
  39667. pathToPoint = [[
  39668. 'L',
  39669. plotX,
  39670. lastPoint.plotY
  39671. ]];
  39672. }
  39673. pathToPoint.push([
  39674. 'L',
  39675. plotX,
  39676. plotY
  39677. ]);
  39678. }
  39679. else {
  39680. // normal line to next point
  39681. pathToPoint = [[
  39682. 'L',
  39683. plotX,
  39684. plotY
  39685. ]];
  39686. }
  39687. // Prepare for animation. When step is enabled, there are
  39688. // two path nodes for each x value.
  39689. xMap.push(point.x);
  39690. if (step) {
  39691. xMap.push(point.x);
  39692. if (step === 2) { // step = center (#8073)
  39693. xMap.push(point.x);
  39694. }
  39695. }
  39696. graphPath.push.apply(graphPath, pathToPoint);
  39697. gap = false;
  39698. }
  39699. });
  39700. graphPath.xMap = xMap;
  39701. series.graphPath = graphPath;
  39702. return graphPath;
  39703. };
  39704. // eslint-disable-next-line valid-jsdoc
  39705. /**
  39706. * Get zones properties for building graphs. Extendable by series with
  39707. * multiple lines within one series.
  39708. *
  39709. * @private
  39710. */
  39711. LineSeries.prototype.getZonesGraphs = function (props) {
  39712. // Add the zone properties if any
  39713. this.zones.forEach(function (zone, i) {
  39714. var propset = [
  39715. 'zone-graph-' + i,
  39716. 'highcharts-graph highcharts-zone-graph-' + i + ' ' +
  39717. (zone.className || '')
  39718. ];
  39719. if (!this.chart.styledMode) {
  39720. propset.push((zone.color || this.color), (zone.dashStyle || this.options.dashStyle));
  39721. }
  39722. props.push(propset);
  39723. }, this);
  39724. return props;
  39725. };
  39726. /**
  39727. * General options for all series types.
  39728. *
  39729. * @optionparent plotOptions.series
  39730. */
  39731. LineSeries.defaultOptions = merge(Series.defaultOptions, {
  39732. // nothing here yet
  39733. });
  39734. return LineSeries;
  39735. }(Series));
  39736. SeriesRegistry.registerSeriesType('line', LineSeries);
  39737. /* *
  39738. *
  39739. * Default Export
  39740. *
  39741. * */
  39742. /* *
  39743. *
  39744. * API Options
  39745. *
  39746. * */
  39747. /**
  39748. * A line series displays information as a series of data points connected by
  39749. * straight line segments.
  39750. *
  39751. * @sample {highcharts} highcharts/demo/line-basic/
  39752. * Line chart
  39753. * @sample {highstock} stock/demo/basic-line/
  39754. * Line chart
  39755. *
  39756. * @extends plotOptions.series
  39757. * @product highcharts highstock
  39758. * @apioption plotOptions.line
  39759. */
  39760. /**
  39761. * The SVG value used for the `stroke-linecap` and `stroke-linejoin`
  39762. * of a line graph. Round means that lines are rounded in the ends and
  39763. * bends.
  39764. *
  39765. * @type {Highcharts.SeriesLinecapValue}
  39766. * @default round
  39767. * @since 3.0.7
  39768. * @apioption plotOptions.line.linecap
  39769. */
  39770. /**
  39771. * A `line` series. If the [type](#series.line.type) option is not
  39772. * specified, it is inherited from [chart.type](#chart.type).
  39773. *
  39774. * @extends series,plotOptions.line
  39775. * @excluding dataParser,dataURL
  39776. * @product highcharts highstock
  39777. * @apioption series.line
  39778. */
  39779. /**
  39780. * An array of data points for the series. For the `line` series type,
  39781. * points can be given in the following ways:
  39782. *
  39783. * 1. An array of numerical values. In this case, the numerical values will be
  39784. * interpreted as `y` options. The `x` values will be automatically
  39785. * calculated, either starting at 0 and incremented by 1, or from
  39786. * `pointStart` and `pointInterval` given in the series options. If the axis
  39787. * has categories, these will be used. Example:
  39788. * ```js
  39789. * data: [0, 5, 3, 5]
  39790. * ```
  39791. *
  39792. * 2. An array of arrays with 2 values. In this case, the values correspond to
  39793. * `x,y`. If the first value is a string, it is applied as the name of the
  39794. * point, and the `x` value is inferred.
  39795. * ```js
  39796. * data: [
  39797. * [0, 1],
  39798. * [1, 2],
  39799. * [2, 8]
  39800. * ]
  39801. * ```
  39802. *
  39803. * 3. An array of objects with named values. The following snippet shows only a
  39804. * few settings, see the complete options set below. If the total number of
  39805. * data points exceeds the series'
  39806. * [turboThreshold](#series.line.turboThreshold),
  39807. * this option is not available.
  39808. * ```js
  39809. * data: [{
  39810. * x: 1,
  39811. * y: 9,
  39812. * name: "Point2",
  39813. * color: "#00FF00"
  39814. * }, {
  39815. * x: 1,
  39816. * y: 6,
  39817. * name: "Point1",
  39818. * color: "#FF00FF"
  39819. * }]
  39820. * ```
  39821. *
  39822. * **Note:** In TypeScript you have to extend `PointOptionsObject` with an
  39823. * additional declaration to allow custom data types:
  39824. * ```ts
  39825. * declare module `highcharts` {
  39826. * interface PointOptionsObject {
  39827. * custom: Record<string, (boolean|number|string)>;
  39828. * }
  39829. * }
  39830. * ```
  39831. *
  39832. * @sample {highcharts} highcharts/chart/reflow-true/
  39833. * Numerical values
  39834. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  39835. * Arrays of numeric x and y
  39836. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  39837. * Arrays of datetime x and y
  39838. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  39839. * Arrays of point.name and y
  39840. * @sample {highcharts} highcharts/series/data-array-of-objects/
  39841. * Config objects
  39842. *
  39843. * @declare Highcharts.PointOptionsObject
  39844. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  39845. * @apioption series.line.data
  39846. */
  39847. /**
  39848. * An additional, individual class name for the data point's graphic
  39849. * representation.
  39850. *
  39851. * @type {string}
  39852. * @since 5.0.0
  39853. * @product highcharts gantt
  39854. * @apioption series.line.data.className
  39855. */
  39856. /**
  39857. * Individual color for the point. By default the color is pulled from
  39858. * the global `colors` array.
  39859. *
  39860. * In styled mode, the `color` option doesn't take effect. Instead, use
  39861. * `colorIndex`.
  39862. *
  39863. * @sample {highcharts} highcharts/point/color/
  39864. * Mark the highest point
  39865. *
  39866. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  39867. * @product highcharts highstock gantt
  39868. * @apioption series.line.data.color
  39869. */
  39870. /**
  39871. * A specific color index to use for the point, so its graphic representations
  39872. * are given the class name `highcharts-color-{n}`. In styled mode this will
  39873. * change the color of the graphic. In non-styled mode, the color by is set by
  39874. * the `fill` attribute, so the change in class name won't have a visual effect
  39875. * by default.
  39876. *
  39877. * @type {number}
  39878. * @since 5.0.0
  39879. * @product highcharts gantt
  39880. * @apioption series.line.data.colorIndex
  39881. */
  39882. /**
  39883. * A reserved subspace to store options and values for customized functionality.
  39884. * Here you can add additional data for your own event callbacks and formatter
  39885. * callbacks.
  39886. *
  39887. * @sample {highcharts} highcharts/point/custom/
  39888. * Point and series with custom data
  39889. *
  39890. * @type {Highcharts.Dictionary<*>}
  39891. * @apioption series.line.data.custom
  39892. */
  39893. /**
  39894. * Individual data label for each point. The options are the same as
  39895. * the ones for [plotOptions.series.dataLabels](
  39896. * #plotOptions.series.dataLabels).
  39897. *
  39898. * @sample highcharts/point/datalabels/
  39899. * Show a label for the last value
  39900. *
  39901. * @declare Highcharts.DataLabelsOptions
  39902. * @extends plotOptions.line.dataLabels
  39903. * @product highcharts highstock gantt
  39904. * @apioption series.line.data.dataLabels
  39905. */
  39906. /**
  39907. * A description of the point to add to the screen reader information
  39908. * about the point.
  39909. *
  39910. * @type {string}
  39911. * @since 5.0.0
  39912. * @requires modules/accessibility
  39913. * @apioption series.line.data.description
  39914. */
  39915. /**
  39916. * An id for the point. This can be used after render time to get a
  39917. * pointer to the point object through `chart.get()`.
  39918. *
  39919. * @sample {highcharts} highcharts/point/id/
  39920. * Remove an id'd point
  39921. *
  39922. * @type {string}
  39923. * @since 1.2.0
  39924. * @product highcharts highstock gantt
  39925. * @apioption series.line.data.id
  39926. */
  39927. /**
  39928. * The rank for this point's data label in case of collision. If two
  39929. * data labels are about to overlap, only the one with the highest `labelrank`
  39930. * will be drawn.
  39931. *
  39932. * @type {number}
  39933. * @apioption series.line.data.labelrank
  39934. */
  39935. /**
  39936. * The name of the point as shown in the legend, tooltip, dataLabels, etc.
  39937. *
  39938. * @see [xAxis.uniqueNames](#xAxis.uniqueNames)
  39939. *
  39940. * @sample {highcharts} highcharts/series/data-array-of-objects/
  39941. * Point names
  39942. *
  39943. * @type {string}
  39944. * @apioption series.line.data.name
  39945. */
  39946. /**
  39947. * Whether the data point is selected initially.
  39948. *
  39949. * @type {boolean}
  39950. * @default false
  39951. * @product highcharts highstock gantt
  39952. * @apioption series.line.data.selected
  39953. */
  39954. /**
  39955. * The x value of the point. For datetime axes, the X value is the timestamp
  39956. * in milliseconds since 1970.
  39957. *
  39958. * @type {number}
  39959. * @product highcharts highstock
  39960. * @apioption series.line.data.x
  39961. */
  39962. /**
  39963. * The y value of the point.
  39964. *
  39965. * @type {number|null}
  39966. * @product highcharts highstock
  39967. * @apioption series.line.data.y
  39968. */
  39969. /**
  39970. * The individual point events.
  39971. *
  39972. * @extends plotOptions.series.point.events
  39973. * @product highcharts highstock gantt
  39974. * @apioption series.line.data.events
  39975. */
  39976. /**
  39977. * Options for the point markers of line-like series.
  39978. *
  39979. * @declare Highcharts.PointMarkerOptionsObject
  39980. * @extends plotOptions.series.marker
  39981. * @product highcharts highstock
  39982. * @apioption series.line.data.marker
  39983. */
  39984. ''; // include precedent doclets in transpilat
  39985. return LineSeries;
  39986. });
  39987. _registerModule(_modules, 'Series/Area/AreaSeries.js', [_modules['Core/Color/Color.js'], _modules['Mixins/LegendSymbol.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (Color, LegendSymbolMixin, SeriesRegistry, U) {
  39988. /* *
  39989. *
  39990. * (c) 2010-2021 Torstein Honsi
  39991. *
  39992. * License: www.highcharts.com/license
  39993. *
  39994. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  39995. *
  39996. * */
  39997. var __extends = (this && this.__extends) || (function () {
  39998. var extendStatics = function (d,
  39999. b) {
  40000. extendStatics = Object.setPrototypeOf ||
  40001. ({ __proto__: [] } instanceof Array && function (d,
  40002. b) { d.__proto__ = b; }) ||
  40003. function (d,
  40004. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  40005. return extendStatics(d, b);
  40006. };
  40007. return function (d, b) {
  40008. extendStatics(d, b);
  40009. function __() { this.constructor = d; }
  40010. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  40011. };
  40012. })();
  40013. var color = Color.parse;
  40014. var LineSeries = SeriesRegistry.seriesTypes.line;
  40015. var extend = U.extend,
  40016. merge = U.merge,
  40017. objectEach = U.objectEach,
  40018. pick = U.pick;
  40019. /* *
  40020. *
  40021. * Class
  40022. *
  40023. * */
  40024. /**
  40025. * Area series type.
  40026. *
  40027. * @private
  40028. * @class
  40029. * @name AreaSeries
  40030. *
  40031. * @augments LineSeries
  40032. */
  40033. var AreaSeries = /** @class */ (function (_super) {
  40034. __extends(AreaSeries, _super);
  40035. function AreaSeries() {
  40036. /* *
  40037. *
  40038. * Static Properties
  40039. *
  40040. * */
  40041. var _this = _super !== null && _super.apply(this,
  40042. arguments) || this;
  40043. _this.data = void 0;
  40044. _this.options = void 0;
  40045. _this.points = void 0;
  40046. return _this;
  40047. /* eslint-enable valid-jsdoc */
  40048. }
  40049. /* *
  40050. *
  40051. * Functions
  40052. *
  40053. * */
  40054. /* eslint-disable valid-jsdoc */
  40055. /**
  40056. * Draw the graph and the underlying area. This method calls the Series
  40057. * base function and adds the area. The areaPath is calculated in the
  40058. * getSegmentPath method called from Series.prototype.drawGraph.
  40059. * @private
  40060. */
  40061. AreaSeries.prototype.drawGraph = function () {
  40062. // Define or reset areaPath
  40063. this.areaPath = [];
  40064. // Call the base method
  40065. _super.prototype.drawGraph.apply(this);
  40066. // Define local variables
  40067. var series = this,
  40068. areaPath = this.areaPath,
  40069. options = this.options,
  40070. zones = this.zones,
  40071. props = [[
  40072. 'area',
  40073. 'highcharts-area',
  40074. this.color,
  40075. options.fillColor
  40076. ]]; // area name, main color, fill color
  40077. zones.forEach(function (zone,
  40078. i) {
  40079. props.push([
  40080. 'zone-area-' + i,
  40081. 'highcharts-area highcharts-zone-area-' + i + ' ' +
  40082. zone.className,
  40083. zone.color || series.color,
  40084. zone.fillColor || options.fillColor
  40085. ]);
  40086. });
  40087. props.forEach(function (prop) {
  40088. var areaKey = prop[0],
  40089. area = series[areaKey],
  40090. verb = area ? 'animate' : 'attr',
  40091. attribs = {};
  40092. // Create or update the area
  40093. if (area) { // update
  40094. area.endX = series.preventGraphAnimation ?
  40095. null :
  40096. areaPath.xMap;
  40097. area.animate({ d: areaPath });
  40098. }
  40099. else { // create
  40100. attribs.zIndex = 0; // #1069
  40101. area = series[areaKey] = series.chart.renderer
  40102. .path(areaPath)
  40103. .addClass(prop[1])
  40104. .add(series.group);
  40105. area.isArea = true;
  40106. }
  40107. if (!series.chart.styledMode) {
  40108. attribs.fill = pick(prop[3], color(prop[2])
  40109. .setOpacity(pick(options.fillOpacity, 0.75))
  40110. .get());
  40111. }
  40112. area[verb](attribs);
  40113. area.startX = areaPath.xMap;
  40114. area.shiftUnit = options.step ? 2 : 1;
  40115. });
  40116. };
  40117. /**
  40118. * @private
  40119. */
  40120. AreaSeries.prototype.getGraphPath = function (points) {
  40121. var getGraphPath = LineSeries.prototype.getGraphPath, graphPath, options = this.options, stacking = options.stacking, yAxis = this.yAxis, topPath, bottomPath, bottomPoints = [], graphPoints = [], seriesIndex = this.index, i, areaPath, plotX, stacks = yAxis.stacking.stacks[this.stackKey], threshold = options.threshold, translatedThreshold = Math.round(// #10909
  40122. yAxis.getThreshold(options.threshold)), isNull, yBottom, connectNulls = pick(// #10574
  40123. options.connectNulls, stacking === 'percent'),
  40124. // To display null points in underlying stacked series, this
  40125. // series graph must be broken, and the area also fall down to
  40126. // fill the gap left by the null point. #2069
  40127. addDummyPoints = function (i, otherI, side) {
  40128. var point = points[i], stackedValues = stacking &&
  40129. stacks[point.x].points[seriesIndex], nullVal = point[side + 'Null'] || 0, cliffVal = point[side + 'Cliff'] || 0, top, bottom, isNull = true;
  40130. if (cliffVal || nullVal) {
  40131. top = (nullVal ?
  40132. stackedValues[0] :
  40133. stackedValues[1]) + cliffVal;
  40134. bottom = stackedValues[0] + cliffVal;
  40135. isNull = !!nullVal;
  40136. }
  40137. else if (!stacking &&
  40138. points[otherI] &&
  40139. points[otherI].isNull) {
  40140. top = bottom = threshold;
  40141. }
  40142. // Add to the top and bottom line of the area
  40143. if (typeof top !== 'undefined') {
  40144. graphPoints.push({
  40145. plotX: plotX,
  40146. plotY: top === null ?
  40147. translatedThreshold :
  40148. yAxis.getThreshold(top),
  40149. isNull: isNull,
  40150. isCliff: true
  40151. });
  40152. bottomPoints.push({
  40153. plotX: plotX,
  40154. plotY: bottom === null ?
  40155. translatedThreshold :
  40156. yAxis.getThreshold(bottom),
  40157. doCurve: false // #1041, gaps in areaspline areas
  40158. });
  40159. }
  40160. };
  40161. // Find what points to use
  40162. points = points || this.points;
  40163. // Fill in missing points
  40164. if (stacking) {
  40165. points = this.getStackPoints(points);
  40166. }
  40167. for (i = 0; i < points.length; i++) {
  40168. // Reset after series.update of stacking property (#12033)
  40169. if (!stacking) {
  40170. points[i].leftCliff = points[i].rightCliff =
  40171. points[i].leftNull = points[i].rightNull = void 0;
  40172. }
  40173. isNull = points[i].isNull;
  40174. plotX = pick(points[i].rectPlotX, points[i].plotX);
  40175. yBottom = stacking ? pick(points[i].yBottom, translatedThreshold) : translatedThreshold;
  40176. if (!isNull || connectNulls) {
  40177. if (!connectNulls) {
  40178. addDummyPoints(i, i - 1, 'left');
  40179. }
  40180. // Skip null point when stacking is false and connectNulls
  40181. // true
  40182. if (!(isNull && !stacking && connectNulls)) {
  40183. graphPoints.push(points[i]);
  40184. bottomPoints.push({
  40185. x: i,
  40186. plotX: plotX,
  40187. plotY: yBottom
  40188. });
  40189. }
  40190. if (!connectNulls) {
  40191. addDummyPoints(i, i + 1, 'right');
  40192. }
  40193. }
  40194. }
  40195. topPath = getGraphPath.call(this, graphPoints, true, true);
  40196. bottomPoints.reversed = true;
  40197. bottomPath = getGraphPath.call(this, bottomPoints, true, true);
  40198. var firstBottomPoint = bottomPath[0];
  40199. if (firstBottomPoint && firstBottomPoint[0] === 'M') {
  40200. bottomPath[0] = ['L', firstBottomPoint[1], firstBottomPoint[2]];
  40201. }
  40202. areaPath = topPath.concat(bottomPath);
  40203. // TODO: don't set leftCliff and rightCliff when connectNulls?
  40204. graphPath = getGraphPath
  40205. .call(this, graphPoints, false, connectNulls);
  40206. areaPath.xMap = topPath.xMap;
  40207. this.areaPath = areaPath;
  40208. return graphPath;
  40209. };
  40210. /**
  40211. * Return an array of stacked points, where null and missing points are
  40212. * replaced by dummy points in order for gaps to be drawn correctly in
  40213. * stacks.
  40214. * @private
  40215. */
  40216. AreaSeries.prototype.getStackPoints = function (points) {
  40217. var series = this,
  40218. segment = [],
  40219. keys = [],
  40220. xAxis = this.xAxis,
  40221. yAxis = this.yAxis,
  40222. stack = yAxis.stacking.stacks[this.stackKey],
  40223. pointMap = {},
  40224. seriesIndex = series.index,
  40225. yAxisSeries = yAxis.series,
  40226. seriesLength = yAxisSeries.length,
  40227. visibleSeries,
  40228. upOrDown = pick(yAxis.options.reversedStacks,
  40229. true) ? 1 : -1,
  40230. i;
  40231. points = points || this.points;
  40232. if (this.options.stacking) {
  40233. for (i = 0; i < points.length; i++) {
  40234. // Reset after point update (#7326)
  40235. points[i].leftNull = points[i].rightNull = void 0;
  40236. // Create a map where we can quickly look up the points by
  40237. // their X values.
  40238. pointMap[points[i].x] = points[i];
  40239. }
  40240. // Sort the keys (#1651)
  40241. objectEach(stack, function (stackX, x) {
  40242. // nulled after switching between
  40243. // grouping and not (#1651, #2336)
  40244. if (stackX.total !== null) {
  40245. keys.push(x);
  40246. }
  40247. });
  40248. keys.sort(function (a, b) {
  40249. return a - b;
  40250. });
  40251. visibleSeries = yAxisSeries.map(function (s) {
  40252. return s.visible;
  40253. });
  40254. keys.forEach(function (x, idx) {
  40255. var y = 0,
  40256. stackPoint,
  40257. stackedValues;
  40258. if (pointMap[x] && !pointMap[x].isNull) {
  40259. segment.push(pointMap[x]);
  40260. // Find left and right cliff. -1 goes left, 1 goes
  40261. // right.
  40262. [-1, 1].forEach(function (direction) {
  40263. var nullName = direction === 1 ?
  40264. 'rightNull' :
  40265. 'leftNull',
  40266. cliffName = direction === 1 ?
  40267. 'rightCliff' :
  40268. 'leftCliff',
  40269. cliff = 0,
  40270. otherStack = stack[keys[idx + direction]];
  40271. // If there is a stack next to this one,
  40272. // to the left or to the right...
  40273. if (otherStack) {
  40274. i = seriesIndex;
  40275. // Can go either up or down,
  40276. // depending on reversedStacks
  40277. while (i >= 0 && i < seriesLength) {
  40278. stackPoint = otherStack.points[i];
  40279. if (!stackPoint) {
  40280. // If the next point in this series
  40281. // is missing, mark the point
  40282. // with point.leftNull or
  40283. // point.rightNull = true.
  40284. if (i === seriesIndex) {
  40285. pointMap[x][nullName] =
  40286. true;
  40287. // If there are missing points in
  40288. // the next stack in any of the
  40289. // series below this one, we need
  40290. // to substract the missing values
  40291. // and add a hiatus to the left or
  40292. // right.
  40293. }
  40294. else if (visibleSeries[i]) {
  40295. stackedValues =
  40296. stack[x].points[i];
  40297. if (stackedValues) {
  40298. cliff -=
  40299. stackedValues[1] -
  40300. stackedValues[0];
  40301. }
  40302. }
  40303. }
  40304. // When reversedStacks is true, loop up,
  40305. // else loop down
  40306. i += upOrDown;
  40307. }
  40308. }
  40309. pointMap[x][cliffName] = cliff;
  40310. });
  40311. // There is no point for this X value in this series, so we
  40312. // insert a dummy point in order for the areas to be drawn
  40313. // correctly.
  40314. }
  40315. else {
  40316. // Loop down the stack to find the series below this
  40317. // one that has a value (#1991)
  40318. i = seriesIndex;
  40319. while (i >= 0 && i < seriesLength) {
  40320. stackPoint = stack[x].points[i];
  40321. if (stackPoint) {
  40322. y = stackPoint[1];
  40323. break;
  40324. }
  40325. // When reversedStacks is true, loop up, else loop
  40326. // down
  40327. i += upOrDown;
  40328. }
  40329. y = yAxis.translate(// #6272
  40330. y, 0, 1, 0, 1);
  40331. segment.push({
  40332. isNull: true,
  40333. plotX: xAxis.translate(// #6272
  40334. x, 0, 0, 0, 1),
  40335. x: x,
  40336. plotY: y,
  40337. yBottom: y
  40338. });
  40339. }
  40340. });
  40341. }
  40342. return segment;
  40343. };
  40344. /**
  40345. * The area series type.
  40346. *
  40347. * @sample {highcharts} highcharts/demo/area-basic/
  40348. * Area chart
  40349. * @sample {highstock} stock/demo/area/
  40350. * Area chart
  40351. *
  40352. * @extends plotOptions.line
  40353. * @excluding useOhlcData
  40354. * @product highcharts highstock
  40355. * @optionparent plotOptions.area
  40356. */
  40357. AreaSeries.defaultOptions = merge(LineSeries.defaultOptions, {
  40358. /**
  40359. * @see [fillColor](#plotOptions.area.fillColor)
  40360. * @see [fillOpacity](#plotOptions.area.fillOpacity)
  40361. *
  40362. * @apioption plotOptions.area.color
  40363. */
  40364. /**
  40365. * Fill color or gradient for the area. When `null`, the series' `color`
  40366. * is used with the series' `fillOpacity`.
  40367. *
  40368. * In styled mode, the fill color can be set with the `.highcharts-area`
  40369. * class name.
  40370. *
  40371. * @see [color](#plotOptions.area.color)
  40372. * @see [fillOpacity](#plotOptions.area.fillOpacity)
  40373. *
  40374. * @sample {highcharts} highcharts/plotoptions/area-fillcolor-default/
  40375. * Null by default
  40376. * @sample {highcharts} highcharts/plotoptions/area-fillcolor-gradient/
  40377. * Gradient
  40378. *
  40379. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  40380. * @product highcharts highstock
  40381. * @apioption plotOptions.area.fillColor
  40382. */
  40383. /**
  40384. * Fill opacity for the area. When you set an explicit `fillColor`,
  40385. * the `fillOpacity` is not applied. Instead, you should define the
  40386. * opacity in the `fillColor` with an rgba color definition. The
  40387. * `fillOpacity` setting, also the default setting, overrides the alpha
  40388. * component of the `color` setting.
  40389. *
  40390. * In styled mode, the fill opacity can be set with the
  40391. * `.highcharts-area` class name.
  40392. *
  40393. * @see [color](#plotOptions.area.color)
  40394. * @see [fillColor](#plotOptions.area.fillColor)
  40395. *
  40396. * @sample {highcharts} highcharts/plotoptions/area-fillopacity/
  40397. * Automatic fill color and fill opacity of 0.1
  40398. *
  40399. * @type {number}
  40400. * @default {highcharts} 0.75
  40401. * @default {highstock} 0.75
  40402. * @product highcharts highstock
  40403. * @apioption plotOptions.area.fillOpacity
  40404. */
  40405. /**
  40406. * A separate color for the graph line. By default the line takes the
  40407. * `color` of the series, but the lineColor setting allows setting a
  40408. * separate color for the line without altering the `fillColor`.
  40409. *
  40410. * In styled mode, the line stroke can be set with the
  40411. * `.highcharts-graph` class name.
  40412. *
  40413. * @sample {highcharts} highcharts/plotoptions/area-linecolor/
  40414. * Dark gray line
  40415. *
  40416. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  40417. * @product highcharts highstock
  40418. * @apioption plotOptions.area.lineColor
  40419. */
  40420. /**
  40421. * A separate color for the negative part of the area.
  40422. *
  40423. * In styled mode, a negative color is set with the
  40424. * `.highcharts-negative` class name.
  40425. *
  40426. * @see [negativeColor](#plotOptions.area.negativeColor)
  40427. *
  40428. * @sample {highcharts} highcharts/css/series-negative-color/
  40429. * Negative color in styled mode
  40430. *
  40431. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  40432. * @since 3.0
  40433. * @product highcharts
  40434. * @apioption plotOptions.area.negativeFillColor
  40435. */
  40436. /**
  40437. * Whether the whole area or just the line should respond to mouseover
  40438. * tooltips and other mouse or touch events.
  40439. *
  40440. * @sample {highcharts|highstock} highcharts/plotoptions/area-trackbyarea/
  40441. * Display the tooltip when the area is hovered
  40442. *
  40443. * @type {boolean}
  40444. * @default false
  40445. * @since 1.1.6
  40446. * @product highcharts highstock
  40447. * @apioption plotOptions.area.trackByArea
  40448. */
  40449. /**
  40450. * The Y axis value to serve as the base for the area, for
  40451. * distinguishing between values above and below a threshold. The area
  40452. * between the graph and the threshold is filled.
  40453. *
  40454. * * If a number is given, the Y axis will scale to the threshold.
  40455. * * If `null`, the scaling behaves like a line series with fill between
  40456. * the graph and the Y axis minimum.
  40457. * * If `Infinity` or `-Infinity`, the area between the graph and the
  40458. * corresponding Y axis extreme is filled (since v6.1.0).
  40459. *
  40460. * @sample {highcharts} highcharts/plotoptions/area-threshold/
  40461. * A threshold of 100
  40462. * @sample {highcharts} highcharts/plotoptions/area-threshold-infinity/
  40463. * A threshold of Infinity
  40464. *
  40465. * @type {number|null}
  40466. * @since 2.0
  40467. * @product highcharts highstock
  40468. */
  40469. threshold: 0
  40470. });
  40471. return AreaSeries;
  40472. }(LineSeries));
  40473. extend(AreaSeries.prototype, {
  40474. singleStacks: false,
  40475. drawLegendSymbol: LegendSymbolMixin.drawRectangle
  40476. });
  40477. SeriesRegistry.registerSeriesType('area', AreaSeries);
  40478. /* *
  40479. *
  40480. * Default Export
  40481. *
  40482. * */
  40483. /* *
  40484. *
  40485. * API Options
  40486. *
  40487. * */
  40488. /**
  40489. * A `area` series. If the [type](#series.area.type) option is not
  40490. * specified, it is inherited from [chart.type](#chart.type).
  40491. *
  40492. * @extends series,plotOptions.area
  40493. * @excluding dataParser, dataURL, useOhlcData
  40494. * @product highcharts highstock
  40495. * @apioption series.area
  40496. */
  40497. /**
  40498. * @see [fillColor](#series.area.fillColor)
  40499. * @see [fillOpacity](#series.area.fillOpacity)
  40500. *
  40501. * @apioption series.area.color
  40502. */
  40503. /**
  40504. * An array of data points for the series. For the `area` series type,
  40505. * points can be given in the following ways:
  40506. *
  40507. * 1. An array of numerical values. In this case, the numerical values will be
  40508. * interpreted as `y` options. The `x` values will be automatically
  40509. * calculated, either starting at 0 and incremented by 1, or from
  40510. * `pointStart` * and `pointInterval` given in the series options. If the
  40511. * axis has categories, these will be used. Example:
  40512. * ```js
  40513. * data: [0, 5, 3, 5]
  40514. * ```
  40515. *
  40516. * 2. An array of arrays with 2 values. In this case, the values correspond to
  40517. * `x,y`. If the first value is a string, it is applied as the name of the
  40518. * point, and the `x` value is inferred.
  40519. * ```js
  40520. * data: [
  40521. * [0, 9],
  40522. * [1, 7],
  40523. * [2, 6]
  40524. * ]
  40525. * ```
  40526. *
  40527. * 3. An array of objects with named values. The following snippet shows only a
  40528. * few settings, see the complete options set below. If the total number of
  40529. * data points exceeds the series'
  40530. * [turboThreshold](#series.area.turboThreshold), this option is not
  40531. * available.
  40532. * ```js
  40533. * data: [{
  40534. * x: 1,
  40535. * y: 9,
  40536. * name: "Point2",
  40537. * color: "#00FF00"
  40538. * }, {
  40539. * x: 1,
  40540. * y: 6,
  40541. * name: "Point1",
  40542. * color: "#FF00FF"
  40543. * }]
  40544. * ```
  40545. *
  40546. * @sample {highcharts} highcharts/chart/reflow-true/
  40547. * Numerical values
  40548. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  40549. * Arrays of numeric x and y
  40550. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  40551. * Arrays of datetime x and y
  40552. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  40553. * Arrays of point.name and y
  40554. * @sample {highcharts} highcharts/series/data-array-of-objects/
  40555. * Config objects
  40556. *
  40557. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  40558. * @extends series.line.data
  40559. * @product highcharts highstock
  40560. * @apioption series.area.data
  40561. */
  40562. /**
  40563. * @see [color](#series.area.color)
  40564. * @see [fillOpacity](#series.area.fillOpacity)
  40565. *
  40566. * @apioption series.area.fillColor
  40567. */
  40568. /**
  40569. * @see [color](#series.area.color)
  40570. * @see [fillColor](#series.area.fillColor)
  40571. *
  40572. * @default {highcharts} 0.75
  40573. * @default {highstock} 0.75
  40574. * @apioption series.area.fillOpacity
  40575. */
  40576. ''; // adds doclets above to transpilat
  40577. return AreaSeries;
  40578. });
  40579. _registerModule(_modules, 'Series/Spline/SplineSeries.js', [_modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (SeriesRegistry, U) {
  40580. /* *
  40581. *
  40582. * (c) 2010-2021 Torstein Honsi
  40583. *
  40584. * License: www.highcharts.com/license
  40585. *
  40586. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  40587. *
  40588. * */
  40589. var __extends = (this && this.__extends) || (function () {
  40590. var extendStatics = function (d,
  40591. b) {
  40592. extendStatics = Object.setPrototypeOf ||
  40593. ({ __proto__: [] } instanceof Array && function (d,
  40594. b) { d.__proto__ = b; }) ||
  40595. function (d,
  40596. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  40597. return extendStatics(d, b);
  40598. };
  40599. return function (d, b) {
  40600. extendStatics(d, b);
  40601. function __() { this.constructor = d; }
  40602. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  40603. };
  40604. })();
  40605. var LineSeries = SeriesRegistry.seriesTypes.line;
  40606. var merge = U.merge,
  40607. pick = U.pick;
  40608. /**
  40609. * Spline series type.
  40610. *
  40611. * @private
  40612. */
  40613. var SplineSeries = /** @class */ (function (_super) {
  40614. __extends(SplineSeries, _super);
  40615. function SplineSeries() {
  40616. /* *
  40617. *
  40618. * Static Properties
  40619. *
  40620. * */
  40621. var _this = _super !== null && _super.apply(this,
  40622. arguments) || this;
  40623. /* *
  40624. *
  40625. * Properties
  40626. *
  40627. * */
  40628. _this.data = void 0;
  40629. _this.options = void 0;
  40630. _this.points = void 0;
  40631. return _this;
  40632. /* eslint-enable valid-jsdoc */
  40633. }
  40634. /* *
  40635. *
  40636. * Functions
  40637. *
  40638. * */
  40639. /* eslint-disable valid-jsdoc */
  40640. /**
  40641. * Get the spline segment from a given point's previous neighbour to the
  40642. * given point.
  40643. *
  40644. * @private
  40645. * @function Highcharts.seriesTypes.spline#getPointSpline
  40646. *
  40647. * @param {Array<Highcharts.Point>}
  40648. *
  40649. * @param {Highcharts.Point} point
  40650. *
  40651. * @param {number} i
  40652. *
  40653. * @return {Highcharts.SVGPathArray}
  40654. */
  40655. SplineSeries.prototype.getPointSpline = function (points, point, i) {
  40656. var
  40657. // 1 means control points midway between points, 2 means 1/3
  40658. // from the point, 3 is 1/4 etc
  40659. smoothing = 1.5,
  40660. denom = smoothing + 1,
  40661. plotX = point.plotX || 0,
  40662. plotY = point.plotY || 0,
  40663. lastPoint = points[i - 1],
  40664. nextPoint = points[i + 1],
  40665. leftContX,
  40666. leftContY,
  40667. rightContX,
  40668. rightContY,
  40669. ret;
  40670. /**
  40671. * @private
  40672. */
  40673. function doCurve(otherPoint) {
  40674. return otherPoint &&
  40675. !otherPoint.isNull &&
  40676. otherPoint.doCurve !== false &&
  40677. // #6387, area splines next to null:
  40678. !point.isCliff;
  40679. }
  40680. // Find control points
  40681. if (doCurve(lastPoint) && doCurve(nextPoint)) {
  40682. var lastX = lastPoint.plotX || 0,
  40683. lastY = lastPoint.plotY || 0,
  40684. nextX = nextPoint.plotX || 0,
  40685. nextY = nextPoint.plotY || 0,
  40686. correction = 0;
  40687. leftContX = (smoothing * plotX + lastX) / denom;
  40688. leftContY = (smoothing * plotY + lastY) / denom;
  40689. rightContX = (smoothing * plotX + nextX) / denom;
  40690. rightContY = (smoothing * plotY + nextY) / denom;
  40691. // Have the two control points make a straight line through main
  40692. // point
  40693. if (rightContX !== leftContX) { // #5016, division by zero
  40694. correction = (((rightContY - leftContY) *
  40695. (rightContX - plotX)) /
  40696. (rightContX - leftContX) + plotY - rightContY);
  40697. }
  40698. leftContY += correction;
  40699. rightContY += correction;
  40700. // to prevent false extremes, check that control points are
  40701. // between neighbouring points' y values
  40702. if (leftContY > lastY && leftContY > plotY) {
  40703. leftContY = Math.max(lastY, plotY);
  40704. // mirror of left control point
  40705. rightContY = 2 * plotY - leftContY;
  40706. }
  40707. else if (leftContY < lastY && leftContY < plotY) {
  40708. leftContY = Math.min(lastY, plotY);
  40709. rightContY = 2 * plotY - leftContY;
  40710. }
  40711. if (rightContY > nextY && rightContY > plotY) {
  40712. rightContY = Math.max(nextY, plotY);
  40713. leftContY = 2 * plotY - rightContY;
  40714. }
  40715. else if (rightContY < nextY && rightContY < plotY) {
  40716. rightContY = Math.min(nextY, plotY);
  40717. leftContY = 2 * plotY - rightContY;
  40718. }
  40719. // record for drawing in next point
  40720. point.rightContX = rightContX;
  40721. point.rightContY = rightContY;
  40722. }
  40723. // Visualize control points for debugging
  40724. /*
  40725. if (leftContX) {
  40726. this.chart.renderer.circle(
  40727. leftContX + this.chart.plotLeft,
  40728. leftContY + this.chart.plotTop,
  40729. 2
  40730. )
  40731. .attr({
  40732. stroke: 'red',
  40733. 'stroke-width': 2,
  40734. fill: 'none',
  40735. zIndex: 9
  40736. })
  40737. .add();
  40738. this.chart.renderer.path(['M', leftContX + this.chart.plotLeft,
  40739. leftContY + this.chart.plotTop,
  40740. 'L', plotX + this.chart.plotLeft, plotY + this.chart.plotTop])
  40741. .attr({
  40742. stroke: 'red',
  40743. 'stroke-width': 2,
  40744. zIndex: 9
  40745. })
  40746. .add();
  40747. }
  40748. if (rightContX) {
  40749. this.chart.renderer.circle(
  40750. rightContX + this.chart.plotLeft,
  40751. rightContY + this.chart.plotTop,
  40752. 2
  40753. )
  40754. .attr({
  40755. stroke: 'green',
  40756. 'stroke-width': 2,
  40757. fill: 'none',
  40758. zIndex: 9
  40759. })
  40760. .add();
  40761. this.chart.renderer.path(['M', rightContX + this.chart.plotLeft,
  40762. rightContY + this.chart.plotTop,
  40763. 'L', plotX + this.chart.plotLeft, plotY + this.chart.plotTop])
  40764. .attr({
  40765. stroke: 'green',
  40766. 'stroke-width': 2,
  40767. zIndex: 9
  40768. })
  40769. .add();
  40770. }
  40771. // */
  40772. ret = [
  40773. 'C',
  40774. pick(lastPoint.rightContX, lastPoint.plotX, 0),
  40775. pick(lastPoint.rightContY, lastPoint.plotY, 0),
  40776. pick(leftContX, plotX, 0),
  40777. pick(leftContY, plotY, 0),
  40778. plotX,
  40779. plotY
  40780. ];
  40781. // reset for updating series later
  40782. lastPoint.rightContX = lastPoint.rightContY = void 0;
  40783. return ret;
  40784. };
  40785. /**
  40786. * A spline series is a special type of line series, where the segments
  40787. * between the data points are smoothed.
  40788. *
  40789. * @sample {highcharts} highcharts/demo/spline-irregular-time/
  40790. * Spline chart
  40791. * @sample {highstock} stock/demo/spline/
  40792. * Spline chart
  40793. *
  40794. * @extends plotOptions.series
  40795. * @excluding step, boostThreshold, boostBlending
  40796. * @product highcharts highstock
  40797. * @optionparent plotOptions.spline
  40798. */
  40799. SplineSeries.defaultOptions = merge(LineSeries.defaultOptions);
  40800. return SplineSeries;
  40801. }(LineSeries));
  40802. SeriesRegistry.registerSeriesType('spline', SplineSeries);
  40803. /* *
  40804. *
  40805. * Default Export
  40806. *
  40807. * */
  40808. /* *
  40809. *
  40810. * API Options
  40811. *
  40812. * */
  40813. /**
  40814. * A `spline` series. If the [type](#series.spline.type) option is
  40815. * not specified, it is inherited from [chart.type](#chart.type).
  40816. *
  40817. * @extends series,plotOptions.spline
  40818. * @excluding dataParser, dataURL, step, boostThreshold, boostBlending
  40819. * @product highcharts highstock
  40820. * @apioption series.spline
  40821. */
  40822. /**
  40823. * An array of data points for the series. For the `spline` series type,
  40824. * points can be given in the following ways:
  40825. *
  40826. * 1. An array of numerical values. In this case, the numerical values will be
  40827. * interpreted as `y` options. The `x` values will be automatically
  40828. * calculated, either starting at 0 and incremented by 1, or from
  40829. * `pointStart` and `pointInterval` given in the series options. If the axis
  40830. * has categories, these will be used. Example:
  40831. * ```js
  40832. * data: [0, 5, 3, 5]
  40833. * ```
  40834. *
  40835. * 2. An array of arrays with 2 values. In this case, the values correspond to
  40836. * `x,y`. If the first value is a string, it is applied as the name of the
  40837. * point, and the `x` value is inferred.
  40838. * ```js
  40839. * data: [
  40840. * [0, 9],
  40841. * [1, 2],
  40842. * [2, 8]
  40843. * ]
  40844. * ```
  40845. *
  40846. * 3. An array of objects with named values. The following snippet shows only a
  40847. * few settings, see the complete options set below. If the total number of
  40848. * data points exceeds the series'
  40849. * [turboThreshold](#series.spline.turboThreshold),
  40850. * this option is not available.
  40851. * ```js
  40852. * data: [{
  40853. * x: 1,
  40854. * y: 9,
  40855. * name: "Point2",
  40856. * color: "#00FF00"
  40857. * }, {
  40858. * x: 1,
  40859. * y: 0,
  40860. * name: "Point1",
  40861. * color: "#FF00FF"
  40862. * }]
  40863. * ```
  40864. *
  40865. * @sample {highcharts} highcharts/chart/reflow-true/
  40866. * Numerical values
  40867. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  40868. * Arrays of numeric x and y
  40869. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  40870. * Arrays of datetime x and y
  40871. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  40872. * Arrays of point.name and y
  40873. * @sample {highcharts} highcharts/series/data-array-of-objects/
  40874. * Config objects
  40875. *
  40876. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  40877. * @extends series.line.data
  40878. * @product highcharts highstock
  40879. * @apioption series.spline.data
  40880. */
  40881. ''; // adds doclets above intro transpilat
  40882. return SplineSeries;
  40883. });
  40884. _registerModule(_modules, 'Series/AreaSpline/AreaSplineSeries.js', [_modules['Series/Area/AreaSeries.js'], _modules['Series/Spline/SplineSeries.js'], _modules['Mixins/LegendSymbol.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (AreaSeries, SplineSeries, LegendSymbolMixin, SeriesRegistry, U) {
  40885. /* *
  40886. *
  40887. * (c) 2010-2021 Torstein Honsi
  40888. *
  40889. * License: www.highcharts.com/license
  40890. *
  40891. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  40892. *
  40893. * */
  40894. var __extends = (this && this.__extends) || (function () {
  40895. var extendStatics = function (d,
  40896. b) {
  40897. extendStatics = Object.setPrototypeOf ||
  40898. ({ __proto__: [] } instanceof Array && function (d,
  40899. b) { d.__proto__ = b; }) ||
  40900. function (d,
  40901. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  40902. return extendStatics(d, b);
  40903. };
  40904. return function (d, b) {
  40905. extendStatics(d, b);
  40906. function __() { this.constructor = d; }
  40907. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  40908. };
  40909. })();
  40910. var areaProto = AreaSeries.prototype;
  40911. var extend = U.extend,
  40912. merge = U.merge;
  40913. /* *
  40914. *
  40915. * Class
  40916. *
  40917. * */
  40918. /**
  40919. * AreaSpline series type.
  40920. *
  40921. * @private
  40922. * @class
  40923. * @name Highcharts.seriesTypes.areaspline
  40924. *
  40925. * @augments Highcharts.Series
  40926. */
  40927. var AreaSplineSeries = /** @class */ (function (_super) {
  40928. __extends(AreaSplineSeries, _super);
  40929. function AreaSplineSeries() {
  40930. /* *
  40931. *
  40932. * Static properties
  40933. *
  40934. * */
  40935. var _this = _super !== null && _super.apply(this,
  40936. arguments) || this;
  40937. /* *
  40938. *
  40939. * Properties
  40940. *
  40941. * */
  40942. _this.data = void 0;
  40943. _this.points = void 0;
  40944. _this.options = void 0;
  40945. return _this;
  40946. }
  40947. /**
  40948. * The area spline series is an area series where the graph between the
  40949. * points is smoothed into a spline.
  40950. *
  40951. * @sample {highcharts} highcharts/demo/areaspline/
  40952. * Area spline chart
  40953. * @sample {highstock} stock/demo/areaspline/
  40954. * Area spline chart
  40955. *
  40956. * @extends plotOptions.area
  40957. * @excluding step, boostThreshold, boostBlending
  40958. * @product highcharts highstock
  40959. * @apioption plotOptions.areaspline
  40960. */
  40961. /**
  40962. * @see [fillColor](#plotOptions.areaspline.fillColor)
  40963. * @see [fillOpacity](#plotOptions.areaspline.fillOpacity)
  40964. *
  40965. * @apioption plotOptions.areaspline.color
  40966. */
  40967. /**
  40968. * @see [color](#plotOptions.areaspline.color)
  40969. * @see [fillOpacity](#plotOptions.areaspline.fillOpacity)
  40970. *
  40971. * @apioption plotOptions.areaspline.fillColor
  40972. */
  40973. /**
  40974. * @see [color](#plotOptions.areaspline.color)
  40975. * @see [fillColor](#plotOptions.areaspline.fillColor)
  40976. *
  40977. * @default {highcharts} 0.75
  40978. * @default {highstock} 0.75
  40979. * @apioption plotOptions.areaspline.fillOpacity
  40980. */
  40981. AreaSplineSeries.defaultOptions = merge(SplineSeries.defaultOptions, AreaSeries.defaultOptions);
  40982. return AreaSplineSeries;
  40983. }(SplineSeries));
  40984. extend(AreaSplineSeries.prototype, {
  40985. getGraphPath: areaProto.getGraphPath,
  40986. getStackPoints: areaProto.getStackPoints,
  40987. drawGraph: areaProto.drawGraph,
  40988. drawLegendSymbol: LegendSymbolMixin.drawRectangle
  40989. });
  40990. SeriesRegistry.registerSeriesType('areaspline', AreaSplineSeries);
  40991. /* *
  40992. *
  40993. * Default export
  40994. *
  40995. * */
  40996. /**
  40997. * A `areaspline` series. If the [type](#series.areaspline.type) option
  40998. * is not specified, it is inherited from [chart.type](#chart.type).
  40999. *
  41000. *
  41001. * @extends series,plotOptions.areaspline
  41002. * @excluding dataParser, dataURL, step, boostThreshold, boostBlending
  41003. * @product highcharts highstock
  41004. * @apioption series.areaspline
  41005. */
  41006. /**
  41007. * @see [fillColor](#series.areaspline.fillColor)
  41008. * @see [fillOpacity](#series.areaspline.fillOpacity)
  41009. *
  41010. * @apioption series.areaspline.color
  41011. */
  41012. /**
  41013. * An array of data points for the series. For the `areaspline` series
  41014. * type, points can be given in the following ways:
  41015. *
  41016. * 1. An array of numerical values. In this case, the numerical values will be
  41017. * interpreted as `y` options. The `x` values will be automatically
  41018. * calculated, either starting at 0 and incremented by 1, or from
  41019. * `pointStart` and `pointInterval` given in the series options. If the axis
  41020. * has categories, these will be used. Example:
  41021. * ```js
  41022. * data: [0, 5, 3, 5]
  41023. * ```
  41024. *
  41025. * 2. An array of arrays with 2 values. In this case, the values correspond to
  41026. * `x,y`. If the first value is a string, it is applied as the name of the
  41027. * point, and the `x` value is inferred.
  41028. * ```js
  41029. * data: [
  41030. * [0, 10],
  41031. * [1, 9],
  41032. * [2, 3]
  41033. * ]
  41034. * ```
  41035. *
  41036. * 3. An array of objects with named values. The following snippet shows only a
  41037. * few settings, see the complete options set below. If the total number of
  41038. * data points exceeds the series'
  41039. * [turboThreshold](#series.areaspline.turboThreshold), this option is not
  41040. * available.
  41041. * ```js
  41042. * data: [{
  41043. * x: 1,
  41044. * y: 4,
  41045. * name: "Point2",
  41046. * color: "#00FF00"
  41047. * }, {
  41048. * x: 1,
  41049. * y: 4,
  41050. * name: "Point1",
  41051. * color: "#FF00FF"
  41052. * }]
  41053. * ```
  41054. *
  41055. * @sample {highcharts} highcharts/chart/reflow-true/
  41056. * Numerical values
  41057. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  41058. * Arrays of numeric x and y
  41059. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  41060. * Arrays of datetime x and y
  41061. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  41062. * Arrays of point.name and y
  41063. * @sample {highcharts} highcharts/series/data-array-of-objects/
  41064. * Config objects
  41065. *
  41066. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  41067. * @extends series.line.data
  41068. * @product highcharts highstock
  41069. * @apioption series.areaspline.data
  41070. */
  41071. /**
  41072. * @see [color](#series.areaspline.color)
  41073. * @see [fillOpacity](#series.areaspline.fillOpacity)
  41074. *
  41075. * @apioption series.areaspline.fillColor
  41076. */
  41077. /**
  41078. * @see [color](#series.areaspline.color)
  41079. * @see [fillColor](#series.areaspline.fillColor)
  41080. *
  41081. * @default {highcharts} 0.75
  41082. * @default {highstock} 0.75
  41083. * @apioption series.areaspline.fillOpacity
  41084. */
  41085. ''; // adds doclets above into transpilat
  41086. return AreaSplineSeries;
  41087. });
  41088. _registerModule(_modules, 'Series/Column/ColumnSeries.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Mixins/LegendSymbol.js'], _modules['Core/Color/Palette.js'], _modules['Core/Series/Series.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (A, Color, H, LegendSymbolMixin, palette, Series, SeriesRegistry, U) {
  41089. /* *
  41090. *
  41091. * (c) 2010-2021 Torstein Honsi
  41092. *
  41093. * License: www.highcharts.com/license
  41094. *
  41095. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  41096. *
  41097. * */
  41098. var __extends = (this && this.__extends) || (function () {
  41099. var extendStatics = function (d,
  41100. b) {
  41101. extendStatics = Object.setPrototypeOf ||
  41102. ({ __proto__: [] } instanceof Array && function (d,
  41103. b) { d.__proto__ = b; }) ||
  41104. function (d,
  41105. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  41106. return extendStatics(d, b);
  41107. };
  41108. return function (d, b) {
  41109. extendStatics(d, b);
  41110. function __() { this.constructor = d; }
  41111. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  41112. };
  41113. })();
  41114. var animObject = A.animObject;
  41115. var color = Color.parse;
  41116. var hasTouch = H.hasTouch,
  41117. noop = H.noop;
  41118. var clamp = U.clamp,
  41119. css = U.css,
  41120. defined = U.defined,
  41121. extend = U.extend,
  41122. fireEvent = U.fireEvent,
  41123. isArray = U.isArray,
  41124. isNumber = U.isNumber,
  41125. merge = U.merge,
  41126. pick = U.pick,
  41127. objectEach = U.objectEach;
  41128. /**
  41129. * The column series type.
  41130. *
  41131. * @private
  41132. * @class
  41133. * @name Highcharts.seriesTypes.column
  41134. *
  41135. * @augments Highcharts.Series
  41136. */
  41137. var ColumnSeries = /** @class */ (function (_super) {
  41138. __extends(ColumnSeries, _super);
  41139. function ColumnSeries() {
  41140. /* *
  41141. *
  41142. * Static Properties
  41143. *
  41144. * */
  41145. var _this = _super !== null && _super.apply(this,
  41146. arguments) || this;
  41147. /* *
  41148. *
  41149. * Properties
  41150. *
  41151. * */
  41152. _this.borderWidth = void 0;
  41153. _this.data = void 0;
  41154. _this.group = void 0;
  41155. _this.options = void 0;
  41156. _this.points = void 0;
  41157. return _this;
  41158. /* eslint-enable valid-jsdoc */
  41159. }
  41160. /* *
  41161. *
  41162. * Functions
  41163. *
  41164. * */
  41165. /* eslint-disable valid-jsdoc */
  41166. /**
  41167. * Animate the column heights one by one from zero.
  41168. *
  41169. * @private
  41170. * @function Highcharts.seriesTypes.column#animate
  41171. *
  41172. * @param {boolean} init
  41173. * Whether to initialize the animation or run it
  41174. */
  41175. ColumnSeries.prototype.animate = function (init) {
  41176. var series = this,
  41177. yAxis = this.yAxis,
  41178. options = series.options,
  41179. inverted = this.chart.inverted,
  41180. attr = {},
  41181. translateProp = inverted ? 'translateX' : 'translateY',
  41182. translateStart,
  41183. translatedThreshold;
  41184. if (init) {
  41185. attr.scaleY = 0.001;
  41186. translatedThreshold = clamp(yAxis.toPixels(options.threshold), yAxis.pos, yAxis.pos + yAxis.len);
  41187. if (inverted) {
  41188. attr.translateX = translatedThreshold - yAxis.len;
  41189. }
  41190. else {
  41191. attr.translateY = translatedThreshold;
  41192. }
  41193. // apply finnal clipping (used in Highstock) (#7083)
  41194. // animation is done by scaleY, so cliping is for panes
  41195. if (series.clipBox) {
  41196. series.setClip();
  41197. }
  41198. series.group.attr(attr);
  41199. }
  41200. else { // run the animation
  41201. translateStart = series.group.attr(translateProp);
  41202. series.group.animate({ scaleY: 1 }, extend(animObject(series.options.animation), {
  41203. // Do the scale synchronously to ensure smooth
  41204. // updating (#5030, #7228)
  41205. step: function (val, fx) {
  41206. if (series.group) {
  41207. attr[translateProp] = translateStart +
  41208. fx.pos * (yAxis.pos - translateStart);
  41209. series.group.attr(attr);
  41210. }
  41211. }
  41212. }));
  41213. }
  41214. };
  41215. /**
  41216. * Initialize the series. Extends the basic Series.init method by
  41217. * marking other series of the same type as dirty.
  41218. *
  41219. * @private
  41220. * @function Highcharts.seriesTypes.column#init
  41221. */
  41222. ColumnSeries.prototype.init = function (chart, options) {
  41223. _super.prototype.init.apply(this, arguments);
  41224. var series = this,
  41225. chart = series.chart;
  41226. // if the series is added dynamically, force redraw of other
  41227. // series affected by a new column
  41228. if (chart.hasRendered) {
  41229. chart.series.forEach(function (otherSeries) {
  41230. if (otherSeries.type === series.type) {
  41231. otherSeries.isDirty = true;
  41232. }
  41233. });
  41234. }
  41235. };
  41236. /**
  41237. * Return the width and x offset of the columns adjusted for grouping,
  41238. * groupPadding, pointPadding, pointWidth etc.
  41239. *
  41240. * @private
  41241. * @function Highcharts.seriesTypes.column#getColumnMetrics
  41242. * @return {Highcharts.ColumnMetricsObject}
  41243. */
  41244. ColumnSeries.prototype.getColumnMetrics = function () {
  41245. var series = this,
  41246. options = series.options,
  41247. xAxis = series.xAxis,
  41248. yAxis = series.yAxis,
  41249. reversedStacks = xAxis.options.reversedStacks,
  41250. // Keep backward compatibility: reversed xAxis had reversed
  41251. // stacks
  41252. reverseStacks = (xAxis.reversed && !reversedStacks) ||
  41253. (!xAxis.reversed && reversedStacks),
  41254. stackKey,
  41255. stackGroups = {},
  41256. columnCount = 0;
  41257. // Get the total number of column type series. This is called on
  41258. // every series. Consider moving this logic to a chart.orderStacks()
  41259. // function and call it on init, addSeries and removeSeries
  41260. if (options.grouping === false) {
  41261. columnCount = 1;
  41262. }
  41263. else {
  41264. series.chart.series.forEach(function (otherSeries) {
  41265. var otherYAxis = otherSeries.yAxis,
  41266. otherOptions = otherSeries.options,
  41267. columnIndex;
  41268. if (otherSeries.type === series.type &&
  41269. (otherSeries.visible ||
  41270. !series.chart.options.chart
  41271. .ignoreHiddenSeries) &&
  41272. yAxis.len === otherYAxis.len &&
  41273. yAxis.pos === otherYAxis.pos) { // #642, #2086
  41274. if (otherOptions.stacking && otherOptions.stacking !== 'group') {
  41275. stackKey = otherSeries.stackKey;
  41276. if (typeof stackGroups[stackKey] ===
  41277. 'undefined') {
  41278. stackGroups[stackKey] = columnCount++;
  41279. }
  41280. columnIndex = stackGroups[stackKey];
  41281. }
  41282. else if (otherOptions.grouping !== false) { // #1162
  41283. columnIndex = columnCount++;
  41284. }
  41285. otherSeries.columnIndex = columnIndex;
  41286. }
  41287. });
  41288. }
  41289. var categoryWidth = Math.min(Math.abs(xAxis.transA) * ((xAxis.ordinal && xAxis.ordinal.slope) ||
  41290. options.pointRange ||
  41291. xAxis.closestPointRange ||
  41292. xAxis.tickInterval ||
  41293. 1), // #2610
  41294. xAxis.len // #1535
  41295. ),
  41296. groupPadding = categoryWidth * options.groupPadding,
  41297. groupWidth = categoryWidth - 2 * groupPadding,
  41298. pointOffsetWidth = groupWidth / (columnCount || 1),
  41299. pointWidth = Math.min(options.maxPointWidth || xAxis.len,
  41300. pick(options.pointWidth,
  41301. pointOffsetWidth * (1 - 2 * options.pointPadding))),
  41302. pointPadding = (pointOffsetWidth - pointWidth) / 2,
  41303. // #1251, #3737
  41304. colIndex = (series.columnIndex || 0) + (reverseStacks ? 1 : 0),
  41305. pointXOffset = pointPadding +
  41306. (groupPadding +
  41307. colIndex * pointOffsetWidth -
  41308. (categoryWidth / 2)) * (reverseStacks ? -1 : 1);
  41309. // Save it for reading in linked series (Error bars particularly)
  41310. series.columnMetrics = {
  41311. width: pointWidth,
  41312. offset: pointXOffset,
  41313. paddedWidth: pointOffsetWidth,
  41314. columnCount: columnCount
  41315. };
  41316. return series.columnMetrics;
  41317. };
  41318. /**
  41319. * Make the columns crisp. The edges are rounded to the nearest full
  41320. * pixel.
  41321. *
  41322. * @private
  41323. * @function Highcharts.seriesTypes.column#crispCol
  41324. */
  41325. ColumnSeries.prototype.crispCol = function (x, y, w, h) {
  41326. var chart = this.chart,
  41327. borderWidth = this.borderWidth,
  41328. xCrisp = -(borderWidth % 2 ? 0.5 : 0),
  41329. yCrisp = borderWidth % 2 ? 0.5 : 1,
  41330. right,
  41331. bottom,
  41332. fromTop;
  41333. if (chart.inverted && chart.renderer.isVML) {
  41334. yCrisp += 1;
  41335. }
  41336. // Horizontal. We need to first compute the exact right edge, then
  41337. // round it and compute the width from there.
  41338. if (this.options.crisp) {
  41339. right = Math.round(x + w) + xCrisp;
  41340. x = Math.round(x) + xCrisp;
  41341. w = right - x;
  41342. }
  41343. // Vertical
  41344. bottom = Math.round(y + h) + yCrisp;
  41345. fromTop = Math.abs(y) <= 0.5 && bottom > 0.5; // #4504, #4656
  41346. y = Math.round(y) + yCrisp;
  41347. h = bottom - y;
  41348. // Top edges are exceptions
  41349. if (fromTop && h) { // #5146
  41350. y -= 1;
  41351. h += 1;
  41352. }
  41353. return {
  41354. x: x,
  41355. y: y,
  41356. width: w,
  41357. height: h
  41358. };
  41359. };
  41360. /**
  41361. * Adjust for missing columns, according to the `centerInCategory`
  41362. * option. Missing columns are either single points or stacks where the
  41363. * point or points are either missing or null.
  41364. *
  41365. * @private
  41366. * @function Highcharts.seriesTypes.column#adjustForMissingColumns
  41367. * @param {number} x
  41368. * The x coordinate of the column, left side
  41369. *
  41370. * @param {number} pointWidth
  41371. * The pointWidth, already computed upstream
  41372. *
  41373. * @param {Highcharts.ColumnPoint} point
  41374. * The point instance
  41375. *
  41376. * @param {Highcharts.ColumnMetricsObject} metrics
  41377. * The series-wide column metrics
  41378. *
  41379. * @return {number}
  41380. * The adjusted x position, or the original if not adjusted
  41381. */
  41382. ColumnSeries.prototype.adjustForMissingColumns = function (x, pointWidth, point, metrics) {
  41383. var _this = this;
  41384. var stacking = this.options.stacking;
  41385. if (!point.isNull && metrics.columnCount > 1) {
  41386. var indexInCategory_1 = 0;
  41387. var totalInCategory_1 = 0;
  41388. // Loop over all the stacks on the Y axis. When stacking is
  41389. // enabled, these are real point stacks. When stacking is not
  41390. // enabled, but `centerInCategory` is true, there is one stack
  41391. // handling the grouping of points in each category. This is
  41392. // done in the `setGroupedPoints` function.
  41393. objectEach(this.yAxis.stacking && this.yAxis.stacking.stacks, function (stack) {
  41394. if (typeof point.x === 'number') {
  41395. var stackItem = stack[point.x.toString()];
  41396. if (stackItem) {
  41397. var pointValues = stackItem.points[_this.index],
  41398. total = stackItem.total;
  41399. // If true `stacking` is enabled, count the
  41400. // total number of non-null stacks in the
  41401. // category, and note which index this point is
  41402. // within those stacks.
  41403. if (stacking) {
  41404. if (pointValues) {
  41405. indexInCategory_1 = totalInCategory_1;
  41406. }
  41407. if (stackItem.hasValidPoints) {
  41408. totalInCategory_1++;
  41409. }
  41410. // If `stacking` is not enabled, look for the
  41411. // index and total of the `group` stack.
  41412. }
  41413. else if (isArray(pointValues)) {
  41414. indexInCategory_1 = pointValues[1];
  41415. totalInCategory_1 = total || 0;
  41416. }
  41417. }
  41418. }
  41419. });
  41420. // Compute the adjusted x position
  41421. var boxWidth = (totalInCategory_1 - 1) * metrics.paddedWidth +
  41422. pointWidth;
  41423. x = (point.plotX || 0) + boxWidth / 2 - pointWidth -
  41424. indexInCategory_1 * metrics.paddedWidth;
  41425. }
  41426. return x;
  41427. };
  41428. /**
  41429. * Translate each point to the plot area coordinate system and find
  41430. * shape positions
  41431. *
  41432. * @private
  41433. * @function Highcharts.seriesTypes.column#translate
  41434. */
  41435. ColumnSeries.prototype.translate = function () {
  41436. var series = this,
  41437. chart = series.chart,
  41438. options = series.options,
  41439. dense = series.dense =
  41440. series.closestPointRange * series.xAxis.transA < 2,
  41441. borderWidth = series.borderWidth = pick(options.borderWidth,
  41442. dense ? 0 : 1 // #3635
  41443. ),
  41444. xAxis = series.xAxis,
  41445. yAxis = series.yAxis,
  41446. threshold = options.threshold,
  41447. translatedThreshold = series.translatedThreshold =
  41448. yAxis.getThreshold(threshold),
  41449. minPointLength = pick(options.minPointLength, 5),
  41450. metrics = series.getColumnMetrics(),
  41451. seriesPointWidth = metrics.width,
  41452. // postprocessed for border width
  41453. seriesBarW = series.barW =
  41454. Math.max(seriesPointWidth, 1 + 2 * borderWidth),
  41455. seriesXOffset = series.pointXOffset = metrics.offset,
  41456. dataMin = series.dataMin,
  41457. dataMax = series.dataMax;
  41458. if (chart.inverted) {
  41459. translatedThreshold -= 0.5; // #3355
  41460. }
  41461. // When the pointPadding is 0, we want the columns to be packed
  41462. // tightly, so we allow individual columns to have individual sizes.
  41463. // When pointPadding is greater, we strive for equal-width columns
  41464. // (#2694).
  41465. if (options.pointPadding) {
  41466. seriesBarW = Math.ceil(seriesBarW);
  41467. }
  41468. Series.prototype.translate.apply(series);
  41469. // Record the new values
  41470. series.points.forEach(function (point) {
  41471. var yBottom = pick(point.yBottom,
  41472. translatedThreshold),
  41473. safeDistance = 999 + Math.abs(yBottom),
  41474. pointWidth = seriesPointWidth,
  41475. plotX = point.plotX || 0,
  41476. // Don't draw too far outside plot area (#1303, #2241,
  41477. // #4264)
  41478. plotY = clamp(point.plotY, -safeDistance,
  41479. yAxis.len + safeDistance),
  41480. barX = plotX + seriesXOffset,
  41481. barW = seriesBarW,
  41482. barY = Math.min(plotY,
  41483. yBottom),
  41484. up,
  41485. barH = Math.max(plotY,
  41486. yBottom) - barY;
  41487. // Handle options.minPointLength
  41488. if (minPointLength && Math.abs(barH) < minPointLength) {
  41489. barH = minPointLength;
  41490. up = (!yAxis.reversed && !point.negative) ||
  41491. (yAxis.reversed && point.negative);
  41492. // Reverse zeros if there's no positive value in the series
  41493. // in visible range (#7046)
  41494. if (isNumber(threshold) &&
  41495. isNumber(dataMax) &&
  41496. point.y === threshold &&
  41497. dataMax <= threshold &&
  41498. // and if there's room for it (#7311)
  41499. (yAxis.min || 0) < threshold &&
  41500. // if all points are the same value (i.e zero) not draw
  41501. // as negative points (#10646), but only if there's room
  41502. // for it (#14876)
  41503. (dataMin !== dataMax || (yAxis.max || 0) <= threshold)) {
  41504. up = !up;
  41505. }
  41506. // If stacked...
  41507. barY = (Math.abs(barY - translatedThreshold) > minPointLength ?
  41508. // ...keep position
  41509. yBottom - minPointLength :
  41510. // #1485, #4051
  41511. translatedThreshold -
  41512. (up ? minPointLength : 0));
  41513. }
  41514. // Handle point.options.pointWidth
  41515. // @todo Handle grouping/stacking too. Calculate offset properly
  41516. if (defined(point.options.pointWidth)) {
  41517. pointWidth = barW =
  41518. Math.ceil(point.options.pointWidth);
  41519. barX -= Math.round((pointWidth - seriesPointWidth) / 2);
  41520. }
  41521. // Adjust for null or missing points
  41522. if (options.centerInCategory) {
  41523. barX = series.adjustForMissingColumns(barX, pointWidth, point, metrics);
  41524. }
  41525. // Cache for access in polar
  41526. point.barX = barX;
  41527. point.pointWidth = pointWidth;
  41528. // Fix the tooltip on center of grouped columns (#1216, #424,
  41529. // #3648)
  41530. point.tooltipPos = chart.inverted ?
  41531. [
  41532. clamp(yAxis.len + yAxis.pos - chart.plotLeft - plotY, yAxis.pos - chart.plotLeft, yAxis.len + yAxis.pos - chart.plotLeft),
  41533. xAxis.len + xAxis.pos - chart.plotTop - (plotX || 0) - seriesXOffset - barW / 2,
  41534. barH
  41535. ] :
  41536. [
  41537. xAxis.left - chart.plotLeft + barX + barW / 2,
  41538. clamp(plotY + yAxis.pos -
  41539. chart.plotTop, yAxis.pos - chart.plotTop, yAxis.len + yAxis.pos - chart.plotTop),
  41540. barH
  41541. ];
  41542. // Register shape type and arguments to be used in drawPoints
  41543. // Allow shapeType defined on pointClass level
  41544. point.shapeType = series.pointClass.prototype.shapeType || 'rect';
  41545. point.shapeArgs = series.crispCol.apply(series, point.isNull ?
  41546. // #3169, drilldown from null must have a position to work
  41547. // from #6585, dataLabel should be placed on xAxis, not
  41548. // floating in the middle of the chart
  41549. [barX, translatedThreshold, barW, 0] :
  41550. [barX, barY, barW, barH]);
  41551. });
  41552. };
  41553. /**
  41554. * Columns have no graph
  41555. *
  41556. * @private
  41557. * @function Highcharts.seriesTypes.column#drawGraph
  41558. */
  41559. ColumnSeries.prototype.drawGraph = function () {
  41560. this.group[this.dense ? 'addClass' : 'removeClass']('highcharts-dense-data');
  41561. };
  41562. /**
  41563. * Get presentational attributes
  41564. *
  41565. * @private
  41566. * @function Highcharts.seriesTypes.column#pointAttribs
  41567. */
  41568. ColumnSeries.prototype.pointAttribs = function (point, state) {
  41569. var options = this.options, stateOptions, ret, p2o = this.pointAttrToOptions || {}, strokeOption = p2o.stroke || 'borderColor', strokeWidthOption = p2o['stroke-width'] || 'borderWidth', fill = (point && point.color) || this.color,
  41570. // set to fill when borderColor null:
  41571. stroke = ((point && point[strokeOption]) ||
  41572. options[strokeOption] ||
  41573. this.color ||
  41574. fill), strokeWidth = (point && point[strokeWidthOption]) ||
  41575. options[strokeWidthOption] ||
  41576. this[strokeWidthOption] || 0, dashstyle = (point && point.options.dashStyle) || options.dashStyle, opacity = pick(point && point.opacity, options.opacity, 1), zone, brightness;
  41577. // Handle zone colors
  41578. if (point && this.zones.length) {
  41579. zone = point.getZone();
  41580. // When zones are present, don't use point.color (#4267).
  41581. // Changed order (#6527), added support for colorAxis (#10670)
  41582. fill = (point.options.color ||
  41583. (zone && (zone.color || point.nonZonedColor)) ||
  41584. this.color);
  41585. if (zone) {
  41586. stroke = zone.borderColor || stroke;
  41587. dashstyle = zone.dashStyle || dashstyle;
  41588. strokeWidth = zone.borderWidth || strokeWidth;
  41589. }
  41590. }
  41591. // Select or hover states
  41592. if (state && point) {
  41593. stateOptions = merge(options.states[state],
  41594. // #6401
  41595. point.options.states &&
  41596. point.options.states[state] ||
  41597. {});
  41598. brightness = stateOptions.brightness;
  41599. fill =
  41600. stateOptions.color || (typeof brightness !== 'undefined' &&
  41601. color(fill)
  41602. .brighten(stateOptions.brightness)
  41603. .get()) || fill;
  41604. stroke = stateOptions[strokeOption] || stroke;
  41605. strokeWidth =
  41606. stateOptions[strokeWidthOption] || strokeWidth;
  41607. dashstyle = stateOptions.dashStyle || dashstyle;
  41608. opacity = pick(stateOptions.opacity, opacity);
  41609. }
  41610. ret = {
  41611. fill: fill,
  41612. stroke: stroke,
  41613. 'stroke-width': strokeWidth,
  41614. opacity: opacity
  41615. };
  41616. if (dashstyle) {
  41617. ret.dashstyle = dashstyle;
  41618. }
  41619. return ret;
  41620. };
  41621. /**
  41622. * Draw the columns. For bars, the series.group is rotated, so the same
  41623. * coordinates apply for columns and bars. This method is inherited by
  41624. * scatter series.
  41625. *
  41626. * @private
  41627. * @function Highcharts.seriesTypes.column#drawPoints
  41628. */
  41629. ColumnSeries.prototype.drawPoints = function () {
  41630. var series = this,
  41631. chart = this.chart,
  41632. options = series.options,
  41633. renderer = chart.renderer,
  41634. animationLimit = options.animationLimit || 250,
  41635. shapeArgs;
  41636. // draw the columns
  41637. series.points.forEach(function (point) {
  41638. var plotY = point.plotY,
  41639. graphic = point.graphic,
  41640. hasGraphic = !!graphic,
  41641. verb = graphic && chart.pointCount < animationLimit ?
  41642. 'animate' : 'attr';
  41643. if (isNumber(plotY) && point.y !== null) {
  41644. shapeArgs = point.shapeArgs;
  41645. // When updating a series between 2d and 3d or cartesian and
  41646. // polar, the shape type changes.
  41647. if (graphic && point.hasNewShapeType()) {
  41648. graphic = graphic.destroy();
  41649. }
  41650. // Set starting position for point sliding animation.
  41651. if (series.enabledDataSorting) {
  41652. point.startXPos = series.xAxis.reversed ?
  41653. -(shapeArgs ? shapeArgs.width : 0) :
  41654. series.xAxis.width;
  41655. }
  41656. if (!graphic) {
  41657. point.graphic = graphic =
  41658. renderer[point.shapeType](shapeArgs)
  41659. .add(point.group || series.group);
  41660. if (graphic &&
  41661. series.enabledDataSorting &&
  41662. chart.hasRendered &&
  41663. chart.pointCount < animationLimit) {
  41664. graphic.attr({
  41665. x: point.startXPos
  41666. });
  41667. hasGraphic = true;
  41668. verb = 'animate';
  41669. }
  41670. }
  41671. if (graphic && hasGraphic) { // update
  41672. graphic[verb](merge(shapeArgs));
  41673. }
  41674. // Border radius is not stylable (#6900)
  41675. if (options.borderRadius) {
  41676. graphic[verb]({
  41677. r: options.borderRadius
  41678. });
  41679. }
  41680. // Presentational
  41681. if (!chart.styledMode) {
  41682. graphic[verb](series.pointAttribs(point, (point.selected && 'select')))
  41683. .shadow(point.allowShadow !== false && options.shadow, null, options.stacking && !options.borderRadius);
  41684. }
  41685. if (graphic) {
  41686. graphic.addClass(point.getClassName(), true);
  41687. graphic.attr({
  41688. visibility: point.visible ? 'inherit' : 'hidden'
  41689. });
  41690. }
  41691. }
  41692. else if (graphic) {
  41693. point.graphic = graphic.destroy(); // #1269
  41694. }
  41695. });
  41696. };
  41697. /**
  41698. * Draw the tracker for a point.
  41699. * @private
  41700. */
  41701. ColumnSeries.prototype.drawTracker = function () {
  41702. var series = this,
  41703. chart = series.chart,
  41704. pointer = chart.pointer,
  41705. onMouseOver = function (e) {
  41706. var point = pointer.getPointFromEvent(e);
  41707. // undefined on graph in scatterchart
  41708. if (typeof point !== 'undefined') {
  41709. pointer.isDirectTouch = true;
  41710. point.onMouseOver(e);
  41711. }
  41712. }, dataLabels;
  41713. // Add reference to the point
  41714. series.points.forEach(function (point) {
  41715. dataLabels = (isArray(point.dataLabels) ?
  41716. point.dataLabels :
  41717. (point.dataLabel ? [point.dataLabel] : []));
  41718. if (point.graphic) {
  41719. point.graphic.element.point = point;
  41720. }
  41721. dataLabels.forEach(function (dataLabel) {
  41722. if (dataLabel.div) {
  41723. dataLabel.div.point = point;
  41724. }
  41725. else {
  41726. dataLabel.element.point = point;
  41727. }
  41728. });
  41729. });
  41730. // Add the event listeners, we need to do this only once
  41731. if (!series._hasTracking) {
  41732. series.trackerGroups.forEach(function (key) {
  41733. if (series[key]) {
  41734. // we don't always have dataLabelsGroup
  41735. series[key]
  41736. .addClass('highcharts-tracker')
  41737. .on('mouseover', onMouseOver)
  41738. .on('mouseout', function (e) {
  41739. pointer.onTrackerMouseOut(e);
  41740. });
  41741. if (hasTouch) {
  41742. series[key].on('touchstart', onMouseOver);
  41743. }
  41744. if (!chart.styledMode && series.options.cursor) {
  41745. series[key]
  41746. .css(css)
  41747. .css({ cursor: series.options.cursor });
  41748. }
  41749. }
  41750. });
  41751. series._hasTracking = true;
  41752. }
  41753. fireEvent(this, 'afterDrawTracker');
  41754. };
  41755. /**
  41756. * Remove this series from the chart
  41757. *
  41758. * @private
  41759. * @function Highcharts.seriesTypes.column#remove
  41760. */
  41761. ColumnSeries.prototype.remove = function () {
  41762. var series = this,
  41763. chart = series.chart;
  41764. // column and bar series affects other series of the same type
  41765. // as they are either stacked or grouped
  41766. if (chart.hasRendered) {
  41767. chart.series.forEach(function (otherSeries) {
  41768. if (otherSeries.type === series.type) {
  41769. otherSeries.isDirty = true;
  41770. }
  41771. });
  41772. }
  41773. Series.prototype.remove.apply(series, arguments);
  41774. };
  41775. /**
  41776. * Column series display one column per value along an X axis.
  41777. *
  41778. * @sample {highcharts} highcharts/demo/column-basic/
  41779. * Column chart
  41780. * @sample {highstock} stock/demo/column/
  41781. * Column chart
  41782. *
  41783. * @extends plotOptions.line
  41784. * @excluding connectEnds, connectNulls, gapSize, gapUnit, linecap,
  41785. * lineWidth, marker, step, useOhlcData
  41786. * @product highcharts highstock
  41787. * @optionparent plotOptions.column
  41788. */
  41789. ColumnSeries.defaultOptions = merge(Series.defaultOptions, {
  41790. /**
  41791. * The corner radius of the border surrounding each column or bar.
  41792. *
  41793. * @sample {highcharts} highcharts/plotoptions/column-borderradius/
  41794. * Rounded columns
  41795. *
  41796. * @product highcharts highstock gantt
  41797. *
  41798. * @private
  41799. */
  41800. borderRadius: 0,
  41801. /**
  41802. * When using automatic point colors pulled from the global
  41803. * [colors](colors) or series-specific
  41804. * [plotOptions.column.colors](series.colors) collections, this option
  41805. * determines whether the chart should receive one color per series or
  41806. * one color per point.
  41807. *
  41808. * In styled mode, the `colors` or `series.colors` arrays are not
  41809. * supported, and instead this option gives the points individual color
  41810. * class names on the form `highcharts-color-{n}`.
  41811. *
  41812. * @see [series colors](#plotOptions.column.colors)
  41813. *
  41814. * @sample {highcharts} highcharts/plotoptions/column-colorbypoint-false/
  41815. * False by default
  41816. * @sample {highcharts} highcharts/plotoptions/column-colorbypoint-true/
  41817. * True
  41818. *
  41819. * @type {boolean}
  41820. * @default false
  41821. * @since 2.0
  41822. * @product highcharts highstock gantt
  41823. * @apioption plotOptions.column.colorByPoint
  41824. */
  41825. /**
  41826. * A series specific or series type specific color set to apply instead
  41827. * of the global [colors](#colors) when [colorByPoint](
  41828. * #plotOptions.column.colorByPoint) is true.
  41829. *
  41830. * @type {Array<Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject>}
  41831. * @since 3.0
  41832. * @product highcharts highstock gantt
  41833. * @apioption plotOptions.column.colors
  41834. */
  41835. /**
  41836. * When `true`, the columns will center in the category, ignoring null
  41837. * or missing points. When `false`, space will be reserved for null or
  41838. * missing points.
  41839. *
  41840. * @sample {highcharts} highcharts/series-column/centerincategory/
  41841. * Center in category
  41842. *
  41843. * @since 8.0.1
  41844. * @product highcharts highstock gantt
  41845. *
  41846. * @private
  41847. */
  41848. centerInCategory: false,
  41849. /**
  41850. * Padding between each value groups, in x axis units.
  41851. *
  41852. * @sample {highcharts} highcharts/plotoptions/column-grouppadding-default/
  41853. * 0.2 by default
  41854. * @sample {highcharts} highcharts/plotoptions/column-grouppadding-none/
  41855. * No group padding - all columns are evenly spaced
  41856. *
  41857. * @product highcharts highstock gantt
  41858. *
  41859. * @private
  41860. */
  41861. groupPadding: 0.2,
  41862. /**
  41863. * Whether to group non-stacked columns or to let them render
  41864. * independent of each other. Non-grouped columns will be laid out
  41865. * individually and overlap each other.
  41866. *
  41867. * @sample {highcharts} highcharts/plotoptions/column-grouping-false/
  41868. * Grouping disabled
  41869. * @sample {highstock} highcharts/plotoptions/column-grouping-false/
  41870. * Grouping disabled
  41871. *
  41872. * @type {boolean}
  41873. * @default true
  41874. * @since 2.3.0
  41875. * @product highcharts highstock gantt
  41876. * @apioption plotOptions.column.grouping
  41877. */
  41878. /**
  41879. * @ignore-option
  41880. * @private
  41881. */
  41882. marker: null,
  41883. /**
  41884. * The maximum allowed pixel width for a column, translated to the
  41885. * height of a bar in a bar chart. This prevents the columns from
  41886. * becoming too wide when there is a small number of points in the
  41887. * chart.
  41888. *
  41889. * @see [pointWidth](#plotOptions.column.pointWidth)
  41890. *
  41891. * @sample {highcharts} highcharts/plotoptions/column-maxpointwidth-20/
  41892. * Limited to 50
  41893. * @sample {highstock} highcharts/plotoptions/column-maxpointwidth-20/
  41894. * Limited to 50
  41895. *
  41896. * @type {number}
  41897. * @since 4.1.8
  41898. * @product highcharts highstock gantt
  41899. * @apioption plotOptions.column.maxPointWidth
  41900. */
  41901. /**
  41902. * Padding between each column or bar, in x axis units.
  41903. *
  41904. * @sample {highcharts} highcharts/plotoptions/column-pointpadding-default/
  41905. * 0.1 by default
  41906. * @sample {highcharts} highcharts/plotoptions/column-pointpadding-025/
  41907. * 0.25
  41908. * @sample {highcharts} highcharts/plotoptions/column-pointpadding-none/
  41909. * 0 for tightly packed columns
  41910. *
  41911. * @product highcharts highstock gantt
  41912. *
  41913. * @private
  41914. */
  41915. pointPadding: 0.1,
  41916. /**
  41917. * A pixel value specifying a fixed width for each column or bar point.
  41918. * When set to `undefined`, the width is calculated from the
  41919. * `pointPadding` and `groupPadding`. The width effects the dimension
  41920. * that is not based on the point value. For column series it is the
  41921. * hoizontal length and for bar series it is the vertical length.
  41922. *
  41923. * @see [maxPointWidth](#plotOptions.column.maxPointWidth)
  41924. *
  41925. * @sample {highcharts} highcharts/plotoptions/column-pointwidth-20/
  41926. * 20px wide columns regardless of chart width or the amount of
  41927. * data points
  41928. *
  41929. * @type {number}
  41930. * @since 1.2.5
  41931. * @product highcharts highstock gantt
  41932. * @apioption plotOptions.column.pointWidth
  41933. */
  41934. /**
  41935. * A pixel value specifying a fixed width for the column or bar.
  41936. * Overrides pointWidth on the series.
  41937. *
  41938. * @see [series.pointWidth](#plotOptions.column.pointWidth)
  41939. *
  41940. * @type {number}
  41941. * @default undefined
  41942. * @since 7.0.0
  41943. * @product highcharts highstock gantt
  41944. * @apioption series.column.data.pointWidth
  41945. */
  41946. /**
  41947. * The minimal height for a column or width for a bar. By default,
  41948. * 0 values are not shown. To visualize a 0 (or close to zero) point,
  41949. * set the minimal point length to a pixel value like 3\. In stacked
  41950. * column charts, minPointLength might not be respected for tightly
  41951. * packed values.
  41952. *
  41953. * @sample {highcharts} highcharts/plotoptions/column-minpointlength/
  41954. * Zero base value
  41955. * @sample {highcharts} highcharts/plotoptions/column-minpointlength-pos-and-neg/
  41956. * Positive and negative close to zero values
  41957. *
  41958. * @product highcharts highstock gantt
  41959. *
  41960. * @private
  41961. */
  41962. minPointLength: 0,
  41963. /**
  41964. * When the series contains less points than the crop threshold, all
  41965. * points are drawn, event if the points fall outside the visible plot
  41966. * area at the current zoom. The advantage of drawing all points
  41967. * (including markers and columns), is that animation is performed on
  41968. * updates. On the other hand, when the series contains more points than
  41969. * the crop threshold, the series data is cropped to only contain points
  41970. * that fall within the plot area. The advantage of cropping away
  41971. * invisible points is to increase performance on large series.
  41972. *
  41973. * @product highcharts highstock gantt
  41974. *
  41975. * @private
  41976. */
  41977. cropThreshold: 50,
  41978. /**
  41979. * The X axis range that each point is valid for. This determines the
  41980. * width of the column. On a categorized axis, the range will be 1
  41981. * by default (one category unit). On linear and datetime axes, the
  41982. * range will be computed as the distance between the two closest data
  41983. * points.
  41984. *
  41985. * The default `null` means it is computed automatically, but this
  41986. * option can be used to override the automatic value.
  41987. *
  41988. * This option is set by default to 1 if data sorting is enabled.
  41989. *
  41990. * @sample {highcharts} highcharts/plotoptions/column-pointrange/
  41991. * Set the point range to one day on a data set with one week
  41992. * between the points
  41993. *
  41994. * @type {number|null}
  41995. * @since 2.3
  41996. * @product highcharts highstock gantt
  41997. *
  41998. * @private
  41999. */
  42000. pointRange: null,
  42001. states: {
  42002. /**
  42003. * Options for the hovered point. These settings override the normal
  42004. * state options when a point is moused over or touched.
  42005. *
  42006. * @extends plotOptions.series.states.hover
  42007. * @excluding halo, lineWidth, lineWidthPlus, marker
  42008. * @product highcharts highstock gantt
  42009. */
  42010. hover: {
  42011. /** @ignore-option */
  42012. halo: false,
  42013. /**
  42014. * A specific border color for the hovered point. Defaults to
  42015. * inherit the normal state border color.
  42016. *
  42017. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  42018. * @product highcharts gantt
  42019. * @apioption plotOptions.column.states.hover.borderColor
  42020. */
  42021. /**
  42022. * A specific color for the hovered point.
  42023. *
  42024. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  42025. * @product highcharts gantt
  42026. * @apioption plotOptions.column.states.hover.color
  42027. */
  42028. /**
  42029. * How much to brighten the point on interaction. Requires the
  42030. * main color to be defined in hex or rgb(a) format.
  42031. *
  42032. * In styled mode, the hover brightening is by default replaced
  42033. * with a fill-opacity set in the `.highcharts-point:hover`
  42034. * rule.
  42035. *
  42036. * @sample {highcharts} highcharts/plotoptions/column-states-hover-brightness/
  42037. * Brighten by 0.5
  42038. *
  42039. * @product highcharts highstock gantt
  42040. */
  42041. brightness: 0.1
  42042. },
  42043. /**
  42044. * Options for the selected point. These settings override the
  42045. * normal state options when a point is selected.
  42046. *
  42047. * @extends plotOptions.series.states.select
  42048. * @excluding halo, lineWidth, lineWidthPlus, marker
  42049. * @product highcharts highstock gantt
  42050. */
  42051. select: {
  42052. /**
  42053. * A specific color for the selected point.
  42054. *
  42055. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  42056. * @default #cccccc
  42057. * @product highcharts highstock gantt
  42058. */
  42059. color: palette.neutralColor20,
  42060. /**
  42061. * A specific border color for the selected point.
  42062. *
  42063. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  42064. * @default #000000
  42065. * @product highcharts highstock gantt
  42066. */
  42067. borderColor: palette.neutralColor100
  42068. }
  42069. },
  42070. dataLabels: {
  42071. align: void 0,
  42072. verticalAlign: void 0,
  42073. /**
  42074. * The y position offset of the label relative to the point in
  42075. * pixels.
  42076. *
  42077. * @type {number}
  42078. */
  42079. y: void 0
  42080. },
  42081. // false doesn't work well: https://jsfiddle.net/highcharts/hz8fopan/14/
  42082. /**
  42083. * @ignore-option
  42084. * @private
  42085. */
  42086. startFromThreshold: true,
  42087. stickyTracking: false,
  42088. tooltip: {
  42089. distance: 6
  42090. },
  42091. /**
  42092. * The Y axis value to serve as the base for the columns, for
  42093. * distinguishing between values above and below a threshold. If `null`,
  42094. * the columns extend from the padding Y axis minimum.
  42095. *
  42096. * @type {number|null}
  42097. * @since 2.0
  42098. * @product highcharts
  42099. *
  42100. * @private
  42101. */
  42102. threshold: 0,
  42103. /**
  42104. * The width of the border surrounding each column or bar. Defaults to
  42105. * `1` when there is room for a border, but to `0` when the columns are
  42106. * so dense that a border would cover the next column.
  42107. *
  42108. * In styled mode, the stroke width can be set with the
  42109. * `.highcharts-point` rule.
  42110. *
  42111. * @sample {highcharts} highcharts/plotoptions/column-borderwidth/
  42112. * 2px black border
  42113. *
  42114. * @type {number}
  42115. * @default undefined
  42116. * @product highcharts highstock gantt
  42117. * @apioption plotOptions.column.borderWidth
  42118. */
  42119. /**
  42120. * The color of the border surrounding each column or bar.
  42121. *
  42122. * In styled mode, the border stroke can be set with the
  42123. * `.highcharts-point` rule.
  42124. *
  42125. * @sample {highcharts} highcharts/plotoptions/column-bordercolor/
  42126. * Dark gray border
  42127. *
  42128. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  42129. * @default #ffffff
  42130. * @product highcharts highstock gantt
  42131. *
  42132. * @private
  42133. */
  42134. borderColor: palette.backgroundColor
  42135. });
  42136. return ColumnSeries;
  42137. }(Series));
  42138. extend(ColumnSeries.prototype, {
  42139. cropShoulder: 0,
  42140. // When tooltip is not shared, this series (and derivatives) requires
  42141. // direct touch/hover. KD-tree does not apply.
  42142. directTouch: true,
  42143. /**
  42144. * Use a solid rectangle like the area series types
  42145. *
  42146. * @private
  42147. * @function Highcharts.seriesTypes.column#drawLegendSymbol
  42148. *
  42149. * @param {Highcharts.Legend} legend
  42150. * The legend object
  42151. *
  42152. * @param {Highcharts.Series|Highcharts.Point} item
  42153. * The series (this) or point
  42154. */
  42155. drawLegendSymbol: LegendSymbolMixin.drawRectangle,
  42156. getSymbol: noop,
  42157. // use separate negative stacks, unlike area stacks where a negative
  42158. // point is substracted from previous (#1910)
  42159. negStacks: true,
  42160. trackerGroups: ['group', 'dataLabelsGroup']
  42161. });
  42162. SeriesRegistry.registerSeriesType('column', ColumnSeries);
  42163. /* *
  42164. *
  42165. * Export
  42166. *
  42167. * */
  42168. /* *
  42169. *
  42170. * API Declarations
  42171. *
  42172. * */
  42173. /**
  42174. * Adjusted width and x offset of the columns for grouping.
  42175. *
  42176. * @private
  42177. * @interface Highcharts.ColumnMetricsObject
  42178. */ /**
  42179. * Width of the columns.
  42180. * @name Highcharts.ColumnMetricsObject#width
  42181. * @type {number}
  42182. */ /**
  42183. * Offset of the columns.
  42184. * @name Highcharts.ColumnMetricsObject#offset
  42185. * @type {number}
  42186. */
  42187. ''; // detach doclets above
  42188. /* *
  42189. *
  42190. * API Options
  42191. *
  42192. * */
  42193. /**
  42194. * A `column` series. If the [type](#series.column.type) option is
  42195. * not specified, it is inherited from [chart.type](#chart.type).
  42196. *
  42197. * @extends series,plotOptions.column
  42198. * @excluding connectNulls, dataParser, dataURL, gapSize, gapUnit, linecap,
  42199. * lineWidth, marker, connectEnds, step
  42200. * @product highcharts highstock
  42201. * @apioption series.column
  42202. */
  42203. /**
  42204. * An array of data points for the series. For the `column` series type,
  42205. * points can be given in the following ways:
  42206. *
  42207. * 1. An array of numerical values. In this case, the numerical values will be
  42208. * interpreted as `y` options. The `x` values will be automatically
  42209. * calculated, either starting at 0 and incremented by 1, or from
  42210. * `pointStart` and `pointInterval` given in the series options. If the axis
  42211. * has categories, these will be used. Example:
  42212. * ```js
  42213. * data: [0, 5, 3, 5]
  42214. * ```
  42215. *
  42216. * 2. An array of arrays with 2 values. In this case, the values correspond to
  42217. * `x,y`. If the first value is a string, it is applied as the name of the
  42218. * point, and the `x` value is inferred.
  42219. * ```js
  42220. * data: [
  42221. * [0, 6],
  42222. * [1, 2],
  42223. * [2, 6]
  42224. * ]
  42225. * ```
  42226. *
  42227. * 3. An array of objects with named values. The following snippet shows only a
  42228. * few settings, see the complete options set below. If the total number of
  42229. * data points exceeds the series'
  42230. * [turboThreshold](#series.column.turboThreshold), this option is not
  42231. * available.
  42232. * ```js
  42233. * data: [{
  42234. * x: 1,
  42235. * y: 9,
  42236. * name: "Point2",
  42237. * color: "#00FF00"
  42238. * }, {
  42239. * x: 1,
  42240. * y: 6,
  42241. * name: "Point1",
  42242. * color: "#FF00FF"
  42243. * }]
  42244. * ```
  42245. *
  42246. * @sample {highcharts} highcharts/chart/reflow-true/
  42247. * Numerical values
  42248. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  42249. * Arrays of numeric x and y
  42250. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  42251. * Arrays of datetime x and y
  42252. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  42253. * Arrays of point.name and y
  42254. * @sample {highcharts} highcharts/series/data-array-of-objects/
  42255. * Config objects
  42256. *
  42257. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  42258. * @extends series.line.data
  42259. * @excluding marker
  42260. * @product highcharts highstock
  42261. * @apioption series.column.data
  42262. */
  42263. /**
  42264. * The color of the border surrounding the column or bar.
  42265. *
  42266. * In styled mode, the border stroke can be set with the `.highcharts-point`
  42267. * rule.
  42268. *
  42269. * @sample {highcharts} highcharts/plotoptions/column-bordercolor/
  42270. * Dark gray border
  42271. *
  42272. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  42273. * @product highcharts highstock
  42274. * @apioption series.column.data.borderColor
  42275. */
  42276. /**
  42277. * The width of the border surrounding the column or bar.
  42278. *
  42279. * In styled mode, the stroke width can be set with the `.highcharts-point`
  42280. * rule.
  42281. *
  42282. * @sample {highcharts} highcharts/plotoptions/column-borderwidth/
  42283. * 2px black border
  42284. *
  42285. * @type {number}
  42286. * @product highcharts highstock
  42287. * @apioption series.column.data.borderWidth
  42288. */
  42289. /**
  42290. * A name for the dash style to use for the column or bar. Overrides
  42291. * dashStyle on the series.
  42292. *
  42293. * In styled mode, the stroke dash-array can be set with the same classes as
  42294. * listed under [data.color](#series.column.data.color).
  42295. *
  42296. * @see [series.pointWidth](#plotOptions.column.dashStyle)
  42297. *
  42298. * @type {Highcharts.DashStyleValue}
  42299. * @apioption series.column.data.dashStyle
  42300. */
  42301. /**
  42302. * A pixel value specifying a fixed width for the column or bar. Overrides
  42303. * pointWidth on the series. The width effects the dimension that is not based
  42304. * on the point value.
  42305. *
  42306. * @see [series.pointWidth](#plotOptions.column.pointWidth)
  42307. *
  42308. * @type {number}
  42309. * @apioption series.column.data.pointWidth
  42310. */
  42311. /**
  42312. * @excluding halo, lineWidth, lineWidthPlus, marker
  42313. * @product highcharts highstock
  42314. * @apioption series.column.states.hover
  42315. */
  42316. /**
  42317. * @excluding halo, lineWidth, lineWidthPlus, marker
  42318. * @product highcharts highstock
  42319. * @apioption series.column.states.select
  42320. */
  42321. ''; // includes above doclets in transpilat
  42322. return ColumnSeries;
  42323. });
  42324. _registerModule(_modules, 'Series/Bar/BarSeries.js', [_modules['Series/Column/ColumnSeries.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (ColumnSeries, SeriesRegistry, U) {
  42325. /* *
  42326. *
  42327. * (c) 2010-2021 Torstein Honsi
  42328. *
  42329. * License: www.highcharts.com/license
  42330. *
  42331. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  42332. *
  42333. * */
  42334. var __extends = (this && this.__extends) || (function () {
  42335. var extendStatics = function (d,
  42336. b) {
  42337. extendStatics = Object.setPrototypeOf ||
  42338. ({ __proto__: [] } instanceof Array && function (d,
  42339. b) { d.__proto__ = b; }) ||
  42340. function (d,
  42341. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  42342. return extendStatics(d, b);
  42343. };
  42344. return function (d, b) {
  42345. extendStatics(d, b);
  42346. function __() { this.constructor = d; }
  42347. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  42348. };
  42349. })();
  42350. var extend = U.extend,
  42351. merge = U.merge;
  42352. /* *
  42353. *
  42354. * Class
  42355. *
  42356. * */
  42357. /**
  42358. * Bar series type.
  42359. *
  42360. * @private
  42361. * @class
  42362. * @name Highcharts.seriesTypes.bar
  42363. *
  42364. * @augments Highcharts.Series
  42365. */
  42366. var BarSeries = /** @class */ (function (_super) {
  42367. __extends(BarSeries, _super);
  42368. function BarSeries() {
  42369. /* *
  42370. *
  42371. * Static Properties
  42372. *
  42373. * */
  42374. var _this = _super !== null && _super.apply(this,
  42375. arguments) || this;
  42376. /* *
  42377. *
  42378. * Properties
  42379. *
  42380. * */
  42381. _this.data = void 0;
  42382. _this.options = void 0;
  42383. _this.points = void 0;
  42384. return _this;
  42385. }
  42386. /**
  42387. * A bar series is a special type of column series where the columns are
  42388. * horizontal.
  42389. *
  42390. * @sample highcharts/demo/bar-basic/
  42391. * Bar chart
  42392. *
  42393. * @extends plotOptions.column
  42394. * @product highcharts
  42395. * @optionparent plotOptions.bar
  42396. */
  42397. BarSeries.defaultOptions = merge(ColumnSeries.defaultOptions, {
  42398. // nothing here yet
  42399. });
  42400. return BarSeries;
  42401. }(ColumnSeries));
  42402. extend(BarSeries.prototype, {
  42403. inverted: true
  42404. });
  42405. SeriesRegistry.registerSeriesType('bar', BarSeries);
  42406. /* *
  42407. *
  42408. * Default Export
  42409. *
  42410. * */
  42411. /* *
  42412. *
  42413. * API Options
  42414. *
  42415. * */
  42416. /**
  42417. * A `bar` series. If the [type](#series.bar.type) option is not specified,
  42418. * it is inherited from [chart.type](#chart.type).
  42419. *
  42420. * @extends series,plotOptions.bar
  42421. * @excluding connectNulls, dashStyle, dataParser, dataURL, gapSize, gapUnit,
  42422. * linecap, lineWidth, marker, connectEnds, step
  42423. * @product highcharts
  42424. * @apioption series.bar
  42425. */
  42426. /**
  42427. * An array of data points for the series. For the `bar` series type,
  42428. * points can be given in the following ways:
  42429. *
  42430. * 1. An array of numerical values. In this case, the numerical values will be
  42431. * interpreted as `y` options. The `x` values will be automatically
  42432. * calculated, either starting at 0 and incremented by 1, or from
  42433. * `pointStart` and `pointInterval` given in the series options. If the axis
  42434. * has categories, these will be used. Example:
  42435. * ```js
  42436. * data: [0, 5, 3, 5]
  42437. * ```
  42438. *
  42439. * 2. An array of arrays with 2 values. In this case, the values correspond to
  42440. * `x,y`. If the first value is a string, it is applied as the name of the
  42441. * point, and the `x` value is inferred.
  42442. * ```js
  42443. * data: [
  42444. * [0, 5],
  42445. * [1, 10],
  42446. * [2, 3]
  42447. * ]
  42448. * ```
  42449. *
  42450. * 3. An array of objects with named values. The following snippet shows only a
  42451. * few settings, see the complete options set below. If the total number of
  42452. * data points exceeds the series'
  42453. * [turboThreshold](#series.bar.turboThreshold), this option is not
  42454. * available.
  42455. * ```js
  42456. * data: [{
  42457. * x: 1,
  42458. * y: 1,
  42459. * name: "Point2",
  42460. * color: "#00FF00"
  42461. * }, {
  42462. * x: 1,
  42463. * y: 10,
  42464. * name: "Point1",
  42465. * color: "#FF00FF"
  42466. * }]
  42467. * ```
  42468. *
  42469. * @sample {highcharts} highcharts/chart/reflow-true/
  42470. * Numerical values
  42471. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  42472. * Arrays of numeric x and y
  42473. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  42474. * Arrays of datetime x and y
  42475. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  42476. * Arrays of point.name and y
  42477. * @sample {highcharts} highcharts/series/data-array-of-objects/
  42478. * Config objects
  42479. *
  42480. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  42481. * @extends series.column.data
  42482. * @product highcharts
  42483. * @apioption series.bar.data
  42484. */
  42485. /**
  42486. * @excluding halo,lineWidth,lineWidthPlus,marker
  42487. * @product highcharts highstock
  42488. * @apioption series.bar.states.hover
  42489. */
  42490. /**
  42491. * @excluding halo,lineWidth,lineWidthPlus,marker
  42492. * @product highcharts highstock
  42493. * @apioption series.bar.states.select
  42494. */
  42495. ''; // gets doclets above into transpilat
  42496. return BarSeries;
  42497. });
  42498. _registerModule(_modules, 'Series/Scatter/ScatterSeries.js', [_modules['Series/Column/ColumnSeries.js'], _modules['Series/Line/LineSeries.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (ColumnSeries, LineSeries, SeriesRegistry, U) {
  42499. /* *
  42500. *
  42501. * (c) 2010-2021 Torstein Honsi
  42502. *
  42503. * License: www.highcharts.com/license
  42504. *
  42505. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  42506. *
  42507. * */
  42508. var __extends = (this && this.__extends) || (function () {
  42509. var extendStatics = function (d,
  42510. b) {
  42511. extendStatics = Object.setPrototypeOf ||
  42512. ({ __proto__: [] } instanceof Array && function (d,
  42513. b) { d.__proto__ = b; }) ||
  42514. function (d,
  42515. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  42516. return extendStatics(d, b);
  42517. };
  42518. return function (d, b) {
  42519. extendStatics(d, b);
  42520. function __() { this.constructor = d; }
  42521. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  42522. };
  42523. })();
  42524. var addEvent = U.addEvent,
  42525. extend = U.extend,
  42526. merge = U.merge;
  42527. /* *
  42528. *
  42529. * Class
  42530. *
  42531. * */
  42532. /**
  42533. * Scatter series type.
  42534. *
  42535. * @private
  42536. */
  42537. var ScatterSeries = /** @class */ (function (_super) {
  42538. __extends(ScatterSeries, _super);
  42539. function ScatterSeries() {
  42540. var _this = _super !== null && _super.apply(this,
  42541. arguments) || this;
  42542. /* *
  42543. *
  42544. * Properties
  42545. *
  42546. * */
  42547. _this.data = void 0;
  42548. _this.options = void 0;
  42549. _this.points = void 0;
  42550. return _this;
  42551. /* eslint-enable valid-jsdoc */
  42552. }
  42553. /* *
  42554. *
  42555. * Functions
  42556. *
  42557. * */
  42558. /* eslint-disable valid-jsdoc */
  42559. /**
  42560. * Optionally add the jitter effect.
  42561. * @private
  42562. */
  42563. ScatterSeries.prototype.applyJitter = function () {
  42564. var series = this,
  42565. jitter = this.options.jitter,
  42566. len = this.points.length;
  42567. /**
  42568. * Return a repeatable, pseudo-random number based on an integer
  42569. * seed.
  42570. * @private
  42571. */
  42572. function unrandom(seed) {
  42573. var rand = Math.sin(seed) * 10000;
  42574. return rand - Math.floor(rand);
  42575. }
  42576. if (jitter) {
  42577. this.points.forEach(function (point, i) {
  42578. ['x', 'y'].forEach(function (dim, j) {
  42579. var axis,
  42580. plotProp = 'plot' + dim.toUpperCase(),
  42581. min,
  42582. max,
  42583. translatedJitter;
  42584. if (jitter[dim] && !point.isNull) {
  42585. axis = series[dim + 'Axis'];
  42586. translatedJitter =
  42587. jitter[dim] * axis.transA;
  42588. if (axis && !axis.isLog) {
  42589. // Identify the outer bounds of the jitter range
  42590. min = Math.max(0, point[plotProp] - translatedJitter);
  42591. max = Math.min(axis.len, point[plotProp] + translatedJitter);
  42592. // Find a random position within this range
  42593. point[plotProp] = min +
  42594. (max - min) * unrandom(i + j * len);
  42595. // Update clientX for the tooltip k-d-tree
  42596. if (dim === 'x') {
  42597. point.clientX = point.plotX;
  42598. }
  42599. }
  42600. }
  42601. });
  42602. });
  42603. }
  42604. };
  42605. /**
  42606. * @private
  42607. * @function Highcharts.seriesTypes.scatter#drawGraph
  42608. */
  42609. ScatterSeries.prototype.drawGraph = function () {
  42610. if (this.options.lineWidth ||
  42611. // In case we have a graph from before and we update the line
  42612. // width to 0 (#13816)
  42613. (this.options.lineWidth === 0 &&
  42614. this.graph &&
  42615. this.graph.strokeWidth())) {
  42616. _super.prototype.drawGraph.call(this);
  42617. }
  42618. };
  42619. /**
  42620. * A scatter plot uses cartesian coordinates to display values for two
  42621. * variables for a set of data.
  42622. *
  42623. * @sample {highcharts} highcharts/demo/scatter/
  42624. * Scatter plot
  42625. *
  42626. * @extends plotOptions.line
  42627. * @excluding cropThreshold, pointPlacement, shadow, useOhlcData
  42628. * @product highcharts highstock
  42629. * @optionparent plotOptions.scatter
  42630. */
  42631. ScatterSeries.defaultOptions = merge(LineSeries.defaultOptions, {
  42632. /**
  42633. * The width of the line connecting the data points.
  42634. *
  42635. * @sample {highcharts} highcharts/plotoptions/scatter-linewidth-none/
  42636. * 0 by default
  42637. * @sample {highcharts} highcharts/plotoptions/scatter-linewidth-1/
  42638. * 1px
  42639. *
  42640. * @product highcharts highstock
  42641. */
  42642. lineWidth: 0,
  42643. findNearestPointBy: 'xy',
  42644. /**
  42645. * Apply a jitter effect for the rendered markers. When plotting
  42646. * discrete values, a little random noise may help telling the points
  42647. * apart. The jitter setting applies a random displacement of up to `n`
  42648. * axis units in either direction. So for example on a horizontal X
  42649. * axis, setting the `jitter.x` to 0.24 will render the point in a
  42650. * random position between 0.24 units to the left and 0.24 units to the
  42651. * right of the true axis position. On a category axis, setting it to
  42652. * 0.5 will fill up the bin and make the data appear continuous.
  42653. *
  42654. * When rendered on top of a box plot or a column series, a jitter value
  42655. * of 0.24 will correspond to the underlying series' default
  42656. * [groupPadding](
  42657. * https://api.highcharts.com/highcharts/plotOptions.column.groupPadding)
  42658. * and [pointPadding](
  42659. * https://api.highcharts.com/highcharts/plotOptions.column.pointPadding)
  42660. * settings.
  42661. *
  42662. * @sample {highcharts} highcharts/series-scatter/jitter
  42663. * Jitter on a scatter plot
  42664. *
  42665. * @sample {highcharts} highcharts/series-scatter/jitter-boxplot
  42666. * Jittered scatter plot on top of a box plot
  42667. *
  42668. * @product highcharts highstock
  42669. * @since 7.0.2
  42670. */
  42671. jitter: {
  42672. /**
  42673. * The maximal X offset for the random jitter effect.
  42674. */
  42675. x: 0,
  42676. /**
  42677. * The maximal Y offset for the random jitter effect.
  42678. */
  42679. y: 0
  42680. },
  42681. marker: {
  42682. enabled: true // Overrides auto-enabling in line series (#3647)
  42683. },
  42684. /**
  42685. * Sticky tracking of mouse events. When true, the `mouseOut` event
  42686. * on a series isn't triggered until the mouse moves over another
  42687. * series, or out of the plot area. When false, the `mouseOut` event on
  42688. * a series is triggered when the mouse leaves the area around the
  42689. * series' graph or markers. This also implies the tooltip. When
  42690. * `stickyTracking` is false and `tooltip.shared` is false, the tooltip
  42691. * will be hidden when moving the mouse between series.
  42692. *
  42693. * @type {boolean}
  42694. * @default false
  42695. * @product highcharts highstock
  42696. * @apioption plotOptions.scatter.stickyTracking
  42697. */
  42698. /**
  42699. * A configuration object for the tooltip rendering of each single
  42700. * series. Properties are inherited from [tooltip](#tooltip).
  42701. * Overridable properties are `headerFormat`, `pointFormat`,
  42702. * `yDecimals`, `xDateFormat`, `yPrefix` and `ySuffix`. Unlike other
  42703. * series, in a scatter plot the series.name by default shows in the
  42704. * headerFormat and point.x and point.y in the pointFormat.
  42705. *
  42706. * @product highcharts highstock
  42707. */
  42708. tooltip: {
  42709. headerFormat: '<span style="color:{point.color}">\u25CF</span> ' +
  42710. '<span style="font-size: 10px"> {series.name}</span><br/>',
  42711. pointFormat: 'x: <b>{point.x}</b><br/>y: <b>{point.y}</b><br/>'
  42712. }
  42713. });
  42714. return ScatterSeries;
  42715. }(LineSeries));
  42716. extend(ScatterSeries.prototype, {
  42717. drawTracker: ColumnSeries.prototype.drawTracker,
  42718. sorted: false,
  42719. requireSorting: false,
  42720. noSharedTooltip: true,
  42721. trackerGroups: ['group', 'markerGroup', 'dataLabelsGroup'],
  42722. takeOrdinalPosition: false // #2342
  42723. });
  42724. /* *
  42725. *
  42726. * Events
  42727. *
  42728. * */
  42729. /* eslint-disable no-invalid-this */
  42730. addEvent(ScatterSeries, 'afterTranslate', function () {
  42731. this.applyJitter();
  42732. });
  42733. SeriesRegistry.registerSeriesType('scatter', ScatterSeries);
  42734. /* *
  42735. *
  42736. * Default Export
  42737. *
  42738. * */
  42739. /* *
  42740. *
  42741. * API Options
  42742. *
  42743. * */
  42744. /**
  42745. * A `scatter` series. If the [type](#series.scatter.type) option is
  42746. * not specified, it is inherited from [chart.type](#chart.type).
  42747. *
  42748. * @extends series,plotOptions.scatter
  42749. * @excluding cropThreshold, dataParser, dataURL, useOhlcData
  42750. * @product highcharts highstock
  42751. * @apioption series.scatter
  42752. */
  42753. /**
  42754. * An array of data points for the series. For the `scatter` series
  42755. * type, points can be given in the following ways:
  42756. *
  42757. * 1. An array of numerical values. In this case, the numerical values will be
  42758. * interpreted as `y` options. The `x` values will be automatically
  42759. * calculated, either starting at 0 and incremented by 1, or from
  42760. * `pointStart` and `pointInterval` given in the series options. If the axis
  42761. * has categories, these will be used. Example:
  42762. * ```js
  42763. * data: [0, 5, 3, 5]
  42764. * ```
  42765. *
  42766. * 2. An array of arrays with 2 values. In this case, the values correspond to
  42767. * `x,y`. If the first value is a string, it is applied as the name of the
  42768. * point, and the `x` value is inferred.
  42769. * ```js
  42770. * data: [
  42771. * [0, 0],
  42772. * [1, 8],
  42773. * [2, 9]
  42774. * ]
  42775. * ```
  42776. *
  42777. * 3. An array of objects with named values. The following snippet shows only a
  42778. * few settings, see the complete options set below. If the total number of
  42779. * data points exceeds the series'
  42780. * [turboThreshold](#series.scatter.turboThreshold), this option is not
  42781. * available.
  42782. * ```js
  42783. * data: [{
  42784. * x: 1,
  42785. * y: 2,
  42786. * name: "Point2",
  42787. * color: "#00FF00"
  42788. * }, {
  42789. * x: 1,
  42790. * y: 4,
  42791. * name: "Point1",
  42792. * color: "#FF00FF"
  42793. * }]
  42794. * ```
  42795. *
  42796. * @sample {highcharts} highcharts/chart/reflow-true/
  42797. * Numerical values
  42798. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  42799. * Arrays of numeric x and y
  42800. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  42801. * Arrays of datetime x and y
  42802. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  42803. * Arrays of point.name and y
  42804. * @sample {highcharts} highcharts/series/data-array-of-objects/
  42805. * Config objects
  42806. *
  42807. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  42808. * @extends series.line.data
  42809. * @product highcharts highstock
  42810. * @apioption series.scatter.data
  42811. */
  42812. ''; // adds doclets above to transpilat
  42813. return ScatterSeries;
  42814. });
  42815. _registerModule(_modules, 'Mixins/CenteredSeries.js', [_modules['Core/Globals.js'], _modules['Core/Series/Series.js'], _modules['Core/Utilities.js']], function (H, Series, U) {
  42816. /* *
  42817. *
  42818. * (c) 2010-2021 Torstein Honsi
  42819. *
  42820. * License: www.highcharts.com/license
  42821. *
  42822. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  42823. *
  42824. * */
  42825. /**
  42826. * @private
  42827. * @interface Highcharts.RadianAngles
  42828. */ /**
  42829. * @name Highcharts.RadianAngles#end
  42830. * @type {number}
  42831. */ /**
  42832. * @name Highcharts.RadianAngles#start
  42833. * @type {number}
  42834. */
  42835. var isNumber = U.isNumber,
  42836. pick = U.pick,
  42837. relativeLength = U.relativeLength;
  42838. var deg2rad = H.deg2rad;
  42839. /* eslint-disable valid-jsdoc */
  42840. /**
  42841. * @private
  42842. * @mixin Highcharts.CenteredSeriesMixin
  42843. */
  42844. var centeredSeriesMixin = H.CenteredSeriesMixin = {
  42845. /**
  42846. * Get the center of the pie based on the size and center options relative
  42847. * to the plot area. Borrowed by the polar and gauge series types.
  42848. *
  42849. * @private
  42850. * @function Highcharts.CenteredSeriesMixin.getCenter
  42851. *
  42852. * @return {Array<number>}
  42853. */
  42854. getCenter: function () {
  42855. var options = this.options,
  42856. chart = this.chart,
  42857. slicingRoom = 2 * (options.slicedOffset || 0),
  42858. handleSlicingRoom,
  42859. plotWidth = chart.plotWidth - 2 * slicingRoom,
  42860. plotHeight = chart.plotHeight - 2 * slicingRoom,
  42861. centerOption = options.center,
  42862. smallestSize = Math.min(plotWidth,
  42863. plotHeight),
  42864. size = options.size,
  42865. innerSize = options.innerSize || 0,
  42866. positions,
  42867. i,
  42868. value;
  42869. if (typeof size === 'string') {
  42870. size = parseFloat(size);
  42871. }
  42872. if (typeof innerSize === 'string') {
  42873. innerSize = parseFloat(innerSize);
  42874. }
  42875. positions = [
  42876. pick(centerOption[0], '50%'),
  42877. pick(centerOption[1], '50%'),
  42878. // Prevent from negative values
  42879. pick(size && size < 0 ? void 0 : options.size, '100%'),
  42880. pick(innerSize && innerSize < 0 ? void 0 : options.innerSize || 0, '0%')
  42881. ];
  42882. // No need for inner size in angular (gauges) series but still required
  42883. // for pie series
  42884. if (chart.angular && !(this instanceof Series)) {
  42885. positions[3] = 0;
  42886. }
  42887. for (i = 0; i < 4; ++i) {
  42888. value = positions[i];
  42889. handleSlicingRoom = i < 2 || (i === 2 && /%$/.test(value));
  42890. // i == 0: centerX, relative to width
  42891. // i == 1: centerY, relative to height
  42892. // i == 2: size, relative to smallestSize
  42893. // i == 3: innerSize, relative to size
  42894. positions[i] = relativeLength(value, [plotWidth, plotHeight, smallestSize, positions[2]][i]) + (handleSlicingRoom ? slicingRoom : 0);
  42895. }
  42896. // innerSize cannot be larger than size (#3632)
  42897. if (positions[3] > positions[2]) {
  42898. positions[3] = positions[2];
  42899. }
  42900. return positions;
  42901. },
  42902. /**
  42903. * getStartAndEndRadians - Calculates start and end angles in radians.
  42904. * Used in series types such as pie and sunburst.
  42905. *
  42906. * @private
  42907. * @function Highcharts.CenteredSeriesMixin.getStartAndEndRadians
  42908. *
  42909. * @param {number} [start]
  42910. * Start angle in degrees.
  42911. *
  42912. * @param {number} [end]
  42913. * Start angle in degrees.
  42914. *
  42915. * @return {Highcharts.RadianAngles}
  42916. * Returns an object containing start and end angles as radians.
  42917. */
  42918. getStartAndEndRadians: function (start, end) {
  42919. var startAngle = isNumber(start) ? start : 0, // must be a number
  42920. endAngle = ((isNumber(end) && // must be a number
  42921. end > startAngle && // must be larger than the start angle
  42922. // difference must be less than 360 degrees
  42923. (end - startAngle) < 360) ?
  42924. end :
  42925. startAngle + 360),
  42926. correction = -90;
  42927. return {
  42928. start: deg2rad * (startAngle + correction),
  42929. end: deg2rad * (endAngle + correction)
  42930. };
  42931. }
  42932. };
  42933. return centeredSeriesMixin;
  42934. });
  42935. _registerModule(_modules, 'Series/Pie/PiePoint.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Series/Point.js'], _modules['Core/Utilities.js']], function (A, Point, U) {
  42936. /* *
  42937. *
  42938. * (c) 2010-2021 Torstein Honsi
  42939. *
  42940. * License: www.highcharts.com/license
  42941. *
  42942. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  42943. *
  42944. * */
  42945. var __extends = (this && this.__extends) || (function () {
  42946. var extendStatics = function (d,
  42947. b) {
  42948. extendStatics = Object.setPrototypeOf ||
  42949. ({ __proto__: [] } instanceof Array && function (d,
  42950. b) { d.__proto__ = b; }) ||
  42951. function (d,
  42952. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  42953. return extendStatics(d, b);
  42954. };
  42955. return function (d, b) {
  42956. extendStatics(d, b);
  42957. function __() { this.constructor = d; }
  42958. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  42959. };
  42960. })();
  42961. var setAnimation = A.setAnimation;
  42962. var addEvent = U.addEvent,
  42963. defined = U.defined,
  42964. extend = U.extend,
  42965. isNumber = U.isNumber,
  42966. pick = U.pick,
  42967. relativeLength = U.relativeLength;
  42968. /* *
  42969. *
  42970. * Class
  42971. *
  42972. * */
  42973. var PiePoint = /** @class */ (function (_super) {
  42974. __extends(PiePoint, _super);
  42975. function PiePoint() {
  42976. /* *
  42977. *
  42978. * Properties
  42979. *
  42980. * */
  42981. var _this = _super !== null && _super.apply(this,
  42982. arguments) || this;
  42983. _this.labelDistance = void 0;
  42984. _this.options = void 0;
  42985. _this.series = void 0;
  42986. return _this;
  42987. }
  42988. /* *
  42989. *
  42990. * Functions
  42991. *
  42992. * */
  42993. /* eslint-disable valid-jsdoc */
  42994. /**
  42995. * Extendable method for getting the path of the connector between the
  42996. * data label and the pie slice.
  42997. * @private
  42998. */
  42999. PiePoint.prototype.getConnectorPath = function () {
  43000. var labelPosition = this.labelPosition,
  43001. options = this.series.options.dataLabels,
  43002. connectorShape = options.connectorShape,
  43003. predefinedShapes = this.connectorShapes;
  43004. // find out whether to use the predefined shape
  43005. if (predefinedShapes[connectorShape]) {
  43006. connectorShape = predefinedShapes[connectorShape];
  43007. }
  43008. return connectorShape.call(this, {
  43009. // pass simplified label position object for user's convenience
  43010. x: labelPosition.final.x,
  43011. y: labelPosition.final.y,
  43012. alignment: labelPosition.alignment
  43013. }, labelPosition.connectorPosition, options);
  43014. };
  43015. /**
  43016. * @private
  43017. */
  43018. PiePoint.prototype.getTranslate = function () {
  43019. return this.sliced ? this.slicedTranslation : {
  43020. translateX: 0,
  43021. translateY: 0
  43022. };
  43023. };
  43024. /**
  43025. * @private
  43026. */
  43027. PiePoint.prototype.haloPath = function (size) {
  43028. var shapeArgs = this.shapeArgs;
  43029. return this.sliced || !this.visible ?
  43030. [] :
  43031. this.series.chart.renderer.symbols.arc(shapeArgs.x, shapeArgs.y, shapeArgs.r + size, shapeArgs.r + size, {
  43032. // Substract 1px to ensure the background is not bleeding
  43033. // through between the halo and the slice (#7495).
  43034. innerR: shapeArgs.r - 1,
  43035. start: shapeArgs.start,
  43036. end: shapeArgs.end
  43037. });
  43038. };
  43039. /**
  43040. * Initialize the pie slice.
  43041. * @private
  43042. */
  43043. PiePoint.prototype.init = function () {
  43044. Point.prototype.init.apply(this, arguments);
  43045. var point = this,
  43046. toggleSlice;
  43047. point.name = pick(point.name, 'Slice');
  43048. // add event listener for select
  43049. toggleSlice = function (e) {
  43050. point.slice(e.type === 'select');
  43051. };
  43052. addEvent(point, 'select', toggleSlice);
  43053. addEvent(point, 'unselect', toggleSlice);
  43054. return point;
  43055. };
  43056. /**
  43057. * Negative points are not valid (#1530, #3623, #5322)
  43058. * @private
  43059. */
  43060. PiePoint.prototype.isValid = function () {
  43061. return isNumber(this.y) && this.y >= 0;
  43062. };
  43063. /**
  43064. * Toggle the visibility of the pie slice.
  43065. * @private
  43066. *
  43067. * @param {boolean} vis
  43068. * Whether to show the slice or not. If undefined, the visibility is
  43069. * toggled.
  43070. */
  43071. PiePoint.prototype.setVisible = function (vis, redraw) {
  43072. var point = this,
  43073. series = point.series,
  43074. chart = series.chart,
  43075. ignoreHiddenPoint = series.options.ignoreHiddenPoint;
  43076. redraw = pick(redraw, ignoreHiddenPoint);
  43077. if (vis !== point.visible) {
  43078. // If called without an argument, toggle visibility
  43079. point.visible = point.options.visible = vis =
  43080. typeof vis === 'undefined' ? !point.visible : vis;
  43081. // update userOptions.data
  43082. series.options.data[series.data.indexOf(point)] =
  43083. point.options;
  43084. // Show and hide associated elements. This is performed
  43085. // regardless of redraw or not, because chart.redraw only
  43086. // handles full series.
  43087. ['graphic', 'dataLabel', 'connector', 'shadowGroup'].forEach(function (key) {
  43088. if (point[key]) {
  43089. point[key][vis ? 'show' : 'hide'](vis);
  43090. }
  43091. });
  43092. if (point.legendItem) {
  43093. chart.legend.colorizeItem(point, vis);
  43094. }
  43095. // #4170, hide halo after hiding point
  43096. if (!vis && point.state === 'hover') {
  43097. point.setState('');
  43098. }
  43099. // Handle ignore hidden slices
  43100. if (ignoreHiddenPoint) {
  43101. series.isDirty = true;
  43102. }
  43103. if (redraw) {
  43104. chart.redraw();
  43105. }
  43106. }
  43107. };
  43108. /**
  43109. * Set or toggle whether the slice is cut out from the pie.
  43110. * @private
  43111. *
  43112. * @param {boolean} sliced
  43113. * When undefined, the slice state is toggled.
  43114. *
  43115. * @param {boolean} redraw
  43116. * Whether to redraw the chart. True by default.
  43117. *
  43118. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>}
  43119. * Animation options.
  43120. */
  43121. PiePoint.prototype.slice = function (sliced, redraw, animation) {
  43122. var point = this,
  43123. series = point.series,
  43124. chart = series.chart;
  43125. setAnimation(animation, chart);
  43126. // redraw is true by default
  43127. redraw = pick(redraw, true);
  43128. /**
  43129. * Pie series only. Whether to display a slice offset from the
  43130. * center.
  43131. * @name Highcharts.Point#sliced
  43132. * @type {boolean|undefined}
  43133. */
  43134. // if called without an argument, toggle
  43135. point.sliced = point.options.sliced = sliced =
  43136. defined(sliced) ? sliced : !point.sliced;
  43137. // update userOptions.data
  43138. series.options.data[series.data.indexOf(point)] =
  43139. point.options;
  43140. if (point.graphic) {
  43141. point.graphic.animate(this.getTranslate());
  43142. }
  43143. if (point.shadowGroup) {
  43144. point.shadowGroup.animate(this.getTranslate());
  43145. }
  43146. };
  43147. return PiePoint;
  43148. }(Point));
  43149. extend(PiePoint.prototype, {
  43150. connectorShapes: {
  43151. // only one available before v7.0.0
  43152. fixedOffset: function (labelPosition, connectorPosition, options) {
  43153. var breakAt = connectorPosition.breakAt,
  43154. touchingSliceAt = connectorPosition.touchingSliceAt,
  43155. lineSegment = options.softConnector ? [
  43156. 'C',
  43157. // 1st control point (of the curve)
  43158. labelPosition.x +
  43159. // 5 gives the connector a little horizontal bend
  43160. (labelPosition.alignment === 'left' ? -5 : 5),
  43161. labelPosition.y,
  43162. 2 * breakAt.x - touchingSliceAt.x,
  43163. 2 * breakAt.y - touchingSliceAt.y,
  43164. breakAt.x,
  43165. breakAt.y //
  43166. ] : [
  43167. 'L',
  43168. breakAt.x,
  43169. breakAt.y
  43170. ];
  43171. // assemble the path
  43172. return ([
  43173. ['M', labelPosition.x, labelPosition.y],
  43174. lineSegment,
  43175. ['L', touchingSliceAt.x, touchingSliceAt.y]
  43176. ]);
  43177. },
  43178. straight: function (labelPosition, connectorPosition) {
  43179. var touchingSliceAt = connectorPosition.touchingSliceAt;
  43180. // direct line to the slice
  43181. return [
  43182. ['M', labelPosition.x, labelPosition.y],
  43183. ['L', touchingSliceAt.x, touchingSliceAt.y]
  43184. ];
  43185. },
  43186. crookedLine: function (labelPosition, connectorPosition, options) {
  43187. var touchingSliceAt = connectorPosition.touchingSliceAt,
  43188. series = this.series,
  43189. pieCenterX = series.center[0],
  43190. plotWidth = series.chart.plotWidth,
  43191. plotLeft = series.chart.plotLeft,
  43192. alignment = labelPosition.alignment,
  43193. radius = this.shapeArgs.r,
  43194. crookDistance = relativeLength(// % to fraction
  43195. options.crookDistance, 1),
  43196. crookX = alignment === 'left' ?
  43197. pieCenterX + radius + (plotWidth + plotLeft -
  43198. pieCenterX - radius) * (1 - crookDistance) :
  43199. plotLeft + (pieCenterX - radius) * crookDistance,
  43200. segmentWithCrook = [
  43201. 'L',
  43202. crookX,
  43203. labelPosition.y
  43204. ],
  43205. useCrook = true;
  43206. // crookedLine formula doesn't make sense if the path overlaps
  43207. // the label - use straight line instead in that case
  43208. if (alignment === 'left' ?
  43209. (crookX > labelPosition.x || crookX < touchingSliceAt.x) :
  43210. (crookX < labelPosition.x || crookX > touchingSliceAt.x)) {
  43211. useCrook = false;
  43212. }
  43213. // assemble the path
  43214. var path = [
  43215. ['M',
  43216. labelPosition.x,
  43217. labelPosition.y]
  43218. ];
  43219. if (useCrook) {
  43220. path.push(segmentWithCrook);
  43221. }
  43222. path.push(['L', touchingSliceAt.x, touchingSliceAt.y]);
  43223. return path;
  43224. }
  43225. }
  43226. });
  43227. /* *
  43228. *
  43229. * Default Export
  43230. *
  43231. * */
  43232. return PiePoint;
  43233. });
  43234. _registerModule(_modules, 'Series/Pie/PieSeries.js', [_modules['Mixins/CenteredSeries.js'], _modules['Series/Column/ColumnSeries.js'], _modules['Core/Globals.js'], _modules['Mixins/LegendSymbol.js'], _modules['Core/Color/Palette.js'], _modules['Series/Pie/PiePoint.js'], _modules['Core/Series/Series.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Renderer/SVG/SVGRenderer.js'], _modules['Core/Utilities.js']], function (CenteredSeriesMixin, ColumnSeries, H, LegendSymbolMixin, palette, PiePoint, Series, SeriesRegistry, SVGRenderer, U) {
  43235. /* *
  43236. *
  43237. * (c) 2010-2021 Torstein Honsi
  43238. *
  43239. * License: www.highcharts.com/license
  43240. *
  43241. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  43242. *
  43243. * */
  43244. var __extends = (this && this.__extends) || (function () {
  43245. var extendStatics = function (d,
  43246. b) {
  43247. extendStatics = Object.setPrototypeOf ||
  43248. ({ __proto__: [] } instanceof Array && function (d,
  43249. b) { d.__proto__ = b; }) ||
  43250. function (d,
  43251. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  43252. return extendStatics(d, b);
  43253. };
  43254. return function (d, b) {
  43255. extendStatics(d, b);
  43256. function __() { this.constructor = d; }
  43257. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  43258. };
  43259. })();
  43260. var getStartAndEndRadians = CenteredSeriesMixin.getStartAndEndRadians;
  43261. var noop = H.noop;
  43262. var clamp = U.clamp,
  43263. extend = U.extend,
  43264. fireEvent = U.fireEvent,
  43265. merge = U.merge,
  43266. pick = U.pick,
  43267. relativeLength = U.relativeLength;
  43268. /* *
  43269. *
  43270. * Class
  43271. *
  43272. * */
  43273. /**
  43274. * Pie series type.
  43275. *
  43276. * @private
  43277. * @class
  43278. * @name Highcharts.seriesTypes.pie
  43279. *
  43280. * @augments Highcharts.Series
  43281. */
  43282. var PieSeries = /** @class */ (function (_super) {
  43283. __extends(PieSeries, _super);
  43284. function PieSeries() {
  43285. /* *
  43286. *
  43287. * Static Properties
  43288. *
  43289. * */
  43290. var _this = _super !== null && _super.apply(this,
  43291. arguments) || this;
  43292. /* *
  43293. *
  43294. * Properties
  43295. *
  43296. * */
  43297. _this.center = void 0;
  43298. _this.data = void 0;
  43299. _this.maxLabelDistance = void 0;
  43300. _this.options = void 0;
  43301. _this.points = void 0;
  43302. return _this;
  43303. /* eslint-enable valid-jsdoc */
  43304. }
  43305. /* *
  43306. *
  43307. * Functions
  43308. *
  43309. * */
  43310. /* eslint-disable valid-jsdoc */
  43311. /**
  43312. * Animates the pies in.
  43313. * @private
  43314. */
  43315. PieSeries.prototype.animate = function (init) {
  43316. var series = this,
  43317. points = series.points,
  43318. startAngleRad = series.startAngleRad;
  43319. if (!init) {
  43320. points.forEach(function (point) {
  43321. var graphic = point.graphic,
  43322. args = point.shapeArgs;
  43323. if (graphic && args) {
  43324. // start values
  43325. graphic.attr({
  43326. // animate from inner radius (#779)
  43327. r: pick(point.startR, (series.center && series.center[3] / 2)),
  43328. start: startAngleRad,
  43329. end: startAngleRad
  43330. });
  43331. // animate
  43332. graphic.animate({
  43333. r: args.r,
  43334. start: args.start,
  43335. end: args.end
  43336. }, series.options.animation);
  43337. }
  43338. });
  43339. }
  43340. };
  43341. /**
  43342. * Called internally to draw auxiliary graph in pie-like series in
  43343. * situtation when the default graph is not sufficient enough to present
  43344. * the data well. Auxiliary graph is saved in the same object as
  43345. * regular graph.
  43346. * @private
  43347. */
  43348. PieSeries.prototype.drawEmpty = function () {
  43349. var centerX,
  43350. centerY,
  43351. start = this.startAngleRad,
  43352. end = this.endAngleRad,
  43353. options = this.options;
  43354. // Draw auxiliary graph if there're no visible points.
  43355. if (this.total === 0 && this.center) {
  43356. centerX = this.center[0];
  43357. centerY = this.center[1];
  43358. if (!this.graph) {
  43359. this.graph = this.chart.renderer
  43360. .arc(centerX, centerY, this.center[1] / 2, 0, start, end)
  43361. .addClass('highcharts-empty-series')
  43362. .add(this.group);
  43363. }
  43364. this.graph.attr({
  43365. d: SVGRenderer.prototype.symbols.arc(centerX, centerY, this.center[2] / 2, 0, {
  43366. start: start,
  43367. end: end,
  43368. innerR: this.center[3] / 2
  43369. })
  43370. });
  43371. if (!this.chart.styledMode) {
  43372. this.graph.attr({
  43373. 'stroke-width': options.borderWidth,
  43374. fill: options.fillColor || 'none',
  43375. stroke: options.color ||
  43376. palette.neutralColor20
  43377. });
  43378. }
  43379. }
  43380. else if (this.graph) { // Destroy the graph object.
  43381. this.graph = this.graph.destroy();
  43382. }
  43383. };
  43384. /**
  43385. * Slices in pie chart are initialized in DOM, but it's shapes and
  43386. * animations are normally run in `drawPoints()`.
  43387. * @private
  43388. */
  43389. PieSeries.prototype.drawPoints = function () {
  43390. var renderer = this.chart.renderer;
  43391. this.points.forEach(function (point) {
  43392. // When updating a series between 2d and 3d or cartesian and
  43393. // polar, the shape type changes.
  43394. if (point.graphic && point.hasNewShapeType()) {
  43395. point.graphic = point.graphic.destroy();
  43396. }
  43397. if (!point.graphic) {
  43398. point.graphic = renderer[point.shapeType](point.shapeArgs)
  43399. .add(point.series.group);
  43400. point.delayedRendering = true;
  43401. }
  43402. });
  43403. };
  43404. /**
  43405. * Extend the generatePoints method by adding total and percentage
  43406. * properties to each point
  43407. * @private
  43408. */
  43409. PieSeries.prototype.generatePoints = function () {
  43410. _super.prototype.generatePoints.call(this);
  43411. this.updateTotals();
  43412. };
  43413. /**
  43414. * Utility for getting the x value from a given y, used for
  43415. * anticollision logic in data labels. Added point for using specific
  43416. * points' label distance.
  43417. * @private
  43418. */
  43419. PieSeries.prototype.getX = function (y, left, point) {
  43420. var center = this.center,
  43421. // Variable pie has individual radius
  43422. radius = this.radii ?
  43423. this.radii[point.index] || 0 :
  43424. center[2] / 2,
  43425. angle,
  43426. x;
  43427. angle = Math.asin(clamp((y - center[1]) / (radius + point.labelDistance), -1, 1));
  43428. x = center[0] +
  43429. (left ? -1 : 1) *
  43430. (Math.cos(angle) * (radius + point.labelDistance)) +
  43431. (point.labelDistance > 0 ?
  43432. (left ? -1 : 1) * this.options.dataLabels.padding :
  43433. 0);
  43434. return x;
  43435. };
  43436. /**
  43437. * Define hasData function for non-cartesian series. Returns true if the
  43438. * series has points at all.
  43439. * @private
  43440. */
  43441. PieSeries.prototype.hasData = function () {
  43442. return !!this.processedXData.length; // != 0
  43443. };
  43444. /**
  43445. * Draw the data points
  43446. * @private
  43447. */
  43448. PieSeries.prototype.redrawPoints = function () {
  43449. var series = this,
  43450. chart = series.chart,
  43451. renderer = chart.renderer,
  43452. groupTranslation,
  43453. graphic,
  43454. pointAttr,
  43455. shapeArgs,
  43456. shadow = series.options.shadow;
  43457. this.drawEmpty();
  43458. if (shadow && !series.shadowGroup && !chart.styledMode) {
  43459. series.shadowGroup = renderer
  43460. .g('shadow')
  43461. .attr({ zIndex: -1 })
  43462. .add(series.group);
  43463. }
  43464. // draw the slices
  43465. series.points.forEach(function (point) {
  43466. var animateTo = {};
  43467. graphic = point.graphic;
  43468. if (!point.isNull && graphic) {
  43469. shapeArgs = point.shapeArgs;
  43470. // If the point is sliced, use special translation, else use
  43471. // plot area translation
  43472. groupTranslation = point.getTranslate();
  43473. if (!chart.styledMode) {
  43474. // Put the shadow behind all points
  43475. var shadowGroup = point.shadowGroup;
  43476. if (shadow && !shadowGroup) {
  43477. shadowGroup = point.shadowGroup = renderer
  43478. .g('shadow')
  43479. .add(series.shadowGroup);
  43480. }
  43481. if (shadowGroup) {
  43482. shadowGroup.attr(groupTranslation);
  43483. }
  43484. pointAttr = series.pointAttribs(point, (point.selected && 'select'));
  43485. }
  43486. // Draw the slice
  43487. if (!point.delayedRendering) {
  43488. graphic
  43489. .setRadialReference(series.center);
  43490. if (!chart.styledMode) {
  43491. merge(true, animateTo, pointAttr);
  43492. }
  43493. merge(true, animateTo, shapeArgs, groupTranslation);
  43494. graphic.animate(animateTo);
  43495. }
  43496. else {
  43497. graphic
  43498. .setRadialReference(series.center)
  43499. .attr(shapeArgs)
  43500. .attr(groupTranslation);
  43501. if (!chart.styledMode) {
  43502. graphic
  43503. .attr(pointAttr)
  43504. .attr({ 'stroke-linejoin': 'round' })
  43505. .shadow(shadow, shadowGroup);
  43506. }
  43507. point.delayedRendering = false;
  43508. }
  43509. graphic.attr({
  43510. visibility: point.visible ? 'inherit' : 'hidden'
  43511. });
  43512. graphic.addClass(point.getClassName(), true);
  43513. }
  43514. else if (graphic) {
  43515. point.graphic = graphic.destroy();
  43516. }
  43517. });
  43518. };
  43519. /**
  43520. * Utility for sorting data labels.
  43521. * @private
  43522. */
  43523. PieSeries.prototype.sortByAngle = function (points, sign) {
  43524. points.sort(function (a, b) {
  43525. return ((typeof a.angle !== 'undefined') &&
  43526. (b.angle - a.angle) * sign);
  43527. });
  43528. };
  43529. /**
  43530. * Do translation for pie slices
  43531. * @private
  43532. */
  43533. PieSeries.prototype.translate = function (positions) {
  43534. this.generatePoints();
  43535. var series = this,
  43536. cumulative = 0,
  43537. precision = 1000, // issue #172
  43538. options = series.options,
  43539. slicedOffset = options.slicedOffset,
  43540. connectorOffset = slicedOffset + (options.borderWidth || 0),
  43541. finalConnectorOffset,
  43542. start,
  43543. end,
  43544. angle,
  43545. radians = getStartAndEndRadians(options.startAngle,
  43546. options.endAngle),
  43547. startAngleRad = series.startAngleRad = radians.start,
  43548. endAngleRad = series.endAngleRad = radians.end,
  43549. circ = endAngleRad - startAngleRad, // 2 * Math.PI,
  43550. points = series.points,
  43551. // the x component of the radius vector for a given point
  43552. radiusX,
  43553. radiusY,
  43554. labelDistance = options.dataLabels.distance,
  43555. ignoreHiddenPoint = options.ignoreHiddenPoint,
  43556. i,
  43557. len = points.length,
  43558. point;
  43559. // Get positions - either an integer or a percentage string must be
  43560. // given. If positions are passed as a parameter, we're in a
  43561. // recursive loop for adjusting space for data labels.
  43562. if (!positions) {
  43563. series.center = positions = series.getCenter();
  43564. }
  43565. // Calculate the geometry for each point
  43566. for (i = 0; i < len; i++) {
  43567. point = points[i];
  43568. // set start and end angle
  43569. start = startAngleRad + (cumulative * circ);
  43570. if (point.isValid() &&
  43571. (!ignoreHiddenPoint || point.visible)) {
  43572. cumulative += point.percentage / 100;
  43573. }
  43574. end = startAngleRad + (cumulative * circ);
  43575. // set the shape
  43576. point.shapeType = 'arc';
  43577. point.shapeArgs = {
  43578. x: positions[0],
  43579. y: positions[1],
  43580. r: positions[2] / 2,
  43581. innerR: positions[3] / 2,
  43582. start: Math.round(start * precision) / precision,
  43583. end: Math.round(end * precision) / precision
  43584. };
  43585. // Used for distance calculation for specific point.
  43586. point.labelDistance = pick((point.options.dataLabels &&
  43587. point.options.dataLabels.distance), labelDistance);
  43588. // Compute point.labelDistance if it's defined as percentage
  43589. // of slice radius (#8854)
  43590. point.labelDistance = relativeLength(point.labelDistance, point.shapeArgs.r);
  43591. // Saved for later dataLabels distance calculation.
  43592. series.maxLabelDistance = Math.max(series.maxLabelDistance || 0, point.labelDistance);
  43593. // The angle must stay within -90 and 270 (#2645)
  43594. angle = (end + start) / 2;
  43595. if (angle > 1.5 * Math.PI) {
  43596. angle -= 2 * Math.PI;
  43597. }
  43598. else if (angle < -Math.PI / 2) {
  43599. angle += 2 * Math.PI;
  43600. }
  43601. // Center for the sliced out slice
  43602. point.slicedTranslation = {
  43603. translateX: Math.round(Math.cos(angle) * slicedOffset),
  43604. translateY: Math.round(Math.sin(angle) * slicedOffset)
  43605. };
  43606. // set the anchor point for tooltips
  43607. radiusX = Math.cos(angle) * positions[2] / 2;
  43608. radiusY = Math.sin(angle) * positions[2] / 2;
  43609. point.tooltipPos = [
  43610. positions[0] + radiusX * 0.7,
  43611. positions[1] + radiusY * 0.7
  43612. ];
  43613. point.half = angle < -Math.PI / 2 || angle > Math.PI / 2 ?
  43614. 1 :
  43615. 0;
  43616. point.angle = angle;
  43617. // Set the anchor point for data labels. Use point.labelDistance
  43618. // instead of labelDistance // #1174
  43619. // finalConnectorOffset - not override connectorOffset value.
  43620. finalConnectorOffset = Math.min(connectorOffset, point.labelDistance / 5); // #1678
  43621. point.labelPosition = {
  43622. natural: {
  43623. // initial position of the data label - it's utilized for
  43624. // finding the final position for the label
  43625. x: positions[0] + radiusX + Math.cos(angle) *
  43626. point.labelDistance,
  43627. y: positions[1] + radiusY + Math.sin(angle) *
  43628. point.labelDistance
  43629. },
  43630. 'final': {
  43631. // used for generating connector path -
  43632. // initialized later in drawDataLabels function
  43633. // x: undefined,
  43634. // y: undefined
  43635. },
  43636. // left - pie on the left side of the data label
  43637. // right - pie on the right side of the data label
  43638. // center - data label overlaps the pie
  43639. alignment: point.labelDistance < 0 ?
  43640. 'center' : point.half ? 'right' : 'left',
  43641. connectorPosition: {
  43642. breakAt: {
  43643. x: positions[0] + radiusX + Math.cos(angle) *
  43644. finalConnectorOffset,
  43645. y: positions[1] + radiusY + Math.sin(angle) *
  43646. finalConnectorOffset
  43647. },
  43648. touchingSliceAt: {
  43649. x: positions[0] + radiusX,
  43650. y: positions[1] + radiusY
  43651. }
  43652. }
  43653. };
  43654. }
  43655. fireEvent(series, 'afterTranslate');
  43656. };
  43657. /**
  43658. * Recompute total chart sum and update percentages of points.
  43659. * @private
  43660. */
  43661. PieSeries.prototype.updateTotals = function () {
  43662. var i,
  43663. total = 0,
  43664. points = this.points,
  43665. len = points.length,
  43666. point,
  43667. ignoreHiddenPoint = this.options.ignoreHiddenPoint;
  43668. // Get the total sum
  43669. for (i = 0; i < len; i++) {
  43670. point = points[i];
  43671. if (point.isValid() &&
  43672. (!ignoreHiddenPoint || point.visible)) {
  43673. total += point.y;
  43674. }
  43675. }
  43676. this.total = total;
  43677. // Set each point's properties
  43678. for (i = 0; i < len; i++) {
  43679. point = points[i];
  43680. point.percentage =
  43681. (total > 0 && (point.visible || !ignoreHiddenPoint)) ?
  43682. point.y / total * 100 :
  43683. 0;
  43684. point.total = total;
  43685. }
  43686. };
  43687. /**
  43688. * A pie chart is a circular graphic which is divided into slices to
  43689. * illustrate numerical proportion.
  43690. *
  43691. * @sample highcharts/demo/pie-basic/
  43692. * Pie chart
  43693. *
  43694. * @extends plotOptions.line
  43695. * @excluding animationLimit, boostThreshold, connectEnds, connectNulls,
  43696. * cropThreshold, dashStyle, dataSorting, dragDrop,
  43697. * findNearestPointBy, getExtremesFromAll, label, lineWidth,
  43698. * marker, negativeColor, pointInterval, pointIntervalUnit,
  43699. * pointPlacement, pointStart, softThreshold, stacking, step,
  43700. * threshold, turboThreshold, zoneAxis, zones, dataSorting,
  43701. * boostBlending
  43702. * @product highcharts
  43703. * @optionparent plotOptions.pie
  43704. */
  43705. PieSeries.defaultOptions = merge(Series.defaultOptions, {
  43706. /**
  43707. * @excluding legendItemClick
  43708. * @apioption plotOptions.pie.events
  43709. */
  43710. /**
  43711. * Fires when the checkbox next to the point name in the legend is
  43712. * clicked. One parameter, event, is passed to the function. The state
  43713. * of the checkbox is found by event.checked. The checked item is found
  43714. * by event.item. Return false to prevent the default action which is to
  43715. * toggle the select state of the series.
  43716. *
  43717. * @sample {highcharts} highcharts/plotoptions/series-events-checkboxclick/
  43718. * Alert checkbox status
  43719. *
  43720. * @type {Function}
  43721. * @since 1.2.0
  43722. * @product highcharts
  43723. * @context Highcharts.Point
  43724. * @apioption plotOptions.pie.events.checkboxClick
  43725. */
  43726. /**
  43727. * Fires when the legend item belonging to the pie point (slice) is
  43728. * clicked. The `this` keyword refers to the point itself. One
  43729. * parameter, `event`, is passed to the function, containing common
  43730. * event information. The default action is to toggle the visibility of
  43731. * the point. This can be prevented by calling `event.preventDefault()`.
  43732. *
  43733. * @sample {highcharts} highcharts/plotoptions/pie-point-events-legenditemclick/
  43734. * Confirm toggle visibility
  43735. *
  43736. * @type {Highcharts.PointLegendItemClickCallbackFunction}
  43737. * @since 1.2.0
  43738. * @product highcharts
  43739. * @apioption plotOptions.pie.point.events.legendItemClick
  43740. */
  43741. /**
  43742. * The center of the pie chart relative to the plot area. Can be
  43743. * percentages or pixel values. The default behaviour (as of 3.0) is to
  43744. * center the pie so that all slices and data labels are within the plot
  43745. * area. As a consequence, the pie may actually jump around in a chart
  43746. * with dynamic values, as the data labels move. In that case, the
  43747. * center should be explicitly set, for example to `["50%", "50%"]`.
  43748. *
  43749. * @sample {highcharts} highcharts/plotoptions/pie-center/
  43750. * Centered at 100, 100
  43751. *
  43752. * @type {Array<(number|string|null),(number|string|null)>}
  43753. * @default [null, null]
  43754. * @product highcharts
  43755. *
  43756. * @private
  43757. */
  43758. center: [null, null],
  43759. /**
  43760. * The color of the pie series. A pie series is represented as an empty
  43761. * circle if the total sum of its values is 0. Use this property to
  43762. * define the color of its border.
  43763. *
  43764. * In styled mode, the color can be defined by the
  43765. * [colorIndex](#plotOptions.series.colorIndex) option. Also, the series
  43766. * color can be set with the `.highcharts-series`,
  43767. * `.highcharts-color-{n}`, `.highcharts-{type}-series` or
  43768. * `.highcharts-series-{n}` class, or individual classes given by the
  43769. * `className` option.
  43770. *
  43771. * @sample {highcharts} highcharts/plotoptions/pie-emptyseries/
  43772. * Empty pie series
  43773. *
  43774. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  43775. * @default ${palette.neutralColor20}
  43776. * @apioption plotOptions.pie.color
  43777. */
  43778. /**
  43779. * @product highcharts
  43780. *
  43781. * @private
  43782. */
  43783. clip: false,
  43784. /**
  43785. * @ignore-option
  43786. *
  43787. * @private
  43788. */
  43789. colorByPoint: true,
  43790. /**
  43791. * A series specific or series type specific color set to use instead
  43792. * of the global [colors](#colors).
  43793. *
  43794. * @sample {highcharts} highcharts/demo/pie-monochrome/
  43795. * Set default colors for all pies
  43796. *
  43797. * @type {Array<Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject>}
  43798. * @since 3.0
  43799. * @product highcharts
  43800. * @apioption plotOptions.pie.colors
  43801. */
  43802. /**
  43803. * @declare Highcharts.SeriesPieDataLabelsOptionsObject
  43804. * @extends plotOptions.series.dataLabels
  43805. * @excluding align, allowOverlap, inside, staggerLines, step
  43806. * @private
  43807. */
  43808. dataLabels: {
  43809. /**
  43810. * Alignment method for data labels. Possible values are:
  43811. *
  43812. * - `toPlotEdges`: Each label touches the nearest vertical edge of
  43813. * the plot area.
  43814. *
  43815. * - `connectors`: Connectors have the same x position and the
  43816. * widest label of each half (left & right) touches the nearest
  43817. * vertical edge of the plot area.
  43818. *
  43819. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-alignto-connectors/
  43820. * alignTo: connectors
  43821. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-alignto-plotedges/
  43822. * alignTo: plotEdges
  43823. *
  43824. * @type {string}
  43825. * @since 7.0.0
  43826. * @product highcharts
  43827. * @apioption plotOptions.pie.dataLabels.alignTo
  43828. */
  43829. allowOverlap: true,
  43830. /**
  43831. * The color of the line connecting the data label to the pie slice.
  43832. * The default color is the same as the point's color.
  43833. *
  43834. * In styled mode, the connector stroke is given in the
  43835. * `.highcharts-data-label-connector` class.
  43836. *
  43837. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorcolor/
  43838. * Blue connectors
  43839. * @sample {highcharts} highcharts/css/pie-point/
  43840. * Styled connectors
  43841. *
  43842. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  43843. * @since 2.1
  43844. * @product highcharts
  43845. * @apioption plotOptions.pie.dataLabels.connectorColor
  43846. */
  43847. /**
  43848. * The distance from the data label to the connector. Note that
  43849. * data labels also have a default `padding`, so in order for the
  43850. * connector to touch the text, the `padding` must also be 0.
  43851. *
  43852. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorpadding/
  43853. * No padding
  43854. *
  43855. * @since 2.1
  43856. * @product highcharts
  43857. */
  43858. connectorPadding: 5,
  43859. /**
  43860. * Specifies the method that is used to generate the connector path.
  43861. * Highcharts provides 3 built-in connector shapes: `'fixedOffset'`
  43862. * (default), `'straight'` and `'crookedLine'`. Using
  43863. * `'crookedLine'` has the most sense (in most of the cases) when
  43864. * `'alignTo'` is set.
  43865. *
  43866. * Users can provide their own method by passing a function instead
  43867. * of a String. 3 arguments are passed to the callback:
  43868. *
  43869. * - Object that holds the information about the coordinates of the
  43870. * label (`x` & `y` properties) and how the label is located in
  43871. * relation to the pie (`alignment` property). `alignment` can by
  43872. * one of the following:
  43873. * `'left'` (pie on the left side of the data label),
  43874. * `'right'` (pie on the right side of the data label) or
  43875. * `'center'` (data label overlaps the pie).
  43876. *
  43877. * - Object that holds the information about the position of the
  43878. * connector. Its `touchingSliceAt` porperty tells the position
  43879. * of the place where the connector touches the slice.
  43880. *
  43881. * - Data label options
  43882. *
  43883. * The function has to return an SVG path definition in array form
  43884. * (see the example).
  43885. *
  43886. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorshape-string/
  43887. * connectorShape is a String
  43888. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorshape-function/
  43889. * connectorShape is a function
  43890. *
  43891. * @type {string|Function}
  43892. * @since 7.0.0
  43893. * @product highcharts
  43894. */
  43895. connectorShape: 'fixedOffset',
  43896. /**
  43897. * The width of the line connecting the data label to the pie slice.
  43898. *
  43899. * In styled mode, the connector stroke width is given in the
  43900. * `.highcharts-data-label-connector` class.
  43901. *
  43902. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorwidth-disabled/
  43903. * Disable the connector
  43904. * @sample {highcharts} highcharts/css/pie-point/
  43905. * Styled connectors
  43906. *
  43907. * @type {number}
  43908. * @default 1
  43909. * @since 2.1
  43910. * @product highcharts
  43911. * @apioption plotOptions.pie.dataLabels.connectorWidth
  43912. */
  43913. /**
  43914. * Works only if `connectorShape` is `'crookedLine'`. It defines how
  43915. * far from the vertical plot edge the coonnector path should be
  43916. * crooked.
  43917. *
  43918. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-crookdistance/
  43919. * crookDistance set to 90%
  43920. *
  43921. * @since 7.0.0
  43922. * @product highcharts
  43923. */
  43924. crookDistance: '70%',
  43925. /**
  43926. * The distance of the data label from the pie's edge. Negative
  43927. * numbers put the data label on top of the pie slices. Can also be
  43928. * defined as a percentage of pie's radius. Connectors are only
  43929. * shown for data labels outside the pie.
  43930. *
  43931. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-distance/
  43932. * Data labels on top of the pie
  43933. *
  43934. * @type {number|string}
  43935. * @since 2.1
  43936. * @product highcharts
  43937. */
  43938. distance: 30,
  43939. enabled: true,
  43940. /**
  43941. * A
  43942. * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
  43943. * for the data label. Available variables are the same as for
  43944. * `formatter`.
  43945. *
  43946. * @sample {highcharts} highcharts/plotoptions/series-datalabels-format/
  43947. * Add a unit
  43948. *
  43949. * @type {string}
  43950. * @default undefined
  43951. * @since 3.0
  43952. * @apioption plotOptions.pie.dataLabels.format
  43953. */
  43954. // eslint-disable-next-line valid-jsdoc
  43955. /**
  43956. * Callback JavaScript function to format the data label. Note that
  43957. * if a `format` is defined, the format takes precedence and the
  43958. * formatter is ignored.
  43959. *
  43960. * @type {Highcharts.DataLabelsFormatterCallbackFunction}
  43961. * @default function () { return this.point.isNull ? void 0 : this.point.name; }
  43962. */
  43963. formatter: function () {
  43964. return this.point.isNull ? void 0 : this.point.name;
  43965. },
  43966. /**
  43967. * Whether to render the connector as a soft arc or a line with
  43968. * sharp break. Works only if `connectorShape` equals to
  43969. * `fixedOffset`.
  43970. *
  43971. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-softconnector-true/
  43972. * Soft
  43973. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-softconnector-false/
  43974. * Non soft
  43975. *
  43976. * @since 2.1.7
  43977. * @product highcharts
  43978. */
  43979. softConnector: true,
  43980. /**
  43981. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-overflow
  43982. * Long labels truncated with an ellipsis
  43983. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-overflow-wrap
  43984. * Long labels are wrapped
  43985. *
  43986. * @type {Highcharts.CSSObject}
  43987. * @apioption plotOptions.pie.dataLabels.style
  43988. */
  43989. x: 0
  43990. },
  43991. /**
  43992. * If the total sum of the pie's values is 0, the series is represented
  43993. * as an empty circle . The `fillColor` option defines the color of that
  43994. * circle. Use [pie.borderWidth](#plotOptions.pie.borderWidth) to set
  43995. * the border thickness.
  43996. *
  43997. * @sample {highcharts} highcharts/plotoptions/pie-emptyseries/
  43998. * Empty pie series
  43999. *
  44000. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  44001. * @private
  44002. */
  44003. fillColor: void 0,
  44004. /**
  44005. * The end angle of the pie in degrees where 0 is top and 90 is right.
  44006. * Defaults to `startAngle` plus 360.
  44007. *
  44008. * @sample {highcharts} highcharts/demo/pie-semi-circle/
  44009. * Semi-circle donut
  44010. *
  44011. * @type {number}
  44012. * @since 1.3.6
  44013. * @product highcharts
  44014. * @apioption plotOptions.pie.endAngle
  44015. */
  44016. /**
  44017. * Equivalent to [chart.ignoreHiddenSeries](#chart.ignoreHiddenSeries),
  44018. * this option tells whether the series shall be redrawn as if the
  44019. * hidden point were `null`.
  44020. *
  44021. * The default value changed from `false` to `true` with Highcharts
  44022. * 3.0.
  44023. *
  44024. * @sample {highcharts} highcharts/plotoptions/pie-ignorehiddenpoint/
  44025. * True, the hiddden point is ignored
  44026. *
  44027. * @since 2.3.0
  44028. * @product highcharts
  44029. *
  44030. * @private
  44031. */
  44032. ignoreHiddenPoint: true,
  44033. /**
  44034. * @ignore-option
  44035. *
  44036. * @private
  44037. */
  44038. inactiveOtherPoints: true,
  44039. /**
  44040. * The size of the inner diameter for the pie. A size greater than 0
  44041. * renders a donut chart. Can be a percentage or pixel value.
  44042. * Percentages are relative to the pie size. Pixel values are given as
  44043. * integers.
  44044. *
  44045. *
  44046. * Note: in Highcharts < 4.1.2, the percentage was relative to the plot
  44047. * area, not the pie size.
  44048. *
  44049. * @sample {highcharts} highcharts/plotoptions/pie-innersize-80px/
  44050. * 80px inner size
  44051. * @sample {highcharts} highcharts/plotoptions/pie-innersize-50percent/
  44052. * 50% of the plot area
  44053. * @sample {highcharts} highcharts/demo/3d-pie-donut/
  44054. * 3D donut
  44055. *
  44056. * @type {number|string}
  44057. * @default 0
  44058. * @since 2.0
  44059. * @product highcharts
  44060. * @apioption plotOptions.pie.innerSize
  44061. */
  44062. /**
  44063. * @ignore-option
  44064. *
  44065. * @private
  44066. */
  44067. legendType: 'point',
  44068. /**
  44069. * @ignore-option
  44070. *
  44071. * @private
  44072. */
  44073. marker: null,
  44074. /**
  44075. * The minimum size for a pie in response to auto margins. The pie will
  44076. * try to shrink to make room for data labels in side the plot area,
  44077. * but only to this size.
  44078. *
  44079. * @type {number|string}
  44080. * @default 80
  44081. * @since 3.0
  44082. * @product highcharts
  44083. * @apioption plotOptions.pie.minSize
  44084. */
  44085. /**
  44086. * The diameter of the pie relative to the plot area. Can be a
  44087. * percentage or pixel value. Pixel values are given as integers. The
  44088. * default behaviour (as of 3.0) is to scale to the plot area and give
  44089. * room for data labels within the plot area.
  44090. * [slicedOffset](#plotOptions.pie.slicedOffset) is also included in the
  44091. * default size calculation. As a consequence, the size of the pie may
  44092. * vary when points are updated and data labels more around. In that
  44093. * case it is best to set a fixed value, for example `"75%"`.
  44094. *
  44095. * @sample {highcharts} highcharts/plotoptions/pie-size/
  44096. * Smaller pie
  44097. *
  44098. * @type {number|string|null}
  44099. * @product highcharts
  44100. *
  44101. * @private
  44102. */
  44103. size: null,
  44104. /**
  44105. * Whether to display this particular series or series type in the
  44106. * legend. Since 2.1, pies are not shown in the legend by default.
  44107. *
  44108. * @sample {highcharts} highcharts/plotoptions/series-showinlegend/
  44109. * One series in the legend, one hidden
  44110. *
  44111. * @product highcharts
  44112. *
  44113. * @private
  44114. */
  44115. showInLegend: false,
  44116. /**
  44117. * If a point is sliced, moved out from the center, how many pixels
  44118. * should it be moved?.
  44119. *
  44120. * @sample {highcharts} highcharts/plotoptions/pie-slicedoffset-20/
  44121. * 20px offset
  44122. *
  44123. * @product highcharts
  44124. *
  44125. * @private
  44126. */
  44127. slicedOffset: 10,
  44128. /**
  44129. * The start angle of the pie slices in degrees where 0 is top and 90
  44130. * right.
  44131. *
  44132. * @sample {highcharts} highcharts/plotoptions/pie-startangle-90/
  44133. * Start from right
  44134. *
  44135. * @type {number}
  44136. * @default 0
  44137. * @since 2.3.4
  44138. * @product highcharts
  44139. * @apioption plotOptions.pie.startAngle
  44140. */
  44141. /**
  44142. * Sticky tracking of mouse events. When true, the `mouseOut` event
  44143. * on a series isn't triggered until the mouse moves over another
  44144. * series, or out of the plot area. When false, the `mouseOut` event on
  44145. * a series is triggered when the mouse leaves the area around the
  44146. * series' graph or markers. This also implies the tooltip. When
  44147. * `stickyTracking` is false and `tooltip.shared` is false, the tooltip
  44148. * will be hidden when moving the mouse between series.
  44149. *
  44150. * @product highcharts
  44151. *
  44152. * @private
  44153. */
  44154. stickyTracking: false,
  44155. tooltip: {
  44156. followPointer: true
  44157. },
  44158. /**
  44159. * The color of the border surrounding each slice. When `null`, the
  44160. * border takes the same color as the slice fill. This can be used
  44161. * together with a `borderWidth` to fill drawing gaps created by
  44162. * antialiazing artefacts in borderless pies.
  44163. *
  44164. * In styled mode, the border stroke is given in the `.highcharts-point`
  44165. * class.
  44166. *
  44167. * @sample {highcharts} highcharts/plotoptions/pie-bordercolor-black/
  44168. * Black border
  44169. *
  44170. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  44171. * @default #ffffff
  44172. * @product highcharts
  44173. *
  44174. * @private
  44175. */
  44176. borderColor: palette.backgroundColor,
  44177. /**
  44178. * The width of the border surrounding each slice.
  44179. *
  44180. * When setting the border width to 0, there may be small gaps between
  44181. * the slices due to SVG antialiasing artefacts. To work around this,
  44182. * keep the border width at 0.5 or 1, but set the `borderColor` to
  44183. * `null` instead.
  44184. *
  44185. * In styled mode, the border stroke width is given in the
  44186. * `.highcharts-point` class.
  44187. *
  44188. * @sample {highcharts} highcharts/plotoptions/pie-borderwidth/
  44189. * 3px border
  44190. *
  44191. * @product highcharts
  44192. *
  44193. * @private
  44194. */
  44195. borderWidth: 1,
  44196. /**
  44197. * @ignore-options
  44198. * @private
  44199. */
  44200. lineWidth: void 0,
  44201. states: {
  44202. /**
  44203. * @extends plotOptions.series.states.hover
  44204. * @excluding marker, lineWidth, lineWidthPlus
  44205. * @product highcharts
  44206. */
  44207. hover: {
  44208. /**
  44209. * How much to brighten the point on interaction. Requires the
  44210. * main color to be defined in hex or rgb(a) format.
  44211. *
  44212. * In styled mode, the hover brightness is by default replaced
  44213. * by a fill-opacity given in the `.highcharts-point-hover`
  44214. * class.
  44215. *
  44216. * @sample {highcharts} highcharts/plotoptions/pie-states-hover-brightness/
  44217. * Brightened by 0.5
  44218. *
  44219. * @product highcharts
  44220. */
  44221. brightness: 0.1
  44222. }
  44223. }
  44224. });
  44225. return PieSeries;
  44226. }(Series));
  44227. extend(PieSeries.prototype, {
  44228. axisTypes: [],
  44229. directTouch: true,
  44230. drawGraph: null,
  44231. drawLegendSymbol: LegendSymbolMixin.drawRectangle,
  44232. drawTracker: ColumnSeries.prototype.drawTracker,
  44233. getCenter: CenteredSeriesMixin.getCenter,
  44234. getSymbol: noop,
  44235. isCartesian: false,
  44236. noSharedTooltip: true,
  44237. pointAttribs: ColumnSeries.prototype.pointAttribs,
  44238. pointClass: PiePoint,
  44239. requireSorting: false,
  44240. searchPoint: noop,
  44241. trackerGroups: ['group', 'dataLabelsGroup']
  44242. });
  44243. SeriesRegistry.registerSeriesType('pie', PieSeries);
  44244. /* *
  44245. *
  44246. * Default Export
  44247. *
  44248. * */
  44249. /* *
  44250. *
  44251. * API Options
  44252. *
  44253. * */
  44254. /**
  44255. * A `pie` series. If the [type](#series.pie.type) option is not specified,
  44256. * it is inherited from [chart.type](#chart.type).
  44257. *
  44258. * @extends series,plotOptions.pie
  44259. * @excluding cropThreshold, dataParser, dataURL, stack, xAxis, yAxis,
  44260. * dataSorting, step, boostThreshold, boostBlending
  44261. * @product highcharts
  44262. * @apioption series.pie
  44263. */
  44264. /**
  44265. * An array of data points for the series. For the `pie` series type,
  44266. * points can be given in the following ways:
  44267. *
  44268. * 1. An array of numerical values. In this case, the numerical values will be
  44269. * interpreted as `y` options. Example:
  44270. * ```js
  44271. * data: [0, 5, 3, 5]
  44272. * ```
  44273. *
  44274. * 2. An array of objects with named values. The following snippet shows only a
  44275. * few settings, see the complete options set below. If the total number of
  44276. * data points exceeds the series'
  44277. * [turboThreshold](#series.pie.turboThreshold),
  44278. * this option is not available.
  44279. * ```js
  44280. * data: [{
  44281. * y: 1,
  44282. * name: "Point2",
  44283. * color: "#00FF00"
  44284. * }, {
  44285. * y: 7,
  44286. * name: "Point1",
  44287. * color: "#FF00FF"
  44288. * }]
  44289. * ```
  44290. *
  44291. * @sample {highcharts} highcharts/chart/reflow-true/
  44292. * Numerical values
  44293. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  44294. * Arrays of numeric x and y
  44295. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  44296. * Arrays of datetime x and y
  44297. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  44298. * Arrays of point.name and y
  44299. * @sample {highcharts} highcharts/series/data-array-of-objects/
  44300. * Config objects
  44301. *
  44302. * @type {Array<number|Array<string,(number|null)>|null|*>}
  44303. * @extends series.line.data
  44304. * @excluding marker, x
  44305. * @product highcharts
  44306. * @apioption series.pie.data
  44307. */
  44308. /**
  44309. * @type {Highcharts.SeriesPieDataLabelsOptionsObject}
  44310. * @product highcharts
  44311. * @apioption series.pie.data.dataLabels
  44312. */
  44313. /**
  44314. * The sequential index of the data point in the legend.
  44315. *
  44316. * @type {number}
  44317. * @product highcharts
  44318. * @apioption series.pie.data.legendIndex
  44319. */
  44320. /**
  44321. * Whether to display a slice offset from the center.
  44322. *
  44323. * @sample {highcharts} highcharts/point/sliced/
  44324. * One sliced point
  44325. *
  44326. * @type {boolean}
  44327. * @product highcharts
  44328. * @apioption series.pie.data.sliced
  44329. */
  44330. /**
  44331. * @extends plotOptions.pie.dataLabels
  44332. * @excluding align, allowOverlap, inside, staggerLines, step
  44333. * @product highcharts
  44334. * @apioption series.pie.dataLabels
  44335. */
  44336. /**
  44337. * @excluding legendItemClick
  44338. * @product highcharts
  44339. * @apioption series.pie.events
  44340. */
  44341. ''; // placeholder for transpiled doclets above
  44342. return PieSeries;
  44343. });
  44344. _registerModule(_modules, 'Core/Series/DataLabels.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Globals.js'], _modules['Core/Color/Palette.js'], _modules['Core/Series/Series.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (A, H, palette, Series, SeriesRegistry, U) {
  44345. /* *
  44346. *
  44347. * (c) 2010-2021 Torstein Honsi
  44348. *
  44349. * License: www.highcharts.com/license
  44350. *
  44351. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  44352. *
  44353. * */
  44354. var getDeferredAnimation = A.getDeferredAnimation;
  44355. var noop = H.noop;
  44356. var seriesTypes = SeriesRegistry.seriesTypes;
  44357. var arrayMax = U.arrayMax,
  44358. clamp = U.clamp,
  44359. defined = U.defined,
  44360. extend = U.extend,
  44361. fireEvent = U.fireEvent,
  44362. format = U.format,
  44363. isArray = U.isArray,
  44364. merge = U.merge,
  44365. objectEach = U.objectEach,
  44366. pick = U.pick,
  44367. relativeLength = U.relativeLength,
  44368. splat = U.splat,
  44369. stableSort = U.stableSort;
  44370. /**
  44371. * Callback JavaScript function to format the data label as a string. Note that
  44372. * if a `format` is defined, the format takes precedence and the formatter is
  44373. * ignored.
  44374. *
  44375. * @callback Highcharts.DataLabelsFormatterCallbackFunction
  44376. *
  44377. * @param {Highcharts.PointLabelObject} this
  44378. * Data label context to format
  44379. *
  44380. * @param {Highcharts.DataLabelsOptions} options
  44381. * [API options](/highcharts/plotOptions.series.dataLabels) of the data label
  44382. *
  44383. * @return {number|string|null|undefined}
  44384. * Formatted data label text
  44385. */
  44386. /**
  44387. * Values for handling data labels that flow outside the plot area.
  44388. *
  44389. * @typedef {"allow"|"justify"} Highcharts.DataLabelsOverflowValue
  44390. */
  44391. ''; // detach doclets above
  44392. /* eslint-disable valid-jsdoc */
  44393. /**
  44394. * General distribution algorithm for distributing labels of differing size
  44395. * along a confined length in two dimensions. The algorithm takes an array of
  44396. * objects containing a size, a target and a rank. It will place the labels as
  44397. * close as possible to their targets, skipping the lowest ranked labels if
  44398. * necessary.
  44399. *
  44400. * @private
  44401. * @function Highcharts.distribute
  44402. * @param {Highcharts.DataLabelsBoxArray} boxes
  44403. * @param {number} len
  44404. * @param {number} [maxDistance]
  44405. * @return {void}
  44406. */
  44407. H.distribute = function (boxes, len, maxDistance) {
  44408. var i,
  44409. overlapping = true,
  44410. origBoxes = boxes, // Original array will be altered with added .pos
  44411. restBoxes = [], // The outranked overshoot
  44412. box,
  44413. target,
  44414. total = 0,
  44415. reducedLen = origBoxes.reducedLen || len;
  44416. /**
  44417. * @private
  44418. */
  44419. function sortByTarget(a, b) {
  44420. return a.target - b.target;
  44421. }
  44422. // If the total size exceeds the len, remove those boxes with the lowest
  44423. // rank
  44424. i = boxes.length;
  44425. while (i--) {
  44426. total += boxes[i].size;
  44427. }
  44428. // Sort by rank, then slice away overshoot
  44429. if (total > reducedLen) {
  44430. stableSort(boxes, function (a, b) {
  44431. return (b.rank || 0) - (a.rank || 0);
  44432. });
  44433. i = 0;
  44434. total = 0;
  44435. while (total <= reducedLen) {
  44436. total += boxes[i].size;
  44437. i++;
  44438. }
  44439. restBoxes = boxes.splice(i - 1, boxes.length);
  44440. }
  44441. // Order by target
  44442. stableSort(boxes, sortByTarget);
  44443. // So far we have been mutating the original array. Now
  44444. // create a copy with target arrays
  44445. boxes = boxes.map(function (box) {
  44446. return {
  44447. size: box.size,
  44448. targets: [box.target],
  44449. align: pick(box.align, 0.5)
  44450. };
  44451. });
  44452. while (overlapping) {
  44453. // Initial positions: target centered in box
  44454. i = boxes.length;
  44455. while (i--) {
  44456. box = boxes[i];
  44457. // Composite box, average of targets
  44458. target = (Math.min.apply(0, box.targets) +
  44459. Math.max.apply(0, box.targets)) / 2;
  44460. box.pos = clamp(target - box.size * box.align, 0, len - box.size);
  44461. }
  44462. // Detect overlap and join boxes
  44463. i = boxes.length;
  44464. overlapping = false;
  44465. while (i--) {
  44466. // Overlap
  44467. if (i > 0 &&
  44468. boxes[i - 1].pos + boxes[i - 1].size >
  44469. boxes[i].pos) {
  44470. // Add this size to the previous box
  44471. boxes[i - 1].size += boxes[i].size;
  44472. boxes[i - 1].targets = boxes[i - 1]
  44473. .targets
  44474. .concat(boxes[i].targets);
  44475. boxes[i - 1].align = 0.5;
  44476. // Overlapping right, push left
  44477. if (boxes[i - 1].pos + boxes[i - 1].size > len) {
  44478. boxes[i - 1].pos = len - boxes[i - 1].size;
  44479. }
  44480. boxes.splice(i, 1); // Remove this item
  44481. overlapping = true;
  44482. }
  44483. }
  44484. }
  44485. // Add the rest (hidden boxes)
  44486. origBoxes.push.apply(origBoxes, restBoxes);
  44487. // Now the composite boxes are placed, we need to put the original boxes
  44488. // within them
  44489. i = 0;
  44490. boxes.some(function (box) {
  44491. var posInCompositeBox = 0;
  44492. if (box.targets.some(function () {
  44493. origBoxes[i].pos = box.pos + posInCompositeBox;
  44494. // If the distance between the position and the target exceeds
  44495. // maxDistance, abort the loop and decrease the length in increments
  44496. // of 10% to recursively reduce the number of visible boxes by
  44497. // rank. Once all boxes are within the maxDistance, we're good.
  44498. if (typeof maxDistance !== 'undefined' &&
  44499. Math.abs(origBoxes[i].pos - origBoxes[i].target) > maxDistance) {
  44500. // Reset the positions that are already set
  44501. origBoxes.slice(0, i + 1).forEach(function (box) {
  44502. delete box.pos;
  44503. });
  44504. // Try with a smaller length
  44505. origBoxes.reducedLen =
  44506. (origBoxes.reducedLen || len) - (len * 0.1);
  44507. // Recurse
  44508. if (origBoxes.reducedLen > len * 0.1) {
  44509. H.distribute(origBoxes, len, maxDistance);
  44510. }
  44511. // Exceeded maxDistance => abort
  44512. return true;
  44513. }
  44514. posInCompositeBox += origBoxes[i].size;
  44515. i++;
  44516. })) {
  44517. // Exceeded maxDistance => abort
  44518. return true;
  44519. }
  44520. });
  44521. // Add the rest (hidden) boxes and sort by target
  44522. stableSort(origBoxes, sortByTarget);
  44523. };
  44524. /**
  44525. * Draw the data labels
  44526. *
  44527. * @private
  44528. * @function Highcharts.Series#drawDataLabels
  44529. * @return {void}
  44530. * @fires Highcharts.Series#event:afterDrawDataLabels
  44531. */
  44532. Series.prototype.drawDataLabels = function () {
  44533. var series = this,
  44534. chart = series.chart,
  44535. seriesOptions = series.options,
  44536. seriesDlOptions = seriesOptions.dataLabels,
  44537. points = series.points,
  44538. pointOptions,
  44539. hasRendered = series.hasRendered || 0,
  44540. dataLabelsGroup,
  44541. dataLabelAnim = seriesDlOptions.animation,
  44542. animationConfig = seriesDlOptions.defer ?
  44543. getDeferredAnimation(chart,
  44544. dataLabelAnim,
  44545. series) :
  44546. { defer: 0,
  44547. duration: 0 },
  44548. renderer = chart.renderer;
  44549. /**
  44550. * Handle the dataLabels.filter option.
  44551. * @private
  44552. */
  44553. function applyFilter(point, options) {
  44554. var filter = options.filter,
  44555. op,
  44556. prop,
  44557. val;
  44558. if (filter) {
  44559. op = filter.operator;
  44560. prop = point[filter.property];
  44561. val = filter.value;
  44562. if ((op === '>' && prop > val) ||
  44563. (op === '<' && prop < val) ||
  44564. (op === '>=' && prop >= val) ||
  44565. (op === '<=' && prop <= val) ||
  44566. (op === '==' && prop == val) || // eslint-disable-line eqeqeq
  44567. (op === '===' && prop === val)) {
  44568. return true;
  44569. }
  44570. return false;
  44571. }
  44572. return true;
  44573. }
  44574. /**
  44575. * Merge two objects that can be arrays. If one of them is an array, the
  44576. * other is merged into each element. If both are arrays, each element is
  44577. * merged by index. If neither are arrays, we use normal merge.
  44578. * @private
  44579. */
  44580. function mergeArrays(one, two) {
  44581. var res = [],
  44582. i;
  44583. if (isArray(one) && !isArray(two)) {
  44584. res = one.map(function (el) {
  44585. return merge(el, two);
  44586. });
  44587. }
  44588. else if (isArray(two) && !isArray(one)) {
  44589. res = two.map(function (el) {
  44590. return merge(one, el);
  44591. });
  44592. }
  44593. else if (!isArray(one) && !isArray(two)) {
  44594. res = merge(one, two);
  44595. }
  44596. else {
  44597. i = Math.max(one.length, two.length);
  44598. while (i--) {
  44599. res[i] = merge(one[i], two[i]);
  44600. }
  44601. }
  44602. return res;
  44603. }
  44604. // Merge in plotOptions.dataLabels for series
  44605. seriesDlOptions = mergeArrays(mergeArrays(chart.options.plotOptions &&
  44606. chart.options.plotOptions.series &&
  44607. chart.options.plotOptions.series.dataLabels, chart.options.plotOptions &&
  44608. chart.options.plotOptions[series.type] &&
  44609. chart.options.plotOptions[series.type].dataLabels), seriesDlOptions);
  44610. fireEvent(this, 'drawDataLabels');
  44611. if (isArray(seriesDlOptions) ||
  44612. seriesDlOptions.enabled ||
  44613. series._hasPointLabels) {
  44614. // Create a separate group for the data labels to avoid rotation
  44615. dataLabelsGroup = series.plotGroup('dataLabelsGroup', 'data-labels', !hasRendered ? 'hidden' : 'inherit', // #5133, #10220
  44616. seriesDlOptions.zIndex || 6);
  44617. dataLabelsGroup.attr({ opacity: +hasRendered }); // #3300
  44618. if (!hasRendered) {
  44619. var group = series.dataLabelsGroup;
  44620. if (group) {
  44621. if (series.visible) { // #2597, #3023, #3024
  44622. dataLabelsGroup.show(true);
  44623. }
  44624. group[seriesOptions.animation ? 'animate' : 'attr']({ opacity: 1 }, animationConfig);
  44625. }
  44626. }
  44627. // Make the labels for each point
  44628. points.forEach(function (point) {
  44629. // Merge in series options for the point.
  44630. // @note dataLabelAttribs (like pointAttribs) would eradicate
  44631. // the need for dlOptions, and simplify the section below.
  44632. pointOptions = splat(mergeArrays(seriesDlOptions, point.dlOptions || // dlOptions is used in treemaps
  44633. (point.options && point.options.dataLabels)));
  44634. // Handle each individual data label for this point
  44635. pointOptions.forEach(function (labelOptions, i) {
  44636. // Options for one datalabel
  44637. var labelEnabled = (labelOptions.enabled &&
  44638. // #2282, #4641, #7112, #10049
  44639. (!point.isNull || point.dataLabelOnNull) &&
  44640. applyFilter(point,
  44641. labelOptions)),
  44642. labelConfig,
  44643. formatString,
  44644. labelText,
  44645. style,
  44646. rotation,
  44647. attr,
  44648. dataLabel = point.dataLabels ? point.dataLabels[i] :
  44649. point.dataLabel,
  44650. connector = point.connectors ? point.connectors[i] :
  44651. point.connector,
  44652. labelDistance = pick(labelOptions.distance,
  44653. point.labelDistance),
  44654. isNew = !dataLabel;
  44655. if (labelEnabled) {
  44656. // Create individual options structure that can be extended
  44657. // without affecting others
  44658. labelConfig = point.getLabelConfig();
  44659. formatString = pick(labelOptions[point.formatPrefix + 'Format'], labelOptions.format);
  44660. labelText = defined(formatString) ?
  44661. format(formatString, labelConfig, chart) :
  44662. (labelOptions[point.formatPrefix + 'Formatter'] ||
  44663. labelOptions.formatter).call(labelConfig, labelOptions);
  44664. style = labelOptions.style;
  44665. rotation = labelOptions.rotation;
  44666. if (!chart.styledMode) {
  44667. // Determine the color
  44668. style.color = pick(labelOptions.color, style.color, series.color, palette.neutralColor100);
  44669. // Get automated contrast color
  44670. if (style.color === 'contrast') {
  44671. point.contrastColor = renderer.getContrast((point.color || series.color));
  44672. style.color = (!defined(labelDistance) &&
  44673. labelOptions.inside) ||
  44674. labelDistance < 0 ||
  44675. !!seriesOptions.stacking ?
  44676. point.contrastColor :
  44677. palette.neutralColor100;
  44678. }
  44679. else {
  44680. delete point.contrastColor;
  44681. }
  44682. if (seriesOptions.cursor) {
  44683. style.cursor = seriesOptions.cursor;
  44684. }
  44685. }
  44686. attr = {
  44687. r: labelOptions.borderRadius || 0,
  44688. rotation: rotation,
  44689. padding: labelOptions.padding,
  44690. zIndex: 1
  44691. };
  44692. if (!chart.styledMode) {
  44693. attr.fill = labelOptions.backgroundColor;
  44694. attr.stroke = labelOptions.borderColor;
  44695. attr['stroke-width'] = labelOptions.borderWidth;
  44696. }
  44697. // Remove unused attributes (#947)
  44698. objectEach(attr, function (val, name) {
  44699. if (typeof val === 'undefined') {
  44700. delete attr[name];
  44701. }
  44702. });
  44703. }
  44704. // If the point is outside the plot area, destroy it. #678, #820
  44705. if (dataLabel && (!labelEnabled || !defined(labelText))) {
  44706. point.dataLabel =
  44707. point.dataLabel && point.dataLabel.destroy();
  44708. if (point.dataLabels) {
  44709. // Remove point.dataLabels if this was the last one
  44710. if (point.dataLabels.length === 1) {
  44711. delete point.dataLabels;
  44712. }
  44713. else {
  44714. delete point.dataLabels[i];
  44715. }
  44716. }
  44717. if (!i) {
  44718. delete point.dataLabel;
  44719. }
  44720. if (connector) {
  44721. point.connector = point.connector.destroy();
  44722. if (point.connectors) {
  44723. // Remove point.connectors if this was the last one
  44724. if (point.connectors.length === 1) {
  44725. delete point.connectors;
  44726. }
  44727. else {
  44728. delete point.connectors[i];
  44729. }
  44730. }
  44731. }
  44732. // Individual labels are disabled if the are explicitly disabled
  44733. // in the point options, or if they fall outside the plot area.
  44734. }
  44735. else if (labelEnabled && defined(labelText)) {
  44736. if (!dataLabel) {
  44737. // Create new label element
  44738. point.dataLabels = point.dataLabels || [];
  44739. dataLabel = point.dataLabels[i] = rotation ?
  44740. // Labels don't rotate, use text element
  44741. renderer.text(labelText, 0, -9999, labelOptions.useHTML)
  44742. .addClass('highcharts-data-label') :
  44743. // We can use label
  44744. renderer.label(labelText, 0, -9999, labelOptions.shape, null, null, labelOptions.useHTML, null, 'data-label');
  44745. // Store for backwards compatibility
  44746. if (!i) {
  44747. point.dataLabel = dataLabel;
  44748. }
  44749. dataLabel.addClass(' highcharts-data-label-color-' + point.colorIndex +
  44750. ' ' + (labelOptions.className || '') +
  44751. ( // #3398
  44752. labelOptions.useHTML ?
  44753. ' highcharts-tracker' :
  44754. ''));
  44755. }
  44756. else {
  44757. // Use old element and just update text
  44758. attr.text = labelText;
  44759. }
  44760. // Store data label options for later access
  44761. dataLabel.options = labelOptions;
  44762. dataLabel.attr(attr);
  44763. if (!chart.styledMode) {
  44764. // Styles must be applied before add in order to read
  44765. // text bounding box
  44766. dataLabel.css(style).shadow(labelOptions.shadow);
  44767. }
  44768. if (!dataLabel.added) {
  44769. dataLabel.add(dataLabelsGroup);
  44770. }
  44771. if (labelOptions.textPath && !labelOptions.useHTML) {
  44772. dataLabel.setTextPath((point.getDataLabelPath &&
  44773. point.getDataLabelPath(dataLabel)) || point.graphic, labelOptions.textPath);
  44774. if (point.dataLabelPath &&
  44775. !labelOptions.textPath.enabled) {
  44776. // clean the DOM
  44777. point.dataLabelPath = point.dataLabelPath.destroy();
  44778. }
  44779. }
  44780. // Now the data label is created and placed at 0,0, so we
  44781. // need to align it
  44782. series.alignDataLabel(point, dataLabel, labelOptions, null, isNew);
  44783. }
  44784. });
  44785. });
  44786. }
  44787. fireEvent(this, 'afterDrawDataLabels');
  44788. };
  44789. /**
  44790. * Align each individual data label.
  44791. *
  44792. * @private
  44793. * @function Highcharts.Series#alignDataLabel
  44794. * @param {Highcharts.Point} point
  44795. * @param {Highcharts.SVGElement} dataLabel
  44796. * @param {Highcharts.DataLabelsOptions} options
  44797. * @param {Highcharts.BBoxObject} alignTo
  44798. * @param {boolean} [isNew]
  44799. * @return {void}
  44800. */
  44801. Series.prototype.alignDataLabel = function (point, dataLabel, options, alignTo, isNew) {
  44802. var series = this,
  44803. chart = this.chart,
  44804. inverted = this.isCartesian && chart.inverted,
  44805. enabledDataSorting = this.enabledDataSorting,
  44806. plotX = pick(point.dlBox && point.dlBox.centerX,
  44807. point.plotX, -9999),
  44808. plotY = pick(point.plotY, -9999),
  44809. bBox = dataLabel.getBBox(),
  44810. baseline,
  44811. rotation = options.rotation,
  44812. normRotation,
  44813. negRotation,
  44814. align = options.align,
  44815. rotCorr, // rotation correction
  44816. isInsidePlot = chart.isInsidePlot(plotX,
  44817. Math.round(plotY),
  44818. inverted),
  44819. // Math.round for rounding errors (#2683), alignTo to allow column
  44820. // labels (#2700)
  44821. alignAttr, // the final position;
  44822. justify = pick(options.overflow, (enabledDataSorting ? 'none' : 'justify')) === 'justify', visible = this.visible &&
  44823. point.visible !== false &&
  44824. (point.series.forceDL ||
  44825. (enabledDataSorting && !justify) ||
  44826. isInsidePlot ||
  44827. (
  44828. // If the data label is inside the align box, it is enough
  44829. // that parts of the align box is inside the plot area
  44830. // (#12370)
  44831. options.inside && alignTo && chart.isInsidePlot(plotX, inverted ?
  44832. alignTo.x + 1 :
  44833. alignTo.y + alignTo.height - 1, inverted))), setStartPos = function (alignOptions) {
  44834. if (enabledDataSorting && series.xAxis && !justify) {
  44835. series.setDataLabelStartPos(point, dataLabel, isNew, isInsidePlot, alignOptions);
  44836. }
  44837. };
  44838. if (visible) {
  44839. baseline = chart.renderer.fontMetrics(chart.styledMode ? void 0 : options.style.fontSize, dataLabel).b;
  44840. // The alignment box is a singular point
  44841. alignTo = extend({
  44842. x: inverted ? this.yAxis.len - plotY : plotX,
  44843. y: Math.round(inverted ? this.xAxis.len - plotX : plotY),
  44844. width: 0,
  44845. height: 0
  44846. }, alignTo);
  44847. // Add the text size for alignment calculation
  44848. extend(options, {
  44849. width: bBox.width,
  44850. height: bBox.height
  44851. });
  44852. // Allow a hook for changing alignment in the last moment, then do the
  44853. // alignment
  44854. if (rotation) {
  44855. justify = false; // Not supported for rotated text
  44856. rotCorr = chart.renderer.rotCorr(baseline, rotation); // #3723
  44857. alignAttr = {
  44858. x: (alignTo.x +
  44859. (options.x || 0) +
  44860. alignTo.width / 2 +
  44861. rotCorr.x),
  44862. y: (alignTo.y +
  44863. (options.y || 0) +
  44864. { top: 0, middle: 0.5, bottom: 1 }[options.verticalAlign] *
  44865. alignTo.height)
  44866. };
  44867. setStartPos(alignAttr); // data sorting
  44868. dataLabel[isNew ? 'attr' : 'animate'](alignAttr)
  44869. .attr({
  44870. align: align
  44871. });
  44872. // Compensate for the rotated label sticking out on the sides
  44873. normRotation = (rotation + 720) % 360;
  44874. negRotation = normRotation > 180 && normRotation < 360;
  44875. if (align === 'left') {
  44876. alignAttr.y -= negRotation ? bBox.height : 0;
  44877. }
  44878. else if (align === 'center') {
  44879. alignAttr.x -= bBox.width / 2;
  44880. alignAttr.y -= bBox.height / 2;
  44881. }
  44882. else if (align === 'right') {
  44883. alignAttr.x -= bBox.width;
  44884. alignAttr.y -= negRotation ? 0 : bBox.height;
  44885. }
  44886. dataLabel.placed = true;
  44887. dataLabel.alignAttr = alignAttr;
  44888. }
  44889. else {
  44890. setStartPos(alignTo); // data sorting
  44891. dataLabel.align(options, null, alignTo);
  44892. alignAttr = dataLabel.alignAttr;
  44893. }
  44894. // Handle justify or crop
  44895. if (justify && alignTo.height >= 0) { // #8830
  44896. this.justifyDataLabel(dataLabel, options, alignAttr, bBox, alignTo, isNew);
  44897. // Now check that the data label is within the plot area
  44898. }
  44899. else if (pick(options.crop, true)) {
  44900. visible =
  44901. chart.isInsidePlot(alignAttr.x, alignAttr.y) &&
  44902. chart.isInsidePlot(alignAttr.x + bBox.width, alignAttr.y + bBox.height);
  44903. }
  44904. // When we're using a shape, make it possible with a connector or an
  44905. // arrow pointing to thie point
  44906. if (options.shape && !rotation) {
  44907. dataLabel[isNew ? 'attr' : 'animate']({
  44908. anchorX: inverted ?
  44909. chart.plotWidth - point.plotY :
  44910. point.plotX,
  44911. anchorY: inverted ?
  44912. chart.plotHeight - point.plotX :
  44913. point.plotY
  44914. });
  44915. }
  44916. }
  44917. // To use alignAttr property in hideOverlappingLabels
  44918. if (isNew && enabledDataSorting) {
  44919. dataLabel.placed = false;
  44920. }
  44921. // Show or hide based on the final aligned position
  44922. if (!visible && (!enabledDataSorting || justify)) {
  44923. dataLabel.hide(true);
  44924. dataLabel.placed = false; // don't animate back in
  44925. }
  44926. };
  44927. /**
  44928. * Set starting position for data label sorting animation.
  44929. *
  44930. * @private
  44931. * @function Highcharts.Series#setDataLabelStartPos
  44932. * @param {Highcharts.SVGElement} dataLabel
  44933. * @param {Highcharts.ColumnPoint} point
  44934. * @param {boolean | undefined} [isNew]
  44935. * @param {boolean} [isInside]
  44936. * @param {Highcharts.AlignObject} [alignOptions]
  44937. *
  44938. * @return {void}
  44939. */
  44940. Series.prototype.setDataLabelStartPos = function (point, dataLabel, isNew, isInside, alignOptions) {
  44941. var chart = this.chart,
  44942. inverted = chart.inverted,
  44943. xAxis = this.xAxis,
  44944. reversed = xAxis.reversed,
  44945. labelCenter = inverted ? dataLabel.height / 2 : dataLabel.width / 2,
  44946. pointWidth = point.pointWidth,
  44947. halfWidth = pointWidth ? pointWidth / 2 : 0,
  44948. startXPos,
  44949. startYPos;
  44950. startXPos = inverted ?
  44951. alignOptions.x :
  44952. (reversed ?
  44953. -labelCenter - halfWidth :
  44954. xAxis.width - labelCenter + halfWidth);
  44955. startYPos = inverted ?
  44956. (reversed ?
  44957. this.yAxis.height - labelCenter + halfWidth :
  44958. -labelCenter - halfWidth) : alignOptions.y;
  44959. dataLabel.startXPos = startXPos;
  44960. dataLabel.startYPos = startYPos;
  44961. // We need to handle visibility in case of sorting point outside plot area
  44962. if (!isInside) {
  44963. dataLabel
  44964. .attr({ opacity: 1 })
  44965. .animate({ opacity: 0 }, void 0, dataLabel.hide);
  44966. }
  44967. else if (dataLabel.visibility === 'hidden') {
  44968. dataLabel.show();
  44969. dataLabel
  44970. .attr({ opacity: 0 })
  44971. .animate({ opacity: 1 });
  44972. }
  44973. // Save start position on first render, but do not change position
  44974. if (!chart.hasRendered) {
  44975. return;
  44976. }
  44977. // Set start position
  44978. if (isNew) {
  44979. dataLabel.attr({ x: dataLabel.startXPos, y: dataLabel.startYPos });
  44980. }
  44981. dataLabel.placed = true;
  44982. };
  44983. /**
  44984. * If data labels fall partly outside the plot area, align them back in, in a
  44985. * way that doesn't hide the point.
  44986. *
  44987. * @private
  44988. * @function Highcharts.Series#justifyDataLabel
  44989. * @param {Highcharts.SVGElement} dataLabel
  44990. * @param {Highcharts.DataLabelsOptions} options
  44991. * @param {Highcharts.SVGAttributes} alignAttr
  44992. * @param {Highcharts.BBoxObject} bBox
  44993. * @param {Highcharts.BBoxObject} [alignTo]
  44994. * @param {boolean} [isNew]
  44995. * @return {boolean|undefined}
  44996. */
  44997. Series.prototype.justifyDataLabel = function (dataLabel, options, alignAttr, bBox, alignTo, isNew) {
  44998. var chart = this.chart,
  44999. align = options.align,
  45000. verticalAlign = options.verticalAlign,
  45001. off,
  45002. justified,
  45003. padding = dataLabel.box ? 0 : (dataLabel.padding || 0);
  45004. var _a = options.x,
  45005. x = _a === void 0 ? 0 : _a,
  45006. _b = options.y,
  45007. y = _b === void 0 ? 0 : _b;
  45008. // Off left
  45009. off = alignAttr.x + padding;
  45010. if (off < 0) {
  45011. if (align === 'right' && x >= 0) {
  45012. options.align = 'left';
  45013. options.inside = true;
  45014. }
  45015. else {
  45016. x -= off;
  45017. }
  45018. justified = true;
  45019. }
  45020. // Off right
  45021. off = alignAttr.x + bBox.width - padding;
  45022. if (off > chart.plotWidth) {
  45023. if (align === 'left' && x <= 0) {
  45024. options.align = 'right';
  45025. options.inside = true;
  45026. }
  45027. else {
  45028. x += chart.plotWidth - off;
  45029. }
  45030. justified = true;
  45031. }
  45032. // Off top
  45033. off = alignAttr.y + padding;
  45034. if (off < 0) {
  45035. if (verticalAlign === 'bottom' && y >= 0) {
  45036. options.verticalAlign = 'top';
  45037. options.inside = true;
  45038. }
  45039. else {
  45040. y -= off;
  45041. }
  45042. justified = true;
  45043. }
  45044. // Off bottom
  45045. off = alignAttr.y + bBox.height - padding;
  45046. if (off > chart.plotHeight) {
  45047. if (verticalAlign === 'top' && y <= 0) {
  45048. options.verticalAlign = 'bottom';
  45049. options.inside = true;
  45050. }
  45051. else {
  45052. y += chart.plotHeight - off;
  45053. }
  45054. justified = true;
  45055. }
  45056. if (justified) {
  45057. options.x = x;
  45058. options.y = y;
  45059. dataLabel.placed = !isNew;
  45060. dataLabel.align(options, void 0, alignTo);
  45061. }
  45062. return justified;
  45063. };
  45064. if (seriesTypes.pie) {
  45065. seriesTypes.pie.prototype.dataLabelPositioners = {
  45066. // Based on the value computed in Highcharts' distribute algorithm.
  45067. radialDistributionY: function (point) {
  45068. return point.top + point.distributeBox.pos;
  45069. },
  45070. // get the x - use the natural x position for labels near the
  45071. // top and bottom, to prevent the top and botton slice
  45072. // connectors from touching each other on either side
  45073. // Based on the value computed in Highcharts' distribute algorithm.
  45074. radialDistributionX: function (series, point, y, naturalY) {
  45075. return series.getX(y < point.top + 2 || y > point.bottom - 2 ?
  45076. naturalY :
  45077. y, point.half, point);
  45078. },
  45079. // dataLabels.distance determines the x position of the label
  45080. justify: function (point, radius, seriesCenter) {
  45081. return seriesCenter[0] + (point.half ? -1 : 1) *
  45082. (radius + point.labelDistance);
  45083. },
  45084. // Left edges of the left-half labels touch the left edge of the plot
  45085. // area. Right edges of the right-half labels touch the right edge of
  45086. // the plot area.
  45087. alignToPlotEdges: function (dataLabel, half, plotWidth, plotLeft) {
  45088. var dataLabelWidth = dataLabel.getBBox().width;
  45089. return half ? dataLabelWidth + plotLeft :
  45090. plotWidth - dataLabelWidth - plotLeft;
  45091. },
  45092. // Connectors of each side end in the same x position. Labels are
  45093. // aligned to them. Left edge of the widest left-half label touches the
  45094. // left edge of the plot area. Right edge of the widest right-half label
  45095. // touches the right edge of the plot area.
  45096. alignToConnectors: function (points, half, plotWidth, plotLeft) {
  45097. var maxDataLabelWidth = 0,
  45098. dataLabelWidth;
  45099. // find widest data label
  45100. points.forEach(function (point) {
  45101. dataLabelWidth = point.dataLabel.getBBox().width;
  45102. if (dataLabelWidth > maxDataLabelWidth) {
  45103. maxDataLabelWidth = dataLabelWidth;
  45104. }
  45105. });
  45106. return half ? maxDataLabelWidth + plotLeft :
  45107. plotWidth - maxDataLabelWidth - plotLeft;
  45108. }
  45109. };
  45110. /**
  45111. * Override the base drawDataLabels method by pie specific functionality
  45112. *
  45113. * @private
  45114. * @function Highcharts.seriesTypes.pie#drawDataLabels
  45115. * @return {void}
  45116. */
  45117. seriesTypes.pie.prototype.drawDataLabels = function () {
  45118. var series = this,
  45119. data = series.data,
  45120. point,
  45121. chart = series.chart,
  45122. options = series.options.dataLabels || {},
  45123. connectorPadding = options.connectorPadding,
  45124. connectorWidth,
  45125. plotWidth = chart.plotWidth,
  45126. plotHeight = chart.plotHeight,
  45127. plotLeft = chart.plotLeft,
  45128. maxWidth = Math.round(chart.chartWidth / 3),
  45129. connector,
  45130. seriesCenter = series.center,
  45131. radius = seriesCenter[2] / 2,
  45132. centerY = seriesCenter[1],
  45133. dataLabel,
  45134. dataLabelWidth,
  45135. // labelPos,
  45136. labelPosition,
  45137. labelHeight,
  45138. // divide the points into right and left halves for anti collision
  45139. halves = [
  45140. [],
  45141. [] // left
  45142. ],
  45143. x,
  45144. y,
  45145. visibility,
  45146. j,
  45147. overflow = [0, 0, 0, 0], // top, right, bottom, left
  45148. dataLabelPositioners = series.dataLabelPositioners,
  45149. pointDataLabelsOptions;
  45150. // get out if not enabled
  45151. if (!series.visible ||
  45152. (!options.enabled &&
  45153. !series._hasPointLabels)) {
  45154. return;
  45155. }
  45156. // Reset all labels that have been shortened
  45157. data.forEach(function (point) {
  45158. if (point.dataLabel && point.visible && point.dataLabel.shortened) {
  45159. point.dataLabel
  45160. .attr({
  45161. width: 'auto'
  45162. }).css({
  45163. width: 'auto',
  45164. textOverflow: 'clip'
  45165. });
  45166. point.dataLabel.shortened = false;
  45167. }
  45168. });
  45169. // run parent method
  45170. Series.prototype.drawDataLabels.apply(series);
  45171. data.forEach(function (point) {
  45172. if (point.dataLabel) {
  45173. if (point.visible) { // #407, #2510
  45174. // Arrange points for detection collision
  45175. halves[point.half].push(point);
  45176. // Reset positions (#4905)
  45177. point.dataLabel._pos = null;
  45178. // Avoid long labels squeezing the pie size too far down
  45179. if (!defined(options.style.width) &&
  45180. !defined(point.options.dataLabels &&
  45181. point.options.dataLabels.style &&
  45182. point.options.dataLabels.style.width)) {
  45183. if (point.dataLabel.getBBox().width > maxWidth) {
  45184. point.dataLabel.css({
  45185. // Use a fraction of the maxWidth to avoid
  45186. // wrapping close to the end of the string.
  45187. width: Math.round(maxWidth * 0.7) + 'px'
  45188. });
  45189. point.dataLabel.shortened = true;
  45190. }
  45191. }
  45192. }
  45193. else {
  45194. point.dataLabel = point.dataLabel.destroy();
  45195. // Workaround to make pies destroy multiple datalabels
  45196. // correctly. This logic needs rewriting to support multiple
  45197. // datalabels fully.
  45198. if (point.dataLabels && point.dataLabels.length === 1) {
  45199. delete point.dataLabels;
  45200. }
  45201. }
  45202. }
  45203. });
  45204. /* Loop over the points in each half, starting from the top and bottom
  45205. * of the pie to detect overlapping labels.
  45206. */
  45207. halves.forEach(function (points, i) {
  45208. var top,
  45209. bottom,
  45210. length = points.length,
  45211. positions = [],
  45212. naturalY,
  45213. sideOverflow,
  45214. size,
  45215. distributionLength;
  45216. if (!length) {
  45217. return;
  45218. }
  45219. // Sort by angle
  45220. series.sortByAngle(points, i - 0.5);
  45221. // Only do anti-collision when we have dataLabels outside the pie
  45222. // and have connectors. (#856)
  45223. if (series.maxLabelDistance > 0) {
  45224. top = Math.max(0, centerY - radius - series.maxLabelDistance);
  45225. bottom = Math.min(centerY + radius + series.maxLabelDistance, chart.plotHeight);
  45226. points.forEach(function (point) {
  45227. // check if specific points' label is outside the pie
  45228. if (point.labelDistance > 0 && point.dataLabel) {
  45229. // point.top depends on point.labelDistance value
  45230. // Used for calculation of y value in getX method
  45231. point.top = Math.max(0, centerY - radius - point.labelDistance);
  45232. point.bottom = Math.min(centerY + radius + point.labelDistance, chart.plotHeight);
  45233. size = point.dataLabel.getBBox().height || 21;
  45234. // point.positionsIndex is needed for getting index of
  45235. // parameter related to specific point inside positions
  45236. // array - not every point is in positions array.
  45237. point.distributeBox = {
  45238. target: point.labelPosition.natural.y -
  45239. point.top + size / 2,
  45240. size: size,
  45241. rank: point.y
  45242. };
  45243. positions.push(point.distributeBox);
  45244. }
  45245. });
  45246. distributionLength = bottom + size - top;
  45247. H.distribute(positions, distributionLength, distributionLength / 5);
  45248. }
  45249. // Now the used slots are sorted, fill them up sequentially
  45250. for (j = 0; j < length; j++) {
  45251. point = points[j];
  45252. // labelPos = point.labelPos;
  45253. labelPosition = point.labelPosition;
  45254. dataLabel = point.dataLabel;
  45255. visibility = point.visible === false ? 'hidden' : 'inherit';
  45256. naturalY = labelPosition.natural.y;
  45257. y = naturalY;
  45258. if (positions && defined(point.distributeBox)) {
  45259. if (typeof point.distributeBox.pos === 'undefined') {
  45260. visibility = 'hidden';
  45261. }
  45262. else {
  45263. labelHeight = point.distributeBox.size;
  45264. // Find label's y position
  45265. y = dataLabelPositioners
  45266. .radialDistributionY(point);
  45267. }
  45268. }
  45269. // It is needed to delete point.positionIndex for
  45270. // dynamically added points etc.
  45271. delete point.positionIndex; // @todo unused
  45272. // Find label's x position
  45273. // justify is undocumented in the API - preserve support for it
  45274. if (options.justify) {
  45275. x = dataLabelPositioners.justify(point, radius, seriesCenter);
  45276. }
  45277. else {
  45278. switch (options.alignTo) {
  45279. case 'connectors':
  45280. x = dataLabelPositioners.alignToConnectors(points, i, plotWidth, plotLeft);
  45281. break;
  45282. case 'plotEdges':
  45283. x = dataLabelPositioners.alignToPlotEdges(dataLabel, i, plotWidth, plotLeft);
  45284. break;
  45285. default:
  45286. x = dataLabelPositioners.radialDistributionX(series, point, y, naturalY);
  45287. }
  45288. }
  45289. // Record the placement and visibility
  45290. dataLabel._attr = {
  45291. visibility: visibility,
  45292. align: labelPosition.alignment
  45293. };
  45294. pointDataLabelsOptions = point.options.dataLabels || {};
  45295. dataLabel._pos = {
  45296. x: (x +
  45297. pick(pointDataLabelsOptions.x, options.x) + // (#12985)
  45298. ({
  45299. left: connectorPadding,
  45300. right: -connectorPadding
  45301. }[labelPosition.alignment] || 0)),
  45302. // 10 is for the baseline (label vs text)
  45303. y: (y +
  45304. pick(pointDataLabelsOptions.y, options.y) - // (#12985)
  45305. 10)
  45306. };
  45307. // labelPos.x = x;
  45308. // labelPos.y = y;
  45309. labelPosition.final.x = x;
  45310. labelPosition.final.y = y;
  45311. // Detect overflowing data labels
  45312. if (pick(options.crop, true)) {
  45313. dataLabelWidth = dataLabel.getBBox().width;
  45314. sideOverflow = null;
  45315. // Overflow left
  45316. if (x - dataLabelWidth < connectorPadding &&
  45317. i === 1 // left half
  45318. ) {
  45319. sideOverflow = Math.round(dataLabelWidth - x + connectorPadding);
  45320. overflow[3] = Math.max(sideOverflow, overflow[3]);
  45321. // Overflow right
  45322. }
  45323. else if (x + dataLabelWidth > plotWidth - connectorPadding &&
  45324. i === 0 // right half
  45325. ) {
  45326. sideOverflow = Math.round(x + dataLabelWidth - plotWidth + connectorPadding);
  45327. overflow[1] = Math.max(sideOverflow, overflow[1]);
  45328. }
  45329. // Overflow top
  45330. if (y - labelHeight / 2 < 0) {
  45331. overflow[0] = Math.max(Math.round(-y + labelHeight / 2), overflow[0]);
  45332. // Overflow left
  45333. }
  45334. else if (y + labelHeight / 2 > plotHeight) {
  45335. overflow[2] = Math.max(Math.round(y + labelHeight / 2 - plotHeight), overflow[2]);
  45336. }
  45337. dataLabel.sideOverflow = sideOverflow;
  45338. }
  45339. } // for each point
  45340. }); // for each half
  45341. // Do not apply the final placement and draw the connectors until we
  45342. // have verified that labels are not spilling over.
  45343. if (arrayMax(overflow) === 0 ||
  45344. this.verifyDataLabelOverflow(overflow)) {
  45345. // Place the labels in the final position
  45346. this.placeDataLabels();
  45347. this.points.forEach(function (point) {
  45348. // #8864: every connector can have individual options
  45349. pointDataLabelsOptions =
  45350. merge(options, point.options.dataLabels);
  45351. connectorWidth =
  45352. pick(pointDataLabelsOptions.connectorWidth, 1);
  45353. // Draw the connector
  45354. if (connectorWidth) {
  45355. var isNew;
  45356. connector = point.connector;
  45357. dataLabel = point.dataLabel;
  45358. if (dataLabel &&
  45359. dataLabel._pos &&
  45360. point.visible &&
  45361. point.labelDistance > 0) {
  45362. visibility = dataLabel._attr.visibility;
  45363. isNew = !connector;
  45364. if (isNew) {
  45365. point.connector = connector = chart.renderer
  45366. .path()
  45367. .addClass('highcharts-data-label-connector ' +
  45368. ' highcharts-color-' + point.colorIndex +
  45369. (point.className ?
  45370. ' ' + point.className :
  45371. ''))
  45372. .add(series.dataLabelsGroup);
  45373. if (!chart.styledMode) {
  45374. connector.attr({
  45375. 'stroke-width': connectorWidth,
  45376. 'stroke': (pointDataLabelsOptions.connectorColor ||
  45377. point.color ||
  45378. palette.neutralColor60)
  45379. });
  45380. }
  45381. }
  45382. connector[isNew ? 'attr' : 'animate']({
  45383. d: point.getConnectorPath()
  45384. });
  45385. connector.attr('visibility', visibility);
  45386. }
  45387. else if (connector) {
  45388. point.connector = connector.destroy();
  45389. }
  45390. }
  45391. });
  45392. }
  45393. };
  45394. /**
  45395. * Extendable method for getting the path of the connector between the data
  45396. * label and the pie slice.
  45397. *
  45398. * @private
  45399. * @function Highcharts.seriesTypes.pie#connectorPath
  45400. *
  45401. * @param {*} labelPos
  45402. *
  45403. * @return {Highcharts.SVGPathArray}
  45404. */
  45405. // TODO: depracated - remove it
  45406. /*
  45407. seriesTypes.pie.prototype.connectorPath = function (labelPos) {
  45408. var x = labelPos.x,
  45409. y = labelPos.y;
  45410. return pick(this.options.dataLabels.softConnector, true) ? [
  45411. 'M',
  45412. // end of the string at the label
  45413. x + (labelPos[6] === 'left' ? 5 : -5), y,
  45414. 'C',
  45415. x, y, // first break, next to the label
  45416. 2 * labelPos[2] - labelPos[4], 2 * labelPos[3] - labelPos[5],
  45417. labelPos[2], labelPos[3], // second break
  45418. 'L',
  45419. labelPos[4], labelPos[5] // base
  45420. ] : [
  45421. 'M',
  45422. // end of the string at the label
  45423. x + (labelPos[6] === 'left' ? 5 : -5), y,
  45424. 'L',
  45425. labelPos[2], labelPos[3], // second break
  45426. 'L',
  45427. labelPos[4], labelPos[5] // base
  45428. ];
  45429. };
  45430. */
  45431. /**
  45432. * Perform the final placement of the data labels after we have verified
  45433. * that they fall within the plot area.
  45434. *
  45435. * @private
  45436. * @function Highcharts.seriesTypes.pie#placeDataLabels
  45437. * @return {void}
  45438. */
  45439. seriesTypes.pie.prototype.placeDataLabels = function () {
  45440. this.points.forEach(function (point) {
  45441. var dataLabel = point.dataLabel,
  45442. _pos;
  45443. if (dataLabel && point.visible) {
  45444. _pos = dataLabel._pos;
  45445. if (_pos) {
  45446. // Shorten data labels with ellipsis if they still overflow
  45447. // after the pie has reached minSize (#223).
  45448. if (dataLabel.sideOverflow) {
  45449. dataLabel._attr.width =
  45450. Math.max(dataLabel.getBBox().width -
  45451. dataLabel.sideOverflow, 0);
  45452. dataLabel.css({
  45453. width: dataLabel._attr.width + 'px',
  45454. textOverflow: ((this.options.dataLabels.style || {})
  45455. .textOverflow ||
  45456. 'ellipsis')
  45457. });
  45458. dataLabel.shortened = true;
  45459. }
  45460. dataLabel.attr(dataLabel._attr);
  45461. dataLabel[dataLabel.moved ? 'animate' : 'attr'](_pos);
  45462. dataLabel.moved = true;
  45463. }
  45464. else if (dataLabel) {
  45465. dataLabel.attr({ y: -9999 });
  45466. }
  45467. }
  45468. // Clear for update
  45469. delete point.distributeBox;
  45470. }, this);
  45471. };
  45472. seriesTypes.pie.prototype.alignDataLabel = noop;
  45473. /**
  45474. * Verify whether the data labels are allowed to draw, or we should run more
  45475. * translation and data label positioning to keep them inside the plot area.
  45476. * Returns true when data labels are ready to draw.
  45477. *
  45478. * @private
  45479. * @function Highcharts.seriesTypes.pie#verifyDataLabelOverflow
  45480. * @param {Array<number>} overflow
  45481. * @return {boolean}
  45482. */
  45483. seriesTypes.pie.prototype.verifyDataLabelOverflow = function (overflow) {
  45484. var center = this.center,
  45485. options = this.options,
  45486. centerOption = options.center,
  45487. minSize = options.minSize || 80,
  45488. newSize = minSize,
  45489. // If a size is set, return true and don't try to shrink the pie
  45490. // to fit the labels.
  45491. ret = options.size !== null;
  45492. if (!ret) {
  45493. // Handle horizontal size and center
  45494. if (centerOption[0] !== null) { // Fixed center
  45495. newSize = Math.max(center[2] -
  45496. Math.max(overflow[1], overflow[3]), minSize);
  45497. }
  45498. else { // Auto center
  45499. newSize = Math.max(
  45500. // horizontal overflow
  45501. center[2] - overflow[1] - overflow[3], minSize);
  45502. // horizontal center
  45503. center[0] += (overflow[3] - overflow[1]) / 2;
  45504. }
  45505. // Handle vertical size and center
  45506. if (centerOption[1] !== null) { // Fixed center
  45507. newSize = clamp(newSize, minSize, center[2] - Math.max(overflow[0], overflow[2]));
  45508. }
  45509. else { // Auto center
  45510. newSize = clamp(newSize, minSize,
  45511. // vertical overflow
  45512. center[2] - overflow[0] - overflow[2]);
  45513. // vertical center
  45514. center[1] += (overflow[0] - overflow[2]) / 2;
  45515. }
  45516. // If the size must be decreased, we need to run translate and
  45517. // drawDataLabels again
  45518. if (newSize < center[2]) {
  45519. center[2] = newSize;
  45520. center[3] = Math.min(// #3632
  45521. relativeLength(options.innerSize || 0, newSize), newSize);
  45522. this.translate(center);
  45523. if (this.drawDataLabels) {
  45524. this.drawDataLabels();
  45525. }
  45526. // Else, return true to indicate that the pie and its labels is
  45527. // within the plot area
  45528. }
  45529. else {
  45530. ret = true;
  45531. }
  45532. }
  45533. return ret;
  45534. };
  45535. }
  45536. if (seriesTypes.column) {
  45537. /**
  45538. * Override the basic data label alignment by adjusting for the position of
  45539. * the column.
  45540. *
  45541. * @private
  45542. * @function Highcharts.seriesTypes.column#alignDataLabel
  45543. * @param {Highcharts.Point} point
  45544. * @param {Highcharts.SVGElement} dataLabel
  45545. * @param {Highcharts.DataLabelsOptions} options
  45546. * @param {Highcharts.BBoxObject} alignTo
  45547. * @param {boolean} [isNew]
  45548. * @return {void}
  45549. */
  45550. seriesTypes.column.prototype.alignDataLabel = function (point, dataLabel, options, alignTo, isNew) {
  45551. var inverted = this.chart.inverted,
  45552. series = point.series,
  45553. // data label box for alignment
  45554. dlBox = point.dlBox || point.shapeArgs,
  45555. below = pick(point.below, // range series
  45556. point.plotY >
  45557. pick(this.translatedThreshold,
  45558. series.yAxis.len)),
  45559. // draw it inside the box?
  45560. inside = pick(options.inside, !!this.options.stacking),
  45561. overshoot;
  45562. // Align to the column itself, or the top of it
  45563. if (dlBox) { // Area range uses this method but not alignTo
  45564. alignTo = merge(dlBox);
  45565. if (alignTo.y < 0) {
  45566. alignTo.height += alignTo.y;
  45567. alignTo.y = 0;
  45568. }
  45569. // If parts of the box overshoots outside the plot area, modify the
  45570. // box to center the label inside
  45571. overshoot = alignTo.y + alignTo.height - series.yAxis.len;
  45572. if (overshoot > 0 && overshoot < alignTo.height) {
  45573. alignTo.height -= overshoot;
  45574. }
  45575. if (inverted) {
  45576. alignTo = {
  45577. x: series.yAxis.len - alignTo.y - alignTo.height,
  45578. y: series.xAxis.len - alignTo.x - alignTo.width,
  45579. width: alignTo.height,
  45580. height: alignTo.width
  45581. };
  45582. }
  45583. // Compute the alignment box
  45584. if (!inside) {
  45585. if (inverted) {
  45586. alignTo.x += below ? 0 : alignTo.width;
  45587. alignTo.width = 0;
  45588. }
  45589. else {
  45590. alignTo.y += below ? alignTo.height : 0;
  45591. alignTo.height = 0;
  45592. }
  45593. }
  45594. }
  45595. // When alignment is undefined (typically columns and bars), display the
  45596. // individual point below or above the point depending on the threshold
  45597. options.align = pick(options.align, !inverted || inside ? 'center' : below ? 'right' : 'left');
  45598. options.verticalAlign = pick(options.verticalAlign, inverted || inside ? 'middle' : below ? 'top' : 'bottom');
  45599. // Call the parent method
  45600. Series.prototype.alignDataLabel.call(this, point, dataLabel, options, alignTo, isNew);
  45601. // If label was justified and we have contrast, set it:
  45602. if (options.inside && point.contrastColor) {
  45603. dataLabel.css({
  45604. color: point.contrastColor
  45605. });
  45606. }
  45607. };
  45608. }
  45609. });
  45610. _registerModule(_modules, 'Extensions/OverlappingDataLabels.js', [_modules['Core/Chart/Chart.js'], _modules['Core/Utilities.js']], function (Chart, U) {
  45611. /* *
  45612. *
  45613. * Highcharts module to hide overlapping data labels.
  45614. * This module is included in Highcharts.
  45615. *
  45616. * (c) 2009-2021 Torstein Honsi
  45617. *
  45618. * License: www.highcharts.com/license
  45619. *
  45620. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  45621. *
  45622. * */
  45623. var addEvent = U.addEvent,
  45624. fireEvent = U.fireEvent,
  45625. isArray = U.isArray,
  45626. isNumber = U.isNumber,
  45627. objectEach = U.objectEach,
  45628. pick = U.pick;
  45629. /**
  45630. * Internal type
  45631. * @private
  45632. */
  45633. /* eslint-disable no-invalid-this */
  45634. // Collect potensial overlapping data labels. Stack labels probably don't need
  45635. // to be considered because they are usually accompanied by data labels that lie
  45636. // inside the columns.
  45637. addEvent(Chart, 'render', function collectAndHide() {
  45638. var labels = [];
  45639. // Consider external label collectors
  45640. (this.labelCollectors || []).forEach(function (collector) {
  45641. labels = labels.concat(collector());
  45642. });
  45643. (this.yAxis || []).forEach(function (yAxis) {
  45644. if (yAxis.stacking &&
  45645. yAxis.options.stackLabels &&
  45646. !yAxis.options.stackLabels.allowOverlap) {
  45647. objectEach(yAxis.stacking.stacks, function (stack) {
  45648. objectEach(stack, function (stackItem) {
  45649. labels.push(stackItem.label);
  45650. });
  45651. });
  45652. }
  45653. });
  45654. (this.series || []).forEach(function (series) {
  45655. var dlOptions = series.options.dataLabels;
  45656. if (series.visible &&
  45657. !(dlOptions.enabled === false && !series._hasPointLabels)) { // #3866
  45658. var push = function (points) {
  45659. return points.forEach(function (point) {
  45660. if (point.visible) {
  45661. var dataLabels = (isArray(point.dataLabels) ?
  45662. point.dataLabels :
  45663. (point.dataLabel ? [point.dataLabel] : []));
  45664. dataLabels.forEach(function (label) {
  45665. var options = label.options;
  45666. label.labelrank = pick(options.labelrank, point.labelrank, point.shapeArgs && point.shapeArgs.height); // #4118
  45667. if (!options.allowOverlap) {
  45668. labels.push(label);
  45669. }
  45670. });
  45671. }
  45672. });
  45673. };
  45674. push(series.nodes || []);
  45675. push(series.points);
  45676. }
  45677. });
  45678. this.hideOverlappingLabels(labels);
  45679. });
  45680. /**
  45681. * Hide overlapping labels. Labels are moved and faded in and out on zoom to
  45682. * provide a smooth visual imression.
  45683. *
  45684. * @private
  45685. * @function Highcharts.Chart#hideOverlappingLabels
  45686. * @param {Array<Highcharts.SVGElement>} labels
  45687. * Rendered data labels
  45688. * @requires modules/overlapping-datalabels
  45689. */
  45690. Chart.prototype.hideOverlappingLabels = function (labels) {
  45691. var chart = this,
  45692. len = labels.length,
  45693. ren = chart.renderer,
  45694. label,
  45695. i,
  45696. j,
  45697. label1,
  45698. label2,
  45699. box1,
  45700. box2,
  45701. isLabelAffected = false,
  45702. isIntersectRect = function (box1,
  45703. box2) {
  45704. return !(box2.x >= box1.x + box1.width ||
  45705. box2.x + box2.width <= box1.x ||
  45706. box2.y >= box1.y + box1.height ||
  45707. box2.y + box2.height <= box1.y);
  45708. },
  45709. // Get the box with its position inside the chart, as opposed to getBBox
  45710. // that only reports the position relative to the parent.
  45711. getAbsoluteBox = function (label) {
  45712. var pos,
  45713. parent,
  45714. bBox,
  45715. // Substract the padding if no background or border (#4333)
  45716. padding = label.box ? 0 : (label.padding || 0),
  45717. lineHeightCorrection = 0,
  45718. xOffset = 0,
  45719. boxWidth,
  45720. alignValue;
  45721. if (label &&
  45722. (!label.alignAttr || label.placed)) {
  45723. pos = label.alignAttr || {
  45724. x: label.attr('x'),
  45725. y: label.attr('y')
  45726. };
  45727. parent = label.parentGroup;
  45728. // Get width and height if pure text nodes (stack labels)
  45729. if (!label.width) {
  45730. bBox = label.getBBox();
  45731. label.width = bBox.width;
  45732. label.height = bBox.height;
  45733. // Labels positions are computed from top left corner, so
  45734. // we need to substract the text height from text nodes too.
  45735. lineHeightCorrection = ren
  45736. .fontMetrics(null, label.element).h;
  45737. }
  45738. boxWidth = label.width - 2 * padding;
  45739. alignValue = {
  45740. left: '0',
  45741. center: '0.5',
  45742. right: '1'
  45743. }[label.alignValue];
  45744. if (alignValue) {
  45745. xOffset = +alignValue * boxWidth;
  45746. }
  45747. else if (isNumber(label.x) && Math.round(label.x) !== label.translateX) {
  45748. xOffset = label.x - label.translateX;
  45749. }
  45750. return {
  45751. x: pos.x + (parent.translateX || 0) + padding -
  45752. (xOffset || 0),
  45753. y: pos.y + (parent.translateY || 0) + padding -
  45754. lineHeightCorrection,
  45755. width: label.width - 2 * padding,
  45756. height: label.height - 2 * padding
  45757. };
  45758. }
  45759. };
  45760. for (i = 0; i < len; i++) {
  45761. label = labels[i];
  45762. if (label) {
  45763. // Mark with initial opacity
  45764. label.oldOpacity = label.opacity;
  45765. label.newOpacity = 1;
  45766. label.absoluteBox = getAbsoluteBox(label);
  45767. }
  45768. }
  45769. // Prevent a situation in a gradually rising slope, that each label will
  45770. // hide the previous one because the previous one always has lower rank.
  45771. labels.sort(function (a, b) {
  45772. return (b.labelrank || 0) - (a.labelrank || 0);
  45773. });
  45774. // Detect overlapping labels
  45775. for (i = 0; i < len; i++) {
  45776. label1 = labels[i];
  45777. box1 = label1 && label1.absoluteBox;
  45778. for (j = i + 1; j < len; ++j) {
  45779. label2 = labels[j];
  45780. box2 = label2 && label2.absoluteBox;
  45781. if (box1 &&
  45782. box2 &&
  45783. label1 !== label2 && // #6465, polar chart with connectEnds
  45784. label1.newOpacity !== 0 &&
  45785. label2.newOpacity !== 0) {
  45786. if (isIntersectRect(box1, box2)) {
  45787. (label1.labelrank < label2.labelrank ? label1 : label2)
  45788. .newOpacity = 0;
  45789. }
  45790. }
  45791. }
  45792. }
  45793. // Hide or show
  45794. labels.forEach(function (label) {
  45795. var complete,
  45796. newOpacity;
  45797. if (label) {
  45798. newOpacity = label.newOpacity;
  45799. if (label.oldOpacity !== newOpacity) {
  45800. // Make sure the label is completely hidden to avoid catching
  45801. // clicks (#4362)
  45802. if (label.alignAttr && label.placed) { // data labels
  45803. label[newOpacity ? 'removeClass' : 'addClass']('highcharts-data-label-hidden');
  45804. complete = function () {
  45805. if (!chart.styledMode) {
  45806. label.css({ pointerEvents: newOpacity ? 'auto' : 'none' });
  45807. }
  45808. label.visibility = newOpacity ? 'inherit' : 'hidden';
  45809. };
  45810. isLabelAffected = true;
  45811. // Animate or set the opacity
  45812. label.alignAttr.opacity = newOpacity;
  45813. label[label.isOld ? 'animate' : 'attr'](label.alignAttr, null, complete);
  45814. fireEvent(chart, 'afterHideOverlappingLabel');
  45815. }
  45816. else { // other labels, tick labels
  45817. label.attr({
  45818. opacity: newOpacity
  45819. });
  45820. }
  45821. }
  45822. label.isOld = true;
  45823. }
  45824. });
  45825. if (isLabelAffected) {
  45826. fireEvent(chart, 'afterHideAllOverlappingLabels');
  45827. }
  45828. };
  45829. });
  45830. _registerModule(_modules, 'Core/Responsive.js', [_modules['Core/Chart/Chart.js'], _modules['Core/Utilities.js']], function (Chart, U) {
  45831. /* *
  45832. *
  45833. * (c) 2010-2021 Torstein Honsi
  45834. *
  45835. * License: www.highcharts.com/license
  45836. *
  45837. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  45838. *
  45839. * */
  45840. var find = U.find,
  45841. isArray = U.isArray,
  45842. isObject = U.isObject,
  45843. merge = U.merge,
  45844. objectEach = U.objectEach,
  45845. pick = U.pick,
  45846. splat = U.splat,
  45847. uniqueKey = U.uniqueKey;
  45848. /**
  45849. * A callback function to gain complete control on when the responsive rule
  45850. * applies.
  45851. *
  45852. * @callback Highcharts.ResponsiveCallbackFunction
  45853. *
  45854. * @param {Highcharts.Chart} this
  45855. * Chart context.
  45856. *
  45857. * @return {boolean}
  45858. * Return `true` if it applies.
  45859. */
  45860. /**
  45861. * Allows setting a set of rules to apply for different screen or chart
  45862. * sizes. Each rule specifies additional chart options.
  45863. *
  45864. * @sample {highstock} stock/demo/responsive/
  45865. * Stock chart
  45866. * @sample highcharts/responsive/axis/
  45867. * Axis
  45868. * @sample highcharts/responsive/legend/
  45869. * Legend
  45870. * @sample highcharts/responsive/classname/
  45871. * Class name
  45872. *
  45873. * @since 5.0.0
  45874. * @apioption responsive
  45875. */
  45876. /**
  45877. * A set of rules for responsive settings. The rules are executed from
  45878. * the top down.
  45879. *
  45880. * @sample {highcharts} highcharts/responsive/axis/
  45881. * Axis changes
  45882. * @sample {highstock} highcharts/responsive/axis/
  45883. * Axis changes
  45884. * @sample {highmaps} highcharts/responsive/axis/
  45885. * Axis changes
  45886. *
  45887. * @type {Array<*>}
  45888. * @since 5.0.0
  45889. * @apioption responsive.rules
  45890. */
  45891. /**
  45892. * A full set of chart options to apply as overrides to the general
  45893. * chart options. The chart options are applied when the given rule
  45894. * is active.
  45895. *
  45896. * A special case is configuration objects that take arrays, for example
  45897. * [xAxis](#xAxis), [yAxis](#yAxis) or [series](#series). For these
  45898. * collections, an `id` option is used to map the new option set to
  45899. * an existing object. If an existing object of the same id is not found,
  45900. * the item of the same indexupdated. So for example, setting `chartOptions`
  45901. * with two series items without an `id`, will cause the existing chart's
  45902. * two series to be updated with respective options.
  45903. *
  45904. * @sample {highstock} stock/demo/responsive/
  45905. * Stock chart
  45906. * @sample highcharts/responsive/axis/
  45907. * Axis
  45908. * @sample highcharts/responsive/legend/
  45909. * Legend
  45910. * @sample highcharts/responsive/classname/
  45911. * Class name
  45912. *
  45913. * @type {Highcharts.Options}
  45914. * @since 5.0.0
  45915. * @apioption responsive.rules.chartOptions
  45916. */
  45917. /**
  45918. * Under which conditions the rule applies.
  45919. *
  45920. * @since 5.0.0
  45921. * @apioption responsive.rules.condition
  45922. */
  45923. /**
  45924. * A callback function to gain complete control on when the responsive
  45925. * rule applies. Return `true` if it applies. This opens for checking
  45926. * against other metrics than the chart size, for example the document
  45927. * size or other elements.
  45928. *
  45929. * @type {Highcharts.ResponsiveCallbackFunction}
  45930. * @since 5.0.0
  45931. * @context Highcharts.Chart
  45932. * @apioption responsive.rules.condition.callback
  45933. */
  45934. /**
  45935. * The responsive rule applies if the chart height is less than this.
  45936. *
  45937. * @type {number}
  45938. * @since 5.0.0
  45939. * @apioption responsive.rules.condition.maxHeight
  45940. */
  45941. /**
  45942. * The responsive rule applies if the chart width is less than this.
  45943. *
  45944. * @sample highcharts/responsive/axis/
  45945. * Max width is 500
  45946. *
  45947. * @type {number}
  45948. * @since 5.0.0
  45949. * @apioption responsive.rules.condition.maxWidth
  45950. */
  45951. /**
  45952. * The responsive rule applies if the chart height is greater than this.
  45953. *
  45954. * @type {number}
  45955. * @default 0
  45956. * @since 5.0.0
  45957. * @apioption responsive.rules.condition.minHeight
  45958. */
  45959. /**
  45960. * The responsive rule applies if the chart width is greater than this.
  45961. *
  45962. * @type {number}
  45963. * @default 0
  45964. * @since 5.0.0
  45965. * @apioption responsive.rules.condition.minWidth
  45966. */
  45967. /* eslint-disable no-invalid-this, valid-jsdoc */
  45968. /**
  45969. * Update the chart based on the current chart/document size and options for
  45970. * responsiveness.
  45971. *
  45972. * @private
  45973. * @function Highcharts.Chart#setResponsive
  45974. * @param {boolean} [redraw=true]
  45975. * @param {boolean} [reset=false]
  45976. * Reset by un-applying all rules. Chart.update resets all rules before applying
  45977. * updated options.
  45978. */
  45979. Chart.prototype.setResponsive = function (redraw, reset) {
  45980. var options = this.options.responsive,
  45981. ruleIds = [],
  45982. currentResponsive = this.currentResponsive,
  45983. currentRuleIds,
  45984. undoOptions;
  45985. if (!reset && options && options.rules) {
  45986. options.rules.forEach(function (rule) {
  45987. if (typeof rule._id === 'undefined') {
  45988. rule._id = uniqueKey();
  45989. }
  45990. this.matchResponsiveRule(rule, ruleIds /* , redraw */);
  45991. }, this);
  45992. }
  45993. // Merge matching rules
  45994. var mergedOptions = merge.apply(0,
  45995. ruleIds.map(function (ruleId) {
  45996. return find(options.rules,
  45997. function (rule) {
  45998. return rule._id === ruleId;
  45999. }).chartOptions;
  46000. }));
  46001. mergedOptions.isResponsiveOptions = true;
  46002. // Stringified key for the rules that currently apply.
  46003. ruleIds = (ruleIds.toString() || void 0);
  46004. currentRuleIds = currentResponsive && currentResponsive.ruleIds;
  46005. // Changes in what rules apply
  46006. if (ruleIds !== currentRuleIds) {
  46007. // Undo previous rules. Before we apply a new set of rules, we need to
  46008. // roll back completely to base options (#6291).
  46009. if (currentResponsive) {
  46010. this.update(currentResponsive.undoOptions, redraw, true);
  46011. }
  46012. if (ruleIds) {
  46013. // Get undo-options for matching rules
  46014. undoOptions = this.currentOptions(mergedOptions);
  46015. undoOptions.isResponsiveOptions = true;
  46016. this.currentResponsive = {
  46017. ruleIds: ruleIds,
  46018. mergedOptions: mergedOptions,
  46019. undoOptions: undoOptions
  46020. };
  46021. this.update(mergedOptions, redraw, true);
  46022. }
  46023. else {
  46024. this.currentResponsive = void 0;
  46025. }
  46026. }
  46027. };
  46028. /**
  46029. * Handle a single responsiveness rule.
  46030. *
  46031. * @private
  46032. * @function Highcharts.Chart#matchResponsiveRule
  46033. * @param {Highcharts.ResponsiveRulesOptions} rule
  46034. * @param {Array<string>} matches
  46035. */
  46036. Chart.prototype.matchResponsiveRule = function (rule, matches) {
  46037. var condition = rule.condition,
  46038. fn = condition.callback || function () {
  46039. return (this.chartWidth <= pick(condition.maxWidth,
  46040. Number.MAX_VALUE) &&
  46041. this.chartHeight <=
  46042. pick(condition.maxHeight,
  46043. Number.MAX_VALUE) &&
  46044. this.chartWidth >= pick(condition.minWidth, 0) &&
  46045. this.chartHeight >= pick(condition.minHeight, 0));
  46046. };
  46047. if (fn.call(this)) {
  46048. matches.push(rule._id);
  46049. }
  46050. };
  46051. /**
  46052. * Get the current values for a given set of options. Used before we update
  46053. * the chart with a new responsiveness rule.
  46054. *
  46055. * @todo Restore axis options (by id?). The matching of items in collections
  46056. * bears resemblance to the oneToOne matching in Chart.update. Probably we can
  46057. * refactor out that matching and reuse it in both functions.
  46058. *
  46059. * @private
  46060. * @function Highcharts.Chart#currentOptions
  46061. * @param {Highcharts.Options} options
  46062. * @return {Highcharts.Options}
  46063. */
  46064. Chart.prototype.currentOptions = function (options) {
  46065. var chart = this,
  46066. ret = {};
  46067. /**
  46068. * Recurse over a set of options and its current values,
  46069. * and store the current values in the ret object.
  46070. */
  46071. function getCurrent(options, curr, ret, depth) {
  46072. var i;
  46073. objectEach(options, function (val, key) {
  46074. if (!depth &&
  46075. chart.collectionsWithUpdate.indexOf(key) > -1 &&
  46076. curr[key]) {
  46077. val = splat(val);
  46078. ret[key] = [];
  46079. // Iterate over collections like series, xAxis or yAxis and map
  46080. // the items by index.
  46081. for (i = 0; i < Math.max(val.length, curr[key].length); i++) {
  46082. // Item exists in current data (#6347)
  46083. if (curr[key][i]) {
  46084. // If the item is missing from the new data, we need to
  46085. // save the whole config structure. Like when
  46086. // responsively updating from a dual axis layout to a
  46087. // single axis and back (#13544).
  46088. if (val[i] === void 0) {
  46089. ret[key][i] = curr[key][i];
  46090. // Otherwise, proceed
  46091. }
  46092. else {
  46093. ret[key][i] = {};
  46094. getCurrent(val[i], curr[key][i], ret[key][i], depth + 1);
  46095. }
  46096. }
  46097. }
  46098. }
  46099. else if (isObject(val)) {
  46100. ret[key] = isArray(val) ? [] : {};
  46101. getCurrent(val, curr[key] || {}, ret[key], depth + 1);
  46102. }
  46103. else if (typeof curr[key] === 'undefined') { // #10286
  46104. ret[key] = null;
  46105. }
  46106. else {
  46107. ret[key] = curr[key];
  46108. }
  46109. });
  46110. }
  46111. getCurrent(options, this.options, ret, 0);
  46112. return ret;
  46113. };
  46114. });
  46115. _registerModule(_modules, 'masters/highcharts.src.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js'], _modules['Core/Renderer/HTML/AST.js'], _modules['Core/Series/Series.js']], function (Highcharts, Utilities, AST, Series) {
  46116. // Utilities
  46117. Highcharts.addEvent = Utilities.addEvent;
  46118. Highcharts.arrayMax = Utilities.arrayMax;
  46119. Highcharts.arrayMin = Utilities.arrayMin;
  46120. Highcharts.attr = Utilities.attr;
  46121. Highcharts.clearTimeout = Utilities.clearTimeout;
  46122. Highcharts.correctFloat = Utilities.correctFloat;
  46123. Highcharts.createElement = Utilities.createElement;
  46124. Highcharts.css = Utilities.css;
  46125. Highcharts.defined = Utilities.defined;
  46126. Highcharts.destroyObjectProperties = Utilities.destroyObjectProperties;
  46127. Highcharts.discardElement = Utilities.discardElement;
  46128. Highcharts.erase = Utilities.erase;
  46129. Highcharts.error = Utilities.error;
  46130. Highcharts.extend = Utilities.extend;
  46131. Highcharts.extendClass = Utilities.extendClass;
  46132. Highcharts.find = Utilities.find;
  46133. Highcharts.fireEvent = Utilities.fireEvent;
  46134. Highcharts.format = Utilities.format;
  46135. Highcharts.getMagnitude = Utilities.getMagnitude;
  46136. Highcharts.getStyle = Utilities.getStyle;
  46137. Highcharts.inArray = Utilities.inArray;
  46138. Highcharts.isArray = Utilities.isArray;
  46139. Highcharts.isClass = Utilities.isClass;
  46140. Highcharts.isDOMElement = Utilities.isDOMElement;
  46141. Highcharts.isFunction = Utilities.isFunction;
  46142. Highcharts.isNumber = Utilities.isNumber;
  46143. Highcharts.isObject = Utilities.isObject;
  46144. Highcharts.isString = Utilities.isString;
  46145. Highcharts.keys = Utilities.keys;
  46146. Highcharts.merge = Utilities.merge;
  46147. Highcharts.normalizeTickInterval = Utilities.normalizeTickInterval;
  46148. Highcharts.numberFormat = Utilities.numberFormat;
  46149. Highcharts.objectEach = Utilities.objectEach;
  46150. Highcharts.offset = Utilities.offset;
  46151. Highcharts.pad = Utilities.pad;
  46152. Highcharts.pick = Utilities.pick;
  46153. Highcharts.pInt = Utilities.pInt;
  46154. Highcharts.relativeLength = Utilities.relativeLength;
  46155. Highcharts.removeEvent = Utilities.removeEvent;
  46156. Highcharts.splat = Utilities.splat;
  46157. Highcharts.stableSort = Utilities.stableSort;
  46158. Highcharts.syncTimeout = Utilities.syncTimeout;
  46159. Highcharts.timeUnits = Utilities.timeUnits;
  46160. Highcharts.uniqueKey = Utilities.uniqueKey;
  46161. Highcharts.useSerialIds = Utilities.useSerialIds;
  46162. Highcharts.wrap = Utilities.wrap;
  46163. // Classes
  46164. Highcharts.AST = AST;
  46165. Highcharts.Series = Series;
  46166. return Highcharts;
  46167. });
  46168. _registerModule(_modules, 'Core/Axis/NavigatorAxis.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
  46169. /* *
  46170. *
  46171. * (c) 2010-2021 Torstein Honsi
  46172. *
  46173. * License: www.highcharts.com/license
  46174. *
  46175. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  46176. *
  46177. * */
  46178. var isTouchDevice = H.isTouchDevice;
  46179. var addEvent = U.addEvent,
  46180. correctFloat = U.correctFloat,
  46181. defined = U.defined,
  46182. isNumber = U.isNumber,
  46183. pick = U.pick;
  46184. /* eslint-disable valid-jsdoc */
  46185. /**
  46186. * @private
  46187. * @class
  46188. */
  46189. var NavigatorAxisAdditions = /** @class */ (function () {
  46190. /* *
  46191. *
  46192. * Constructors
  46193. *
  46194. * */
  46195. function NavigatorAxisAdditions(axis) {
  46196. this.axis = axis;
  46197. }
  46198. /* *
  46199. *
  46200. * Functions
  46201. *
  46202. * */
  46203. /**
  46204. * @private
  46205. */
  46206. NavigatorAxisAdditions.prototype.destroy = function () {
  46207. this.axis = void 0;
  46208. };
  46209. /**
  46210. * Add logic to normalize the zoomed range in order to preserve the pressed
  46211. * state of range selector buttons
  46212. *
  46213. * @private
  46214. * @function Highcharts.Axis#toFixedRange
  46215. * @param {number} [pxMin]
  46216. * @param {number} [pxMax]
  46217. * @param {number} [fixedMin]
  46218. * @param {number} [fixedMax]
  46219. * @return {*}
  46220. */
  46221. NavigatorAxisAdditions.prototype.toFixedRange = function (pxMin, pxMax, fixedMin, fixedMax) {
  46222. var navigator = this;
  46223. var axis = navigator.axis;
  46224. var chart = axis.chart;
  46225. var fixedRange = chart && chart.fixedRange,
  46226. halfPointRange = (axis.pointRange || 0) / 2,
  46227. newMin = pick(fixedMin,
  46228. axis.translate(pxMin,
  46229. true, !axis.horiz)),
  46230. newMax = pick(fixedMax,
  46231. axis.translate(pxMax,
  46232. true, !axis.horiz)),
  46233. changeRatio = fixedRange && (newMax - newMin) / fixedRange;
  46234. // Add/remove half point range to/from the extremes (#1172)
  46235. if (!defined(fixedMin)) {
  46236. newMin = correctFloat(newMin + halfPointRange);
  46237. }
  46238. if (!defined(fixedMax)) {
  46239. newMax = correctFloat(newMax - halfPointRange);
  46240. }
  46241. // If the difference between the fixed range and the actual requested
  46242. // range is too great, the user is dragging across an ordinal gap, and
  46243. // we need to release the range selector button.
  46244. if (changeRatio > 0.7 && changeRatio < 1.3) {
  46245. if (fixedMax) {
  46246. newMin = newMax - fixedRange;
  46247. }
  46248. else {
  46249. newMax = newMin + fixedRange;
  46250. }
  46251. }
  46252. if (!isNumber(newMin) || !isNumber(newMax)) { // #1195, #7411
  46253. newMin = newMax = void 0;
  46254. }
  46255. return {
  46256. min: newMin,
  46257. max: newMax
  46258. };
  46259. };
  46260. return NavigatorAxisAdditions;
  46261. }());
  46262. /**
  46263. * @private
  46264. * @class
  46265. */
  46266. var NavigatorAxis = /** @class */ (function () {
  46267. function NavigatorAxis() {
  46268. }
  46269. /* *
  46270. *
  46271. * Static Functions
  46272. *
  46273. * */
  46274. /**
  46275. * @private
  46276. */
  46277. NavigatorAxis.compose = function (AxisClass) {
  46278. AxisClass.keepProps.push('navigatorAxis');
  46279. /* eslint-disable no-invalid-this */
  46280. addEvent(AxisClass, 'init', function () {
  46281. var axis = this;
  46282. if (!axis.navigatorAxis) {
  46283. axis.navigatorAxis = new NavigatorAxisAdditions(axis);
  46284. }
  46285. });
  46286. // For Stock charts, override selection zooming with some special
  46287. // features because X axis zooming is already allowed by the Navigator
  46288. // and Range selector.
  46289. addEvent(AxisClass, 'zoom', function (e) {
  46290. var axis = this;
  46291. var chart = axis.chart;
  46292. var chartOptions = chart.options;
  46293. var navigator = chartOptions.navigator;
  46294. var navigatorAxis = axis.navigatorAxis;
  46295. var pinchType = chartOptions.chart.pinchType;
  46296. var rangeSelector = chartOptions.rangeSelector;
  46297. var zoomType = chartOptions.chart.zoomType;
  46298. var previousZoom;
  46299. if (axis.isXAxis && ((navigator && navigator.enabled) ||
  46300. (rangeSelector && rangeSelector.enabled))) {
  46301. // For y only zooming, ignore the X axis completely
  46302. if (zoomType === 'y') {
  46303. e.zoomed = false;
  46304. // For xy zooming, record the state of the zoom before zoom
  46305. // selection, then when the reset button is pressed, revert to
  46306. // this state. This should apply only if the chart is
  46307. // initialized with a range (#6612), otherwise zoom all the way
  46308. // out.
  46309. }
  46310. else if (((!isTouchDevice && zoomType === 'xy') ||
  46311. (isTouchDevice && pinchType === 'xy')) &&
  46312. axis.options.range) {
  46313. previousZoom = navigatorAxis.previousZoom;
  46314. if (defined(e.newMin)) {
  46315. navigatorAxis.previousZoom = [axis.min, axis.max];
  46316. }
  46317. else if (previousZoom) {
  46318. e.newMin = previousZoom[0];
  46319. e.newMax = previousZoom[1];
  46320. navigatorAxis.previousZoom = void 0;
  46321. }
  46322. }
  46323. }
  46324. if (typeof e.zoomed !== 'undefined') {
  46325. e.preventDefault();
  46326. }
  46327. });
  46328. /* eslint-enable no-invalid-this */
  46329. };
  46330. /* *
  46331. *
  46332. * Static Properties
  46333. *
  46334. * */
  46335. /**
  46336. * @private
  46337. */
  46338. NavigatorAxis.AdditionsClass = NavigatorAxisAdditions;
  46339. return NavigatorAxis;
  46340. }());
  46341. return NavigatorAxis;
  46342. });
  46343. _registerModule(_modules, 'Core/Axis/ScrollbarAxis.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
  46344. /* *
  46345. *
  46346. * (c) 2010-2021 Torstein Honsi
  46347. *
  46348. * License: www.highcharts.com/license
  46349. *
  46350. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  46351. *
  46352. * */
  46353. var addEvent = U.addEvent,
  46354. defined = U.defined,
  46355. pick = U.pick;
  46356. /* eslint-disable no-invalid-this, valid-jsdoc */
  46357. /**
  46358. * Creates scrollbars if enabled.
  46359. *
  46360. * @private
  46361. */
  46362. var ScrollbarAxis = /** @class */ (function () {
  46363. function ScrollbarAxis() {
  46364. }
  46365. /**
  46366. * Attaches to axis events to create scrollbars if enabled.
  46367. *
  46368. * @private
  46369. *
  46370. * @param AxisClass
  46371. * Axis class to extend.
  46372. *
  46373. * @param ScrollbarClass
  46374. * Scrollbar class to use.
  46375. */
  46376. ScrollbarAxis.compose = function (AxisClass, ScrollbarClass) {
  46377. var getExtremes = function (axis) {
  46378. var axisMin = pick(axis.options && axis.options.min, axis.min);
  46379. var axisMax = pick(axis.options && axis.options.max,
  46380. axis.max);
  46381. return {
  46382. axisMin: axisMin,
  46383. axisMax: axisMax,
  46384. scrollMin: defined(axis.dataMin) ?
  46385. Math.min(axisMin, axis.min, axis.dataMin, pick(axis.threshold, Infinity)) : axisMin,
  46386. scrollMax: defined(axis.dataMax) ?
  46387. Math.max(axisMax, axis.max, axis.dataMax, pick(axis.threshold, -Infinity)) : axisMax
  46388. };
  46389. };
  46390. // Wrap axis initialization and create scrollbar if enabled:
  46391. addEvent(AxisClass, 'afterInit', function () {
  46392. var axis = this;
  46393. if (axis.options &&
  46394. axis.options.scrollbar &&
  46395. axis.options.scrollbar.enabled) {
  46396. // Predefined options:
  46397. axis.options.scrollbar.vertical = !axis.horiz;
  46398. axis.options.startOnTick = axis.options.endOnTick = false;
  46399. axis.scrollbar = new ScrollbarClass(axis.chart.renderer, axis.options.scrollbar, axis.chart);
  46400. addEvent(axis.scrollbar, 'changed', function (e) {
  46401. var _a = getExtremes(axis),
  46402. axisMin = _a.axisMin,
  46403. axisMax = _a.axisMax,
  46404. unitedMin = _a.scrollMin,
  46405. unitedMax = _a.scrollMax,
  46406. range = unitedMax - unitedMin,
  46407. to,
  46408. from;
  46409. // #12834, scroll when show/hide series, wrong extremes
  46410. if (!defined(axisMin) || !defined(axisMax)) {
  46411. return;
  46412. }
  46413. if ((axis.horiz && !axis.reversed) ||
  46414. (!axis.horiz && axis.reversed)) {
  46415. to = unitedMin + range * this.to;
  46416. from = unitedMin + range * this.from;
  46417. }
  46418. else {
  46419. // y-values in browser are reversed, but this also
  46420. // applies for reversed horizontal axis:
  46421. to = unitedMin + range * (1 - this.from);
  46422. from = unitedMin + range * (1 - this.to);
  46423. }
  46424. if (pick(this.options.liveRedraw, H.svg && !H.isTouchDevice && !this.chart.isBoosting) ||
  46425. // Mouseup always should change extremes
  46426. e.DOMType === 'mouseup' ||
  46427. e.DOMType === 'touchend' ||
  46428. // Internal events
  46429. !defined(e.DOMType)) {
  46430. axis.setExtremes(from, to, true, e.DOMType !== 'mousemove' && e.DOMType !== 'touchmove', e);
  46431. }
  46432. else {
  46433. // When live redraw is disabled, don't change extremes
  46434. // Only change the position of the scollbar thumb
  46435. this.setRange(this.from, this.to);
  46436. }
  46437. });
  46438. }
  46439. });
  46440. // Wrap rendering axis, and update scrollbar if one is created:
  46441. addEvent(AxisClass, 'afterRender', function () {
  46442. var axis = this,
  46443. _a = getExtremes(axis),
  46444. scrollMin = _a.scrollMin,
  46445. scrollMax = _a.scrollMax,
  46446. scrollbar = axis.scrollbar,
  46447. offset = axis.axisTitleMargin + (axis.titleOffset || 0),
  46448. scrollbarsOffsets = axis.chart.scrollbarsOffsets,
  46449. axisMargin = axis.options.margin || 0,
  46450. offsetsIndex,
  46451. from,
  46452. to;
  46453. if (scrollbar) {
  46454. if (axis.horiz) {
  46455. // Reserve space for labels/title
  46456. if (!axis.opposite) {
  46457. scrollbarsOffsets[1] += offset;
  46458. }
  46459. scrollbar.position(axis.left, axis.top + axis.height + 2 + scrollbarsOffsets[1] -
  46460. (axis.opposite ? axisMargin : 0), axis.width, axis.height);
  46461. // Next scrollbar should reserve space for margin (if set)
  46462. if (!axis.opposite) {
  46463. scrollbarsOffsets[1] += axisMargin;
  46464. }
  46465. offsetsIndex = 1;
  46466. }
  46467. else {
  46468. // Reserve space for labels/title
  46469. if (axis.opposite) {
  46470. scrollbarsOffsets[0] += offset;
  46471. }
  46472. scrollbar.position(axis.left + axis.width + 2 + scrollbarsOffsets[0] -
  46473. (axis.opposite ? 0 : axisMargin), axis.top, axis.width, axis.height);
  46474. // Next scrollbar should reserve space for margin (if set)
  46475. if (axis.opposite) {
  46476. scrollbarsOffsets[0] += axisMargin;
  46477. }
  46478. offsetsIndex = 0;
  46479. }
  46480. scrollbarsOffsets[offsetsIndex] += scrollbar.size +
  46481. scrollbar.options.margin;
  46482. if (isNaN(scrollMin) ||
  46483. isNaN(scrollMax) ||
  46484. !defined(axis.min) ||
  46485. !defined(axis.max) ||
  46486. axis.min === axis.max // #10733
  46487. ) {
  46488. // default action: when extremes are the same or there is
  46489. // not extremes on the axis, but scrollbar exists, make it
  46490. // full size
  46491. scrollbar.setRange(0, 1);
  46492. }
  46493. else {
  46494. from =
  46495. (axis.min - scrollMin) / (scrollMax - scrollMin);
  46496. to =
  46497. (axis.max - scrollMin) / (scrollMax - scrollMin);
  46498. if ((axis.horiz && !axis.reversed) ||
  46499. (!axis.horiz && axis.reversed)) {
  46500. scrollbar.setRange(from, to);
  46501. }
  46502. else {
  46503. // inverse vertical axis
  46504. scrollbar.setRange(1 - to, 1 - from);
  46505. }
  46506. }
  46507. }
  46508. });
  46509. // Make space for a scrollbar:
  46510. addEvent(AxisClass, 'afterGetOffset', function () {
  46511. var axis = this,
  46512. index = axis.horiz ? 2 : 1,
  46513. scrollbar = axis.scrollbar;
  46514. if (scrollbar) {
  46515. axis.chart.scrollbarsOffsets = [0, 0]; // reset scrollbars offsets
  46516. axis.chart.axisOffset[index] +=
  46517. scrollbar.size + scrollbar.options.margin;
  46518. }
  46519. });
  46520. };
  46521. return ScrollbarAxis;
  46522. }());
  46523. return ScrollbarAxis;
  46524. });
  46525. _registerModule(_modules, 'Core/Scrollbar.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Globals.js'], _modules['Core/Color/Palette.js'], _modules['Core/Axis/ScrollbarAxis.js'], _modules['Core/Utilities.js'], _modules['Core/Options.js']], function (Axis, H, palette, ScrollbarAxis, U, O) {
  46526. /* *
  46527. *
  46528. * (c) 2010-2021 Torstein Honsi
  46529. *
  46530. * License: www.highcharts.com/license
  46531. *
  46532. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  46533. *
  46534. * */
  46535. var addEvent = U.addEvent,
  46536. correctFloat = U.correctFloat,
  46537. defined = U.defined,
  46538. destroyObjectProperties = U.destroyObjectProperties,
  46539. fireEvent = U.fireEvent,
  46540. merge = U.merge,
  46541. pick = U.pick,
  46542. removeEvent = U.removeEvent;
  46543. var defaultOptions = O.defaultOptions;
  46544. var isTouchDevice = H.isTouchDevice;
  46545. /**
  46546. * When we have vertical scrollbar, rifles and arrow in buttons should be
  46547. * rotated. The same method is used in Navigator's handles, to rotate them.
  46548. *
  46549. * @function Highcharts.swapXY
  46550. *
  46551. * @param {Highcharts.SVGPathArray} path
  46552. * Path to be rotated.
  46553. *
  46554. * @param {boolean} [vertical]
  46555. * If vertical scrollbar, swap x-y values.
  46556. *
  46557. * @return {Highcharts.SVGPathArray}
  46558. * Rotated path.
  46559. *
  46560. * @requires modules/stock
  46561. */
  46562. var swapXY = H.swapXY = function (path,
  46563. vertical) {
  46564. if (vertical) {
  46565. path.forEach(function (seg) {
  46566. var len = seg.length;
  46567. var temp;
  46568. for (var i = 0; i < len; i += 2) {
  46569. temp = seg[i + 1];
  46570. if (typeof temp === 'number') {
  46571. seg[i + 1] = seg[i + 2];
  46572. seg[i + 2] = temp;
  46573. }
  46574. }
  46575. });
  46576. }
  46577. return path;
  46578. };
  46579. /* eslint-disable no-invalid-this, valid-jsdoc */
  46580. /**
  46581. * A reusable scrollbar, internally used in Highstock's navigator and optionally
  46582. * on individual axes.
  46583. *
  46584. * @private
  46585. * @class
  46586. * @name Highcharts.Scrollbar
  46587. * @param {Highcharts.SVGRenderer} renderer
  46588. * @param {Highcharts.ScrollbarOptions} options
  46589. * @param {Highcharts.Chart} chart
  46590. */
  46591. var Scrollbar = /** @class */ (function () {
  46592. /* *
  46593. *
  46594. * Constructors
  46595. *
  46596. * */
  46597. function Scrollbar(renderer, options, chart) {
  46598. /* *
  46599. *
  46600. * Properties
  46601. *
  46602. * */
  46603. this._events = [];
  46604. this.chartX = 0;
  46605. this.chartY = 0;
  46606. this.from = 0;
  46607. this.group = void 0;
  46608. this.scrollbar = void 0;
  46609. this.scrollbarButtons = [];
  46610. this.scrollbarGroup = void 0;
  46611. this.scrollbarLeft = 0;
  46612. this.scrollbarRifles = void 0;
  46613. this.scrollbarStrokeWidth = 1;
  46614. this.scrollbarTop = 0;
  46615. this.size = 0;
  46616. this.to = 0;
  46617. this.track = void 0;
  46618. this.trackBorderWidth = 1;
  46619. this.userOptions = {};
  46620. this.x = 0;
  46621. this.y = 0;
  46622. this.chart = chart;
  46623. this.options = options;
  46624. this.renderer = chart.renderer;
  46625. this.init(renderer, options, chart);
  46626. }
  46627. /* *
  46628. *
  46629. * Functions
  46630. *
  46631. * */
  46632. /**
  46633. * Set up the mouse and touch events for the Scrollbar
  46634. *
  46635. * @private
  46636. * @function Highcharts.Scrollbar#addEvents
  46637. * @return {void}
  46638. */
  46639. Scrollbar.prototype.addEvents = function () {
  46640. var buttonsOrder = this.options.inverted ? [1, 0] : [0, 1],
  46641. buttons = this.scrollbarButtons,
  46642. bar = this.scrollbarGroup.element,
  46643. track = this.track.element,
  46644. mouseDownHandler = this.mouseDownHandler.bind(this),
  46645. mouseMoveHandler = this.mouseMoveHandler.bind(this),
  46646. mouseUpHandler = this.mouseUpHandler.bind(this),
  46647. _events;
  46648. // Mouse events
  46649. _events = [
  46650. [buttons[buttonsOrder[0]].element, 'click', this.buttonToMinClick.bind(this)],
  46651. [buttons[buttonsOrder[1]].element, 'click', this.buttonToMaxClick.bind(this)],
  46652. [track, 'click', this.trackClick.bind(this)],
  46653. [bar, 'mousedown', mouseDownHandler],
  46654. [bar.ownerDocument, 'mousemove', mouseMoveHandler],
  46655. [bar.ownerDocument, 'mouseup', mouseUpHandler]
  46656. ];
  46657. // Touch events
  46658. if (H.hasTouch) {
  46659. _events.push([bar, 'touchstart', mouseDownHandler], [bar.ownerDocument, 'touchmove', mouseMoveHandler], [bar.ownerDocument, 'touchend', mouseUpHandler]);
  46660. }
  46661. // Add them all
  46662. _events.forEach(function (args) {
  46663. addEvent.apply(null, args);
  46664. });
  46665. this._events = _events;
  46666. };
  46667. Scrollbar.prototype.buttonToMaxClick = function (e) {
  46668. var scroller = this;
  46669. var range = (scroller.to - scroller.from) * pick(scroller.options.step, 0.2);
  46670. scroller.updatePosition(scroller.from + range, scroller.to + range);
  46671. fireEvent(scroller, 'changed', {
  46672. from: scroller.from,
  46673. to: scroller.to,
  46674. trigger: 'scrollbar',
  46675. DOMEvent: e
  46676. });
  46677. };
  46678. Scrollbar.prototype.buttonToMinClick = function (e) {
  46679. var scroller = this;
  46680. var range = correctFloat(scroller.to - scroller.from) *
  46681. pick(scroller.options.step, 0.2);
  46682. scroller.updatePosition(correctFloat(scroller.from - range), correctFloat(scroller.to - range));
  46683. fireEvent(scroller, 'changed', {
  46684. from: scroller.from,
  46685. to: scroller.to,
  46686. trigger: 'scrollbar',
  46687. DOMEvent: e
  46688. });
  46689. };
  46690. /**
  46691. * Get normalized (0-1) cursor position over the scrollbar
  46692. *
  46693. * @private
  46694. * @function Highcharts.Scrollbar#cursorToScrollbarPosition
  46695. *
  46696. * @param {*} normalizedEvent
  46697. * normalized event, with chartX and chartY values
  46698. *
  46699. * @return {Highcharts.Dictionary<number>}
  46700. * Local position {chartX, chartY}
  46701. */
  46702. Scrollbar.prototype.cursorToScrollbarPosition = function (normalizedEvent) {
  46703. var scroller = this,
  46704. options = scroller.options,
  46705. minWidthDifference = options.minWidth > scroller.calculatedWidth ?
  46706. options.minWidth :
  46707. 0; // minWidth distorts translation
  46708. return {
  46709. chartX: (normalizedEvent.chartX - scroller.x -
  46710. scroller.xOffset) /
  46711. (scroller.barWidth - minWidthDifference),
  46712. chartY: (normalizedEvent.chartY - scroller.y -
  46713. scroller.yOffset) /
  46714. (scroller.barWidth - minWidthDifference)
  46715. };
  46716. };
  46717. /**
  46718. * Destroys allocated elements.
  46719. *
  46720. * @private
  46721. * @function Highcharts.Scrollbar#destroy
  46722. * @return {void}
  46723. */
  46724. Scrollbar.prototype.destroy = function () {
  46725. var scroller = this.chart.scroller;
  46726. // Disconnect events added in addEvents
  46727. this.removeEvents();
  46728. // Destroy properties
  46729. [
  46730. 'track',
  46731. 'scrollbarRifles',
  46732. 'scrollbar',
  46733. 'scrollbarGroup',
  46734. 'group'
  46735. ].forEach(function (prop) {
  46736. if (this[prop] && this[prop].destroy) {
  46737. this[prop] = this[prop].destroy();
  46738. }
  46739. }, this);
  46740. // #6421, chart may have more scrollbars
  46741. if (scroller && this === scroller.scrollbar) {
  46742. scroller.scrollbar = null;
  46743. // Destroy elements in collection
  46744. destroyObjectProperties(scroller.scrollbarButtons);
  46745. }
  46746. };
  46747. /**
  46748. * Draw the scrollbar buttons with arrows
  46749. *
  46750. * @private
  46751. * @function Highcharts.Scrollbar#drawScrollbarButton
  46752. * @param {number} index
  46753. * 0 is left, 1 is right
  46754. * @return {void}
  46755. */
  46756. Scrollbar.prototype.drawScrollbarButton = function (index) {
  46757. var scroller = this,
  46758. renderer = scroller.renderer,
  46759. scrollbarButtons = scroller.scrollbarButtons,
  46760. options = scroller.options,
  46761. size = scroller.size,
  46762. group,
  46763. tempElem;
  46764. group = renderer.g().add(scroller.group);
  46765. scrollbarButtons.push(group);
  46766. // Create a rectangle for the scrollbar button
  46767. tempElem = renderer.rect()
  46768. .addClass('highcharts-scrollbar-button')
  46769. .add(group);
  46770. // Presentational attributes
  46771. if (!this.chart.styledMode) {
  46772. tempElem.attr({
  46773. stroke: options.buttonBorderColor,
  46774. 'stroke-width': options.buttonBorderWidth,
  46775. fill: options.buttonBackgroundColor
  46776. });
  46777. }
  46778. // Place the rectangle based on the rendered stroke width
  46779. tempElem.attr(tempElem.crisp({
  46780. x: -0.5,
  46781. y: -0.5,
  46782. width: size + 1,
  46783. height: size + 1,
  46784. r: options.buttonBorderRadius
  46785. }, tempElem.strokeWidth()));
  46786. // Button arrow
  46787. tempElem = renderer
  46788. .path(swapXY([[
  46789. 'M',
  46790. size / 2 + (index ? -1 : 1),
  46791. size / 2 - 3
  46792. ], [
  46793. 'L',
  46794. size / 2 + (index ? -1 : 1),
  46795. size / 2 + 3
  46796. ], [
  46797. 'L',
  46798. size / 2 + (index ? 2 : -2),
  46799. size / 2
  46800. ]], options.vertical))
  46801. .addClass('highcharts-scrollbar-arrow')
  46802. .add(scrollbarButtons[index]);
  46803. if (!this.chart.styledMode) {
  46804. tempElem.attr({
  46805. fill: options.buttonArrowColor
  46806. });
  46807. }
  46808. };
  46809. /**
  46810. * @private
  46811. * @function Highcharts.Scrollbar#init
  46812. * @param {Highcharts.SVGRenderer} renderer
  46813. * @param {Highcharts.ScrollbarOptions} options
  46814. * @param {Highcharts.Chart} chart
  46815. */
  46816. Scrollbar.prototype.init = function (renderer, options, chart) {
  46817. this.scrollbarButtons = [];
  46818. this.renderer = renderer;
  46819. this.userOptions = options;
  46820. this.options = merge(Scrollbar.defaultOptions, options);
  46821. this.chart = chart;
  46822. // backward compatibility
  46823. this.size = pick(this.options.size, this.options.height);
  46824. // Init
  46825. if (options.enabled) {
  46826. this.render();
  46827. this.addEvents();
  46828. }
  46829. };
  46830. Scrollbar.prototype.mouseDownHandler = function (e) {
  46831. var scroller = this;
  46832. var normalizedEvent = scroller.chart.pointer.normalize(e),
  46833. mousePosition = scroller.cursorToScrollbarPosition(normalizedEvent);
  46834. scroller.chartX = mousePosition.chartX;
  46835. scroller.chartY = mousePosition.chartY;
  46836. scroller.initPositions = [scroller.from, scroller.to];
  46837. scroller.grabbedCenter = true;
  46838. };
  46839. /**
  46840. * Event handler for the mouse move event.
  46841. * @private
  46842. */
  46843. Scrollbar.prototype.mouseMoveHandler = function (e) {
  46844. var scroller = this;
  46845. var normalizedEvent = scroller.chart.pointer.normalize(e),
  46846. options = scroller.options,
  46847. direction = options.vertical ? 'chartY' : 'chartX',
  46848. initPositions = scroller.initPositions || [],
  46849. scrollPosition,
  46850. chartPosition,
  46851. change;
  46852. // In iOS, a mousemove event with e.pageX === 0 is fired when
  46853. // holding the finger down in the center of the scrollbar. This
  46854. // should be ignored.
  46855. if (scroller.grabbedCenter &&
  46856. // #4696, scrollbar failed on Android
  46857. (!e.touches || e.touches[0][direction] !== 0)) {
  46858. chartPosition = scroller.cursorToScrollbarPosition(normalizedEvent)[direction];
  46859. scrollPosition = scroller[direction];
  46860. change = chartPosition - scrollPosition;
  46861. scroller.hasDragged = true;
  46862. scroller.updatePosition(initPositions[0] + change, initPositions[1] + change);
  46863. if (scroller.hasDragged) {
  46864. fireEvent(scroller, 'changed', {
  46865. from: scroller.from,
  46866. to: scroller.to,
  46867. trigger: 'scrollbar',
  46868. DOMType: e.type,
  46869. DOMEvent: e
  46870. });
  46871. }
  46872. }
  46873. };
  46874. /**
  46875. * Event handler for the mouse up event.
  46876. * @private
  46877. */
  46878. Scrollbar.prototype.mouseUpHandler = function (e) {
  46879. var scroller = this;
  46880. if (scroller.hasDragged) {
  46881. fireEvent(scroller, 'changed', {
  46882. from: scroller.from,
  46883. to: scroller.to,
  46884. trigger: 'scrollbar',
  46885. DOMType: e.type,
  46886. DOMEvent: e
  46887. });
  46888. }
  46889. scroller.grabbedCenter =
  46890. scroller.hasDragged =
  46891. scroller.chartX =
  46892. scroller.chartY = null;
  46893. };
  46894. /**
  46895. * Position the scrollbar, method called from a parent with defined
  46896. * dimensions.
  46897. *
  46898. * @private
  46899. * @function Highcharts.Scrollbar#position
  46900. * @param {number} x
  46901. * x-position on the chart
  46902. * @param {number} y
  46903. * y-position on the chart
  46904. * @param {number} width
  46905. * width of the scrollbar
  46906. * @param {number} height
  46907. * height of the scorllbar
  46908. * @return {void}
  46909. */
  46910. Scrollbar.prototype.position = function (x, y, width, height) {
  46911. var scroller = this,
  46912. options = scroller.options,
  46913. vertical = options.vertical,
  46914. xOffset = height,
  46915. yOffset = 0,
  46916. method = scroller.rendered ? 'animate' : 'attr';
  46917. scroller.x = x;
  46918. scroller.y = y + this.trackBorderWidth;
  46919. scroller.width = width; // width with buttons
  46920. scroller.height = height;
  46921. scroller.xOffset = xOffset;
  46922. scroller.yOffset = yOffset;
  46923. // If Scrollbar is a vertical type, swap options:
  46924. if (vertical) {
  46925. scroller.width = scroller.yOffset = width = yOffset = scroller.size;
  46926. scroller.xOffset = xOffset = 0;
  46927. scroller.barWidth = height - width * 2; // width without buttons
  46928. scroller.x = x = x + scroller.options.margin;
  46929. }
  46930. else {
  46931. scroller.height = scroller.xOffset = height = xOffset =
  46932. scroller.size;
  46933. scroller.barWidth = width - height * 2; // width without buttons
  46934. scroller.y = scroller.y + scroller.options.margin;
  46935. }
  46936. // Set general position for a group:
  46937. scroller.group[method]({
  46938. translateX: x,
  46939. translateY: scroller.y
  46940. });
  46941. // Resize background/track:
  46942. scroller.track[method]({
  46943. width: width,
  46944. height: height
  46945. });
  46946. // Move right/bottom button ot it's place:
  46947. scroller.scrollbarButtons[1][method]({
  46948. translateX: vertical ? 0 : width - xOffset,
  46949. translateY: vertical ? height - yOffset : 0
  46950. });
  46951. };
  46952. /**
  46953. * Removes the event handlers attached previously with addEvents.
  46954. *
  46955. * @private
  46956. * @function Highcharts.Scrollbar#removeEvents
  46957. * @return {void}
  46958. */
  46959. Scrollbar.prototype.removeEvents = function () {
  46960. this._events.forEach(function (args) {
  46961. removeEvent.apply(null, args);
  46962. });
  46963. this._events.length = 0;
  46964. };
  46965. /**
  46966. * Render scrollbar with all required items.
  46967. *
  46968. * @private
  46969. * @function Highcharts.Scrollbar#render
  46970. */
  46971. Scrollbar.prototype.render = function () {
  46972. var scroller = this,
  46973. renderer = scroller.renderer,
  46974. options = scroller.options,
  46975. size = scroller.size,
  46976. styledMode = this.chart.styledMode,
  46977. group;
  46978. // Draw the scrollbar group
  46979. scroller.group = group = renderer.g('scrollbar').attr({
  46980. zIndex: options.zIndex,
  46981. translateY: -99999
  46982. }).add();
  46983. // Draw the scrollbar track:
  46984. scroller.track = renderer.rect()
  46985. .addClass('highcharts-scrollbar-track')
  46986. .attr({
  46987. x: 0,
  46988. r: options.trackBorderRadius || 0,
  46989. height: size,
  46990. width: size
  46991. }).add(group);
  46992. if (!styledMode) {
  46993. scroller.track.attr({
  46994. fill: options.trackBackgroundColor,
  46995. stroke: options.trackBorderColor,
  46996. 'stroke-width': options.trackBorderWidth
  46997. });
  46998. }
  46999. this.trackBorderWidth = scroller.track.strokeWidth();
  47000. scroller.track.attr({
  47001. y: -this.trackBorderWidth % 2 / 2
  47002. });
  47003. // Draw the scrollbar itself
  47004. scroller.scrollbarGroup = renderer.g().add(group);
  47005. scroller.scrollbar = renderer.rect()
  47006. .addClass('highcharts-scrollbar-thumb')
  47007. .attr({
  47008. height: size,
  47009. width: size,
  47010. r: options.barBorderRadius || 0
  47011. }).add(scroller.scrollbarGroup);
  47012. scroller.scrollbarRifles = renderer
  47013. .path(swapXY([
  47014. ['M', -3, size / 4],
  47015. ['L', -3, 2 * size / 3],
  47016. ['M', 0, size / 4],
  47017. ['L', 0, 2 * size / 3],
  47018. ['M', 3, size / 4],
  47019. ['L', 3, 2 * size / 3]
  47020. ], options.vertical))
  47021. .addClass('highcharts-scrollbar-rifles')
  47022. .add(scroller.scrollbarGroup);
  47023. if (!styledMode) {
  47024. scroller.scrollbar.attr({
  47025. fill: options.barBackgroundColor,
  47026. stroke: options.barBorderColor,
  47027. 'stroke-width': options.barBorderWidth
  47028. });
  47029. scroller.scrollbarRifles.attr({
  47030. stroke: options.rifleColor,
  47031. 'stroke-width': 1
  47032. });
  47033. }
  47034. scroller.scrollbarStrokeWidth = scroller.scrollbar.strokeWidth();
  47035. scroller.scrollbarGroup.translate(-scroller.scrollbarStrokeWidth % 2 / 2, -scroller.scrollbarStrokeWidth % 2 / 2);
  47036. // Draw the buttons:
  47037. scroller.drawScrollbarButton(0);
  47038. scroller.drawScrollbarButton(1);
  47039. };
  47040. /**
  47041. * Set scrollbar size, with a given scale.
  47042. *
  47043. * @private
  47044. * @function Highcharts.Scrollbar#setRange
  47045. * @param {number} from
  47046. * scale (0-1) where bar should start
  47047. * @param {number} to
  47048. * scale (0-1) where bar should end
  47049. * @return {void}
  47050. */
  47051. Scrollbar.prototype.setRange = function (from, to) {
  47052. var scroller = this,
  47053. options = scroller.options,
  47054. vertical = options.vertical,
  47055. minWidth = options.minWidth,
  47056. fullWidth = scroller.barWidth,
  47057. fromPX,
  47058. toPX,
  47059. newPos,
  47060. newSize,
  47061. newRiflesPos,
  47062. method = (this.rendered &&
  47063. !this.hasDragged &&
  47064. !(this.chart.navigator && this.chart.navigator.hasDragged)) ? 'animate' : 'attr';
  47065. if (!defined(fullWidth)) {
  47066. return;
  47067. }
  47068. from = Math.max(from, 0);
  47069. fromPX = Math.ceil(fullWidth * from);
  47070. toPX = fullWidth * Math.min(to, 1);
  47071. scroller.calculatedWidth = newSize = correctFloat(toPX - fromPX);
  47072. // We need to recalculate position, if minWidth is used
  47073. if (newSize < minWidth) {
  47074. fromPX = (fullWidth - minWidth + newSize) * from;
  47075. newSize = minWidth;
  47076. }
  47077. newPos = Math.floor(fromPX + scroller.xOffset + scroller.yOffset);
  47078. newRiflesPos = newSize / 2 - 0.5; // -0.5 -> rifle line width / 2
  47079. // Store current position:
  47080. scroller.from = from;
  47081. scroller.to = to;
  47082. if (!vertical) {
  47083. scroller.scrollbarGroup[method]({
  47084. translateX: newPos
  47085. });
  47086. scroller.scrollbar[method]({
  47087. width: newSize
  47088. });
  47089. scroller.scrollbarRifles[method]({
  47090. translateX: newRiflesPos
  47091. });
  47092. scroller.scrollbarLeft = newPos;
  47093. scroller.scrollbarTop = 0;
  47094. }
  47095. else {
  47096. scroller.scrollbarGroup[method]({
  47097. translateY: newPos
  47098. });
  47099. scroller.scrollbar[method]({
  47100. height: newSize
  47101. });
  47102. scroller.scrollbarRifles[method]({
  47103. translateY: newRiflesPos
  47104. });
  47105. scroller.scrollbarTop = newPos;
  47106. scroller.scrollbarLeft = 0;
  47107. }
  47108. if (newSize <= 12) {
  47109. scroller.scrollbarRifles.hide();
  47110. }
  47111. else {
  47112. scroller.scrollbarRifles.show(true);
  47113. }
  47114. // Show or hide the scrollbar based on the showFull setting
  47115. if (options.showFull === false) {
  47116. if (from <= 0 && to >= 1) {
  47117. scroller.group.hide();
  47118. }
  47119. else {
  47120. scroller.group.show();
  47121. }
  47122. }
  47123. scroller.rendered = true;
  47124. };
  47125. Scrollbar.prototype.trackClick = function (e) {
  47126. var scroller = this;
  47127. var normalizedEvent = scroller.chart.pointer.normalize(e),
  47128. range = scroller.to - scroller.from,
  47129. top = scroller.y + scroller.scrollbarTop,
  47130. left = scroller.x + scroller.scrollbarLeft;
  47131. if ((scroller.options.vertical && normalizedEvent.chartY > top) ||
  47132. (!scroller.options.vertical && normalizedEvent.chartX > left)) {
  47133. // On the top or on the left side of the track:
  47134. scroller.updatePosition(scroller.from + range, scroller.to + range);
  47135. }
  47136. else {
  47137. // On the bottom or the right side of the track:
  47138. scroller.updatePosition(scroller.from - range, scroller.to - range);
  47139. }
  47140. fireEvent(scroller, 'changed', {
  47141. from: scroller.from,
  47142. to: scroller.to,
  47143. trigger: 'scrollbar',
  47144. DOMEvent: e
  47145. });
  47146. };
  47147. /**
  47148. * Update the scrollbar with new options
  47149. *
  47150. * @private
  47151. * @function Highcharts.Scrollbar#update
  47152. * @param {Highcharts.ScrollbarOptions} options
  47153. * @return {void}
  47154. */
  47155. Scrollbar.prototype.update = function (options) {
  47156. this.destroy();
  47157. this.init(this.chart.renderer, merge(true, this.options, options), this.chart);
  47158. };
  47159. /**
  47160. * Update position option in the Scrollbar, with normalized 0-1 scale
  47161. *
  47162. * @private
  47163. * @function Highcharts.Scrollbar#updatePosition
  47164. * @param {number} from
  47165. * @param {number} to
  47166. * @return {void}
  47167. */
  47168. Scrollbar.prototype.updatePosition = function (from, to) {
  47169. if (to > 1) {
  47170. from = correctFloat(1 - correctFloat(to - from));
  47171. to = 1;
  47172. }
  47173. if (from < 0) {
  47174. to = correctFloat(to - from);
  47175. from = 0;
  47176. }
  47177. this.from = from;
  47178. this.to = to;
  47179. };
  47180. /* *
  47181. *
  47182. * Static Properties
  47183. *
  47184. * */
  47185. /**
  47186. *
  47187. * The scrollbar is a means of panning over the X axis of a stock chart.
  47188. * Scrollbars can also be applied to other types of axes.
  47189. *
  47190. * Another approach to scrollable charts is the [chart.scrollablePlotArea](
  47191. * https://api.highcharts.com/highcharts/chart.scrollablePlotArea) option that
  47192. * is especially suitable for simpler cartesian charts on mobile.
  47193. *
  47194. * In styled mode, all the presentational options for the
  47195. * scrollbar are replaced by the classes `.highcharts-scrollbar-thumb`,
  47196. * `.highcharts-scrollbar-arrow`, `.highcharts-scrollbar-button`,
  47197. * `.highcharts-scrollbar-rifles` and `.highcharts-scrollbar-track`.
  47198. *
  47199. * @sample stock/yaxis/inverted-bar-scrollbar/
  47200. * A scrollbar on a simple bar chart
  47201. *
  47202. * @product highstock gantt
  47203. * @optionparent scrollbar
  47204. *
  47205. * @private
  47206. */
  47207. Scrollbar.defaultOptions = {
  47208. /**
  47209. * The height of the scrollbar. The height also applies to the width
  47210. * of the scroll arrows so that they are always squares. Defaults to
  47211. * 20 for touch devices and 14 for mouse devices.
  47212. *
  47213. * @sample stock/scrollbar/height/
  47214. * A 30px scrollbar
  47215. *
  47216. * @type {number}
  47217. * @default 20/14
  47218. */
  47219. height: isTouchDevice ? 20 : 14,
  47220. /**
  47221. * The border rounding radius of the bar.
  47222. *
  47223. * @sample stock/scrollbar/style/
  47224. * Scrollbar styling
  47225. */
  47226. barBorderRadius: 0,
  47227. /**
  47228. * The corner radius of the scrollbar buttons.
  47229. *
  47230. * @sample stock/scrollbar/style/
  47231. * Scrollbar styling
  47232. */
  47233. buttonBorderRadius: 0,
  47234. /**
  47235. * Enable or disable the scrollbar.
  47236. *
  47237. * @sample stock/scrollbar/enabled/
  47238. * Disable the scrollbar, only use navigator
  47239. *
  47240. * @type {boolean}
  47241. * @default true
  47242. * @apioption scrollbar.enabled
  47243. */
  47244. /**
  47245. * Whether to redraw the main chart as the scrollbar or the navigator
  47246. * zoomed window is moved. Defaults to `true` for modern browsers and
  47247. * `false` for legacy IE browsers as well as mobile devices.
  47248. *
  47249. * @sample stock/scrollbar/liveredraw
  47250. * Setting live redraw to false
  47251. *
  47252. * @type {boolean}
  47253. * @since 1.3
  47254. */
  47255. liveRedraw: void 0,
  47256. /**
  47257. * The margin between the scrollbar and its axis when the scrollbar is
  47258. * applied directly to an axis.
  47259. */
  47260. margin: 10,
  47261. /**
  47262. * The minimum width of the scrollbar.
  47263. *
  47264. * @since 1.2.5
  47265. */
  47266. minWidth: 6,
  47267. /**
  47268. * Whether to show or hide the scrollbar when the scrolled content is
  47269. * zoomed out to it full extent.
  47270. *
  47271. * @type {boolean}
  47272. * @default true
  47273. * @apioption scrollbar.showFull
  47274. */
  47275. step: 0.2,
  47276. /**
  47277. * The z index of the scrollbar group.
  47278. */
  47279. zIndex: 3,
  47280. /**
  47281. * The background color of the scrollbar itself.
  47282. *
  47283. * @sample stock/scrollbar/style/
  47284. * Scrollbar styling
  47285. *
  47286. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  47287. */
  47288. barBackgroundColor: palette.neutralColor20,
  47289. /**
  47290. * The width of the bar's border.
  47291. *
  47292. * @sample stock/scrollbar/style/
  47293. * Scrollbar styling
  47294. */
  47295. barBorderWidth: 1,
  47296. /**
  47297. * The color of the scrollbar's border.
  47298. *
  47299. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  47300. */
  47301. barBorderColor: palette.neutralColor20,
  47302. /**
  47303. * The color of the small arrow inside the scrollbar buttons.
  47304. *
  47305. * @sample stock/scrollbar/style/
  47306. * Scrollbar styling
  47307. *
  47308. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  47309. */
  47310. buttonArrowColor: palette.neutralColor80,
  47311. /**
  47312. * The color of scrollbar buttons.
  47313. *
  47314. * @sample stock/scrollbar/style/
  47315. * Scrollbar styling
  47316. *
  47317. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  47318. */
  47319. buttonBackgroundColor: palette.neutralColor10,
  47320. /**
  47321. * The color of the border of the scrollbar buttons.
  47322. *
  47323. * @sample stock/scrollbar/style/
  47324. * Scrollbar styling
  47325. *
  47326. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  47327. */
  47328. buttonBorderColor: palette.neutralColor20,
  47329. /**
  47330. * The border width of the scrollbar buttons.
  47331. *
  47332. * @sample stock/scrollbar/style/
  47333. * Scrollbar styling
  47334. */
  47335. buttonBorderWidth: 1,
  47336. /**
  47337. * The color of the small rifles in the middle of the scrollbar.
  47338. *
  47339. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  47340. */
  47341. rifleColor: palette.neutralColor80,
  47342. /**
  47343. * The color of the track background.
  47344. *
  47345. * @sample stock/scrollbar/style/
  47346. * Scrollbar styling
  47347. *
  47348. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  47349. */
  47350. trackBackgroundColor: palette.neutralColor5,
  47351. /**
  47352. * The color of the border of the scrollbar track.
  47353. *
  47354. * @sample stock/scrollbar/style/
  47355. * Scrollbar styling
  47356. *
  47357. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  47358. */
  47359. trackBorderColor: palette.neutralColor5,
  47360. /**
  47361. * The corner radius of the border of the scrollbar track.
  47362. *
  47363. * @sample stock/scrollbar/style/
  47364. * Scrollbar styling
  47365. *
  47366. * @type {number}
  47367. * @default 0
  47368. * @apioption scrollbar.trackBorderRadius
  47369. */
  47370. /**
  47371. * The width of the border of the scrollbar track.
  47372. *
  47373. * @sample stock/scrollbar/style/
  47374. * Scrollbar styling
  47375. */
  47376. trackBorderWidth: 1
  47377. };
  47378. return Scrollbar;
  47379. }());
  47380. if (!H.Scrollbar) {
  47381. defaultOptions.scrollbar = merge(true, Scrollbar.defaultOptions, defaultOptions.scrollbar);
  47382. H.Scrollbar = Scrollbar;
  47383. ScrollbarAxis.compose(Axis, Scrollbar);
  47384. }
  47385. return H.Scrollbar;
  47386. });
  47387. _registerModule(_modules, 'Core/Navigator.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Chart/Chart.js'], _modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Core/Axis/NavigatorAxis.js'], _modules['Core/Options.js'], _modules['Core/Color/Palette.js'], _modules['Core/Scrollbar.js'], _modules['Core/Series/Series.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (Axis, Chart, Color, H, NavigatorAxis, O, palette, Scrollbar, Series, SeriesRegistry, U) {
  47388. /* *
  47389. *
  47390. * (c) 2010-2021 Torstein Honsi
  47391. *
  47392. * License: www.highcharts.com/license
  47393. *
  47394. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  47395. *
  47396. * */
  47397. var color = Color.parse;
  47398. var hasTouch = H.hasTouch,
  47399. isTouchDevice = H.isTouchDevice;
  47400. var defaultOptions = O.defaultOptions;
  47401. var seriesTypes = SeriesRegistry.seriesTypes;
  47402. var addEvent = U.addEvent,
  47403. clamp = U.clamp,
  47404. correctFloat = U.correctFloat,
  47405. defined = U.defined,
  47406. destroyObjectProperties = U.destroyObjectProperties,
  47407. erase = U.erase,
  47408. extend = U.extend,
  47409. find = U.find,
  47410. isArray = U.isArray,
  47411. isNumber = U.isNumber,
  47412. merge = U.merge,
  47413. pick = U.pick,
  47414. removeEvent = U.removeEvent,
  47415. splat = U.splat;
  47416. var defaultSeriesType,
  47417. // Finding the min or max of a set of variables where we don't know if they
  47418. // are defined, is a pattern that is repeated several places in Highcharts.
  47419. // Consider making this a global utility method.
  47420. numExt = function (extreme) {
  47421. var args = [];
  47422. for (var _i = 1; _i < arguments.length; _i++) {
  47423. args[_i - 1] = arguments[_i];
  47424. }
  47425. var numbers = [].filter.call(args,
  47426. isNumber);
  47427. if (numbers.length) {
  47428. return Math[extreme].apply(0, numbers);
  47429. }
  47430. };
  47431. defaultSeriesType = typeof seriesTypes.areaspline === 'undefined' ?
  47432. 'line' :
  47433. 'areaspline';
  47434. extend(defaultOptions, {
  47435. /**
  47436. * Maximum range which can be set using the navigator's handles.
  47437. * Opposite of [xAxis.minRange](#xAxis.minRange).
  47438. *
  47439. * @sample {highstock} stock/navigator/maxrange/
  47440. * Defined max and min range
  47441. *
  47442. * @type {number}
  47443. * @since 6.0.0
  47444. * @product highstock gantt
  47445. * @apioption xAxis.maxRange
  47446. */
  47447. /**
  47448. * The navigator is a small series below the main series, displaying
  47449. * a view of the entire data set. It provides tools to zoom in and
  47450. * out on parts of the data as well as panning across the dataset.
  47451. *
  47452. * @product highstock gantt
  47453. * @optionparent navigator
  47454. */
  47455. navigator: {
  47456. /**
  47457. * Whether the navigator and scrollbar should adapt to updated data
  47458. * in the base X axis. When loading data async, as in the demo below,
  47459. * this should be `false`. Otherwise new data will trigger navigator
  47460. * redraw, which will cause unwanted looping. In the demo below, the
  47461. * data in the navigator is set only once. On navigating, only the main
  47462. * chart content is updated.
  47463. *
  47464. * @sample {highstock} stock/demo/lazy-loading/
  47465. * Set to false with async data loading
  47466. *
  47467. * @type {boolean}
  47468. * @default true
  47469. * @apioption navigator.adaptToUpdatedData
  47470. */
  47471. /**
  47472. * An integer identifying the index to use for the base series, or a
  47473. * string representing the id of the series.
  47474. *
  47475. * **Note**: As of Highcharts 5.0, this is now a deprecated option.
  47476. * Prefer [series.showInNavigator](#plotOptions.series.showInNavigator).
  47477. *
  47478. * @see [series.showInNavigator](#plotOptions.series.showInNavigator)
  47479. *
  47480. * @deprecated
  47481. * @type {number|string}
  47482. * @default 0
  47483. * @apioption navigator.baseSeries
  47484. */
  47485. /**
  47486. * Enable or disable the navigator.
  47487. *
  47488. * @sample {highstock} stock/navigator/enabled/
  47489. * Disable the navigator
  47490. *
  47491. * @type {boolean}
  47492. * @default true
  47493. * @apioption navigator.enabled
  47494. */
  47495. /**
  47496. * When the chart is inverted, whether to draw the navigator on the
  47497. * opposite side.
  47498. *
  47499. * @type {boolean}
  47500. * @default false
  47501. * @since 5.0.8
  47502. * @apioption navigator.opposite
  47503. */
  47504. /**
  47505. * The height of the navigator.
  47506. *
  47507. * @sample {highstock} stock/navigator/height/
  47508. * A higher navigator
  47509. */
  47510. height: 40,
  47511. /**
  47512. * The distance from the nearest element, the X axis or X axis labels.
  47513. *
  47514. * @sample {highstock} stock/navigator/margin/
  47515. * A margin of 2 draws the navigator closer to the X axis labels
  47516. */
  47517. margin: 25,
  47518. /**
  47519. * Whether the mask should be inside the range marking the zoomed
  47520. * range, or outside. In Highstock 1.x it was always `false`.
  47521. *
  47522. * @sample {highstock} stock/navigator/maskinside-false/
  47523. * False, mask outside
  47524. *
  47525. * @since 2.0
  47526. */
  47527. maskInside: true,
  47528. /**
  47529. * Options for the handles for dragging the zoomed area.
  47530. *
  47531. * @sample {highstock} stock/navigator/handles/
  47532. * Colored handles
  47533. */
  47534. handles: {
  47535. /**
  47536. * Width for handles.
  47537. *
  47538. * @sample {highstock} stock/navigator/styled-handles/
  47539. * Styled handles
  47540. *
  47541. * @since 6.0.0
  47542. */
  47543. width: 7,
  47544. /**
  47545. * Height for handles.
  47546. *
  47547. * @sample {highstock} stock/navigator/styled-handles/
  47548. * Styled handles
  47549. *
  47550. * @since 6.0.0
  47551. */
  47552. height: 15,
  47553. /**
  47554. * Array to define shapes of handles. 0-index for left, 1-index for
  47555. * right.
  47556. *
  47557. * Additionally, the URL to a graphic can be given on this form:
  47558. * `url(graphic.png)`. Note that for the image to be applied to
  47559. * exported charts, its URL needs to be accessible by the export
  47560. * server.
  47561. *
  47562. * Custom callbacks for symbol path generation can also be added to
  47563. * `Highcharts.SVGRenderer.prototype.symbols`. The callback is then
  47564. * used by its method name, as shown in the demo.
  47565. *
  47566. * @sample {highstock} stock/navigator/styled-handles/
  47567. * Styled handles
  47568. *
  47569. * @type {Array<string>}
  47570. * @default ["navigator-handle", "navigator-handle"]
  47571. * @since 6.0.0
  47572. */
  47573. symbols: ['navigator-handle', 'navigator-handle'],
  47574. /**
  47575. * Allows to enable/disable handles.
  47576. *
  47577. * @since 6.0.0
  47578. */
  47579. enabled: true,
  47580. /**
  47581. * The width for the handle border and the stripes inside.
  47582. *
  47583. * @sample {highstock} stock/navigator/styled-handles/
  47584. * Styled handles
  47585. *
  47586. * @since 6.0.0
  47587. * @apioption navigator.handles.lineWidth
  47588. */
  47589. lineWidth: 1,
  47590. /**
  47591. * The fill for the handle.
  47592. *
  47593. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  47594. */
  47595. backgroundColor: palette.neutralColor5,
  47596. /**
  47597. * The stroke for the handle border and the stripes inside.
  47598. *
  47599. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  47600. */
  47601. borderColor: palette.neutralColor40
  47602. },
  47603. /**
  47604. * The color of the mask covering the areas of the navigator series
  47605. * that are currently not visible in the main series. The default
  47606. * color is bluish with an opacity of 0.3 to see the series below.
  47607. *
  47608. * @see In styled mode, the mask is styled with the
  47609. * `.highcharts-navigator-mask` and
  47610. * `.highcharts-navigator-mask-inside` classes.
  47611. *
  47612. * @sample {highstock} stock/navigator/maskfill/
  47613. * Blue, semi transparent mask
  47614. *
  47615. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  47616. * @default rgba(102,133,194,0.3)
  47617. */
  47618. maskFill: color(palette.highlightColor60).setOpacity(0.3).get(),
  47619. /**
  47620. * The color of the line marking the currently zoomed area in the
  47621. * navigator.
  47622. *
  47623. * @sample {highstock} stock/navigator/outline/
  47624. * 2px blue outline
  47625. *
  47626. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  47627. * @default #cccccc
  47628. */
  47629. outlineColor: palette.neutralColor20,
  47630. /**
  47631. * The width of the line marking the currently zoomed area in the
  47632. * navigator.
  47633. *
  47634. * @see In styled mode, the outline stroke width is set with the
  47635. * `.highcharts-navigator-outline` class.
  47636. *
  47637. * @sample {highstock} stock/navigator/outline/
  47638. * 2px blue outline
  47639. *
  47640. * @type {number}
  47641. */
  47642. outlineWidth: 1,
  47643. /**
  47644. * Options for the navigator series. Available options are the same
  47645. * as any series, documented at [plotOptions](#plotOptions.series)
  47646. * and [series](#series).
  47647. *
  47648. * Unless data is explicitly defined on navigator.series, the data
  47649. * is borrowed from the first series in the chart.
  47650. *
  47651. * Default series options for the navigator series are:
  47652. * ```js
  47653. * series: {
  47654. * type: 'areaspline',
  47655. * fillOpacity: 0.05,
  47656. * dataGrouping: {
  47657. * smoothed: true
  47658. * },
  47659. * lineWidth: 1,
  47660. * marker: {
  47661. * enabled: false
  47662. * }
  47663. * }
  47664. * ```
  47665. *
  47666. * @see In styled mode, the navigator series is styled with the
  47667. * `.highcharts-navigator-series` class.
  47668. *
  47669. * @sample {highstock} stock/navigator/series-data/
  47670. * Using a separate data set for the navigator
  47671. * @sample {highstock} stock/navigator/series/
  47672. * A green navigator series
  47673. *
  47674. * @type {*|Array<*>|Highcharts.SeriesOptionsType|Array<Highcharts.SeriesOptionsType>}
  47675. */
  47676. series: {
  47677. /**
  47678. * The type of the navigator series.
  47679. *
  47680. * Heads up:
  47681. * In column-type navigator, zooming is limited to at least one
  47682. * point with its `pointRange`.
  47683. *
  47684. * @sample {highstock} stock/navigator/column/
  47685. * Column type navigator
  47686. *
  47687. * @type {string}
  47688. * @default {highstock} `areaspline` if defined, otherwise `line`
  47689. * @default {gantt} gantt
  47690. */
  47691. type: defaultSeriesType,
  47692. /**
  47693. * The fill opacity of the navigator series.
  47694. */
  47695. fillOpacity: 0.05,
  47696. /**
  47697. * The pixel line width of the navigator series.
  47698. */
  47699. lineWidth: 1,
  47700. /**
  47701. * @ignore-option
  47702. */
  47703. compare: null,
  47704. /**
  47705. * Unless data is explicitly defined, the data is borrowed from the
  47706. * first series in the chart.
  47707. *
  47708. * @type {Array<number|Array<number|string|null>|object|null>}
  47709. * @product highstock
  47710. * @apioption navigator.series.data
  47711. */
  47712. /**
  47713. * Data grouping options for the navigator series.
  47714. *
  47715. * @extends plotOptions.series.dataGrouping
  47716. */
  47717. dataGrouping: {
  47718. approximation: 'average',
  47719. enabled: true,
  47720. groupPixelWidth: 2,
  47721. smoothed: true,
  47722. // Day and week differs from plotOptions.series.dataGrouping
  47723. units: [
  47724. ['millisecond', [1, 2, 5, 10, 20, 25, 50, 100, 200, 500]],
  47725. ['second', [1, 2, 5, 10, 15, 30]],
  47726. ['minute', [1, 2, 5, 10, 15, 30]],
  47727. ['hour', [1, 2, 3, 4, 6, 8, 12]],
  47728. ['day', [1, 2, 3, 4]],
  47729. ['week', [1, 2, 3]],
  47730. ['month', [1, 3, 6]],
  47731. ['year', null]
  47732. ]
  47733. },
  47734. /**
  47735. * Data label options for the navigator series. Data labels are
  47736. * disabled by default on the navigator series.
  47737. *
  47738. * @extends plotOptions.series.dataLabels
  47739. */
  47740. dataLabels: {
  47741. enabled: false,
  47742. zIndex: 2 // #1839
  47743. },
  47744. id: 'highcharts-navigator-series',
  47745. className: 'highcharts-navigator-series',
  47746. /**
  47747. * Sets the fill color of the navigator series.
  47748. *
  47749. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  47750. * @apioption navigator.series.color
  47751. */
  47752. /**
  47753. * Line color for the navigator series. Allows setting the color
  47754. * while disallowing the default candlestick setting.
  47755. *
  47756. * @type {Highcharts.ColorString|null}
  47757. */
  47758. lineColor: null,
  47759. marker: {
  47760. enabled: false
  47761. },
  47762. /**
  47763. * Since Highstock v8, default value is the same as default
  47764. * `pointRange` defined for a specific type (e.g. `null` for
  47765. * column type).
  47766. *
  47767. * In Highstock version < 8, defaults to 0.
  47768. *
  47769. * @extends plotOptions.series.pointRange
  47770. * @type {number|null}
  47771. * @apioption navigator.series.pointRange
  47772. */
  47773. /**
  47774. * The threshold option. Setting it to 0 will make the default
  47775. * navigator area series draw its area from the 0 value and up.
  47776. *
  47777. * @type {number|null}
  47778. */
  47779. threshold: null
  47780. },
  47781. /**
  47782. * Options for the navigator X axis. Default series options for the
  47783. * navigator xAxis are:
  47784. * ```js
  47785. * xAxis: {
  47786. * tickWidth: 0,
  47787. * lineWidth: 0,
  47788. * gridLineWidth: 1,
  47789. * tickPixelInterval: 200,
  47790. * labels: {
  47791. * align: 'left',
  47792. * style: {
  47793. * color: '#888'
  47794. * },
  47795. * x: 3,
  47796. * y: -4
  47797. * }
  47798. * }
  47799. * ```
  47800. *
  47801. * @extends xAxis
  47802. * @excluding linkedTo, maxZoom, minRange, opposite, range, scrollbar,
  47803. * showEmpty, maxRange
  47804. */
  47805. xAxis: {
  47806. /**
  47807. * Additional range on the right side of the xAxis. Works similar to
  47808. * xAxis.maxPadding, but value is set in milliseconds.
  47809. * Can be set for both, main xAxis and navigator's xAxis.
  47810. *
  47811. * @since 6.0.0
  47812. */
  47813. overscroll: 0,
  47814. className: 'highcharts-navigator-xaxis',
  47815. tickLength: 0,
  47816. lineWidth: 0,
  47817. gridLineColor: palette.neutralColor10,
  47818. gridLineWidth: 1,
  47819. tickPixelInterval: 200,
  47820. labels: {
  47821. align: 'left',
  47822. /**
  47823. * @type {Highcharts.CSSObject}
  47824. */
  47825. style: {
  47826. /** @ignore */
  47827. color: palette.neutralColor40
  47828. },
  47829. x: 3,
  47830. y: -4
  47831. },
  47832. crosshair: false
  47833. },
  47834. /**
  47835. * Options for the navigator Y axis. Default series options for the
  47836. * navigator yAxis are:
  47837. * ```js
  47838. * yAxis: {
  47839. * gridLineWidth: 0,
  47840. * startOnTick: false,
  47841. * endOnTick: false,
  47842. * minPadding: 0.1,
  47843. * maxPadding: 0.1,
  47844. * labels: {
  47845. * enabled: false
  47846. * },
  47847. * title: {
  47848. * text: null
  47849. * },
  47850. * tickWidth: 0
  47851. * }
  47852. * ```
  47853. *
  47854. * @extends yAxis
  47855. * @excluding height, linkedTo, maxZoom, minRange, ordinal, range,
  47856. * showEmpty, scrollbar, top, units, maxRange, minLength,
  47857. * maxLength, resize
  47858. */
  47859. yAxis: {
  47860. className: 'highcharts-navigator-yaxis',
  47861. gridLineWidth: 0,
  47862. startOnTick: false,
  47863. endOnTick: false,
  47864. minPadding: 0.1,
  47865. maxPadding: 0.1,
  47866. labels: {
  47867. enabled: false
  47868. },
  47869. crosshair: false,
  47870. title: {
  47871. text: null
  47872. },
  47873. tickLength: 0,
  47874. tickWidth: 0
  47875. }
  47876. }
  47877. });
  47878. /* eslint-disable no-invalid-this, valid-jsdoc */
  47879. /**
  47880. * Draw one of the handles on the side of the zoomed range in the navigator
  47881. *
  47882. * @private
  47883. * @function Highcharts.Renderer#symbols.navigator-handle
  47884. * @param {number} x
  47885. * @param {number} y
  47886. * @param {number} w
  47887. * @param {number} h
  47888. * @param {Highcharts.NavigatorHandlesOptions} options
  47889. * @return {Highcharts.SVGPathArray}
  47890. * Path to be used in a handle
  47891. */
  47892. H.Renderer.prototype.symbols['navigator-handle'] = function (x, y, w, h, options) {
  47893. var halfWidth = (options && options.width || 0) / 2,
  47894. markerPosition = Math.round(halfWidth / 3) + 0.5,
  47895. height = options && options.height || 0;
  47896. return [
  47897. ['M', -halfWidth - 1, 0.5],
  47898. ['L', halfWidth, 0.5],
  47899. ['L', halfWidth, height + 0.5],
  47900. ['L', -halfWidth - 1, height + 0.5],
  47901. ['L', -halfWidth - 1, 0.5],
  47902. ['M', -markerPosition, 4],
  47903. ['L', -markerPosition, height - 3],
  47904. ['M', markerPosition - 1, 4],
  47905. ['L', markerPosition - 1, height - 3]
  47906. ];
  47907. };
  47908. /**
  47909. * The Navigator class
  47910. *
  47911. * @private
  47912. * @class
  47913. * @name Highcharts.Navigator
  47914. *
  47915. * @param {Highcharts.Chart} chart
  47916. * Chart object
  47917. */
  47918. var Navigator = /** @class */ (function () {
  47919. function Navigator(chart) {
  47920. this.baseSeries = void 0;
  47921. this.chart = void 0;
  47922. this.handles = void 0;
  47923. this.height = void 0;
  47924. this.left = void 0;
  47925. this.navigatorEnabled = void 0;
  47926. this.navigatorGroup = void 0;
  47927. this.navigatorOptions = void 0;
  47928. this.navigatorSeries = void 0;
  47929. this.navigatorSize = void 0;
  47930. this.opposite = void 0;
  47931. this.outline = void 0;
  47932. this.outlineHeight = void 0;
  47933. this.range = void 0;
  47934. this.rendered = void 0;
  47935. this.shades = void 0;
  47936. this.size = void 0;
  47937. this.top = void 0;
  47938. this.xAxis = void 0;
  47939. this.yAxis = void 0;
  47940. this.zoomedMax = void 0;
  47941. this.zoomedMin = void 0;
  47942. this.init(chart);
  47943. }
  47944. /**
  47945. * Draw one of the handles on the side of the zoomed range in the navigator
  47946. *
  47947. * @private
  47948. * @function Highcharts.Navigator#drawHandle
  47949. *
  47950. * @param {number} x
  47951. * The x center for the handle
  47952. *
  47953. * @param {number} index
  47954. * 0 for left and 1 for right
  47955. *
  47956. * @param {boolean|undefined} inverted
  47957. * flag for chart.inverted
  47958. *
  47959. * @param {string} verb
  47960. * use 'animate' or 'attr'
  47961. */
  47962. Navigator.prototype.drawHandle = function (x, index, inverted, verb) {
  47963. var navigator = this,
  47964. height = navigator.navigatorOptions.handles.height;
  47965. // Place it
  47966. navigator.handles[index][verb](inverted ? {
  47967. translateX: Math.round(navigator.left + navigator.height / 2),
  47968. translateY: Math.round(navigator.top + parseInt(x, 10) + 0.5 - height)
  47969. } : {
  47970. translateX: Math.round(navigator.left + parseInt(x, 10)),
  47971. translateY: Math.round(navigator.top + navigator.height / 2 - height / 2 - 1)
  47972. });
  47973. };
  47974. /**
  47975. * Render outline around the zoomed range
  47976. *
  47977. * @private
  47978. * @function Highcharts.Navigator#drawOutline
  47979. *
  47980. * @param {number} zoomedMin
  47981. * in pixels position where zoomed range starts
  47982. *
  47983. * @param {number} zoomedMax
  47984. * in pixels position where zoomed range ends
  47985. *
  47986. * @param {boolean|undefined} inverted
  47987. * flag if chart is inverted
  47988. *
  47989. * @param {string} verb
  47990. * use 'animate' or 'attr'
  47991. */
  47992. Navigator.prototype.drawOutline = function (zoomedMin, zoomedMax, inverted, verb) {
  47993. var navigator = this,
  47994. maskInside = navigator.navigatorOptions.maskInside,
  47995. outlineWidth = navigator.outline.strokeWidth(),
  47996. halfOutline = outlineWidth / 2,
  47997. outlineCorrection = (outlineWidth % 2) / 2, // #5800
  47998. outlineHeight = navigator.outlineHeight,
  47999. scrollbarHeight = navigator.scrollbarHeight || 0,
  48000. navigatorSize = navigator.size,
  48001. left = navigator.left - scrollbarHeight,
  48002. navigatorTop = navigator.top,
  48003. verticalMin,
  48004. path;
  48005. if (inverted) {
  48006. left -= halfOutline;
  48007. verticalMin = navigatorTop + zoomedMax + outlineCorrection;
  48008. zoomedMax = navigatorTop + zoomedMin + outlineCorrection;
  48009. path = [
  48010. ['M', left + outlineHeight, navigatorTop - scrollbarHeight - outlineCorrection],
  48011. ['L', left + outlineHeight, verticalMin],
  48012. ['L', left, verticalMin],
  48013. ['L', left, zoomedMax],
  48014. ['L', left + outlineHeight, zoomedMax],
  48015. ['L', left + outlineHeight, navigatorTop + navigatorSize + scrollbarHeight]
  48016. ];
  48017. if (maskInside) {
  48018. path.push(['M', left + outlineHeight, verticalMin - halfOutline], // upper left of zoomed range
  48019. ['L', left + outlineHeight, zoomedMax + halfOutline] // upper right of z.r.
  48020. );
  48021. }
  48022. }
  48023. else {
  48024. zoomedMin += left + scrollbarHeight - outlineCorrection;
  48025. zoomedMax += left + scrollbarHeight - outlineCorrection;
  48026. navigatorTop += halfOutline;
  48027. path = [
  48028. ['M', left, navigatorTop],
  48029. ['L', zoomedMin, navigatorTop],
  48030. ['L', zoomedMin, navigatorTop + outlineHeight],
  48031. ['L', zoomedMax, navigatorTop + outlineHeight],
  48032. ['L', zoomedMax, navigatorTop],
  48033. ['L', left + navigatorSize + scrollbarHeight * 2, navigatorTop] // right
  48034. ];
  48035. if (maskInside) {
  48036. path.push(['M', zoomedMin - halfOutline, navigatorTop], // upper left of zoomed range
  48037. ['L', zoomedMax + halfOutline, navigatorTop] // upper right of z.r.
  48038. );
  48039. }
  48040. }
  48041. navigator.outline[verb]({
  48042. d: path
  48043. });
  48044. };
  48045. /**
  48046. * Render outline around the zoomed range
  48047. *
  48048. * @private
  48049. * @function Highcharts.Navigator#drawMasks
  48050. *
  48051. * @param {number} zoomedMin
  48052. * in pixels position where zoomed range starts
  48053. *
  48054. * @param {number} zoomedMax
  48055. * in pixels position where zoomed range ends
  48056. *
  48057. * @param {boolean|undefined} inverted
  48058. * flag if chart is inverted
  48059. *
  48060. * @param {string} verb
  48061. * use 'animate' or 'attr'
  48062. */
  48063. Navigator.prototype.drawMasks = function (zoomedMin, zoomedMax, inverted, verb) {
  48064. var navigator = this,
  48065. left = navigator.left,
  48066. top = navigator.top,
  48067. navigatorHeight = navigator.height,
  48068. height,
  48069. width,
  48070. x,
  48071. y;
  48072. // Determine rectangle position & size
  48073. // According to (non)inverted position:
  48074. if (inverted) {
  48075. x = [left, left, left];
  48076. y = [top, top + zoomedMin, top + zoomedMax];
  48077. width = [navigatorHeight, navigatorHeight, navigatorHeight];
  48078. height = [
  48079. zoomedMin,
  48080. zoomedMax - zoomedMin,
  48081. navigator.size - zoomedMax
  48082. ];
  48083. }
  48084. else {
  48085. x = [left, left + zoomedMin, left + zoomedMax];
  48086. y = [top, top, top];
  48087. width = [
  48088. zoomedMin,
  48089. zoomedMax - zoomedMin,
  48090. navigator.size - zoomedMax
  48091. ];
  48092. height = [navigatorHeight, navigatorHeight, navigatorHeight];
  48093. }
  48094. navigator.shades.forEach(function (shade, i) {
  48095. shade[verb]({
  48096. x: x[i],
  48097. y: y[i],
  48098. width: width[i],
  48099. height: height[i]
  48100. });
  48101. });
  48102. };
  48103. /**
  48104. * Generate DOM elements for a navigator:
  48105. *
  48106. * - main navigator group
  48107. *
  48108. * - all shades
  48109. *
  48110. * - outline
  48111. *
  48112. * - handles
  48113. *
  48114. * @private
  48115. * @function Highcharts.Navigator#renderElements
  48116. */
  48117. Navigator.prototype.renderElements = function () {
  48118. var navigator = this,
  48119. navigatorOptions = navigator.navigatorOptions,
  48120. maskInside = navigatorOptions.maskInside,
  48121. chart = navigator.chart,
  48122. inverted = chart.inverted,
  48123. renderer = chart.renderer,
  48124. navigatorGroup,
  48125. mouseCursor = {
  48126. cursor: inverted ? 'ns-resize' : 'ew-resize'
  48127. };
  48128. // Create the main navigator group
  48129. navigator.navigatorGroup = navigatorGroup = renderer.g('navigator')
  48130. .attr({
  48131. zIndex: 8,
  48132. visibility: 'hidden'
  48133. })
  48134. .add();
  48135. // Create masks, each mask will get events and fill:
  48136. [
  48137. !maskInside,
  48138. maskInside,
  48139. !maskInside
  48140. ].forEach(function (hasMask, index) {
  48141. navigator.shades[index] = renderer.rect()
  48142. .addClass('highcharts-navigator-mask' +
  48143. (index === 1 ? '-inside' : '-outside'))
  48144. .add(navigatorGroup);
  48145. if (!chart.styledMode) {
  48146. navigator.shades[index]
  48147. .attr({
  48148. fill: hasMask ?
  48149. navigatorOptions.maskFill :
  48150. 'rgba(0,0,0,0)'
  48151. })
  48152. .css((index === 1) && mouseCursor);
  48153. }
  48154. });
  48155. // Create the outline:
  48156. navigator.outline = renderer.path()
  48157. .addClass('highcharts-navigator-outline')
  48158. .add(navigatorGroup);
  48159. if (!chart.styledMode) {
  48160. navigator.outline.attr({
  48161. 'stroke-width': navigatorOptions.outlineWidth,
  48162. stroke: navigatorOptions.outlineColor
  48163. });
  48164. }
  48165. // Create the handlers:
  48166. if (navigatorOptions.handles.enabled) {
  48167. [0, 1].forEach(function (index) {
  48168. navigatorOptions.handles.inverted = chart.inverted;
  48169. navigator.handles[index] = renderer.symbol(navigatorOptions.handles.symbols[index], -navigatorOptions.handles.width / 2 - 1, 0, navigatorOptions.handles.width, navigatorOptions.handles.height, navigatorOptions.handles);
  48170. // zIndex = 6 for right handle, 7 for left.
  48171. // Can't be 10, because of the tooltip in inverted chart #2908
  48172. navigator.handles[index].attr({ zIndex: 7 - index })
  48173. .addClass('highcharts-navigator-handle ' +
  48174. 'highcharts-navigator-handle-' +
  48175. ['left', 'right'][index]).add(navigatorGroup);
  48176. if (!chart.styledMode) {
  48177. var handlesOptions = navigatorOptions.handles;
  48178. navigator.handles[index]
  48179. .attr({
  48180. fill: handlesOptions.backgroundColor,
  48181. stroke: handlesOptions.borderColor,
  48182. 'stroke-width': handlesOptions.lineWidth
  48183. })
  48184. .css(mouseCursor);
  48185. }
  48186. });
  48187. }
  48188. };
  48189. /**
  48190. * Update navigator
  48191. *
  48192. * @private
  48193. * @function Highcharts.Navigator#update
  48194. *
  48195. * @param {Highcharts.NavigatorOptions} options
  48196. * Options to merge in when updating navigator
  48197. */
  48198. Navigator.prototype.update = function (options) {
  48199. // Remove references to old navigator series in base series
  48200. (this.series || []).forEach(function (series) {
  48201. if (series.baseSeries) {
  48202. delete series.baseSeries.navigatorSeries;
  48203. }
  48204. });
  48205. // Destroy and rebuild navigator
  48206. this.destroy();
  48207. var chartOptions = this.chart.options;
  48208. merge(true, chartOptions.navigator, this.options, options);
  48209. this.init(this.chart);
  48210. };
  48211. /**
  48212. * Render the navigator
  48213. *
  48214. * @private
  48215. * @function Highcharts.Navigator#render
  48216. * @param {number} min
  48217. * X axis value minimum
  48218. * @param {number} max
  48219. * X axis value maximum
  48220. * @param {number} [pxMin]
  48221. * Pixel value minimum
  48222. * @param {number} [pxMax]
  48223. * Pixel value maximum
  48224. * @return {void}
  48225. */
  48226. Navigator.prototype.render = function (min, max, pxMin, pxMax) {
  48227. var navigator = this,
  48228. chart = navigator.chart,
  48229. navigatorWidth,
  48230. scrollbarLeft,
  48231. scrollbarTop,
  48232. scrollbarHeight = navigator.scrollbarHeight,
  48233. navigatorSize,
  48234. xAxis = navigator.xAxis,
  48235. pointRange = xAxis.pointRange || 0,
  48236. scrollbarXAxis = xAxis.navigatorAxis.fake ? chart.xAxis[0] : xAxis,
  48237. navigatorEnabled = navigator.navigatorEnabled,
  48238. zoomedMin,
  48239. zoomedMax,
  48240. rendered = navigator.rendered,
  48241. inverted = chart.inverted,
  48242. verb,
  48243. newMin,
  48244. newMax,
  48245. currentRange,
  48246. minRange = chart.xAxis[0].minRange,
  48247. maxRange = chart.xAxis[0].options.maxRange;
  48248. // Don't redraw while moving the handles (#4703).
  48249. if (this.hasDragged && !defined(pxMin)) {
  48250. return;
  48251. }
  48252. min = correctFloat(min - pointRange / 2);
  48253. max = correctFloat(max + pointRange / 2);
  48254. // Don't render the navigator until we have data (#486, #4202, #5172).
  48255. if (!isNumber(min) || !isNumber(max)) {
  48256. // However, if navigator was already rendered, we may need to resize
  48257. // it. For example hidden series, but visible navigator (#6022).
  48258. if (rendered) {
  48259. pxMin = 0;
  48260. pxMax = pick(xAxis.width, scrollbarXAxis.width);
  48261. }
  48262. else {
  48263. return;
  48264. }
  48265. }
  48266. navigator.left = pick(xAxis.left,
  48267. // in case of scrollbar only, without navigator
  48268. chart.plotLeft + scrollbarHeight +
  48269. (inverted ? chart.plotWidth : 0));
  48270. navigator.size = zoomedMax = navigatorSize = pick(xAxis.len, (inverted ? chart.plotHeight : chart.plotWidth) -
  48271. 2 * scrollbarHeight);
  48272. if (inverted) {
  48273. navigatorWidth = scrollbarHeight;
  48274. }
  48275. else {
  48276. navigatorWidth = navigatorSize + 2 * scrollbarHeight;
  48277. }
  48278. // Get the pixel position of the handles
  48279. pxMin = pick(pxMin, xAxis.toPixels(min, true));
  48280. pxMax = pick(pxMax, xAxis.toPixels(max, true));
  48281. // Verify (#1851, #2238)
  48282. if (!isNumber(pxMin) || Math.abs(pxMin) === Infinity) {
  48283. pxMin = 0;
  48284. pxMax = navigatorWidth;
  48285. }
  48286. // Are we below the minRange? (#2618, #6191)
  48287. newMin = xAxis.toValue(pxMin, true);
  48288. newMax = xAxis.toValue(pxMax, true);
  48289. currentRange = Math.abs(correctFloat(newMax - newMin));
  48290. if (currentRange < minRange) {
  48291. if (this.grabbedLeft) {
  48292. pxMin = xAxis.toPixels(newMax - minRange - pointRange, true);
  48293. }
  48294. else if (this.grabbedRight) {
  48295. pxMax = xAxis.toPixels(newMin + minRange + pointRange, true);
  48296. }
  48297. }
  48298. else if (defined(maxRange) &&
  48299. correctFloat(currentRange - pointRange) > maxRange) {
  48300. if (this.grabbedLeft) {
  48301. pxMin = xAxis.toPixels(newMax - maxRange - pointRange, true);
  48302. }
  48303. else if (this.grabbedRight) {
  48304. pxMax = xAxis.toPixels(newMin + maxRange + pointRange, true);
  48305. }
  48306. }
  48307. // Handles are allowed to cross, but never exceed the plot area
  48308. navigator.zoomedMax = clamp(Math.max(pxMin, pxMax), 0, zoomedMax);
  48309. navigator.zoomedMin = clamp(navigator.fixedWidth ?
  48310. navigator.zoomedMax - navigator.fixedWidth :
  48311. Math.min(pxMin, pxMax), 0, zoomedMax);
  48312. navigator.range = navigator.zoomedMax - navigator.zoomedMin;
  48313. zoomedMax = Math.round(navigator.zoomedMax);
  48314. zoomedMin = Math.round(navigator.zoomedMin);
  48315. if (navigatorEnabled) {
  48316. navigator.navigatorGroup.attr({
  48317. visibility: 'visible'
  48318. });
  48319. // Place elements
  48320. verb = rendered && !navigator.hasDragged ? 'animate' : 'attr';
  48321. navigator.drawMasks(zoomedMin, zoomedMax, inverted, verb);
  48322. navigator.drawOutline(zoomedMin, zoomedMax, inverted, verb);
  48323. if (navigator.navigatorOptions.handles.enabled) {
  48324. navigator.drawHandle(zoomedMin, 0, inverted, verb);
  48325. navigator.drawHandle(zoomedMax, 1, inverted, verb);
  48326. }
  48327. }
  48328. if (navigator.scrollbar) {
  48329. if (inverted) {
  48330. scrollbarTop = navigator.top - scrollbarHeight;
  48331. scrollbarLeft = navigator.left - scrollbarHeight +
  48332. (navigatorEnabled || !scrollbarXAxis.opposite ? 0 :
  48333. // Multiple axes has offsets:
  48334. (scrollbarXAxis.titleOffset || 0) +
  48335. // Self margin from the axis.title
  48336. scrollbarXAxis.axisTitleMargin);
  48337. scrollbarHeight = navigatorSize + 2 * scrollbarHeight;
  48338. }
  48339. else {
  48340. scrollbarTop = navigator.top + (navigatorEnabled ?
  48341. navigator.height :
  48342. -scrollbarHeight);
  48343. scrollbarLeft = navigator.left - scrollbarHeight;
  48344. }
  48345. // Reposition scrollbar
  48346. navigator.scrollbar.position(scrollbarLeft, scrollbarTop, navigatorWidth, scrollbarHeight);
  48347. // Keep scale 0-1
  48348. navigator.scrollbar.setRange(
  48349. // Use real value, not rounded because range can be very small
  48350. // (#1716)
  48351. navigator.zoomedMin / (navigatorSize || 1), navigator.zoomedMax / (navigatorSize || 1));
  48352. }
  48353. navigator.rendered = true;
  48354. };
  48355. /**
  48356. * Set up the mouse and touch events for the navigator
  48357. *
  48358. * @private
  48359. * @function Highcharts.Navigator#addMouseEvents
  48360. */
  48361. Navigator.prototype.addMouseEvents = function () {
  48362. var navigator = this,
  48363. chart = navigator.chart,
  48364. container = chart.container,
  48365. eventsToUnbind = [],
  48366. mouseMoveHandler,
  48367. mouseUpHandler;
  48368. /**
  48369. * Create mouse events' handlers.
  48370. * Make them as separate functions to enable wrapping them:
  48371. */
  48372. navigator.mouseMoveHandler = mouseMoveHandler = function (e) {
  48373. navigator.onMouseMove(e);
  48374. };
  48375. navigator.mouseUpHandler = mouseUpHandler = function (e) {
  48376. navigator.onMouseUp(e);
  48377. };
  48378. // Add shades and handles mousedown events
  48379. eventsToUnbind = navigator.getPartsEvents('mousedown');
  48380. // Add mouse move and mouseup events. These are bind to doc/container,
  48381. // because Navigator.grabbedSomething flags are stored in mousedown
  48382. // events
  48383. eventsToUnbind.push(addEvent(chart.renderTo, 'mousemove', mouseMoveHandler), addEvent(container.ownerDocument, 'mouseup', mouseUpHandler));
  48384. // Touch events
  48385. if (hasTouch) {
  48386. eventsToUnbind.push(addEvent(chart.renderTo, 'touchmove', mouseMoveHandler), addEvent(container.ownerDocument, 'touchend', mouseUpHandler));
  48387. eventsToUnbind.concat(navigator.getPartsEvents('touchstart'));
  48388. }
  48389. navigator.eventsToUnbind = eventsToUnbind;
  48390. // Data events
  48391. if (navigator.series && navigator.series[0]) {
  48392. eventsToUnbind.push(addEvent(navigator.series[0].xAxis, 'foundExtremes', function () {
  48393. chart.navigator.modifyNavigatorAxisExtremes();
  48394. }));
  48395. }
  48396. };
  48397. /**
  48398. * Generate events for handles and masks
  48399. *
  48400. * @private
  48401. * @function Highcharts.Navigator#getPartsEvents
  48402. *
  48403. * @param {string} eventName
  48404. * Event name handler, 'mousedown' or 'touchstart'
  48405. *
  48406. * @return {Array<Function>}
  48407. * An array of functions to remove navigator functions from the
  48408. * events again.
  48409. */
  48410. Navigator.prototype.getPartsEvents = function (eventName) {
  48411. var navigator = this,
  48412. events = [];
  48413. ['shades', 'handles'].forEach(function (name) {
  48414. navigator[name].forEach(function (navigatorItem, index) {
  48415. events.push(addEvent(navigatorItem.element, eventName, function (e) {
  48416. navigator[name + 'Mousedown'](e, index);
  48417. }));
  48418. });
  48419. });
  48420. return events;
  48421. };
  48422. /**
  48423. * Mousedown on a shaded mask, either:
  48424. *
  48425. * - will be stored for future drag&drop
  48426. *
  48427. * - will directly shift to a new range
  48428. *
  48429. * @private
  48430. * @function Highcharts.Navigator#shadesMousedown
  48431. *
  48432. * @param {Highcharts.PointerEventObject} e
  48433. * Mouse event
  48434. *
  48435. * @param {number} index
  48436. * Index of a mask in Navigator.shades array
  48437. */
  48438. Navigator.prototype.shadesMousedown = function (e, index) {
  48439. e = this.chart.pointer.normalize(e);
  48440. var navigator = this,
  48441. chart = navigator.chart,
  48442. xAxis = navigator.xAxis,
  48443. zoomedMin = navigator.zoomedMin,
  48444. navigatorPosition = navigator.left,
  48445. navigatorSize = navigator.size,
  48446. range = navigator.range,
  48447. chartX = e.chartX,
  48448. fixedMax,
  48449. fixedMin,
  48450. ext,
  48451. left;
  48452. // For inverted chart, swap some options:
  48453. if (chart.inverted) {
  48454. chartX = e.chartY;
  48455. navigatorPosition = navigator.top;
  48456. }
  48457. if (index === 1) {
  48458. // Store information for drag&drop
  48459. navigator.grabbedCenter = chartX;
  48460. navigator.fixedWidth = range;
  48461. navigator.dragOffset = chartX - zoomedMin;
  48462. }
  48463. else {
  48464. // Shift the range by clicking on shaded areas
  48465. left = chartX - navigatorPosition - range / 2;
  48466. if (index === 0) {
  48467. left = Math.max(0, left);
  48468. }
  48469. else if (index === 2 && left + range >= navigatorSize) {
  48470. left = navigatorSize - range;
  48471. if (navigator.reversedExtremes) {
  48472. // #7713
  48473. left -= range;
  48474. fixedMin = navigator.getUnionExtremes().dataMin;
  48475. }
  48476. else {
  48477. // #2293, #3543
  48478. fixedMax = navigator.getUnionExtremes().dataMax;
  48479. }
  48480. }
  48481. if (left !== zoomedMin) { // it has actually moved
  48482. navigator.fixedWidth = range; // #1370
  48483. ext = xAxis.navigatorAxis.toFixedRange(left, left + range, fixedMin, fixedMax);
  48484. if (defined(ext.min)) { // #7411
  48485. chart.xAxis[0].setExtremes(Math.min(ext.min, ext.max), Math.max(ext.min, ext.max), true, null, // auto animation
  48486. { trigger: 'navigator' });
  48487. }
  48488. }
  48489. }
  48490. };
  48491. /**
  48492. * Mousedown on a handle mask.
  48493. * Will store necessary information for drag&drop.
  48494. *
  48495. * @private
  48496. * @function Highcharts.Navigator#handlesMousedown
  48497. * @param {Highcharts.PointerEventObject} e
  48498. * Mouse event
  48499. * @param {number} index
  48500. * Index of a handle in Navigator.handles array
  48501. * @return {void}
  48502. */
  48503. Navigator.prototype.handlesMousedown = function (e, index) {
  48504. e = this.chart.pointer.normalize(e);
  48505. var navigator = this,
  48506. chart = navigator.chart,
  48507. baseXAxis = chart.xAxis[0],
  48508. // For reversed axes, min and max are changed,
  48509. // so the other extreme should be stored
  48510. reverse = navigator.reversedExtremes;
  48511. if (index === 0) {
  48512. // Grab the left handle
  48513. navigator.grabbedLeft = true;
  48514. navigator.otherHandlePos = navigator.zoomedMax;
  48515. navigator.fixedExtreme = reverse ? baseXAxis.min : baseXAxis.max;
  48516. }
  48517. else {
  48518. // Grab the right handle
  48519. navigator.grabbedRight = true;
  48520. navigator.otherHandlePos = navigator.zoomedMin;
  48521. navigator.fixedExtreme = reverse ? baseXAxis.max : baseXAxis.min;
  48522. }
  48523. chart.fixedRange = null;
  48524. };
  48525. /**
  48526. * Mouse move event based on x/y mouse position.
  48527. *
  48528. * @private
  48529. * @function Highcharts.Navigator#onMouseMove
  48530. *
  48531. * @param {Highcharts.PointerEventObject} e
  48532. * Mouse event
  48533. */
  48534. Navigator.prototype.onMouseMove = function (e) {
  48535. var navigator = this,
  48536. chart = navigator.chart,
  48537. left = navigator.left,
  48538. navigatorSize = navigator.navigatorSize,
  48539. range = navigator.range,
  48540. dragOffset = navigator.dragOffset,
  48541. inverted = chart.inverted,
  48542. chartX;
  48543. // In iOS, a mousemove event with e.pageX === 0 is fired when holding
  48544. // the finger down in the center of the scrollbar. This should be
  48545. // ignored.
  48546. if (!e.touches || e.touches[0].pageX !== 0) { // #4696
  48547. e = chart.pointer.normalize(e);
  48548. chartX = e.chartX;
  48549. // Swap some options for inverted chart
  48550. if (inverted) {
  48551. left = navigator.top;
  48552. chartX = e.chartY;
  48553. }
  48554. // Drag left handle or top handle
  48555. if (navigator.grabbedLeft) {
  48556. navigator.hasDragged = true;
  48557. navigator.render(0, 0, chartX - left, navigator.otherHandlePos);
  48558. // Drag right handle or bottom handle
  48559. }
  48560. else if (navigator.grabbedRight) {
  48561. navigator.hasDragged = true;
  48562. navigator.render(0, 0, navigator.otherHandlePos, chartX - left);
  48563. // Drag scrollbar or open area in navigator
  48564. }
  48565. else if (navigator.grabbedCenter) {
  48566. navigator.hasDragged = true;
  48567. if (chartX < dragOffset) { // outside left
  48568. chartX = dragOffset;
  48569. // outside right
  48570. }
  48571. else if (chartX >
  48572. navigatorSize + dragOffset - range) {
  48573. chartX = navigatorSize + dragOffset - range;
  48574. }
  48575. navigator.render(0, 0, chartX - dragOffset, chartX - dragOffset + range);
  48576. }
  48577. if (navigator.hasDragged &&
  48578. navigator.scrollbar &&
  48579. pick(navigator.scrollbar.options.liveRedraw,
  48580. // By default, don't run live redraw on VML, on touch
  48581. // devices or if the chart is in boost.
  48582. H.svg && !isTouchDevice && !this.chart.isBoosting)) {
  48583. e.DOMType = e.type; // DOMType is for IE8
  48584. setTimeout(function () {
  48585. navigator.onMouseUp(e);
  48586. }, 0);
  48587. }
  48588. }
  48589. };
  48590. /**
  48591. * Mouse up event based on x/y mouse position.
  48592. *
  48593. * @private
  48594. * @function Highcharts.Navigator#onMouseUp
  48595. * @param {Highcharts.PointerEventObject} e
  48596. * Mouse event
  48597. * @return {void}
  48598. */
  48599. Navigator.prototype.onMouseUp = function (e) {
  48600. var navigator = this,
  48601. chart = navigator.chart,
  48602. xAxis = navigator.xAxis,
  48603. scrollbar = navigator.scrollbar,
  48604. DOMEvent = e.DOMEvent || e,
  48605. inverted = chart.inverted,
  48606. verb = navigator.rendered && !navigator.hasDragged ?
  48607. 'animate' : 'attr',
  48608. zoomedMax,
  48609. zoomedMin,
  48610. unionExtremes,
  48611. fixedMin,
  48612. fixedMax,
  48613. ext;
  48614. if (
  48615. // MouseUp is called for both, navigator and scrollbar (that order),
  48616. // which causes calling afterSetExtremes twice. Prevent first call
  48617. // by checking if scrollbar is going to set new extremes (#6334)
  48618. (navigator.hasDragged && (!scrollbar || !scrollbar.hasDragged)) ||
  48619. e.trigger === 'scrollbar') {
  48620. unionExtremes = navigator.getUnionExtremes();
  48621. // When dragging one handle, make sure the other one doesn't change
  48622. if (navigator.zoomedMin === navigator.otherHandlePos) {
  48623. fixedMin = navigator.fixedExtreme;
  48624. }
  48625. else if (navigator.zoomedMax === navigator.otherHandlePos) {
  48626. fixedMax = navigator.fixedExtreme;
  48627. }
  48628. // Snap to right edge (#4076)
  48629. if (navigator.zoomedMax === navigator.size) {
  48630. fixedMax = navigator.reversedExtremes ?
  48631. unionExtremes.dataMin :
  48632. unionExtremes.dataMax;
  48633. }
  48634. // Snap to left edge (#7576)
  48635. if (navigator.zoomedMin === 0) {
  48636. fixedMin = navigator.reversedExtremes ?
  48637. unionExtremes.dataMax :
  48638. unionExtremes.dataMin;
  48639. }
  48640. ext = xAxis.navigatorAxis.toFixedRange(navigator.zoomedMin, navigator.zoomedMax, fixedMin, fixedMax);
  48641. if (defined(ext.min)) {
  48642. chart.xAxis[0].setExtremes(Math.min(ext.min, ext.max), Math.max(ext.min, ext.max), true,
  48643. // Run animation when clicking buttons, scrollbar track etc,
  48644. // but not when dragging handles or scrollbar
  48645. navigator.hasDragged ? false : null, {
  48646. trigger: 'navigator',
  48647. triggerOp: 'navigator-drag',
  48648. DOMEvent: DOMEvent // #1838
  48649. });
  48650. }
  48651. }
  48652. if (e.DOMType !== 'mousemove' &&
  48653. e.DOMType !== 'touchmove') {
  48654. navigator.grabbedLeft = navigator.grabbedRight =
  48655. navigator.grabbedCenter = navigator.fixedWidth =
  48656. navigator.fixedExtreme = navigator.otherHandlePos =
  48657. navigator.hasDragged = navigator.dragOffset = null;
  48658. }
  48659. // Update position of navigator shades, outline and handles (#12573)
  48660. if (navigator.navigatorEnabled &&
  48661. isNumber(navigator.zoomedMin) &&
  48662. isNumber(navigator.zoomedMax)) {
  48663. zoomedMin = Math.round(navigator.zoomedMin);
  48664. zoomedMax = Math.round(navigator.zoomedMax);
  48665. if (navigator.shades) {
  48666. navigator.drawMasks(zoomedMin, zoomedMax, inverted, verb);
  48667. }
  48668. if (navigator.outline) {
  48669. navigator.drawOutline(zoomedMin, zoomedMax, inverted, verb);
  48670. }
  48671. if (navigator.navigatorOptions.handles.enabled &&
  48672. Object.keys(navigator.handles).length ===
  48673. navigator.handles.length) {
  48674. navigator.drawHandle(zoomedMin, 0, inverted, verb);
  48675. navigator.drawHandle(zoomedMax, 1, inverted, verb);
  48676. }
  48677. }
  48678. };
  48679. /**
  48680. * Removes the event handlers attached previously with addEvents.
  48681. *
  48682. * @private
  48683. * @function Highcharts.Navigator#removeEvents
  48684. * @return {void}
  48685. */
  48686. Navigator.prototype.removeEvents = function () {
  48687. if (this.eventsToUnbind) {
  48688. this.eventsToUnbind.forEach(function (unbind) {
  48689. unbind();
  48690. });
  48691. this.eventsToUnbind = void 0;
  48692. }
  48693. this.removeBaseSeriesEvents();
  48694. };
  48695. /**
  48696. * Remove data events.
  48697. *
  48698. * @private
  48699. * @function Highcharts.Navigator#removeBaseSeriesEvents
  48700. * @return {void}
  48701. */
  48702. Navigator.prototype.removeBaseSeriesEvents = function () {
  48703. var baseSeries = this.baseSeries || [];
  48704. if (this.navigatorEnabled && baseSeries[0]) {
  48705. if (this.navigatorOptions.adaptToUpdatedData !== false) {
  48706. baseSeries.forEach(function (series) {
  48707. removeEvent(series, 'updatedData', this.updatedDataHandler);
  48708. }, this);
  48709. }
  48710. // We only listen for extremes-events on the first baseSeries
  48711. if (baseSeries[0].xAxis) {
  48712. removeEvent(baseSeries[0].xAxis, 'foundExtremes', this.modifyBaseAxisExtremes);
  48713. }
  48714. }
  48715. };
  48716. /**
  48717. * Initialize the Navigator object
  48718. *
  48719. * @private
  48720. * @function Highcharts.Navigator#init
  48721. *
  48722. * @param {Highcharts.Chart} chart
  48723. */
  48724. Navigator.prototype.init = function (chart) {
  48725. var chartOptions = chart.options,
  48726. navigatorOptions = chartOptions.navigator,
  48727. navigatorEnabled = navigatorOptions.enabled,
  48728. scrollbarOptions = chartOptions.scrollbar,
  48729. scrollbarEnabled = scrollbarOptions.enabled,
  48730. height = navigatorEnabled ? navigatorOptions.height : 0,
  48731. scrollbarHeight = scrollbarEnabled ?
  48732. scrollbarOptions.height :
  48733. 0;
  48734. this.handles = [];
  48735. this.shades = [];
  48736. this.chart = chart;
  48737. this.setBaseSeries();
  48738. this.height = height;
  48739. this.scrollbarHeight = scrollbarHeight;
  48740. this.scrollbarEnabled = scrollbarEnabled;
  48741. this.navigatorEnabled = navigatorEnabled;
  48742. this.navigatorOptions = navigatorOptions;
  48743. this.scrollbarOptions = scrollbarOptions;
  48744. this.outlineHeight = height + scrollbarHeight;
  48745. this.opposite = pick(navigatorOptions.opposite, Boolean(!navigatorEnabled && chart.inverted)); // #6262
  48746. var navigator = this,
  48747. baseSeries = navigator.baseSeries,
  48748. xAxisIndex = chart.xAxis.length,
  48749. yAxisIndex = chart.yAxis.length,
  48750. baseXaxis = baseSeries && baseSeries[0] && baseSeries[0].xAxis ||
  48751. chart.xAxis[0] || { options: {} };
  48752. chart.isDirtyBox = true;
  48753. if (navigator.navigatorEnabled) {
  48754. // an x axis is required for scrollbar also
  48755. navigator.xAxis = new Axis(chart, merge({
  48756. // inherit base xAxis' break and ordinal options
  48757. breaks: baseXaxis.options.breaks,
  48758. ordinal: baseXaxis.options.ordinal
  48759. }, navigatorOptions.xAxis, {
  48760. id: 'navigator-x-axis',
  48761. yAxis: 'navigator-y-axis',
  48762. isX: true,
  48763. type: 'datetime',
  48764. index: xAxisIndex,
  48765. isInternal: true,
  48766. offset: 0,
  48767. keepOrdinalPadding: true,
  48768. startOnTick: false,
  48769. endOnTick: false,
  48770. minPadding: 0,
  48771. maxPadding: 0,
  48772. zoomEnabled: false
  48773. }, chart.inverted ? {
  48774. offsets: [scrollbarHeight, 0, -scrollbarHeight, 0],
  48775. width: height
  48776. } : {
  48777. offsets: [0, -scrollbarHeight, 0, scrollbarHeight],
  48778. height: height
  48779. }));
  48780. navigator.yAxis = new Axis(chart, merge(navigatorOptions.yAxis, {
  48781. id: 'navigator-y-axis',
  48782. alignTicks: false,
  48783. offset: 0,
  48784. index: yAxisIndex,
  48785. isInternal: true,
  48786. reversed: pick((navigatorOptions.yAxis && navigatorOptions.yAxis.reversed), (chart.yAxis[0] && chart.yAxis[0].reversed), false),
  48787. zoomEnabled: false
  48788. }, chart.inverted ? {
  48789. width: height
  48790. } : {
  48791. height: height
  48792. }));
  48793. // If we have a base series, initialize the navigator series
  48794. if (baseSeries || navigatorOptions.series.data) {
  48795. navigator.updateNavigatorSeries(false);
  48796. // If not, set up an event to listen for added series
  48797. }
  48798. else if (chart.series.length === 0) {
  48799. navigator.unbindRedraw = addEvent(chart, 'beforeRedraw', function () {
  48800. // We've got one, now add it as base
  48801. if (chart.series.length > 0 && !navigator.series) {
  48802. navigator.setBaseSeries();
  48803. navigator.unbindRedraw(); // reset
  48804. }
  48805. });
  48806. }
  48807. navigator.reversedExtremes = (chart.inverted && !navigator.xAxis.reversed) || (!chart.inverted && navigator.xAxis.reversed);
  48808. // Render items, so we can bind events to them:
  48809. navigator.renderElements();
  48810. // Add mouse events
  48811. navigator.addMouseEvents();
  48812. // in case of scrollbar only, fake an x axis to get translation
  48813. }
  48814. else {
  48815. navigator.xAxis = {
  48816. chart: chart,
  48817. navigatorAxis: {
  48818. fake: true
  48819. },
  48820. translate: function (value, reverse) {
  48821. var axis = chart.xAxis[0], ext = axis.getExtremes(), scrollTrackWidth = axis.len - 2 * scrollbarHeight, min = numExt('min', axis.options.min, ext.dataMin), valueRange = numExt('max', axis.options.max, ext.dataMax) - min;
  48822. return reverse ?
  48823. // from pixel to value
  48824. (value * valueRange / scrollTrackWidth) + min :
  48825. // from value to pixel
  48826. scrollTrackWidth * (value - min) / valueRange;
  48827. },
  48828. toPixels: function (value) {
  48829. return this.translate(value);
  48830. },
  48831. toValue: function (value) {
  48832. return this.translate(value, true);
  48833. }
  48834. };
  48835. navigator.xAxis.navigatorAxis.axis = navigator.xAxis;
  48836. navigator.xAxis.navigatorAxis.toFixedRange = (NavigatorAxis.AdditionsClass.prototype.toFixedRange.bind(navigator.xAxis.navigatorAxis));
  48837. }
  48838. // Initialize the scrollbar
  48839. if (chart.options.scrollbar.enabled) {
  48840. chart.scrollbar = navigator.scrollbar = new Scrollbar(chart.renderer, merge(chart.options.scrollbar, {
  48841. margin: navigator.navigatorEnabled ? 0 : 10,
  48842. vertical: chart.inverted
  48843. }), chart);
  48844. addEvent(navigator.scrollbar, 'changed', function (e) {
  48845. var range = navigator.size,
  48846. to = range * this.to,
  48847. from = range * this.from;
  48848. navigator.hasDragged = navigator.scrollbar.hasDragged;
  48849. navigator.render(0, 0, from, to);
  48850. if (chart.options.scrollbar.liveRedraw ||
  48851. (e.DOMType !== 'mousemove' &&
  48852. e.DOMType !== 'touchmove')) {
  48853. setTimeout(function () {
  48854. navigator.onMouseUp(e);
  48855. });
  48856. }
  48857. });
  48858. }
  48859. // Add data events
  48860. navigator.addBaseSeriesEvents();
  48861. // Add redraw events
  48862. navigator.addChartEvents();
  48863. };
  48864. /**
  48865. * Get the union data extremes of the chart - the outer data extremes of the
  48866. * base X axis and the navigator axis.
  48867. *
  48868. * @private
  48869. * @function Highcharts.Navigator#getUnionExtremes
  48870. * @param {boolean} [returnFalseOnNoBaseSeries]
  48871. * as the param says.
  48872. * @return {Highcharts.Dictionary<(number|undefined)>|undefined}
  48873. */
  48874. Navigator.prototype.getUnionExtremes = function (returnFalseOnNoBaseSeries) {
  48875. var baseAxis = this.chart.xAxis[0],
  48876. navAxis = this.xAxis,
  48877. navAxisOptions = navAxis.options,
  48878. baseAxisOptions = baseAxis.options,
  48879. ret;
  48880. if (!returnFalseOnNoBaseSeries || baseAxis.dataMin !== null) {
  48881. ret = {
  48882. dataMin: pick(// #4053
  48883. navAxisOptions && navAxisOptions.min, numExt('min', baseAxisOptions.min, baseAxis.dataMin, navAxis.dataMin, navAxis.min)),
  48884. dataMax: pick(navAxisOptions && navAxisOptions.max, numExt('max', baseAxisOptions.max, baseAxis.dataMax, navAxis.dataMax, navAxis.max))
  48885. };
  48886. }
  48887. return ret;
  48888. };
  48889. /**
  48890. * Set the base series and update the navigator series from this. With a bit
  48891. * of modification we should be able to make this an API method to be called
  48892. * from the outside
  48893. *
  48894. * @private
  48895. * @function Highcharts.Navigator#setBaseSeries
  48896. * @param {Highcharts.SeriesOptionsType} [baseSeriesOptions]
  48897. * Additional series options for a navigator
  48898. * @param {boolean} [redraw]
  48899. * Whether to redraw after update.
  48900. * @return {void}
  48901. */
  48902. Navigator.prototype.setBaseSeries = function (baseSeriesOptions, redraw) {
  48903. var chart = this.chart,
  48904. baseSeries = this.baseSeries = [];
  48905. baseSeriesOptions = (baseSeriesOptions ||
  48906. chart.options && chart.options.navigator.baseSeries ||
  48907. (chart.series.length ?
  48908. // Find the first non-navigator series (#8430)
  48909. find(chart.series, function (s) {
  48910. return !s.options.isInternal;
  48911. }).index :
  48912. 0));
  48913. // Iterate through series and add the ones that should be shown in
  48914. // navigator.
  48915. (chart.series || []).forEach(function (series, i) {
  48916. if (
  48917. // Don't include existing nav series
  48918. !series.options.isInternal &&
  48919. (series.options.showInNavigator ||
  48920. (i === baseSeriesOptions ||
  48921. series.options.id === baseSeriesOptions) &&
  48922. series.options.showInNavigator !== false)) {
  48923. baseSeries.push(series);
  48924. }
  48925. });
  48926. // When run after render, this.xAxis already exists
  48927. if (this.xAxis && !this.xAxis.navigatorAxis.fake) {
  48928. this.updateNavigatorSeries(true, redraw);
  48929. }
  48930. };
  48931. /**
  48932. * Update series in the navigator from baseSeries, adding new if does not
  48933. * exist.
  48934. *
  48935. * @private
  48936. * @function Highcharts.Navigator.updateNavigatorSeries
  48937. * @param {boolean} addEvents
  48938. * @param {boolean} [redraw]
  48939. * @return {void}
  48940. */
  48941. Navigator.prototype.updateNavigatorSeries = function (addEvents, redraw) {
  48942. var navigator = this,
  48943. chart = navigator.chart,
  48944. baseSeries = navigator.baseSeries,
  48945. baseOptions,
  48946. mergedNavSeriesOptions,
  48947. chartNavigatorSeriesOptions = navigator.navigatorOptions.series,
  48948. baseNavigatorOptions,
  48949. navSeriesMixin = {
  48950. enableMouseTracking: false,
  48951. index: null,
  48952. linkedTo: null,
  48953. group: 'nav',
  48954. padXAxis: false,
  48955. xAxis: 'navigator-x-axis',
  48956. yAxis: 'navigator-y-axis',
  48957. showInLegend: false,
  48958. stacking: void 0,
  48959. isInternal: true,
  48960. states: {
  48961. inactive: {
  48962. opacity: 1
  48963. }
  48964. }
  48965. },
  48966. // Remove navigator series that are no longer in the baseSeries
  48967. navigatorSeries = navigator.series =
  48968. (navigator.series || []).filter(function (navSeries) {
  48969. var base = navSeries.baseSeries;
  48970. if (baseSeries.indexOf(base) < 0) { // Not in array
  48971. // If there is still a base series connected to this
  48972. // series, remove event handler and reference.
  48973. if (base) {
  48974. removeEvent(base, 'updatedData', navigator.updatedDataHandler);
  48975. delete base.navigatorSeries;
  48976. }
  48977. // Kill the nav series. It may already have been
  48978. // destroyed (#8715).
  48979. if (navSeries.chart) {
  48980. navSeries.destroy();
  48981. }
  48982. return false;
  48983. }
  48984. return true;
  48985. });
  48986. // Go through each base series and merge the options to create new
  48987. // series
  48988. if (baseSeries && baseSeries.length) {
  48989. baseSeries.forEach(function eachBaseSeries(base) {
  48990. var linkedNavSeries = base.navigatorSeries,
  48991. userNavOptions = extend(
  48992. // Grab color and visibility from base as default
  48993. {
  48994. color: base.color,
  48995. visible: base.visible
  48996. }, !isArray(chartNavigatorSeriesOptions) ?
  48997. chartNavigatorSeriesOptions :
  48998. defaultOptions.navigator.series);
  48999. // Don't update if the series exists in nav and we have disabled
  49000. // adaptToUpdatedData.
  49001. if (linkedNavSeries &&
  49002. navigator.navigatorOptions.adaptToUpdatedData === false) {
  49003. return;
  49004. }
  49005. navSeriesMixin.name = 'Navigator ' + baseSeries.length;
  49006. baseOptions = base.options || {};
  49007. baseNavigatorOptions = baseOptions.navigatorOptions || {};
  49008. mergedNavSeriesOptions = merge(baseOptions, navSeriesMixin, userNavOptions, baseNavigatorOptions);
  49009. // Once nav series type is resolved, pick correct pointRange
  49010. mergedNavSeriesOptions.pointRange = pick(
  49011. // Stricte set pointRange in options
  49012. userNavOptions.pointRange, baseNavigatorOptions.pointRange,
  49013. // Fallback to default values, e.g. `null` for column
  49014. defaultOptions.plotOptions[mergedNavSeriesOptions.type || 'line'].pointRange);
  49015. // Merge data separately. Do a slice to avoid mutating the
  49016. // navigator options from base series (#4923).
  49017. var navigatorSeriesData = baseNavigatorOptions.data || userNavOptions.data;
  49018. navigator.hasNavigatorData =
  49019. navigator.hasNavigatorData || !!navigatorSeriesData;
  49020. mergedNavSeriesOptions.data =
  49021. navigatorSeriesData ||
  49022. baseOptions.data && baseOptions.data.slice(0);
  49023. // Update or add the series
  49024. if (linkedNavSeries && linkedNavSeries.options) {
  49025. linkedNavSeries.update(mergedNavSeriesOptions, redraw);
  49026. }
  49027. else {
  49028. base.navigatorSeries = chart.initSeries(mergedNavSeriesOptions);
  49029. base.navigatorSeries.baseSeries = base; // Store ref
  49030. navigatorSeries.push(base.navigatorSeries);
  49031. }
  49032. });
  49033. }
  49034. // If user has defined data (and no base series) or explicitly defined
  49035. // navigator.series as an array, we create these series on top of any
  49036. // base series.
  49037. if (chartNavigatorSeriesOptions.data &&
  49038. !(baseSeries && baseSeries.length) ||
  49039. isArray(chartNavigatorSeriesOptions)) {
  49040. navigator.hasNavigatorData = false;
  49041. // Allow navigator.series to be an array
  49042. chartNavigatorSeriesOptions =
  49043. splat(chartNavigatorSeriesOptions);
  49044. chartNavigatorSeriesOptions.forEach(function (userSeriesOptions, i) {
  49045. navSeriesMixin.name =
  49046. 'Navigator ' + (navigatorSeries.length + 1);
  49047. mergedNavSeriesOptions = merge(defaultOptions.navigator.series, {
  49048. // Since we don't have a base series to pull color from,
  49049. // try to fake it by using color from series with same
  49050. // index. Otherwise pull from the colors array. We need
  49051. // an explicit color as otherwise updates will increment
  49052. // color counter and we'll get a new color for each
  49053. // update of the nav series.
  49054. color: chart.series[i] &&
  49055. !chart.series[i].options.isInternal &&
  49056. chart.series[i].color ||
  49057. chart.options.colors[i] ||
  49058. chart.options.colors[0]
  49059. }, navSeriesMixin, userSeriesOptions);
  49060. mergedNavSeriesOptions.data = userSeriesOptions.data;
  49061. if (mergedNavSeriesOptions.data) {
  49062. navigator.hasNavigatorData = true;
  49063. navigatorSeries.push(chart.initSeries(mergedNavSeriesOptions));
  49064. }
  49065. });
  49066. }
  49067. if (addEvents) {
  49068. this.addBaseSeriesEvents();
  49069. }
  49070. };
  49071. /**
  49072. * Add data events.
  49073. * For example when main series is updated we need to recalculate extremes
  49074. *
  49075. * @private
  49076. * @function Highcharts.Navigator#addBaseSeriesEvent
  49077. * @return {void}
  49078. */
  49079. Navigator.prototype.addBaseSeriesEvents = function () {
  49080. var navigator = this,
  49081. baseSeries = navigator.baseSeries || [];
  49082. // Bind modified extremes event to first base's xAxis only.
  49083. // In event of > 1 base-xAxes, the navigator will ignore those.
  49084. // Adding this multiple times to the same axis is no problem, as
  49085. // duplicates should be discarded by the browser.
  49086. if (baseSeries[0] && baseSeries[0].xAxis) {
  49087. addEvent(baseSeries[0].xAxis, 'foundExtremes', this.modifyBaseAxisExtremes);
  49088. }
  49089. baseSeries.forEach(function (base) {
  49090. // Link base series show/hide to navigator series visibility
  49091. addEvent(base, 'show', function () {
  49092. if (this.navigatorSeries) {
  49093. this.navigatorSeries.setVisible(true, false);
  49094. }
  49095. });
  49096. addEvent(base, 'hide', function () {
  49097. if (this.navigatorSeries) {
  49098. this.navigatorSeries.setVisible(false, false);
  49099. }
  49100. });
  49101. // Respond to updated data in the base series, unless explicitily
  49102. // not adapting to data changes.
  49103. if (this.navigatorOptions.adaptToUpdatedData !== false) {
  49104. if (base.xAxis) {
  49105. addEvent(base, 'updatedData', this.updatedDataHandler);
  49106. }
  49107. }
  49108. // Handle series removal
  49109. addEvent(base, 'remove', function () {
  49110. if (this.navigatorSeries) {
  49111. erase(navigator.series, this.navigatorSeries);
  49112. if (defined(this.navigatorSeries.options)) {
  49113. this.navigatorSeries.remove(false);
  49114. }
  49115. delete this.navigatorSeries;
  49116. }
  49117. });
  49118. }, this);
  49119. };
  49120. /**
  49121. * Get minimum from all base series connected to the navigator
  49122. * @private
  49123. * @param {number} currentSeriesMin
  49124. * Minium from the current series
  49125. * @return {number} Minimum from all series
  49126. */
  49127. Navigator.prototype.getBaseSeriesMin = function (currentSeriesMin) {
  49128. return this.baseSeries.reduce(function (min, series) {
  49129. // (#10193)
  49130. return Math.min(min, series.xData ? series.xData[0] : min);
  49131. }, currentSeriesMin);
  49132. };
  49133. /**
  49134. * Set the navigator x axis extremes to reflect the total. The navigator
  49135. * extremes should always be the extremes of the union of all series in the
  49136. * chart as well as the navigator series.
  49137. *
  49138. * @private
  49139. * @function Highcharts.Navigator#modifyNavigatorAxisExtremes
  49140. */
  49141. Navigator.prototype.modifyNavigatorAxisExtremes = function () {
  49142. var xAxis = this.xAxis,
  49143. unionExtremes;
  49144. if (typeof xAxis.getExtremes !== 'undefined') {
  49145. unionExtremes = this.getUnionExtremes(true);
  49146. if (unionExtremes &&
  49147. (unionExtremes.dataMin !== xAxis.min ||
  49148. unionExtremes.dataMax !== xAxis.max)) {
  49149. xAxis.min = unionExtremes.dataMin;
  49150. xAxis.max = unionExtremes.dataMax;
  49151. }
  49152. }
  49153. };
  49154. /**
  49155. * Hook to modify the base axis extremes with information from the Navigator
  49156. *
  49157. * @private
  49158. * @function Highcharts.Navigator#modifyBaseAxisExtremes
  49159. */
  49160. Navigator.prototype.modifyBaseAxisExtremes = function () {
  49161. var baseXAxis = this,
  49162. navigator = baseXAxis.chart.navigator,
  49163. baseExtremes = baseXAxis.getExtremes(),
  49164. baseMin = baseExtremes.min,
  49165. baseMax = baseExtremes.max,
  49166. baseDataMin = baseExtremes.dataMin,
  49167. baseDataMax = baseExtremes.dataMax,
  49168. range = baseMax - baseMin,
  49169. stickToMin = navigator.stickToMin,
  49170. stickToMax = navigator.stickToMax,
  49171. overscroll = pick(baseXAxis.options.overscroll, 0),
  49172. newMax,
  49173. newMin,
  49174. navigatorSeries = navigator.series && navigator.series[0],
  49175. hasSetExtremes = !!baseXAxis.setExtremes,
  49176. // When the extremes have been set by range selector button, don't
  49177. // stick to min or max. The range selector buttons will handle the
  49178. // extremes. (#5489)
  49179. unmutable = baseXAxis.eventArgs &&
  49180. baseXAxis.eventArgs.trigger === 'rangeSelectorButton';
  49181. if (!unmutable) {
  49182. // If the zoomed range is already at the min, move it to the right
  49183. // as new data comes in
  49184. if (stickToMin) {
  49185. newMin = baseDataMin;
  49186. newMax = newMin + range;
  49187. }
  49188. // If the zoomed range is already at the max, move it to the right
  49189. // as new data comes in
  49190. if (stickToMax) {
  49191. newMax = baseDataMax + overscroll;
  49192. // If stickToMin is true, the new min value is set above
  49193. if (!stickToMin) {
  49194. newMin = Math.max(baseDataMin, // don't go below data extremes (#13184)
  49195. newMax - range, navigator.getBaseSeriesMin(navigatorSeries && navigatorSeries.xData ?
  49196. navigatorSeries.xData[0] :
  49197. -Number.MAX_VALUE));
  49198. }
  49199. }
  49200. // Update the extremes
  49201. if (hasSetExtremes && (stickToMin || stickToMax)) {
  49202. if (isNumber(newMin)) {
  49203. baseXAxis.min = baseXAxis.userMin = newMin;
  49204. baseXAxis.max = baseXAxis.userMax = newMax;
  49205. }
  49206. }
  49207. }
  49208. // Reset
  49209. navigator.stickToMin =
  49210. navigator.stickToMax = null;
  49211. };
  49212. /**
  49213. * Handler for updated data on the base series. When data is modified, the
  49214. * navigator series must reflect it. This is called from the Chart.redraw
  49215. * function before axis and series extremes are computed.
  49216. *
  49217. * @private
  49218. * @function Highcharts.Navigator#updateDataHandler
  49219. */
  49220. Navigator.prototype.updatedDataHandler = function () {
  49221. var navigator = this.chart.navigator,
  49222. baseSeries = this,
  49223. navigatorSeries = this.navigatorSeries,
  49224. xDataMin = navigator.getBaseSeriesMin(baseSeries.xData[0]);
  49225. // If the scrollbar is scrolled all the way to the right, keep right as
  49226. // new data comes in.
  49227. navigator.stickToMax = navigator.reversedExtremes ?
  49228. Math.round(navigator.zoomedMin) === 0 :
  49229. Math.round(navigator.zoomedMax) >= Math.round(navigator.size);
  49230. // Detect whether the zoomed area should stick to the minimum or
  49231. // maximum. If the current axis minimum falls outside the new updated
  49232. // dataset, we must adjust.
  49233. navigator.stickToMin = isNumber(baseSeries.xAxis.min) &&
  49234. (baseSeries.xAxis.min <= xDataMin) &&
  49235. (!this.chart.fixedRange || !navigator.stickToMax);
  49236. // Set the navigator series data to the new data of the base series
  49237. if (navigatorSeries && !navigator.hasNavigatorData) {
  49238. navigatorSeries.options.pointStart = baseSeries.xData[0];
  49239. navigatorSeries.setData(baseSeries.options.data, false, null, false); // #5414
  49240. }
  49241. };
  49242. /**
  49243. * Add chart events, like redrawing navigator, when chart requires that.
  49244. *
  49245. * @private
  49246. * @function Highcharts.Navigator#addChartEvents
  49247. * @return {void}
  49248. */
  49249. Navigator.prototype.addChartEvents = function () {
  49250. if (!this.eventsToUnbind) {
  49251. this.eventsToUnbind = [];
  49252. }
  49253. this.eventsToUnbind.push(
  49254. // Move the scrollbar after redraw, like after data updata even if
  49255. // axes don't redraw
  49256. addEvent(this.chart, 'redraw', function () {
  49257. var navigator = this.navigator,
  49258. xAxis = navigator && (navigator.baseSeries &&
  49259. navigator.baseSeries[0] &&
  49260. navigator.baseSeries[0].xAxis ||
  49261. this.xAxis[0]); // #5709, #13114
  49262. if (xAxis) {
  49263. navigator.render(xAxis.min,
  49264. xAxis.max);
  49265. }
  49266. }),
  49267. // Make room for the navigator, can be placed around the chart:
  49268. addEvent(this.chart, 'getMargins', function () {
  49269. var chart = this,
  49270. navigator = chart.navigator,
  49271. marginName = navigator.opposite ?
  49272. 'plotTop' : 'marginBottom';
  49273. if (chart.inverted) {
  49274. marginName = navigator.opposite ?
  49275. 'marginRight' : 'plotLeft';
  49276. }
  49277. chart[marginName] =
  49278. (chart[marginName] || 0) + (navigator.navigatorEnabled || !chart.inverted ?
  49279. navigator.outlineHeight :
  49280. 0) + navigator.navigatorOptions.margin;
  49281. }));
  49282. };
  49283. /**
  49284. * Destroys allocated elements.
  49285. *
  49286. * @private
  49287. * @function Highcharts.Navigator#destroy
  49288. */
  49289. Navigator.prototype.destroy = function () {
  49290. // Disconnect events added in addEvents
  49291. this.removeEvents();
  49292. if (this.xAxis) {
  49293. erase(this.chart.xAxis, this.xAxis);
  49294. erase(this.chart.axes, this.xAxis);
  49295. }
  49296. if (this.yAxis) {
  49297. erase(this.chart.yAxis, this.yAxis);
  49298. erase(this.chart.axes, this.yAxis);
  49299. }
  49300. // Destroy series
  49301. (this.series || []).forEach(function (s) {
  49302. if (s.destroy) {
  49303. s.destroy();
  49304. }
  49305. });
  49306. // Destroy properties
  49307. [
  49308. 'series', 'xAxis', 'yAxis', 'shades', 'outline', 'scrollbarTrack',
  49309. 'scrollbarRifles', 'scrollbarGroup', 'scrollbar', 'navigatorGroup',
  49310. 'rendered'
  49311. ].forEach(function (prop) {
  49312. if (this[prop] && this[prop].destroy) {
  49313. this[prop].destroy();
  49314. }
  49315. this[prop] = null;
  49316. }, this);
  49317. // Destroy elements in collection
  49318. [this.handles].forEach(function (coll) {
  49319. destroyObjectProperties(coll);
  49320. }, this);
  49321. };
  49322. return Navigator;
  49323. }());
  49324. // End of prototype
  49325. if (!H.Navigator) {
  49326. H.Navigator = Navigator;
  49327. NavigatorAxis.compose(Axis);
  49328. // For Stock charts. For x only zooming, do not to create the zoom button
  49329. // because X axis zooming is already allowed by the Navigator and Range
  49330. // selector. (#9285)
  49331. addEvent(Chart, 'beforeShowResetZoom', function () {
  49332. var chartOptions = this.options,
  49333. navigator = chartOptions.navigator,
  49334. rangeSelector = chartOptions.rangeSelector;
  49335. if (((navigator && navigator.enabled) ||
  49336. (rangeSelector && rangeSelector.enabled)) &&
  49337. ((!isTouchDevice && chartOptions.chart.zoomType === 'x') ||
  49338. (isTouchDevice && chartOptions.chart.pinchType === 'x'))) {
  49339. return false;
  49340. }
  49341. });
  49342. // Initialize navigator for stock charts
  49343. addEvent(Chart, 'beforeRender', function () {
  49344. var options = this.options;
  49345. if (options.navigator.enabled ||
  49346. options.scrollbar.enabled) {
  49347. this.scroller = this.navigator = new Navigator(this);
  49348. }
  49349. });
  49350. // For stock charts, extend the Chart.setChartSize method so that we can set
  49351. // the final top position of the navigator once the height of the chart,
  49352. // including the legend, is determined. #367. We can't use Chart.getMargins,
  49353. // because labels offsets are not calculated yet.
  49354. addEvent(Chart, 'afterSetChartSize', function () {
  49355. var legend = this.legend,
  49356. navigator = this.navigator,
  49357. scrollbarHeight,
  49358. legendOptions,
  49359. xAxis,
  49360. yAxis;
  49361. if (navigator) {
  49362. legendOptions = legend && legend.options;
  49363. xAxis = navigator.xAxis;
  49364. yAxis = navigator.yAxis;
  49365. scrollbarHeight = navigator.scrollbarHeight;
  49366. // Compute the top position
  49367. if (this.inverted) {
  49368. navigator.left = navigator.opposite ?
  49369. this.chartWidth - scrollbarHeight -
  49370. navigator.height :
  49371. this.spacing[3] + scrollbarHeight;
  49372. navigator.top = this.plotTop + scrollbarHeight;
  49373. }
  49374. else {
  49375. navigator.left = this.plotLeft + scrollbarHeight;
  49376. navigator.top = navigator.navigatorOptions.top ||
  49377. this.chartHeight -
  49378. navigator.height -
  49379. scrollbarHeight -
  49380. this.spacing[2] -
  49381. (this.rangeSelector && this.extraBottomMargin ?
  49382. this.rangeSelector.getHeight() :
  49383. 0) -
  49384. ((legendOptions &&
  49385. legendOptions.verticalAlign === 'bottom' &&
  49386. legendOptions.layout !== 'proximate' && // #13392
  49387. legendOptions.enabled &&
  49388. !legendOptions.floating) ?
  49389. legend.legendHeight +
  49390. pick(legendOptions.margin, 10) :
  49391. 0) -
  49392. (this.titleOffset ? this.titleOffset[2] : 0);
  49393. }
  49394. if (xAxis && yAxis) { // false if navigator is disabled (#904)
  49395. if (this.inverted) {
  49396. xAxis.options.left = yAxis.options.left = navigator.left;
  49397. }
  49398. else {
  49399. xAxis.options.top = yAxis.options.top = navigator.top;
  49400. }
  49401. xAxis.setAxisSize();
  49402. yAxis.setAxisSize();
  49403. }
  49404. }
  49405. });
  49406. // Merge options, if no scrolling exists yet
  49407. addEvent(Chart, 'update', function (e) {
  49408. var navigatorOptions = (e.options.navigator || {}),
  49409. scrollbarOptions = (e.options.scrollbar || {});
  49410. if (!this.navigator && !this.scroller &&
  49411. (navigatorOptions.enabled || scrollbarOptions.enabled)) {
  49412. merge(true, this.options.navigator, navigatorOptions);
  49413. merge(true, this.options.scrollbar, scrollbarOptions);
  49414. delete e.options.navigator;
  49415. delete e.options.scrollbar;
  49416. }
  49417. });
  49418. // Initialize navigator, if no scrolling exists yet
  49419. addEvent(Chart, 'afterUpdate', function (event) {
  49420. if (!this.navigator && !this.scroller &&
  49421. (this.options.navigator.enabled ||
  49422. this.options.scrollbar.enabled)) {
  49423. this.scroller = this.navigator = new Navigator(this);
  49424. if (pick(event.redraw, true)) {
  49425. this.redraw(event.animation); // #7067
  49426. }
  49427. }
  49428. });
  49429. // Handle adding new series
  49430. addEvent(Chart, 'afterAddSeries', function () {
  49431. if (this.navigator) {
  49432. // Recompute which series should be shown in navigator, and add them
  49433. this.navigator.setBaseSeries(null, false);
  49434. }
  49435. });
  49436. // Handle updating series
  49437. addEvent(Series, 'afterUpdate', function () {
  49438. if (this.chart.navigator && !this.options.isInternal) {
  49439. this.chart.navigator.setBaseSeries(null, false);
  49440. }
  49441. });
  49442. Chart.prototype.callbacks.push(function (chart) {
  49443. var extremes,
  49444. navigator = chart.navigator;
  49445. // Initialize the navigator
  49446. if (navigator && chart.xAxis[0]) {
  49447. extremes = chart.xAxis[0].getExtremes();
  49448. navigator.render(extremes.min, extremes.max);
  49449. }
  49450. });
  49451. }
  49452. H.Navigator = Navigator;
  49453. return H.Navigator;
  49454. });
  49455. _registerModule(_modules, 'Core/Axis/OrdinalAxis.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Globals.js'], _modules['Core/Series/Series.js'], _modules['Core/Utilities.js'], _modules['Core/Chart/Chart.js']], function (Axis, H, Series, U, Chart) {
  49456. /* *
  49457. *
  49458. * (c) 2010-2021 Torstein Honsi
  49459. *
  49460. * License: www.highcharts.com/license
  49461. *
  49462. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  49463. *
  49464. * */
  49465. var addEvent = U.addEvent,
  49466. css = U.css,
  49467. defined = U.defined,
  49468. error = U.error,
  49469. pick = U.pick,
  49470. timeUnits = U.timeUnits;
  49471. // Has a dependency on Navigator due to the use of Axis.toFixedRange
  49472. /**
  49473. * Extends the axis with ordinal support.
  49474. * @private
  49475. */
  49476. var OrdinalAxis;
  49477. (function (OrdinalAxis) {
  49478. /* *
  49479. *
  49480. * Classes
  49481. *
  49482. * */
  49483. /**
  49484. * @private
  49485. */
  49486. var Composition = /** @class */ (function () {
  49487. /* *
  49488. *
  49489. * Constructors
  49490. *
  49491. * */
  49492. /**
  49493. * @private
  49494. */
  49495. function Composition(axis) {
  49496. this.index = {};
  49497. this.axis = axis;
  49498. }
  49499. /* *
  49500. *
  49501. * Functions
  49502. *
  49503. * */
  49504. /**
  49505. * Calculate the ordinal positions before tick positions are calculated.
  49506. *
  49507. * @private
  49508. */
  49509. Composition.prototype.beforeSetTickPositions = function () {
  49510. var axis = this.axis,
  49511. ordinal = axis.ordinal,
  49512. len,
  49513. ordinalPositions = [],
  49514. uniqueOrdinalPositions,
  49515. useOrdinal = false,
  49516. dist,
  49517. extremes = axis.getExtremes(),
  49518. min = extremes.min,
  49519. max = extremes.max,
  49520. minIndex,
  49521. maxIndex,
  49522. slope,
  49523. hasBreaks = axis.isXAxis && !!axis.options.breaks,
  49524. isOrdinal = axis.options.ordinal,
  49525. overscrollPointsRange = Number.MAX_VALUE,
  49526. ignoreHiddenSeries = axis.chart.options.chart.ignoreHiddenSeries,
  49527. i,
  49528. hasBoostedSeries;
  49529. // Apply the ordinal logic
  49530. if (isOrdinal || hasBreaks) { // #4167 YAxis is never ordinal ?
  49531. axis.series.forEach(function (series, i) {
  49532. uniqueOrdinalPositions = [];
  49533. if ((!ignoreHiddenSeries || series.visible !== false) &&
  49534. (series.takeOrdinalPosition !== false || hasBreaks)) {
  49535. // concatenate the processed X data into the existing
  49536. // positions, or the empty array
  49537. ordinalPositions = ordinalPositions.concat(series.processedXData);
  49538. len = ordinalPositions.length;
  49539. // remove duplicates (#1588)
  49540. ordinalPositions.sort(function (a, b) {
  49541. // without a custom function it is sorted as strings
  49542. return a - b;
  49543. });
  49544. overscrollPointsRange = Math.min(overscrollPointsRange, pick(
  49545. // Check for a single-point series:
  49546. series.closestPointRange, overscrollPointsRange));
  49547. if (len) {
  49548. i = 0;
  49549. while (i < len - 1) {
  49550. if (ordinalPositions[i] !== ordinalPositions[i + 1]) {
  49551. uniqueOrdinalPositions.push(ordinalPositions[i + 1]);
  49552. }
  49553. i++;
  49554. }
  49555. // Check first item:
  49556. if (uniqueOrdinalPositions[0] !== ordinalPositions[0]) {
  49557. uniqueOrdinalPositions.unshift(ordinalPositions[0]);
  49558. }
  49559. ordinalPositions = uniqueOrdinalPositions;
  49560. }
  49561. }
  49562. if (series.isSeriesBoosting) {
  49563. hasBoostedSeries = true;
  49564. }
  49565. });
  49566. if (hasBoostedSeries) {
  49567. ordinalPositions.length = 0;
  49568. }
  49569. // cache the length
  49570. len = ordinalPositions.length;
  49571. // Check if we really need the overhead of mapping axis data
  49572. // against the ordinal positions. If the series consist of
  49573. // evenly spaced data any way, we don't need any ordinal logic.
  49574. if (len > 2) { // two points have equal distance by default
  49575. dist = ordinalPositions[1] - ordinalPositions[0];
  49576. i = len - 1;
  49577. while (i-- && !useOrdinal) {
  49578. if (ordinalPositions[i + 1] - ordinalPositions[i] !== dist) {
  49579. useOrdinal = true;
  49580. }
  49581. }
  49582. // When zooming in on a week, prevent axis padding for
  49583. // weekends even though the data within the week is evenly
  49584. // spaced.
  49585. if (!axis.options.keepOrdinalPadding &&
  49586. (ordinalPositions[0] - min > dist ||
  49587. max - ordinalPositions[ordinalPositions.length - 1] >
  49588. dist)) {
  49589. useOrdinal = true;
  49590. }
  49591. }
  49592. else if (axis.options.overscroll) {
  49593. if (len === 2) {
  49594. // Exactly two points, distance for overscroll is fixed:
  49595. overscrollPointsRange =
  49596. ordinalPositions[1] - ordinalPositions[0];
  49597. }
  49598. else if (len === 1) {
  49599. // We have just one point, closest distance is unknown.
  49600. // Assume then it is last point and overscrolled range:
  49601. overscrollPointsRange = axis.options.overscroll;
  49602. ordinalPositions = [
  49603. ordinalPositions[0],
  49604. ordinalPositions[0] + overscrollPointsRange
  49605. ];
  49606. }
  49607. else {
  49608. // In case of zooming in on overscrolled range, stick to
  49609. // the old range:
  49610. overscrollPointsRange = ordinal.overscrollPointsRange;
  49611. }
  49612. }
  49613. // Record the slope and offset to compute the linear values from
  49614. // the array index. Since the ordinal positions may exceed the
  49615. // current range, get the start and end positions within it
  49616. // (#719, #665b)
  49617. if (useOrdinal) {
  49618. if (axis.options.overscroll) {
  49619. ordinal.overscrollPointsRange = overscrollPointsRange;
  49620. ordinalPositions = ordinalPositions.concat(ordinal.getOverscrollPositions());
  49621. }
  49622. // Register
  49623. ordinal.positions = ordinalPositions;
  49624. // This relies on the ordinalPositions being set. Use
  49625. // Math.max and Math.min to prevent padding on either sides
  49626. // of the data.
  49627. minIndex = axis.ordinal2lin(// #5979
  49628. Math.max(min, ordinalPositions[0]), true);
  49629. maxIndex = Math.max(axis.ordinal2lin(Math.min(max, ordinalPositions[ordinalPositions.length - 1]), true), 1); // #3339
  49630. // Set the slope and offset of the values compared to the
  49631. // indices in the ordinal positions
  49632. ordinal.slope = slope = (max - min) / (maxIndex - minIndex);
  49633. ordinal.offset = min - (minIndex * slope);
  49634. }
  49635. else {
  49636. ordinal.overscrollPointsRange = pick(axis.closestPointRange, ordinal.overscrollPointsRange);
  49637. ordinal.positions = axis.ordinal.slope = ordinal.offset =
  49638. void 0;
  49639. }
  49640. }
  49641. axis.isOrdinal = isOrdinal && useOrdinal; // #3818, #4196, #4926
  49642. ordinal.groupIntervalFactor = null; // reset for next run
  49643. };
  49644. /**
  49645. * Get the ordinal positions for the entire data set. This is necessary
  49646. * in chart panning because we need to find out what points or data
  49647. * groups are available outside the visible range. When a panning
  49648. * operation starts, if an index for the given grouping does not exists,
  49649. * it is created and cached. This index is deleted on updated data, so
  49650. * it will be regenerated the next time a panning operation starts.
  49651. *
  49652. * @private
  49653. */
  49654. Composition.prototype.getExtendedPositions = function () {
  49655. var ordinal = this,
  49656. axis = ordinal.axis,
  49657. axisProto = axis.constructor.prototype,
  49658. chart = axis.chart,
  49659. grouping = axis.series[0].currentDataGrouping,
  49660. ordinalIndex = ordinal.index,
  49661. key = grouping ?
  49662. grouping.count + grouping.unitName :
  49663. 'raw',
  49664. overscroll = axis.options.overscroll,
  49665. extremes = axis.getExtremes(),
  49666. fakeAxis,
  49667. fakeSeries;
  49668. // If this is the first time, or the ordinal index is deleted by
  49669. // updatedData,
  49670. // create it.
  49671. if (!ordinalIndex) {
  49672. ordinalIndex = ordinal.index = {};
  49673. }
  49674. if (!ordinalIndex[key]) {
  49675. // Create a fake axis object where the extended ordinal
  49676. // positions are emulated
  49677. fakeAxis = {
  49678. series: [],
  49679. chart: chart,
  49680. getExtremes: function () {
  49681. return {
  49682. min: extremes.dataMin,
  49683. max: extremes.dataMax + overscroll
  49684. };
  49685. },
  49686. options: {
  49687. ordinal: true
  49688. },
  49689. ordinal: {},
  49690. ordinal2lin: axisProto.ordinal2lin,
  49691. val2lin: axisProto.val2lin // #2590
  49692. };
  49693. fakeAxis.ordinal.axis = fakeAxis;
  49694. // Add the fake series to hold the full data, then apply
  49695. // processData to it
  49696. axis.series.forEach(function (series) {
  49697. fakeSeries = {
  49698. xAxis: fakeAxis,
  49699. xData: series.xData.slice(),
  49700. chart: chart,
  49701. destroyGroupedData: H.noop,
  49702. getProcessedData: Series.prototype.getProcessedData
  49703. };
  49704. fakeSeries.xData = fakeSeries.xData.concat(ordinal.getOverscrollPositions());
  49705. fakeSeries.options = {
  49706. dataGrouping: grouping ? {
  49707. enabled: true,
  49708. forced: true,
  49709. // doesn't matter which, use the fastest
  49710. approximation: 'open',
  49711. units: [[
  49712. grouping.unitName,
  49713. [grouping.count]
  49714. ]]
  49715. } : {
  49716. enabled: false
  49717. }
  49718. };
  49719. series.processData.apply(fakeSeries);
  49720. fakeAxis.series.push(fakeSeries);
  49721. });
  49722. // Run beforeSetTickPositions to compute the ordinalPositions
  49723. axis.ordinal.beforeSetTickPositions.apply({ axis: fakeAxis });
  49724. // Cache it
  49725. ordinalIndex[key] = fakeAxis.ordinal.positions;
  49726. }
  49727. return ordinalIndex[key];
  49728. };
  49729. /**
  49730. * Find the factor to estimate how wide the plot area would have been if
  49731. * ordinal gaps were included. This value is used to compute an imagined
  49732. * plot width in order to establish the data grouping interval.
  49733. *
  49734. * A real world case is the intraday-candlestick example. Without this
  49735. * logic, it would show the correct data grouping when viewing a range
  49736. * within each day, but once moving the range to include the gap between
  49737. * two days, the interval would include the cut-away night hours and the
  49738. * data grouping would be wrong. So the below method tries to compensate
  49739. * by identifying the most common point interval, in this case days.
  49740. *
  49741. * An opposite case is presented in issue #718. We have a long array of
  49742. * daily data, then one point is appended one hour after the last point.
  49743. * We expect the data grouping not to change.
  49744. *
  49745. * In the future, if we find cases where this estimation doesn't work
  49746. * optimally, we might need to add a second pass to the data grouping
  49747. * logic, where we do another run with a greater interval if the number
  49748. * of data groups is more than a certain fraction of the desired group
  49749. * count.
  49750. *
  49751. * @private
  49752. */
  49753. Composition.prototype.getGroupIntervalFactor = function (xMin, xMax, series) {
  49754. var ordinal = this,
  49755. axis = ordinal.axis,
  49756. i,
  49757. processedXData = series.processedXData,
  49758. len = processedXData.length,
  49759. distances = [],
  49760. median,
  49761. groupIntervalFactor = ordinal.groupIntervalFactor;
  49762. // Only do this computation for the first series, let the other
  49763. // inherit it (#2416)
  49764. if (!groupIntervalFactor) {
  49765. // Register all the distances in an array
  49766. for (i = 0; i < len - 1; i++) {
  49767. distances[i] =
  49768. processedXData[i + 1] - processedXData[i];
  49769. }
  49770. // Sort them and find the median
  49771. distances.sort(function (a, b) {
  49772. return a - b;
  49773. });
  49774. median = distances[Math.floor(len / 2)];
  49775. // Compensate for series that don't extend through the entire
  49776. // axis extent. #1675.
  49777. xMin = Math.max(xMin, processedXData[0]);
  49778. xMax = Math.min(xMax, processedXData[len - 1]);
  49779. ordinal.groupIntervalFactor = groupIntervalFactor =
  49780. (len * median) / (xMax - xMin);
  49781. }
  49782. // Return the factor needed for data grouping
  49783. return groupIntervalFactor;
  49784. };
  49785. /**
  49786. * Get ticks for an ordinal axis within a range where points don't
  49787. * exist. It is required when overscroll is enabled. We can't base on
  49788. * points, because we may not have any, so we use approximated
  49789. * pointRange and generate these ticks between Axis.dataMax,
  49790. * Axis.dataMax + Axis.overscroll evenly spaced. Used in panning and
  49791. * navigator scrolling.
  49792. *
  49793. * @private
  49794. */
  49795. Composition.prototype.getOverscrollPositions = function () {
  49796. var ordinal = this,
  49797. axis = ordinal.axis,
  49798. extraRange = axis.options.overscroll,
  49799. distance = ordinal.overscrollPointsRange,
  49800. positions = [],
  49801. max = axis.dataMax;
  49802. if (defined(distance)) {
  49803. // Max + pointRange because we need to scroll to the last
  49804. positions.push(max);
  49805. while (max <= axis.dataMax + extraRange) {
  49806. max += distance;
  49807. positions.push(max);
  49808. }
  49809. }
  49810. return positions;
  49811. };
  49812. /**
  49813. * Make the tick intervals closer because the ordinal gaps make the
  49814. * ticks spread out or cluster.
  49815. *
  49816. * @private
  49817. */
  49818. Composition.prototype.postProcessTickInterval = function (tickInterval) {
  49819. // Problem: https://jsfiddle.net/highcharts/FQm4E/1/
  49820. // This is a case where this algorithm doesn't work optimally. In
  49821. // this case, the tick labels are spread out per week, but all the
  49822. // gaps reside within weeks. So we have a situation where the labels
  49823. // are courser than the ordinal gaps, and thus the tick interval
  49824. // should not be altered.
  49825. var ordinal = this,
  49826. axis = ordinal.axis,
  49827. ordinalSlope = ordinal.slope,
  49828. ret;
  49829. if (ordinalSlope) {
  49830. if (!axis.options.breaks) {
  49831. ret = tickInterval / (ordinalSlope / axis.closestPointRange);
  49832. }
  49833. else {
  49834. ret = axis.closestPointRange || tickInterval; // #7275
  49835. }
  49836. }
  49837. else {
  49838. ret = tickInterval;
  49839. }
  49840. return ret;
  49841. };
  49842. return Composition;
  49843. }());
  49844. OrdinalAxis.Composition = Composition;
  49845. /* *
  49846. *
  49847. * Functions
  49848. *
  49849. * */
  49850. /**
  49851. * Extends the axis with ordinal support.
  49852. *
  49853. * @private
  49854. *
  49855. * @param AxisClass
  49856. * Axis class to extend.
  49857. *
  49858. * @param ChartClass
  49859. * Chart class to use.
  49860. *
  49861. * @param SeriesClass
  49862. * Series class to use.
  49863. */
  49864. function compose(AxisClass, ChartClass, SeriesClass) {
  49865. AxisClass.keepProps.push('ordinal');
  49866. var axisProto = AxisClass.prototype;
  49867. /**
  49868. * In an ordinal axis, there might be areas with dense consentrations of
  49869. * points, then large gaps between some. Creating equally distributed
  49870. * ticks over this entire range may lead to a huge number of ticks that
  49871. * will later be removed. So instead, break the positions up in
  49872. * segments, find the tick positions for each segment then concatenize
  49873. * them. This method is used from both data grouping logic and X axis
  49874. * tick position logic.
  49875. *
  49876. * @private
  49877. */
  49878. AxisClass.prototype.getTimeTicks = function (normalizedInterval, min, max, startOfWeek, positions, closestDistance, findHigherRanks) {
  49879. if (positions === void 0) { positions = []; }
  49880. if (closestDistance === void 0) { closestDistance = 0; }
  49881. var start = 0,
  49882. end,
  49883. segmentPositions,
  49884. higherRanks = {},
  49885. hasCrossedHigherRank,
  49886. info,
  49887. posLength,
  49888. outsideMax,
  49889. groupPositions = [],
  49890. lastGroupPosition = -Number.MAX_VALUE,
  49891. tickPixelIntervalOption = this.options.tickPixelInterval,
  49892. time = this.chart.time,
  49893. // Record all the start positions of a segment, to use when
  49894. // deciding what's a gap in the data.
  49895. segmentStarts = [];
  49896. // The positions are not always defined, for example for ordinal
  49897. // positions when data has regular interval (#1557, #2090)
  49898. if ((!this.options.ordinal && !this.options.breaks) ||
  49899. !positions ||
  49900. positions.length < 3 ||
  49901. typeof min === 'undefined') {
  49902. return time.getTimeTicks.apply(time, arguments);
  49903. }
  49904. // Analyze the positions array to split it into segments on gaps
  49905. // larger than 5 times the closest distance. The closest distance is
  49906. // already found at this point, so we reuse that instead of
  49907. // computing it again.
  49908. posLength = positions.length;
  49909. for (end = 0; end < posLength; end++) {
  49910. outsideMax = end && positions[end - 1] > max;
  49911. if (positions[end] < min) { // Set the last position before min
  49912. start = end;
  49913. }
  49914. if (end === posLength - 1 ||
  49915. positions[end + 1] - positions[end] > closestDistance * 5 ||
  49916. outsideMax) {
  49917. // For each segment, calculate the tick positions from the
  49918. // getTimeTicks utility function. The interval will be the
  49919. // same regardless of how long the segment is.
  49920. if (positions[end] > lastGroupPosition) { // #1475
  49921. segmentPositions = time.getTimeTicks(normalizedInterval, positions[start], positions[end], startOfWeek);
  49922. // Prevent duplicate groups, for example for multiple
  49923. // segments within one larger time frame (#1475)
  49924. while (segmentPositions.length &&
  49925. segmentPositions[0] <= lastGroupPosition) {
  49926. segmentPositions.shift();
  49927. }
  49928. if (segmentPositions.length) {
  49929. lastGroupPosition =
  49930. segmentPositions[segmentPositions.length - 1];
  49931. }
  49932. segmentStarts.push(groupPositions.length);
  49933. groupPositions = groupPositions.concat(segmentPositions);
  49934. }
  49935. // Set start of next segment
  49936. start = end + 1;
  49937. }
  49938. if (outsideMax) {
  49939. break;
  49940. }
  49941. }
  49942. // Get the grouping info from the last of the segments. The info is
  49943. // the same for all segments.
  49944. if (segmentPositions) {
  49945. info = segmentPositions.info;
  49946. // Optionally identify ticks with higher rank, for example
  49947. // when the ticks have crossed midnight.
  49948. if (findHigherRanks && info.unitRange <= timeUnits.hour) {
  49949. end = groupPositions.length - 1;
  49950. // Compare points two by two
  49951. for (start = 1; start < end; start++) {
  49952. if (time.dateFormat('%d', groupPositions[start]) !==
  49953. time.dateFormat('%d', groupPositions[start - 1])) {
  49954. higherRanks[groupPositions[start]] = 'day';
  49955. hasCrossedHigherRank = true;
  49956. }
  49957. }
  49958. // If the complete array has crossed midnight, we want
  49959. // to mark the first positions also as higher rank
  49960. if (hasCrossedHigherRank) {
  49961. higherRanks[groupPositions[0]] = 'day';
  49962. }
  49963. info.higherRanks = higherRanks;
  49964. }
  49965. // Save the info
  49966. info.segmentStarts = segmentStarts;
  49967. groupPositions.info = info;
  49968. }
  49969. else {
  49970. error(12, false, this.chart);
  49971. }
  49972. // Don't show ticks within a gap in the ordinal axis, where the
  49973. // space between two points is greater than a portion of the tick
  49974. // pixel interval
  49975. if (findHigherRanks && defined(tickPixelIntervalOption)) {
  49976. var length = groupPositions.length,
  49977. i = length,
  49978. itemToRemove,
  49979. translated,
  49980. translatedArr = [],
  49981. lastTranslated,
  49982. medianDistance,
  49983. distance,
  49984. distances = [];
  49985. // Find median pixel distance in order to keep a reasonably even
  49986. // distance between ticks (#748)
  49987. while (i--) {
  49988. translated = this.translate(groupPositions[i]);
  49989. if (lastTranslated) {
  49990. distances[i] = lastTranslated - translated;
  49991. }
  49992. translatedArr[i] = lastTranslated = translated;
  49993. }
  49994. distances.sort();
  49995. medianDistance = distances[Math.floor(distances.length / 2)];
  49996. if (medianDistance < tickPixelIntervalOption * 0.6) {
  49997. medianDistance = null;
  49998. }
  49999. // Now loop over again and remove ticks where needed
  50000. i = groupPositions[length - 1] > max ? length - 1 : length; // #817
  50001. lastTranslated = void 0;
  50002. while (i--) {
  50003. translated = translatedArr[i];
  50004. distance = Math.abs(lastTranslated - translated);
  50005. // #4175 - when axis is reversed, the distance, is negative
  50006. // but tickPixelIntervalOption positive, so we need to
  50007. // compare the same values
  50008. // Remove ticks that are closer than 0.6 times the pixel
  50009. // interval from the one to the right, but not if it is
  50010. // close to the median distance (#748).
  50011. if (lastTranslated &&
  50012. distance < tickPixelIntervalOption * 0.8 &&
  50013. (medianDistance === null || distance < medianDistance * 0.8)) {
  50014. // Is this a higher ranked position with a normal
  50015. // position to the right?
  50016. if (higherRanks[groupPositions[i]] &&
  50017. !higherRanks[groupPositions[i + 1]]) {
  50018. // Yes: remove the lower ranked neighbour to the
  50019. // right
  50020. itemToRemove = i + 1;
  50021. lastTranslated = translated; // #709
  50022. }
  50023. else {
  50024. // No: remove this one
  50025. itemToRemove = i;
  50026. }
  50027. groupPositions.splice(itemToRemove, 1);
  50028. }
  50029. else {
  50030. lastTranslated = translated;
  50031. }
  50032. }
  50033. }
  50034. return groupPositions;
  50035. };
  50036. /**
  50037. * Translate from linear (internal) to axis value.
  50038. *
  50039. * @private
  50040. * @function Highcharts.Axis#lin2val
  50041. *
  50042. * @param {number} val
  50043. * The linear abstracted value.
  50044. *
  50045. * @param {boolean} [fromIndex]
  50046. * Translate from an index in the ordinal positions rather than a
  50047. * value.
  50048. *
  50049. * @return {number}
  50050. */
  50051. axisProto.lin2val = function (val, fromIndex) {
  50052. var axis = this,
  50053. ordinal = axis.ordinal,
  50054. ordinalPositions = ordinal.positions,
  50055. ret;
  50056. // the visible range contains only equally spaced values
  50057. if (!ordinalPositions) {
  50058. ret = val;
  50059. }
  50060. else {
  50061. var ordinalSlope = ordinal.slope,
  50062. ordinalOffset = ordinal.offset,
  50063. i = ordinalPositions.length - 1,
  50064. linearEquivalentLeft,
  50065. linearEquivalentRight,
  50066. distance;
  50067. // Handle the case where we translate from the index directly,
  50068. // used only when panning an ordinal axis
  50069. if (fromIndex) {
  50070. if (val < 0) { // out of range, in effect panning to the left
  50071. val = ordinalPositions[0];
  50072. }
  50073. else if (val > i) { // out of range, panning to the right
  50074. val = ordinalPositions[i];
  50075. }
  50076. else { // split it up
  50077. i = Math.floor(val);
  50078. distance = val - i; // the decimal
  50079. }
  50080. // Loop down along the ordinal positions. When the linear
  50081. // equivalent of i matches an ordinal position, interpolate
  50082. // between the left and right values.
  50083. }
  50084. else {
  50085. while (i--) {
  50086. linearEquivalentLeft =
  50087. (ordinalSlope * i) + ordinalOffset;
  50088. if (val >= linearEquivalentLeft) {
  50089. linearEquivalentRight =
  50090. (ordinalSlope *
  50091. (i + 1)) +
  50092. ordinalOffset;
  50093. // something between 0 and 1
  50094. distance = (val - linearEquivalentLeft) /
  50095. (linearEquivalentRight - linearEquivalentLeft);
  50096. break;
  50097. }
  50098. }
  50099. }
  50100. // If the index is within the range of the ordinal positions,
  50101. // return the associated or interpolated value. If not, just
  50102. // return the value.
  50103. return (typeof distance !== 'undefined' &&
  50104. typeof ordinalPositions[i] !== 'undefined' ?
  50105. ordinalPositions[i] + (distance ?
  50106. distance *
  50107. (ordinalPositions[i + 1] - ordinalPositions[i]) :
  50108. 0) :
  50109. val);
  50110. }
  50111. return ret;
  50112. };
  50113. /**
  50114. * Translate from a linear axis value to the corresponding ordinal axis
  50115. * position. If there are no gaps in the ordinal axis this will be the
  50116. * same. The translated value is the value that the point would have if
  50117. * the axis were linear, using the same min and max.
  50118. *
  50119. * @private
  50120. * @function Highcharts.Axis#val2lin
  50121. *
  50122. * @param {number} val
  50123. * The axis value.
  50124. *
  50125. * @param {boolean} [toIndex]
  50126. * Whether to return the index in the ordinalPositions or the new value.
  50127. *
  50128. * @return {number}
  50129. */
  50130. axisProto.val2lin = function (val, toIndex) {
  50131. var axis = this,
  50132. ordinal = axis.ordinal,
  50133. ordinalPositions = ordinal.positions,
  50134. ret;
  50135. if (!ordinalPositions) {
  50136. ret = val;
  50137. }
  50138. else {
  50139. var ordinalLength = ordinalPositions.length,
  50140. i,
  50141. distance,
  50142. ordinalIndex;
  50143. // first look for an exact match in the ordinalpositions array
  50144. i = ordinalLength;
  50145. while (i--) {
  50146. if (ordinalPositions[i] === val) {
  50147. ordinalIndex = i;
  50148. break;
  50149. }
  50150. }
  50151. // if that failed, find the intermediate position between the
  50152. // two nearest values
  50153. i = ordinalLength - 1;
  50154. while (i--) {
  50155. if (val > ordinalPositions[i] || i === 0) { // interpolate
  50156. // something between 0 and 1
  50157. distance = (val - ordinalPositions[i]) /
  50158. (ordinalPositions[i + 1] - ordinalPositions[i]);
  50159. ordinalIndex = i + distance;
  50160. break;
  50161. }
  50162. }
  50163. ret = toIndex ?
  50164. ordinalIndex :
  50165. ordinal.slope *
  50166. (ordinalIndex || 0) +
  50167. ordinal.offset;
  50168. }
  50169. return ret;
  50170. };
  50171. // Record this to prevent overwriting by broken-axis module (#5979)
  50172. axisProto.ordinal2lin = axisProto.val2lin;
  50173. /* eslint-disable no-invalid-this */
  50174. addEvent(AxisClass, 'afterInit', function () {
  50175. var axis = this;
  50176. if (!axis.ordinal) {
  50177. axis.ordinal = new OrdinalAxis.Composition(axis);
  50178. }
  50179. });
  50180. addEvent(AxisClass, 'foundExtremes', function () {
  50181. var axis = this;
  50182. if (axis.isXAxis &&
  50183. defined(axis.options.overscroll) &&
  50184. axis.max === axis.dataMax &&
  50185. (
  50186. // Panning is an execption. We don't want to apply
  50187. // overscroll when panning over the dataMax
  50188. !axis.chart.mouseIsDown ||
  50189. axis.isInternal) && (
  50190. // Scrollbar buttons are the other execption:
  50191. !axis.eventArgs ||
  50192. axis.eventArgs && axis.eventArgs.trigger !== 'navigator')) {
  50193. axis.max += axis.options.overscroll;
  50194. // Live data and buttons require translation for the min:
  50195. if (!axis.isInternal && defined(axis.userMin)) {
  50196. axis.min += axis.options.overscroll;
  50197. }
  50198. }
  50199. });
  50200. // For ordinal axis, that loads data async, redraw axis after data is
  50201. // loaded. If we don't do that, axis will have the same extremes as
  50202. // previously, but ordinal positions won't be calculated. See #10290
  50203. addEvent(AxisClass, 'afterSetScale', function () {
  50204. var axis = this;
  50205. if (axis.horiz && !axis.isDirty) {
  50206. axis.isDirty = axis.isOrdinal &&
  50207. axis.chart.navigator &&
  50208. !axis.chart.navigator.adaptToUpdatedData;
  50209. }
  50210. });
  50211. addEvent(AxisClass, 'initialAxisTranslation', function () {
  50212. var axis = this;
  50213. if (axis.ordinal) {
  50214. axis.ordinal.beforeSetTickPositions();
  50215. axis.tickInterval = axis.ordinal.postProcessTickInterval(axis.tickInterval);
  50216. }
  50217. });
  50218. // Extending the Chart.pan method for ordinal axes
  50219. addEvent(ChartClass, 'pan', function (e) {
  50220. var chart = this,
  50221. xAxis = chart.xAxis[0],
  50222. overscroll = xAxis.options.overscroll,
  50223. chartX = e.originalEvent.chartX,
  50224. panning = chart.options.chart &&
  50225. chart.options.chart.panning,
  50226. runBase = false;
  50227. if (panning &&
  50228. panning.type !== 'y' &&
  50229. xAxis.options.ordinal &&
  50230. xAxis.series.length) {
  50231. var mouseDownX = chart.mouseDownX,
  50232. extremes = xAxis.getExtremes(),
  50233. dataMax = extremes.dataMax,
  50234. min = extremes.min,
  50235. max = extremes.max,
  50236. trimmedRange,
  50237. hoverPoints = chart.hoverPoints,
  50238. closestPointRange = (xAxis.closestPointRange ||
  50239. (xAxis.ordinal && xAxis.ordinal.overscrollPointsRange)),
  50240. pointPixelWidth = (xAxis.translationSlope *
  50241. (xAxis.ordinal.slope || closestPointRange)),
  50242. // how many ordinal units did we move?
  50243. movedUnits = (mouseDownX - chartX) / pointPixelWidth,
  50244. // get index of all the chart's points
  50245. extendedAxis = { ordinal: { positions: xAxis.ordinal.getExtendedPositions() } },
  50246. ordinalPositions,
  50247. searchAxisLeft,
  50248. lin2val = xAxis.lin2val,
  50249. val2lin = xAxis.val2lin,
  50250. searchAxisRight;
  50251. // we have an ordinal axis, but the data is equally spaced
  50252. if (!extendedAxis.ordinal.positions) {
  50253. runBase = true;
  50254. }
  50255. else if (Math.abs(movedUnits) > 1) {
  50256. // Remove active points for shared tooltip
  50257. if (hoverPoints) {
  50258. hoverPoints.forEach(function (point) {
  50259. point.setState();
  50260. });
  50261. }
  50262. if (movedUnits < 0) {
  50263. searchAxisLeft = extendedAxis;
  50264. searchAxisRight = xAxis.ordinal.positions ? xAxis : extendedAxis;
  50265. }
  50266. else {
  50267. searchAxisLeft = xAxis.ordinal.positions ? xAxis : extendedAxis;
  50268. searchAxisRight = extendedAxis;
  50269. }
  50270. // In grouped data series, the last ordinal position
  50271. // represents the grouped data, which is to the left of the
  50272. // real data max. If we don't compensate for this, we will
  50273. // be allowed to pan grouped data series passed the right of
  50274. // the plot area.
  50275. ordinalPositions = searchAxisRight.ordinal.positions;
  50276. if (dataMax >
  50277. ordinalPositions[ordinalPositions.length - 1]) {
  50278. ordinalPositions.push(dataMax);
  50279. }
  50280. // Get the new min and max values by getting the ordinal
  50281. // index for the current extreme, then add the moved units
  50282. // and translate back to values. This happens on the
  50283. // extended ordinal positions if the new position is out of
  50284. // range, else it happens on the current x axis which is
  50285. // smaller and faster.
  50286. chart.fixedRange = max - min;
  50287. trimmedRange = xAxis.navigatorAxis.toFixedRange(null, null, lin2val.apply(searchAxisLeft, [
  50288. val2lin.apply(searchAxisLeft, [min, true]) + movedUnits,
  50289. true // translate from index
  50290. ]), lin2val.apply(searchAxisRight, [
  50291. val2lin.apply(searchAxisRight, [max, true]) + movedUnits,
  50292. true // translate from index
  50293. ]));
  50294. // Apply it if it is within the available data range
  50295. if (trimmedRange.min >= Math.min(extremes.dataMin, min) &&
  50296. trimmedRange.max <= Math.max(dataMax, max) + overscroll) {
  50297. xAxis.setExtremes(trimmedRange.min, trimmedRange.max, true, false, { trigger: 'pan' });
  50298. }
  50299. chart.mouseDownX = chartX; // set new reference for next run
  50300. css(chart.container, { cursor: 'move' });
  50301. }
  50302. }
  50303. else {
  50304. runBase = true;
  50305. }
  50306. // revert to the linear chart.pan version
  50307. if (runBase || (panning && /y/.test(panning.type))) {
  50308. if (overscroll) {
  50309. xAxis.max = xAxis.dataMax + overscroll;
  50310. }
  50311. }
  50312. else {
  50313. e.preventDefault();
  50314. }
  50315. });
  50316. addEvent(SeriesClass, 'updatedData', function () {
  50317. var xAxis = this.xAxis;
  50318. // Destroy the extended ordinal index on updated data
  50319. if (xAxis && xAxis.options.ordinal) {
  50320. delete xAxis.ordinal.index;
  50321. }
  50322. });
  50323. /* eslint-enable no-invalid-this */
  50324. }
  50325. OrdinalAxis.compose = compose;
  50326. })(OrdinalAxis || (OrdinalAxis = {}));
  50327. OrdinalAxis.compose(Axis, Chart, Series); // @todo move to StockChart, remove from master
  50328. return OrdinalAxis;
  50329. });
  50330. _registerModule(_modules, 'Core/Axis/BrokenAxis.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Series/Series.js'], _modules['Extensions/Stacking.js'], _modules['Core/Utilities.js']], function (Axis, Series, StackItem, U) {
  50331. /* *
  50332. *
  50333. * (c) 2009-2021 Torstein Honsi
  50334. *
  50335. * License: www.highcharts.com/license
  50336. *
  50337. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  50338. *
  50339. * */
  50340. var addEvent = U.addEvent,
  50341. find = U.find,
  50342. fireEvent = U.fireEvent,
  50343. isArray = U.isArray,
  50344. isNumber = U.isNumber,
  50345. pick = U.pick;
  50346. /* eslint-disable valid-jsdoc */
  50347. /**
  50348. * Provides support for broken axes.
  50349. * @private
  50350. * @class
  50351. */
  50352. var BrokenAxisAdditions = /** @class */ (function () {
  50353. /* *
  50354. *
  50355. * Constructors
  50356. *
  50357. * */
  50358. function BrokenAxisAdditions(axis) {
  50359. this.hasBreaks = false;
  50360. this.axis = axis;
  50361. }
  50362. /* *
  50363. *
  50364. * Static Functions
  50365. *
  50366. * */
  50367. /**
  50368. * @private
  50369. */
  50370. BrokenAxisAdditions.isInBreak = function (brk, val) {
  50371. var ret,
  50372. repeat = brk.repeat || Infinity,
  50373. from = brk.from,
  50374. length = brk.to - brk.from,
  50375. test = (val >= from ?
  50376. (val - from) % repeat :
  50377. repeat - ((from - val) % repeat));
  50378. if (!brk.inclusive) {
  50379. ret = test < length && test !== 0;
  50380. }
  50381. else {
  50382. ret = test <= length;
  50383. }
  50384. return ret;
  50385. };
  50386. /**
  50387. * @private
  50388. */
  50389. BrokenAxisAdditions.lin2Val = function (val) {
  50390. var axis = this;
  50391. var brokenAxis = axis.brokenAxis;
  50392. var breakArray = brokenAxis && brokenAxis.breakArray;
  50393. if (!breakArray) {
  50394. return val;
  50395. }
  50396. var nval = val,
  50397. brk,
  50398. i;
  50399. for (i = 0; i < breakArray.length; i++) {
  50400. brk = breakArray[i];
  50401. if (brk.from >= nval) {
  50402. break;
  50403. }
  50404. else if (brk.to < nval) {
  50405. nval += brk.len;
  50406. }
  50407. else if (BrokenAxisAdditions.isInBreak(brk, nval)) {
  50408. nval += brk.len;
  50409. }
  50410. }
  50411. return nval;
  50412. };
  50413. /**
  50414. * @private
  50415. */
  50416. BrokenAxisAdditions.val2Lin = function (val) {
  50417. var axis = this;
  50418. var brokenAxis = axis.brokenAxis;
  50419. var breakArray = brokenAxis && brokenAxis.breakArray;
  50420. if (!breakArray) {
  50421. return val;
  50422. }
  50423. var nval = val,
  50424. brk,
  50425. i;
  50426. for (i = 0; i < breakArray.length; i++) {
  50427. brk = breakArray[i];
  50428. if (brk.to <= val) {
  50429. nval -= brk.len;
  50430. }
  50431. else if (brk.from >= val) {
  50432. break;
  50433. }
  50434. else if (BrokenAxisAdditions.isInBreak(brk, val)) {
  50435. nval -= (val - brk.from);
  50436. break;
  50437. }
  50438. }
  50439. return nval;
  50440. };
  50441. /* *
  50442. *
  50443. * Functions
  50444. *
  50445. * */
  50446. /**
  50447. * Returns the first break found where the x is larger then break.from and
  50448. * smaller then break.to.
  50449. *
  50450. * @param {number} x
  50451. * The number which should be within a break.
  50452. *
  50453. * @param {Array<Highcharts.XAxisBreaksOptions>} breaks
  50454. * The array of breaks to search within.
  50455. *
  50456. * @return {Highcharts.XAxisBreaksOptions|undefined}
  50457. * Returns the first break found that matches, returns false if no break is
  50458. * found.
  50459. */
  50460. BrokenAxisAdditions.prototype.findBreakAt = function (x, breaks) {
  50461. return find(breaks, function (b) {
  50462. return b.from < x && x < b.to;
  50463. });
  50464. };
  50465. /**
  50466. * @private
  50467. */
  50468. BrokenAxisAdditions.prototype.isInAnyBreak = function (val, testKeep) {
  50469. var brokenAxis = this;
  50470. var axis = brokenAxis.axis;
  50471. var breaks = axis.options.breaks,
  50472. i = breaks && breaks.length,
  50473. inbrk,
  50474. keep,
  50475. ret;
  50476. if (i) {
  50477. while (i--) {
  50478. if (BrokenAxisAdditions.isInBreak(breaks[i], val)) {
  50479. inbrk = true;
  50480. if (!keep) {
  50481. keep = pick(breaks[i].showPoints, !axis.isXAxis);
  50482. }
  50483. }
  50484. }
  50485. if (inbrk && testKeep) {
  50486. ret = inbrk && !keep;
  50487. }
  50488. else {
  50489. ret = inbrk;
  50490. }
  50491. }
  50492. return ret;
  50493. };
  50494. /**
  50495. * Dynamically set or unset breaks in an axis. This function in lighter than
  50496. * usin Axis.update, and it also preserves animation.
  50497. *
  50498. * @private
  50499. * @function Highcharts.Axis#setBreaks
  50500. *
  50501. * @param {Array<Highcharts.XAxisBreaksOptions>} [breaks]
  50502. * The breaks to add. When `undefined` it removes existing breaks.
  50503. *
  50504. * @param {boolean} [redraw=true]
  50505. * Whether to redraw the chart immediately.
  50506. *
  50507. * @return {void}
  50508. */
  50509. BrokenAxisAdditions.prototype.setBreaks = function (breaks, redraw) {
  50510. var brokenAxis = this;
  50511. var axis = brokenAxis.axis;
  50512. var hasBreaks = (isArray(breaks) && !!breaks.length);
  50513. axis.isDirty = brokenAxis.hasBreaks !== hasBreaks;
  50514. brokenAxis.hasBreaks = hasBreaks;
  50515. axis.options.breaks = axis.userOptions.breaks = breaks;
  50516. axis.forceRedraw = true; // Force recalculation in setScale
  50517. // Recalculate series related to the axis.
  50518. axis.series.forEach(function (series) {
  50519. series.isDirty = true;
  50520. });
  50521. if (!hasBreaks && axis.val2lin === BrokenAxisAdditions.val2Lin) {
  50522. // Revert to prototype functions
  50523. delete axis.val2lin;
  50524. delete axis.lin2val;
  50525. }
  50526. if (hasBreaks) {
  50527. axis.userOptions.ordinal = false;
  50528. axis.lin2val = BrokenAxisAdditions.lin2Val;
  50529. axis.val2lin = BrokenAxisAdditions.val2Lin;
  50530. axis.setExtremes = function (newMin, newMax, redraw, animation, eventArguments) {
  50531. // If trying to set extremes inside a break, extend min to
  50532. // after, and max to before the break ( #3857 )
  50533. if (brokenAxis.hasBreaks) {
  50534. var axisBreak,
  50535. breaks = this.options.breaks;
  50536. while ((axisBreak = brokenAxis.findBreakAt(newMin, breaks))) {
  50537. newMin = axisBreak.to;
  50538. }
  50539. while ((axisBreak = brokenAxis.findBreakAt(newMax, breaks))) {
  50540. newMax = axisBreak.from;
  50541. }
  50542. // If both min and max is within the same break.
  50543. if (newMax < newMin) {
  50544. newMax = newMin;
  50545. }
  50546. }
  50547. Axis.prototype.setExtremes.call(this, newMin, newMax, redraw, animation, eventArguments);
  50548. };
  50549. axis.setAxisTranslation = function () {
  50550. Axis.prototype.setAxisTranslation.call(this);
  50551. brokenAxis.unitLength = null;
  50552. if (brokenAxis.hasBreaks) {
  50553. var breaks = axis.options.breaks || [],
  50554. // Temporary one:
  50555. breakArrayT = [],
  50556. breakArray = [],
  50557. length = 0,
  50558. inBrk,
  50559. repeat,
  50560. min = axis.userMin || axis.min,
  50561. max = axis.userMax || axis.max,
  50562. pointRangePadding = pick(axis.pointRangePadding, 0),
  50563. start,
  50564. i;
  50565. // Min & max check (#4247)
  50566. breaks.forEach(function (brk) {
  50567. repeat = brk.repeat || Infinity;
  50568. if (BrokenAxisAdditions.isInBreak(brk, min)) {
  50569. min +=
  50570. (brk.to % repeat) -
  50571. (min % repeat);
  50572. }
  50573. if (BrokenAxisAdditions.isInBreak(brk, max)) {
  50574. max -=
  50575. (max % repeat) -
  50576. (brk.from % repeat);
  50577. }
  50578. });
  50579. // Construct an array holding all breaks in the axis
  50580. breaks.forEach(function (brk) {
  50581. start = brk.from;
  50582. repeat = brk.repeat || Infinity;
  50583. while (start - repeat > min) {
  50584. start -= repeat;
  50585. }
  50586. while (start < min) {
  50587. start += repeat;
  50588. }
  50589. for (i = start; i < max; i += repeat) {
  50590. breakArrayT.push({
  50591. value: i,
  50592. move: 'in'
  50593. });
  50594. breakArrayT.push({
  50595. value: i + (brk.to - brk.from),
  50596. move: 'out',
  50597. size: brk.breakSize
  50598. });
  50599. }
  50600. });
  50601. breakArrayT.sort(function (a, b) {
  50602. return ((a.value === b.value) ?
  50603. ((a.move === 'in' ? 0 : 1) -
  50604. (b.move === 'in' ? 0 : 1)) :
  50605. a.value - b.value);
  50606. });
  50607. // Simplify the breaks
  50608. inBrk = 0;
  50609. start = min;
  50610. breakArrayT.forEach(function (brk) {
  50611. inBrk += (brk.move === 'in' ? 1 : -1);
  50612. if (inBrk === 1 && brk.move === 'in') {
  50613. start = brk.value;
  50614. }
  50615. if (inBrk === 0) {
  50616. breakArray.push({
  50617. from: start,
  50618. to: brk.value,
  50619. len: brk.value - start - (brk.size || 0)
  50620. });
  50621. length += brk.value - start - (brk.size || 0);
  50622. }
  50623. });
  50624. /**
  50625. * HC <= 8 backwards compatibility, used by demo samples.
  50626. * @deprecated
  50627. * @private
  50628. * @requires modules/broken-axis
  50629. */
  50630. axis.breakArray = brokenAxis.breakArray = breakArray;
  50631. // Used with staticScale, and below the actual axis length,
  50632. // when breaks are substracted.
  50633. brokenAxis.unitLength = max - min - length + pointRangePadding;
  50634. fireEvent(axis, 'afterBreaks');
  50635. if (axis.staticScale) {
  50636. axis.transA = axis.staticScale;
  50637. }
  50638. else if (brokenAxis.unitLength) {
  50639. axis.transA *=
  50640. (max - axis.min + pointRangePadding) /
  50641. brokenAxis.unitLength;
  50642. }
  50643. if (pointRangePadding) {
  50644. axis.minPixelPadding =
  50645. axis.transA * axis.minPointOffset;
  50646. }
  50647. axis.min = min;
  50648. axis.max = max;
  50649. }
  50650. };
  50651. }
  50652. if (pick(redraw, true)) {
  50653. axis.chart.redraw();
  50654. }
  50655. };
  50656. return BrokenAxisAdditions;
  50657. }());
  50658. /**
  50659. * Axis with support of broken data rows.
  50660. * @private
  50661. * @class
  50662. */
  50663. var BrokenAxis = /** @class */ (function () {
  50664. function BrokenAxis() {
  50665. }
  50666. /**
  50667. * Adds support for broken axes.
  50668. * @private
  50669. */
  50670. BrokenAxis.compose = function (AxisClass, SeriesClass) {
  50671. AxisClass.keepProps.push('brokenAxis');
  50672. var seriesProto = Series.prototype;
  50673. /**
  50674. * @private
  50675. */
  50676. seriesProto.drawBreaks = function (axis, keys) {
  50677. var series = this,
  50678. points = series.points,
  50679. breaks,
  50680. threshold,
  50681. eventName,
  50682. y;
  50683. if (axis && // #5950
  50684. axis.brokenAxis &&
  50685. axis.brokenAxis.hasBreaks) {
  50686. var brokenAxis_1 = axis.brokenAxis;
  50687. keys.forEach(function (key) {
  50688. breaks = brokenAxis_1 && brokenAxis_1.breakArray || [];
  50689. threshold = axis.isXAxis ?
  50690. axis.min :
  50691. pick(series.options.threshold, axis.min);
  50692. points.forEach(function (point) {
  50693. y = pick(point['stack' + key.toUpperCase()], point[key]);
  50694. breaks.forEach(function (brk) {
  50695. if (isNumber(threshold) && isNumber(y)) {
  50696. eventName = false;
  50697. if ((threshold < brk.from && y > brk.to) ||
  50698. (threshold > brk.from && y < brk.from)) {
  50699. eventName = 'pointBreak';
  50700. }
  50701. else if ((threshold < brk.from && y > brk.from && y < brk.to) ||
  50702. (threshold > brk.from && y > brk.to && y < brk.from)) {
  50703. eventName = 'pointInBreak';
  50704. }
  50705. if (eventName) {
  50706. fireEvent(axis, eventName, { point: point, brk: brk });
  50707. }
  50708. }
  50709. });
  50710. });
  50711. });
  50712. }
  50713. };
  50714. /**
  50715. * Extend getGraphPath by identifying gaps in the data so that we can
  50716. * draw a gap in the line or area. This was moved from ordinal axis
  50717. * module to broken axis module as of #5045.
  50718. *
  50719. * @private
  50720. * @function Highcharts.Series#gappedPath
  50721. *
  50722. * @return {Highcharts.SVGPathArray}
  50723. * Gapped path
  50724. */
  50725. seriesProto.gappedPath = function () {
  50726. var currentDataGrouping = this.currentDataGrouping,
  50727. groupingSize = currentDataGrouping && currentDataGrouping.gapSize,
  50728. gapSize = this.options.gapSize,
  50729. points = this.points.slice(),
  50730. i = points.length - 1,
  50731. yAxis = this.yAxis,
  50732. stack;
  50733. /**
  50734. * Defines when to display a gap in the graph, together with the
  50735. * [gapUnit](plotOptions.series.gapUnit) option.
  50736. *
  50737. * In case when `dataGrouping` is enabled, points can be grouped
  50738. * into a larger time span. This can make the grouped points to have
  50739. * a greater distance than the absolute value of `gapSize` property,
  50740. * which will result in disappearing graph completely. To prevent
  50741. * this situation the mentioned distance between grouped points is
  50742. * used instead of previously defined `gapSize`.
  50743. *
  50744. * In practice, this option is most often used to visualize gaps in
  50745. * time series. In a stock chart, intraday data is available for
  50746. * daytime hours, while gaps will appear in nights and weekends.
  50747. *
  50748. * @see [gapUnit](plotOptions.series.gapUnit)
  50749. * @see [xAxis.breaks](#xAxis.breaks)
  50750. *
  50751. * @sample {highstock} stock/plotoptions/series-gapsize/
  50752. * Setting the gap size to 2 introduces gaps for weekends
  50753. * in daily datasets.
  50754. *
  50755. * @type {number}
  50756. * @default 0
  50757. * @product highstock
  50758. * @requires modules/broken-axis
  50759. * @apioption plotOptions.series.gapSize
  50760. */
  50761. /**
  50762. * Together with [gapSize](plotOptions.series.gapSize), this option
  50763. * defines where to draw gaps in the graph.
  50764. *
  50765. * When the `gapUnit` is `"relative"` (default), a gap size of 5
  50766. * means that if the distance between two points is greater than
  50767. * 5 times that of the two closest points, the graph will be broken.
  50768. *
  50769. * When the `gapUnit` is `"value"`, the gap is based on absolute
  50770. * axis values, which on a datetime axis is milliseconds. This also
  50771. * applies to the navigator series that inherits gap options from
  50772. * the base series.
  50773. *
  50774. * @see [gapSize](plotOptions.series.gapSize)
  50775. *
  50776. * @type {string}
  50777. * @default relative
  50778. * @since 5.0.13
  50779. * @product highstock
  50780. * @validvalue ["relative", "value"]
  50781. * @requires modules/broken-axis
  50782. * @apioption plotOptions.series.gapUnit
  50783. */
  50784. if (gapSize && i > 0) { // #5008
  50785. // Gap unit is relative
  50786. if (this.options.gapUnit !== 'value') {
  50787. gapSize *= this.basePointRange;
  50788. }
  50789. // Setting a new gapSize in case dataGrouping is enabled (#7686)
  50790. if (groupingSize &&
  50791. groupingSize > gapSize &&
  50792. // Except when DG is forced (e.g. from other series)
  50793. // and has lower granularity than actual points (#11351)
  50794. groupingSize >= this.basePointRange) {
  50795. gapSize = groupingSize;
  50796. }
  50797. // extension for ordinal breaks
  50798. var current = void 0,
  50799. next = void 0;
  50800. while (i--) {
  50801. // Reassign next if it is not visible
  50802. if (!(next && next.visible !== false)) {
  50803. next = points[i + 1];
  50804. }
  50805. current = points[i];
  50806. // Skip iteration if one of the points is not visible
  50807. if (next.visible === false || current.visible === false) {
  50808. continue;
  50809. }
  50810. if (next.x - current.x > gapSize) {
  50811. var xRange = (current.x + next.x) / 2;
  50812. points.splice(// insert after this one
  50813. i + 1, 0, {
  50814. isNull: true,
  50815. x: xRange
  50816. });
  50817. // For stacked chart generate empty stack items, #6546
  50818. if (yAxis.stacking && this.options.stacking) {
  50819. stack = yAxis.stacking.stacks[this.stackKey][xRange] =
  50820. new StackItem(yAxis, yAxis.options
  50821. .stackLabels, false, xRange, this.stack);
  50822. stack.total = 0;
  50823. }
  50824. }
  50825. // Assign current to next for the upcoming iteration
  50826. next = current;
  50827. }
  50828. }
  50829. // Call base method
  50830. return this.getGraphPath(points);
  50831. };
  50832. /* eslint-disable no-invalid-this */
  50833. addEvent(AxisClass, 'init', function () {
  50834. var axis = this;
  50835. if (!axis.brokenAxis) {
  50836. axis.brokenAxis = new BrokenAxisAdditions(axis);
  50837. }
  50838. });
  50839. addEvent(AxisClass, 'afterInit', function () {
  50840. if (typeof this.brokenAxis !== 'undefined') {
  50841. this.brokenAxis.setBreaks(this.options.breaks, false);
  50842. }
  50843. });
  50844. addEvent(AxisClass, 'afterSetTickPositions', function () {
  50845. var axis = this;
  50846. var brokenAxis = axis.brokenAxis;
  50847. if (brokenAxis &&
  50848. brokenAxis.hasBreaks) {
  50849. var tickPositions = this.tickPositions,
  50850. info = this.tickPositions.info,
  50851. newPositions = [],
  50852. i;
  50853. for (i = 0; i < tickPositions.length; i++) {
  50854. if (!brokenAxis.isInAnyBreak(tickPositions[i])) {
  50855. newPositions.push(tickPositions[i]);
  50856. }
  50857. }
  50858. this.tickPositions = newPositions;
  50859. this.tickPositions.info = info;
  50860. }
  50861. });
  50862. // Force Axis to be not-ordinal when breaks are defined
  50863. addEvent(AxisClass, 'afterSetOptions', function () {
  50864. if (this.brokenAxis && this.brokenAxis.hasBreaks) {
  50865. this.options.ordinal = false;
  50866. }
  50867. });
  50868. addEvent(SeriesClass, 'afterGeneratePoints', function () {
  50869. var _a = this,
  50870. isDirty = _a.isDirty,
  50871. connectNulls = _a.options.connectNulls,
  50872. points = _a.points,
  50873. xAxis = _a.xAxis,
  50874. yAxis = _a.yAxis;
  50875. // Set, or reset visibility of the points. Axis.setBreaks marks the
  50876. // series as isDirty
  50877. if (isDirty) {
  50878. var i = points.length;
  50879. while (i--) {
  50880. var point = points[i];
  50881. // Respect nulls inside the break (#4275)
  50882. var nullGap = point.y === null && connectNulls === false;
  50883. var isPointInBreak = (!nullGap && ((xAxis &&
  50884. xAxis.brokenAxis &&
  50885. xAxis.brokenAxis.isInAnyBreak(point.x,
  50886. true)) || (yAxis &&
  50887. yAxis.brokenAxis &&
  50888. yAxis.brokenAxis.isInAnyBreak(point.y,
  50889. true))));
  50890. // Set point.visible if in any break.
  50891. // If not in break, reset visible to original value.
  50892. point.visible = isPointInBreak ?
  50893. false :
  50894. point.options.visible !== false;
  50895. }
  50896. }
  50897. });
  50898. addEvent(SeriesClass, 'afterRender', function drawPointsWrapped() {
  50899. this.drawBreaks(this.xAxis, ['x']);
  50900. this.drawBreaks(this.yAxis, pick(this.pointArrayMap, ['y']));
  50901. });
  50902. };
  50903. return BrokenAxis;
  50904. }());
  50905. BrokenAxis.compose(Axis, Series); // @todo remove automatism
  50906. return BrokenAxis;
  50907. });
  50908. _registerModule(_modules, 'masters/modules/broken-axis.src.js', [], function () {
  50909. });
  50910. _registerModule(_modules, 'Extensions/DataGrouping.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Axis/DateTimeAxis.js'], _modules['Core/Globals.js'], _modules['Core/Options.js'], _modules['Core/Series/Point.js'], _modules['Core/Series/Series.js'], _modules['Core/Tooltip.js'], _modules['Core/Utilities.js']], function (Axis, DateTimeAxis, H, O, Point, Series, Tooltip, U) {
  50911. /* *
  50912. *
  50913. * (c) 2010-2021 Torstein Honsi
  50914. *
  50915. * License: www.highcharts.com/license
  50916. *
  50917. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  50918. *
  50919. * */
  50920. var seriesProto = Series.prototype;
  50921. var addEvent = U.addEvent,
  50922. arrayMax = U.arrayMax,
  50923. arrayMin = U.arrayMin,
  50924. correctFloat = U.correctFloat,
  50925. defined = U.defined,
  50926. error = U.error,
  50927. extend = U.extend,
  50928. format = U.format,
  50929. isNumber = U.isNumber,
  50930. merge = U.merge,
  50931. pick = U.pick;
  50932. /**
  50933. * @typedef {"average"|"averages"|"open"|"high"|"low"|"close"|"sum"} Highcharts.DataGroupingApproximationValue
  50934. */
  50935. /**
  50936. * @interface Highcharts.DataGroupingInfoObject
  50937. */ /**
  50938. * @name Highcharts.DataGroupingInfoObject#length
  50939. * @type {number}
  50940. */ /**
  50941. * @name Highcharts.DataGroupingInfoObject#options
  50942. * @type {Highcharts.SeriesOptionsType|undefined}
  50943. */ /**
  50944. * @name Highcharts.DataGroupingInfoObject#start
  50945. * @type {number}
  50946. */
  50947. ''; // detach doclets above
  50948. /* ************************************************************************** *
  50949. * Start data grouping module *
  50950. * ************************************************************************** */
  50951. /* eslint-disable no-invalid-this, valid-jsdoc */
  50952. /**
  50953. * Define the available approximation types. The data grouping
  50954. * approximations takes an array or numbers as the first parameter. In case
  50955. * of ohlc, four arrays are sent in as four parameters. Each array consists
  50956. * only of numbers. In case null values belong to the group, the property
  50957. * .hasNulls will be set to true on the array.
  50958. *
  50959. * @product highstock
  50960. *
  50961. * @private
  50962. * @name Highcharts.approximations
  50963. * @type {Highcharts.Dictionary<Function>}
  50964. */
  50965. var approximations = H.approximations = {
  50966. sum: function (arr) {
  50967. var len = arr.length,
  50968. ret;
  50969. // 1. it consists of nulls exclusive
  50970. if (!len && arr.hasNulls) {
  50971. ret = null;
  50972. // 2. it has a length and real values
  50973. }
  50974. else if (len) {
  50975. ret = 0;
  50976. while (len--) {
  50977. ret += arr[len];
  50978. }
  50979. }
  50980. // 3. it has zero length, so just return undefined
  50981. // => doNothing()
  50982. return ret;
  50983. },
  50984. average: function (arr) {
  50985. var len = arr.length,
  50986. ret = approximations.sum(arr);
  50987. // If we have a number, return it divided by the length. If not,
  50988. // return null or undefined based on what the sum method finds.
  50989. if (isNumber(ret) && len) {
  50990. ret = correctFloat(ret / len);
  50991. }
  50992. return ret;
  50993. },
  50994. // The same as average, but for series with multiple values, like area
  50995. // ranges.
  50996. averages: function () {
  50997. var ret = [];
  50998. [].forEach.call(arguments, function (arr) {
  50999. ret.push(approximations.average(arr));
  51000. });
  51001. // Return undefined when first elem. is undefined and let
  51002. // sum method handle null (#7377)
  51003. return typeof ret[0] === 'undefined' ? void 0 : ret;
  51004. },
  51005. open: function (arr) {
  51006. return arr.length ? arr[0] : (arr.hasNulls ? null : void 0);
  51007. },
  51008. high: function (arr) {
  51009. return arr.length ?
  51010. arrayMax(arr) :
  51011. (arr.hasNulls ? null : void 0);
  51012. },
  51013. low: function (arr) {
  51014. return arr.length ?
  51015. arrayMin(arr) :
  51016. (arr.hasNulls ? null : void 0);
  51017. },
  51018. close: function (arr) {
  51019. return arr.length ?
  51020. arr[arr.length - 1] :
  51021. (arr.hasNulls ? null : void 0);
  51022. },
  51023. // ohlc and range are special cases where a multidimensional array is
  51024. // input and an array is output
  51025. ohlc: function (open, high, low, close) {
  51026. open = approximations.open(open);
  51027. high = approximations.high(high);
  51028. low = approximations.low(low);
  51029. close = approximations.close(close);
  51030. if (isNumber(open) ||
  51031. isNumber(high) ||
  51032. isNumber(low) ||
  51033. isNumber(close)) {
  51034. return [open, high, low, close];
  51035. }
  51036. // else, return is undefined
  51037. },
  51038. range: function (low, high) {
  51039. low = approximations.low(low);
  51040. high = approximations.high(high);
  51041. if (isNumber(low) || isNumber(high)) {
  51042. return [low, high];
  51043. }
  51044. if (low === null && high === null) {
  51045. return null;
  51046. }
  51047. // else, return is undefined
  51048. }
  51049. };
  51050. var groupData = function (xData,
  51051. yData,
  51052. groupPositions,
  51053. approximation) {
  51054. var series = this,
  51055. data = series.data,
  51056. dataOptions = series.options && series.options.data,
  51057. groupedXData = [],
  51058. groupedYData = [],
  51059. groupMap = [],
  51060. dataLength = xData.length,
  51061. pointX,
  51062. pointY,
  51063. groupedY,
  51064. // when grouping the fake extended axis for panning,
  51065. // we don't need to consider y
  51066. handleYData = !!yData,
  51067. values = [],
  51068. approximationFn,
  51069. pointArrayMap = series.pointArrayMap,
  51070. pointArrayMapLength = pointArrayMap && pointArrayMap.length,
  51071. extendedPointArrayMap = ['x'].concat(pointArrayMap || ['y']),
  51072. pos = 0,
  51073. start = 0,
  51074. valuesLen,
  51075. i,
  51076. j;
  51077. /**
  51078. * @private
  51079. */
  51080. function getApproximation(approx) {
  51081. if (typeof approx === 'function') {
  51082. return approx;
  51083. }
  51084. if (approximations[approx]) {
  51085. return approximations[approx];
  51086. }
  51087. return approximations[(series.getDGApproximation && series.getDGApproximation()) ||
  51088. 'average'];
  51089. }
  51090. approximationFn = getApproximation(approximation);
  51091. // Calculate values array size from pointArrayMap length
  51092. if (pointArrayMapLength) {
  51093. pointArrayMap.forEach(function () {
  51094. values.push([]);
  51095. });
  51096. }
  51097. else {
  51098. values.push([]);
  51099. }
  51100. valuesLen = pointArrayMapLength || 1;
  51101. // Start with the first point within the X axis range (#2696)
  51102. for (i = 0; i <= dataLength; i++) {
  51103. if (xData[i] >= groupPositions[0]) {
  51104. break;
  51105. }
  51106. }
  51107. for (i; i <= dataLength; i++) {
  51108. // when a new group is entered, summarize and initialize
  51109. // the previous group
  51110. while ((typeof groupPositions[pos + 1] !== 'undefined' &&
  51111. xData[i] >= groupPositions[pos + 1]) ||
  51112. i === dataLength) { // get the last group
  51113. // get group x and y
  51114. pointX = groupPositions[pos];
  51115. series.dataGroupInfo = {
  51116. start: series.cropStart + start,
  51117. length: values[0].length
  51118. };
  51119. groupedY = approximationFn.apply(series, values);
  51120. // By default, let options of the first grouped point be passed over
  51121. // to the grouped point. This allows preserving properties like
  51122. // `name` and `color` or custom properties. Implementers can
  51123. // override this from the approximation function, where they can
  51124. // write custom options to `this.dataGroupInfo.options`.
  51125. if (series.pointClass && !defined(series.dataGroupInfo.options)) {
  51126. // Convert numbers and arrays into objects
  51127. series.dataGroupInfo.options = merge(series.pointClass.prototype
  51128. .optionsToObject.call({ series: series }, series.options.data[series.cropStart + start]));
  51129. // Make sure the raw data (x, y, open, high etc) is not copied
  51130. // over and overwriting approximated data.
  51131. extendedPointArrayMap.forEach(function (key) {
  51132. delete series.dataGroupInfo.options[key];
  51133. });
  51134. }
  51135. // push the grouped data
  51136. if (typeof groupedY !== 'undefined') {
  51137. groupedXData.push(pointX);
  51138. groupedYData.push(groupedY);
  51139. groupMap.push(series.dataGroupInfo);
  51140. }
  51141. // reset the aggregate arrays
  51142. start = i;
  51143. for (j = 0; j < valuesLen; j++) {
  51144. values[j].length = 0; // faster than values[j] = []
  51145. values[j].hasNulls = false;
  51146. }
  51147. // Advance on the group positions
  51148. pos += 1;
  51149. // don't loop beyond the last group
  51150. if (i === dataLength) {
  51151. break;
  51152. }
  51153. }
  51154. // break out
  51155. if (i === dataLength) {
  51156. break;
  51157. }
  51158. // for each raw data point, push it to an array that contains all values
  51159. // for this specific group
  51160. if (pointArrayMap) {
  51161. var index = series.cropStart + i,
  51162. point = (data && data[index]) ||
  51163. series.pointClass.prototype.applyOptions.apply({
  51164. series: series
  51165. },
  51166. [dataOptions[index]]),
  51167. val;
  51168. for (j = 0; j < pointArrayMapLength; j++) {
  51169. val = point[pointArrayMap[j]];
  51170. if (isNumber(val)) {
  51171. values[j].push(val);
  51172. }
  51173. else if (val === null) {
  51174. values[j].hasNulls = true;
  51175. }
  51176. }
  51177. }
  51178. else {
  51179. pointY = handleYData ? yData[i] : null;
  51180. if (isNumber(pointY)) {
  51181. values[0].push(pointY);
  51182. }
  51183. else if (pointY === null) {
  51184. values[0].hasNulls = true;
  51185. }
  51186. }
  51187. }
  51188. return {
  51189. groupedXData: groupedXData,
  51190. groupedYData: groupedYData,
  51191. groupMap: groupMap
  51192. };
  51193. };
  51194. var dataGrouping = {
  51195. approximations: approximations,
  51196. groupData: groupData
  51197. };
  51198. // -----------------------------------------------------------------------------
  51199. // The following code applies to implementation of data grouping on a Series
  51200. var baseProcessData = seriesProto.processData, baseGeneratePoints = seriesProto.generatePoints,
  51201. /** @ignore */
  51202. commonOptions = {
  51203. // enabled: null, // (true for stock charts, false for basic),
  51204. // forced: undefined,
  51205. groupPixelWidth: 2,
  51206. // the first one is the point or start value, the second is the start
  51207. // value if we're dealing with range, the third one is the end value if
  51208. // dealing with a range
  51209. dateTimeLabelFormats: {
  51210. millisecond: [
  51211. '%A, %b %e, %H:%M:%S.%L',
  51212. '%A, %b %e, %H:%M:%S.%L',
  51213. '-%H:%M:%S.%L'
  51214. ],
  51215. second: [
  51216. '%A, %b %e, %H:%M:%S',
  51217. '%A, %b %e, %H:%M:%S',
  51218. '-%H:%M:%S'
  51219. ],
  51220. minute: [
  51221. '%A, %b %e, %H:%M',
  51222. '%A, %b %e, %H:%M',
  51223. '-%H:%M'
  51224. ],
  51225. hour: [
  51226. '%A, %b %e, %H:%M',
  51227. '%A, %b %e, %H:%M',
  51228. '-%H:%M'
  51229. ],
  51230. day: [
  51231. '%A, %b %e, %Y',
  51232. '%A, %b %e',
  51233. '-%A, %b %e, %Y'
  51234. ],
  51235. week: [
  51236. 'Week from %A, %b %e, %Y',
  51237. '%A, %b %e',
  51238. '-%A, %b %e, %Y'
  51239. ],
  51240. month: [
  51241. '%B %Y',
  51242. '%B',
  51243. '-%B %Y'
  51244. ],
  51245. year: [
  51246. '%Y',
  51247. '%Y',
  51248. '-%Y'
  51249. ]
  51250. }
  51251. // smoothed = false, // enable this for navigator series only
  51252. }, specificOptions = {
  51253. line: {},
  51254. spline: {},
  51255. area: {},
  51256. areaspline: {},
  51257. arearange: {},
  51258. column: {
  51259. groupPixelWidth: 10
  51260. },
  51261. columnrange: {
  51262. groupPixelWidth: 10
  51263. },
  51264. candlestick: {
  51265. groupPixelWidth: 10
  51266. },
  51267. ohlc: {
  51268. groupPixelWidth: 5
  51269. }
  51270. },
  51271. // units are defined in a separate array to allow complete overriding in
  51272. // case of a user option
  51273. defaultDataGroupingUnits = H.defaultDataGroupingUnits = [
  51274. [
  51275. 'millisecond',
  51276. [1, 2, 5, 10, 20, 25, 50, 100, 200, 500] // allowed multiples
  51277. ], [
  51278. 'second',
  51279. [1, 2, 5, 10, 15, 30]
  51280. ], [
  51281. 'minute',
  51282. [1, 2, 5, 10, 15, 30]
  51283. ], [
  51284. 'hour',
  51285. [1, 2, 3, 4, 6, 8, 12]
  51286. ], [
  51287. 'day',
  51288. [1]
  51289. ], [
  51290. 'week',
  51291. [1]
  51292. ], [
  51293. 'month',
  51294. [1, 3, 6]
  51295. ], [
  51296. 'year',
  51297. null
  51298. ]
  51299. ];
  51300. // Set default approximations to the prototypes if present. Properties are
  51301. // inherited down. Can be overridden for individual series types.
  51302. seriesProto.getDGApproximation = function () {
  51303. if (this.is('arearange')) {
  51304. return 'range';
  51305. }
  51306. if (this.is('ohlc')) {
  51307. return 'ohlc';
  51308. }
  51309. if (this.is('column')) {
  51310. return 'sum';
  51311. }
  51312. return 'average';
  51313. };
  51314. /**
  51315. * Takes parallel arrays of x and y data and groups the data into intervals
  51316. * defined by groupPositions, a collection of starting x values for each group.
  51317. *
  51318. * @private
  51319. * @function Highcharts.Series#groupData
  51320. *
  51321. * @param {Array<number>} xData
  51322. *
  51323. * @param {Array<number>|Array<Array<number>>} yData
  51324. *
  51325. * @param {boolean} groupPositions
  51326. *
  51327. * @param {string|Function} approximation
  51328. *
  51329. * @return {void}
  51330. */
  51331. seriesProto.groupData = groupData;
  51332. // Extend the basic processData method, that crops the data to the current zoom
  51333. // range, with data grouping logic.
  51334. seriesProto.processData = function () {
  51335. var series = this,
  51336. chart = series.chart,
  51337. options = series.options,
  51338. dataGroupingOptions = options.dataGrouping,
  51339. groupingEnabled = series.allowDG !== false && dataGroupingOptions &&
  51340. pick(dataGroupingOptions.enabled,
  51341. chart.options.isStock),
  51342. visible = (series.visible || !chart.options.chart.ignoreHiddenSeries),
  51343. hasGroupedData,
  51344. skip,
  51345. lastDataGrouping = this.currentDataGrouping,
  51346. currentDataGrouping,
  51347. croppedData,
  51348. revertRequireSorting = false;
  51349. // Run base method
  51350. series.forceCrop = groupingEnabled; // #334
  51351. series.groupPixelWidth = null; // #2110
  51352. series.hasProcessed = true; // #2692
  51353. // Data needs to be sorted for dataGrouping
  51354. if (groupingEnabled && !series.requireSorting) {
  51355. series.requireSorting = revertRequireSorting = true;
  51356. }
  51357. // Skip if processData returns false or if grouping is disabled (in that
  51358. // order)
  51359. skip = (baseProcessData.apply(series, arguments) === false ||
  51360. !groupingEnabled);
  51361. // Revert original requireSorting value if changed
  51362. if (revertRequireSorting) {
  51363. series.requireSorting = false;
  51364. }
  51365. if (!skip) {
  51366. series.destroyGroupedData();
  51367. var i,
  51368. processedXData = dataGroupingOptions.groupAll ?
  51369. series.xData :
  51370. series.processedXData,
  51371. processedYData = dataGroupingOptions.groupAll ?
  51372. series.yData :
  51373. series.processedYData,
  51374. plotSizeX = chart.plotSizeX,
  51375. xAxis = series.xAxis,
  51376. ordinal = xAxis.options.ordinal,
  51377. groupPixelWidth = series.groupPixelWidth =
  51378. xAxis.getGroupPixelWidth && xAxis.getGroupPixelWidth();
  51379. // Execute grouping if the amount of points is greater than the limit
  51380. // defined in groupPixelWidth
  51381. if (groupPixelWidth) {
  51382. hasGroupedData = true;
  51383. // Force recreation of point instances in series.translate, #5699
  51384. series.isDirty = true;
  51385. series.points = null; // #6709
  51386. var extremes = xAxis.getExtremes(),
  51387. xMin = extremes.min,
  51388. xMax = extremes.max,
  51389. groupIntervalFactor = (ordinal &&
  51390. xAxis.ordinal &&
  51391. xAxis.ordinal.getGroupIntervalFactor(xMin,
  51392. xMax,
  51393. series)) || 1,
  51394. interval = (groupPixelWidth * (xMax - xMin) / plotSizeX) *
  51395. groupIntervalFactor,
  51396. groupPositions = xAxis.getTimeTicks(DateTimeAxis.AdditionsClass.prototype.normalizeTimeTickInterval(interval,
  51397. dataGroupingOptions.units ||
  51398. defaultDataGroupingUnits),
  51399. // Processed data may extend beyond axis (#4907)
  51400. Math.min(xMin,
  51401. processedXData[0]),
  51402. Math.max(xMax,
  51403. processedXData[processedXData.length - 1]),
  51404. xAxis.options.startOfWeek,
  51405. processedXData,
  51406. series.closestPointRange),
  51407. groupedData = seriesProto.groupData.apply(series,
  51408. [
  51409. processedXData,
  51410. processedYData,
  51411. groupPositions,
  51412. dataGroupingOptions.approximation
  51413. ]),
  51414. groupedXData = groupedData.groupedXData,
  51415. groupedYData = groupedData.groupedYData,
  51416. gapSize = 0;
  51417. // Prevent the smoothed data to spill out left and right, and make
  51418. // sure data is not shifted to the left
  51419. if (dataGroupingOptions.smoothed && groupedXData.length) {
  51420. i = groupedXData.length - 1;
  51421. groupedXData[i] = Math.min(groupedXData[i], xMax);
  51422. while (i-- && i > 0) {
  51423. groupedXData[i] += interval / 2;
  51424. }
  51425. groupedXData[0] = Math.max(groupedXData[0], xMin);
  51426. }
  51427. // Record what data grouping values were used
  51428. for (i = 1; i < groupPositions.length; i++) {
  51429. // The grouped gapSize needs to be the largest distance between
  51430. // the group to capture varying group sizes like months or DST
  51431. // crossing (#10000). Also check that the gap is not at the
  51432. // start of a segment.
  51433. if (!groupPositions.info.segmentStarts ||
  51434. groupPositions.info.segmentStarts.indexOf(i) === -1) {
  51435. gapSize = Math.max(groupPositions[i] - groupPositions[i - 1], gapSize);
  51436. }
  51437. }
  51438. currentDataGrouping = groupPositions.info;
  51439. currentDataGrouping.gapSize = gapSize;
  51440. series.closestPointRange = groupPositions.info.totalRange;
  51441. series.groupMap = groupedData.groupMap;
  51442. // Make sure the X axis extends to show the first group (#2533)
  51443. // But only for visible series (#5493, #6393)
  51444. if (defined(groupedXData[0]) &&
  51445. groupedXData[0] < xAxis.min &&
  51446. visible) {
  51447. if ((!defined(xAxis.options.min) &&
  51448. xAxis.min <= xAxis.dataMin) ||
  51449. xAxis.min === xAxis.dataMin) {
  51450. xAxis.min = Math.min(groupedXData[0], xAxis.min);
  51451. }
  51452. xAxis.dataMin = Math.min(groupedXData[0], xAxis.dataMin);
  51453. }
  51454. // We calculated all group positions but we should render
  51455. // only the ones within the visible range
  51456. if (dataGroupingOptions.groupAll) {
  51457. croppedData = series.cropData(groupedXData, groupedYData, xAxis.min, xAxis.max, 1 // Ordinal xAxis will remove left-most points otherwise
  51458. );
  51459. groupedXData = croppedData.xData;
  51460. groupedYData = croppedData.yData;
  51461. }
  51462. // Set series props
  51463. series.processedXData = groupedXData;
  51464. series.processedYData = groupedYData;
  51465. }
  51466. else {
  51467. series.groupMap = null;
  51468. }
  51469. series.hasGroupedData = hasGroupedData;
  51470. series.currentDataGrouping = currentDataGrouping;
  51471. series.preventGraphAnimation =
  51472. (lastDataGrouping && lastDataGrouping.totalRange) !==
  51473. (currentDataGrouping && currentDataGrouping.totalRange);
  51474. }
  51475. };
  51476. // Destroy the grouped data points. #622, #740
  51477. seriesProto.destroyGroupedData = function () {
  51478. // Clear previous groups
  51479. if (this.groupedData) {
  51480. this.groupedData.forEach(function (point, i) {
  51481. if (point) {
  51482. this.groupedData[i] = point.destroy ?
  51483. point.destroy() : null;
  51484. }
  51485. }, this);
  51486. // Clears all:
  51487. // - `this.groupedData`
  51488. // - `this.points`
  51489. // - `preserve` object in series.update()
  51490. this.groupedData.length = 0;
  51491. }
  51492. };
  51493. // Override the generatePoints method by adding a reference to grouped data
  51494. seriesProto.generatePoints = function () {
  51495. baseGeneratePoints.apply(this);
  51496. // Record grouped data in order to let it be destroyed the next time
  51497. // processData runs
  51498. this.destroyGroupedData(); // #622
  51499. this.groupedData = this.hasGroupedData ? this.points : null;
  51500. };
  51501. // Override point prototype to throw a warning when trying to update grouped
  51502. // points.
  51503. addEvent(Point, 'update', function () {
  51504. if (this.dataGroup) {
  51505. error(24, false, this.series.chart);
  51506. return false;
  51507. }
  51508. });
  51509. // Extend the original method, make the tooltip's header reflect the grouped
  51510. // range.
  51511. addEvent(Tooltip, 'headerFormatter', function (e) {
  51512. var tooltip = this,
  51513. chart = this.chart,
  51514. time = chart.time,
  51515. labelConfig = e.labelConfig,
  51516. series = labelConfig.series,
  51517. options = series.options,
  51518. tooltipOptions = series.tooltipOptions,
  51519. dataGroupingOptions = options.dataGrouping,
  51520. xDateFormat = tooltipOptions.xDateFormat,
  51521. xDateFormatEnd,
  51522. xAxis = series.xAxis,
  51523. currentDataGrouping,
  51524. dateTimeLabelFormats,
  51525. labelFormats,
  51526. formattedKey,
  51527. formatString = tooltipOptions[(e.isFooter ? 'footer' : 'header') + 'Format'];
  51528. // apply only to grouped series
  51529. if (xAxis &&
  51530. xAxis.options.type === 'datetime' &&
  51531. dataGroupingOptions &&
  51532. isNumber(labelConfig.key)) {
  51533. // set variables
  51534. currentDataGrouping = series.currentDataGrouping;
  51535. dateTimeLabelFormats = dataGroupingOptions.dateTimeLabelFormats ||
  51536. // Fallback to commonOptions (#9693)
  51537. commonOptions.dateTimeLabelFormats;
  51538. // if we have grouped data, use the grouping information to get the
  51539. // right format
  51540. if (currentDataGrouping) {
  51541. labelFormats =
  51542. dateTimeLabelFormats[currentDataGrouping.unitName];
  51543. if (currentDataGrouping.count === 1) {
  51544. xDateFormat = labelFormats[0];
  51545. }
  51546. else {
  51547. xDateFormat = labelFormats[1];
  51548. xDateFormatEnd = labelFormats[2];
  51549. }
  51550. // if not grouped, and we don't have set the xDateFormat option, get the
  51551. // best fit, so if the least distance between points is one minute, show
  51552. // it, but if the least distance is one day, skip hours and minutes etc.
  51553. }
  51554. else if (!xDateFormat && dateTimeLabelFormats) {
  51555. xDateFormat = tooltip.getXDateFormat(labelConfig, tooltipOptions, xAxis);
  51556. }
  51557. // now format the key
  51558. formattedKey = time.dateFormat(xDateFormat, labelConfig.key);
  51559. if (xDateFormatEnd) {
  51560. formattedKey += time.dateFormat(xDateFormatEnd, labelConfig.key + currentDataGrouping.totalRange - 1);
  51561. }
  51562. // Replace default header style with class name
  51563. if (series.chart.styledMode) {
  51564. formatString = this.styledModeFormat(formatString);
  51565. }
  51566. // return the replaced format
  51567. e.text = format(formatString, {
  51568. point: extend(labelConfig.point, { key: formattedKey }),
  51569. series: series
  51570. }, chart);
  51571. e.preventDefault();
  51572. }
  51573. });
  51574. // Destroy grouped data on series destroy
  51575. addEvent(Series, 'destroy', seriesProto.destroyGroupedData);
  51576. // Handle default options for data grouping. This must be set at runtime because
  51577. // some series types are defined after this.
  51578. addEvent(Series, 'afterSetOptions', function (e) {
  51579. var options = e.options,
  51580. type = this.type,
  51581. plotOptions = this.chart.options.plotOptions,
  51582. defaultOptions = O.defaultOptions.plotOptions[type].dataGrouping,
  51583. // External series, for example technical indicators should also
  51584. // inherit commonOptions which are not available outside this module
  51585. baseOptions = this.useCommonDataGrouping && commonOptions;
  51586. if (specificOptions[type] || baseOptions) { // #1284
  51587. if (!defaultOptions) {
  51588. defaultOptions = merge(commonOptions, specificOptions[type]);
  51589. }
  51590. options.dataGrouping = merge(baseOptions, defaultOptions, plotOptions.series && plotOptions.series.dataGrouping, // #1228
  51591. // Set by the StockChart constructor:
  51592. plotOptions[type].dataGrouping, this.userOptions.dataGrouping);
  51593. }
  51594. });
  51595. // When resetting the scale reset the hasProccessed flag to avoid taking
  51596. // previous data grouping of neighbour series into accound when determining
  51597. // group pixel width (#2692).
  51598. addEvent(Axis, 'afterSetScale', function () {
  51599. this.series.forEach(function (series) {
  51600. series.hasProcessed = false;
  51601. });
  51602. });
  51603. // Get the data grouping pixel width based on the greatest defined individual
  51604. // width of the axis' series, and if whether one of the axes need grouping.
  51605. Axis.prototype.getGroupPixelWidth = function () {
  51606. var series = this.series,
  51607. len = series.length,
  51608. i,
  51609. groupPixelWidth = 0,
  51610. doGrouping = false,
  51611. dataLength,
  51612. dgOptions;
  51613. // If multiple series are compared on the same x axis, give them the same
  51614. // group pixel width (#334)
  51615. i = len;
  51616. while (i--) {
  51617. dgOptions = series[i].options.dataGrouping;
  51618. if (dgOptions) {
  51619. groupPixelWidth = Math.max(groupPixelWidth,
  51620. // Fallback to commonOptions (#9693)
  51621. pick(dgOptions.groupPixelWidth, commonOptions.groupPixelWidth));
  51622. }
  51623. }
  51624. // If one of the series needs grouping, apply it to all (#1634)
  51625. i = len;
  51626. while (i--) {
  51627. dgOptions = series[i].options.dataGrouping;
  51628. if (dgOptions && series[i].hasProcessed) { // #2692
  51629. dataLength = (series[i].processedXData || series[i].data).length;
  51630. // Execute grouping if the amount of points is greater than the
  51631. // limit defined in groupPixelWidth
  51632. if (series[i].groupPixelWidth ||
  51633. dataLength >
  51634. (this.chart.plotSizeX / groupPixelWidth) ||
  51635. (dataLength && dgOptions.forced)) {
  51636. doGrouping = true;
  51637. }
  51638. }
  51639. }
  51640. return doGrouping ? groupPixelWidth : 0;
  51641. };
  51642. /**
  51643. * Highstock only. Force data grouping on all the axis' series.
  51644. *
  51645. * @product highstock
  51646. *
  51647. * @function Highcharts.Axis#setDataGrouping
  51648. *
  51649. * @param {boolean|Highcharts.DataGroupingOptionsObject} [dataGrouping]
  51650. * A `dataGrouping` configuration. Use `false` to disable data grouping
  51651. * dynamically.
  51652. *
  51653. * @param {boolean} [redraw=true]
  51654. * Whether to redraw the chart or wait for a later call to
  51655. * {@link Chart#redraw}.
  51656. *
  51657. * @return {void}
  51658. */
  51659. Axis.prototype.setDataGrouping = function (dataGrouping, redraw) {
  51660. var axis = this;
  51661. var i;
  51662. redraw = pick(redraw, true);
  51663. if (!dataGrouping) {
  51664. dataGrouping = {
  51665. forced: false,
  51666. units: null
  51667. };
  51668. }
  51669. // Axis is instantiated, update all series
  51670. if (this instanceof Axis) {
  51671. i = this.series.length;
  51672. while (i--) {
  51673. this.series[i].update({
  51674. dataGrouping: dataGrouping
  51675. }, false);
  51676. }
  51677. // Axis not yet instanciated, alter series options
  51678. }
  51679. else {
  51680. this.chart.options.series.forEach(function (seriesOptions) {
  51681. seriesOptions.dataGrouping = dataGrouping;
  51682. }, false);
  51683. }
  51684. // Clear ordinal slope, so we won't accidentaly use the old one (#7827)
  51685. if (axis.ordinal) {
  51686. axis.ordinal.slope = void 0;
  51687. }
  51688. if (redraw) {
  51689. this.chart.redraw();
  51690. }
  51691. };
  51692. H.dataGrouping = dataGrouping;
  51693. /* eslint-enable no-invalid-this, valid-jsdoc */
  51694. /**
  51695. * Data grouping is the concept of sampling the data values into larger
  51696. * blocks in order to ease readability and increase performance of the
  51697. * JavaScript charts. Highstock by default applies data grouping when
  51698. * the points become closer than a certain pixel value, determined by
  51699. * the `groupPixelWidth` option.
  51700. *
  51701. * If data grouping is applied, the grouping information of grouped
  51702. * points can be read from the [Point.dataGroup](
  51703. * /class-reference/Highcharts.Point#dataGroup). If point options other than
  51704. * the data itself are set, for example `name` or `color` or custom properties,
  51705. * the grouping logic doesn't know how to group it. In this case the options of
  51706. * the first point instance are copied over to the group point. This can be
  51707. * altered through a custom `approximation` callback function.
  51708. *
  51709. * @declare Highcharts.DataGroupingOptionsObject
  51710. * @product highstock
  51711. * @requires product:highstock
  51712. * @requires module:modules/datagrouping
  51713. * @apioption plotOptions.series.dataGrouping
  51714. */
  51715. /**
  51716. * The method of approximation inside a group. When for example 30 days
  51717. * are grouped into one month, this determines what value should represent
  51718. * the group. Possible values are "average", "averages", "open", "high",
  51719. * "low", "close" and "sum". For OHLC and candlestick series the approximation
  51720. * is "ohlc" by default, which finds the open, high, low and close values
  51721. * within all the grouped data. For ranges, the approximation is "range",
  51722. * which finds the low and high values. For multi-dimensional data,
  51723. * like ranges and OHLC, "averages" will compute the average for each
  51724. * dimension.
  51725. *
  51726. * Custom aggregate methods can be added by assigning a callback function
  51727. * as the approximation. This function takes a numeric array as the
  51728. * argument and should return a single numeric value or `null`. Note
  51729. * that the numeric array will never contain null values, only true
  51730. * numbers. Instead, if null values are present in the raw data, the
  51731. * numeric array will have an `.hasNulls` property set to `true`. For
  51732. * single-value data sets the data is available in the first argument
  51733. * of the callback function. For OHLC data sets, all the open values
  51734. * are in the first argument, all high values in the second etc.
  51735. *
  51736. * Since v4.2.7, grouping meta data is available in the approximation
  51737. * callback from `this.dataGroupInfo`. It can be used to extract information
  51738. * from the raw data.
  51739. *
  51740. * Defaults to `average` for line-type series, `sum` for columns, `range`
  51741. * for range series and `ohlc` for OHLC and candlestick.
  51742. *
  51743. * @sample {highstock} stock/plotoptions/series-datagrouping-approximation
  51744. * Approximation callback with custom data
  51745. *
  51746. * @type {Highcharts.DataGroupingApproximationValue|Function}
  51747. * @apioption plotOptions.series.dataGrouping.approximation
  51748. */
  51749. /**
  51750. * Datetime formats for the header of the tooltip in a stock chart.
  51751. * The format can vary within a chart depending on the currently selected
  51752. * time range and the current data grouping.
  51753. *
  51754. * The default formats are:
  51755. * ```js
  51756. * {
  51757. * millisecond: [
  51758. * '%A, %b %e, %H:%M:%S.%L', '%A, %b %e, %H:%M:%S.%L', '-%H:%M:%S.%L'
  51759. * ],
  51760. * second: ['%A, %b %e, %H:%M:%S', '%A, %b %e, %H:%M:%S', '-%H:%M:%S'],
  51761. * minute: ['%A, %b %e, %H:%M', '%A, %b %e, %H:%M', '-%H:%M'],
  51762. * hour: ['%A, %b %e, %H:%M', '%A, %b %e, %H:%M', '-%H:%M'],
  51763. * day: ['%A, %b %e, %Y', '%A, %b %e', '-%A, %b %e, %Y'],
  51764. * week: ['Week from %A, %b %e, %Y', '%A, %b %e', '-%A, %b %e, %Y'],
  51765. * month: ['%B %Y', '%B', '-%B %Y'],
  51766. * year: ['%Y', '%Y', '-%Y']
  51767. * }
  51768. * ```
  51769. *
  51770. * For each of these array definitions, the first item is the format
  51771. * used when the active time span is one unit. For instance, if the
  51772. * current data applies to one week, the first item of the week array
  51773. * is used. The second and third items are used when the active time
  51774. * span is more than two units. For instance, if the current data applies
  51775. * to two weeks, the second and third item of the week array are used,
  51776. * and applied to the start and end date of the time span.
  51777. *
  51778. * @type {object}
  51779. * @apioption plotOptions.series.dataGrouping.dateTimeLabelFormats
  51780. */
  51781. /**
  51782. * Enable or disable data grouping.
  51783. *
  51784. * @type {boolean}
  51785. * @default true
  51786. * @apioption plotOptions.series.dataGrouping.enabled
  51787. */
  51788. /**
  51789. * When data grouping is forced, it runs no matter how small the intervals
  51790. * are. This can be handy for example when the sum should be calculated
  51791. * for values appearing at random times within each hour.
  51792. *
  51793. * @type {boolean}
  51794. * @default false
  51795. * @apioption plotOptions.series.dataGrouping.forced
  51796. */
  51797. /**
  51798. * The approximate pixel width of each group. If for example a series
  51799. * with 30 points is displayed over a 600 pixel wide plot area, no grouping
  51800. * is performed. If however the series contains so many points that
  51801. * the spacing is less than the groupPixelWidth, Highcharts will try
  51802. * to group it into appropriate groups so that each is more or less
  51803. * two pixels wide. If multiple series with different group pixel widths
  51804. * are drawn on the same x axis, all series will take the greatest width.
  51805. * For example, line series have 2px default group width, while column
  51806. * series have 10px. If combined, both the line and the column will
  51807. * have 10px by default.
  51808. *
  51809. * @type {number}
  51810. * @default 2
  51811. * @apioption plotOptions.series.dataGrouping.groupPixelWidth
  51812. */
  51813. /**
  51814. * By default only points within the visible range are grouped. Enabling this
  51815. * option will force data grouping to calculate all grouped points for a given
  51816. * dataset. That option prevents for example a column series from calculating
  51817. * a grouped point partially. The effect is similar to
  51818. * [Series.getExtremesFromAll](#plotOptions.series.getExtremesFromAll) but does
  51819. * not affect yAxis extremes.
  51820. *
  51821. * @sample {highstock} stock/plotoptions/series-datagrouping-groupall/
  51822. * Two series with the same data but different groupAll setting
  51823. *
  51824. * @type {boolean}
  51825. * @default false
  51826. * @since 6.1.0
  51827. * @apioption plotOptions.series.dataGrouping.groupAll
  51828. */
  51829. /**
  51830. * Normally, a group is indexed by the start of that group, so for example
  51831. * when 30 daily values are grouped into one month, that month's x value
  51832. * will be the 1st of the month. This apparently shifts the data to
  51833. * the left. When the smoothed option is true, this is compensated for.
  51834. * The data is shifted to the middle of the group, and min and max
  51835. * values are preserved. Internally, this is used in the Navigator series.
  51836. *
  51837. * @type {boolean}
  51838. * @default false
  51839. * @apioption plotOptions.series.dataGrouping.smoothed
  51840. */
  51841. /**
  51842. * An array determining what time intervals the data is allowed to be
  51843. * grouped to. Each array item is an array where the first value is
  51844. * the time unit and the second value another array of allowed multiples.
  51845. *
  51846. * Defaults to:
  51847. * ```js
  51848. * units: [[
  51849. * 'millisecond', // unit name
  51850. * [1, 2, 5, 10, 20, 25, 50, 100, 200, 500] // allowed multiples
  51851. * ], [
  51852. * 'second',
  51853. * [1, 2, 5, 10, 15, 30]
  51854. * ], [
  51855. * 'minute',
  51856. * [1, 2, 5, 10, 15, 30]
  51857. * ], [
  51858. * 'hour',
  51859. * [1, 2, 3, 4, 6, 8, 12]
  51860. * ], [
  51861. * 'day',
  51862. * [1]
  51863. * ], [
  51864. * 'week',
  51865. * [1]
  51866. * ], [
  51867. * 'month',
  51868. * [1, 3, 6]
  51869. * ], [
  51870. * 'year',
  51871. * null
  51872. * ]]
  51873. * ```
  51874. *
  51875. * @type {Array<Array<string,(Array<number>|null)>>}
  51876. * @apioption plotOptions.series.dataGrouping.units
  51877. */
  51878. /**
  51879. * The approximate pixel width of each group. If for example a series
  51880. * with 30 points is displayed over a 600 pixel wide plot area, no grouping
  51881. * is performed. If however the series contains so many points that
  51882. * the spacing is less than the groupPixelWidth, Highcharts will try
  51883. * to group it into appropriate groups so that each is more or less
  51884. * two pixels wide. Defaults to `10`.
  51885. *
  51886. * @sample {highstock} stock/plotoptions/series-datagrouping-grouppixelwidth/
  51887. * Two series with the same data density but different groupPixelWidth
  51888. *
  51889. * @type {number}
  51890. * @default 10
  51891. * @apioption plotOptions.column.dataGrouping.groupPixelWidth
  51892. */
  51893. ''; // required by JSDoc parsing
  51894. return dataGrouping;
  51895. });
  51896. _registerModule(_modules, 'Series/OHLC/OHLCPoint.js', [_modules['Core/Series/SeriesRegistry.js']], function (SeriesRegistry) {
  51897. /* *
  51898. *
  51899. * (c) 2010-2021 Torstein Honsi
  51900. *
  51901. * License: www.highcharts.com/license
  51902. *
  51903. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  51904. *
  51905. * */
  51906. var __extends = (this && this.__extends) || (function () {
  51907. var extendStatics = function (d,
  51908. b) {
  51909. extendStatics = Object.setPrototypeOf ||
  51910. ({ __proto__: [] } instanceof Array && function (d,
  51911. b) { d.__proto__ = b; }) ||
  51912. function (d,
  51913. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  51914. return extendStatics(d, b);
  51915. };
  51916. return function (d, b) {
  51917. extendStatics(d, b);
  51918. function __() { this.constructor = d; }
  51919. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  51920. };
  51921. })();
  51922. var ColumnSeries = SeriesRegistry.seriesTypes.column;
  51923. /* *
  51924. *
  51925. * Class
  51926. *
  51927. * */
  51928. var OHLCPoint = /** @class */ (function (_super) {
  51929. __extends(OHLCPoint, _super);
  51930. function OHLCPoint() {
  51931. /* *
  51932. *
  51933. * Properties
  51934. *
  51935. * */
  51936. var _this = _super !== null && _super.apply(this,
  51937. arguments) || this;
  51938. _this.close = void 0;
  51939. _this.high = void 0;
  51940. _this.low = void 0;
  51941. _this.open = void 0;
  51942. _this.options = void 0;
  51943. _this.plotClose = void 0;
  51944. _this.plotOpen = void 0;
  51945. _this.series = void 0;
  51946. return _this;
  51947. /* eslint-enable valid-jsdoc */
  51948. }
  51949. /* *
  51950. *
  51951. * Functions
  51952. *
  51953. * */
  51954. /* eslint-disable valid-jsdoc */
  51955. /**
  51956. * Extend the parent method by adding up or down to the class name.
  51957. * @private
  51958. * @function Highcharts.seriesTypes.ohlc#getClassName
  51959. * @return {string}
  51960. */
  51961. OHLCPoint.prototype.getClassName = function () {
  51962. return _super.prototype.getClassName.call(this) +
  51963. (this.open < this.close ?
  51964. ' highcharts-point-up' :
  51965. ' highcharts-point-down');
  51966. };
  51967. /**
  51968. * Save upColor as point color (#14826).
  51969. * @private
  51970. * @function Highcharts.seriesTypes.ohlc#resolveUpColor
  51971. */
  51972. OHLCPoint.prototype.resolveUpColor = function () {
  51973. if (this.open < this.close &&
  51974. !this.options.color &&
  51975. this.series.options.upColor) {
  51976. this.color = this.series.options.upColor;
  51977. }
  51978. };
  51979. /**
  51980. * Extend the parent method by saving upColor.
  51981. * @private
  51982. * @function Highcharts.seriesTypes.ohlc#resolveColor
  51983. */
  51984. OHLCPoint.prototype.resolveColor = function () {
  51985. _super.prototype.resolveColor.call(this);
  51986. this.resolveUpColor();
  51987. };
  51988. /**
  51989. * Extend the parent method by saving upColor.
  51990. * @private
  51991. * @function Highcharts.seriesTypes.ohlc#getZone
  51992. *
  51993. * @return {Highcharts.SeriesZonesOptionsObject}
  51994. * The zone item.
  51995. */
  51996. OHLCPoint.prototype.getZone = function () {
  51997. var zone = _super.prototype.getZone.call(this);
  51998. this.resolveUpColor();
  51999. return zone;
  52000. };
  52001. return OHLCPoint;
  52002. }(ColumnSeries.prototype.pointClass));
  52003. /* *
  52004. *
  52005. * Default Export
  52006. *
  52007. * */
  52008. return OHLCPoint;
  52009. });
  52010. _registerModule(_modules, 'Series/OHLC/OHLCSeries.js', [_modules['Series/OHLC/OHLCPoint.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (OHLCPoint, SeriesRegistry, U) {
  52011. /* *
  52012. *
  52013. * (c) 2010-2021 Torstein Honsi
  52014. *
  52015. * License: www.highcharts.com/license
  52016. *
  52017. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  52018. *
  52019. * */
  52020. var __extends = (this && this.__extends) || (function () {
  52021. var extendStatics = function (d,
  52022. b) {
  52023. extendStatics = Object.setPrototypeOf ||
  52024. ({ __proto__: [] } instanceof Array && function (d,
  52025. b) { d.__proto__ = b; }) ||
  52026. function (d,
  52027. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  52028. return extendStatics(d, b);
  52029. };
  52030. return function (d, b) {
  52031. extendStatics(d, b);
  52032. function __() { this.constructor = d; }
  52033. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  52034. };
  52035. })();
  52036. var ColumnSeries = SeriesRegistry.seriesTypes.column;
  52037. var extend = U.extend,
  52038. merge = U.merge;
  52039. /* *
  52040. *
  52041. * Class
  52042. *
  52043. * */
  52044. /**
  52045. * The ohlc series type.
  52046. *
  52047. * @private
  52048. * @class
  52049. * @name Highcharts.seriesTypes.ohlc
  52050. *
  52051. * @augments Highcharts.Series
  52052. */
  52053. var OHLCSeries = /** @class */ (function (_super) {
  52054. __extends(OHLCSeries, _super);
  52055. function OHLCSeries() {
  52056. /* *
  52057. *
  52058. * Static Properties
  52059. *
  52060. * */
  52061. var _this = _super !== null && _super.apply(this,
  52062. arguments) || this;
  52063. /* *
  52064. *
  52065. * Properties
  52066. *
  52067. * */
  52068. _this.data = void 0;
  52069. _this.options = void 0;
  52070. _this.points = void 0;
  52071. _this.yData = void 0;
  52072. return _this;
  52073. /* eslint-enable valid-jsdoc */
  52074. }
  52075. /* *
  52076. *
  52077. * Functions
  52078. *
  52079. * */
  52080. /* eslint-disable valid-jsdoc */
  52081. /**
  52082. * Draw the data points
  52083. * @private
  52084. */
  52085. OHLCSeries.prototype.drawPoints = function () {
  52086. var series = this,
  52087. points = series.points,
  52088. chart = series.chart,
  52089. /**
  52090. * Extend vertical stem to open and close values.
  52091. */
  52092. extendStem = function (path,
  52093. halfStrokeWidth,
  52094. openOrClose) {
  52095. var start = path[0];
  52096. var end = path[1];
  52097. // We don't need to worry about crisp - openOrClose value
  52098. // is already crisped and halfStrokeWidth should remove it.
  52099. if (typeof start[2] === 'number') {
  52100. start[2] = Math.max(openOrClose + halfStrokeWidth, start[2]);
  52101. }
  52102. if (typeof end[2] === 'number') {
  52103. end[2] = Math.min(openOrClose - halfStrokeWidth, end[2]);
  52104. }
  52105. };
  52106. points.forEach(function (point) {
  52107. var plotOpen,
  52108. plotClose,
  52109. crispCorr,
  52110. halfWidth,
  52111. path,
  52112. graphic = point.graphic,
  52113. crispX,
  52114. isNew = !graphic,
  52115. strokeWidth;
  52116. if (typeof point.plotY !== 'undefined') {
  52117. // Create and/or update the graphic
  52118. if (!graphic) {
  52119. point.graphic = graphic = chart.renderer.path()
  52120. .add(series.group);
  52121. }
  52122. if (!chart.styledMode) {
  52123. graphic.attr(series.pointAttribs(point, (point.selected && 'select'))); // #3897
  52124. }
  52125. // crisp vector coordinates
  52126. strokeWidth = graphic.strokeWidth();
  52127. crispCorr = (strokeWidth % 2) / 2;
  52128. // #2596:
  52129. crispX = Math.round(point.plotX) - crispCorr;
  52130. halfWidth = Math.round(point.shapeArgs.width / 2);
  52131. // the vertical stem
  52132. path = [
  52133. ['M', crispX, Math.round(point.yBottom)],
  52134. ['L', crispX, Math.round(point.plotHigh)]
  52135. ];
  52136. // open
  52137. if (point.open !== null) {
  52138. plotOpen = Math.round(point.plotOpen) + crispCorr;
  52139. path.push(['M', crispX, plotOpen], ['L', crispX - halfWidth, plotOpen]);
  52140. extendStem(path, strokeWidth / 2, plotOpen);
  52141. }
  52142. // close
  52143. if (point.close !== null) {
  52144. plotClose = Math.round(point.plotClose) + crispCorr;
  52145. path.push(['M', crispX, plotClose], ['L', crispX + halfWidth, plotClose]);
  52146. extendStem(path, strokeWidth / 2, plotClose);
  52147. }
  52148. graphic[isNew ? 'attr' : 'animate']({ d: path })
  52149. .addClass(point.getClassName(), true);
  52150. }
  52151. });
  52152. };
  52153. /**
  52154. * @private
  52155. * @function Highcarts.seriesTypes.ohlc#init
  52156. * @return {void}
  52157. */
  52158. OHLCSeries.prototype.init = function () {
  52159. _super.prototype.init.apply(this, arguments);
  52160. this.options.stacking = void 0; // #8817
  52161. };
  52162. /**
  52163. * Postprocess mapping between options and SVG attributes
  52164. * @private
  52165. */
  52166. OHLCSeries.prototype.pointAttribs = function (point, state) {
  52167. var attribs = _super.prototype.pointAttribs.call(this,
  52168. point,
  52169. state),
  52170. options = this.options;
  52171. delete attribs.fill;
  52172. if (!point.options.color &&
  52173. options.upColor &&
  52174. point.open < point.close) {
  52175. attribs.stroke = options.upColor;
  52176. }
  52177. return attribs;
  52178. };
  52179. OHLCSeries.prototype.toYData = function (point) {
  52180. // return a plain array for speedy calculation
  52181. return [point.open, point.high, point.low, point.close];
  52182. };
  52183. /**
  52184. * Translate data points from raw values x and y to plotX and plotY
  52185. *
  52186. * @private
  52187. * @function Highcharts.seriesTypes.ohlc#translate
  52188. * @return {void}
  52189. */
  52190. OHLCSeries.prototype.translate = function () {
  52191. var series = this,
  52192. yAxis = series.yAxis,
  52193. hasModifyValue = !!series.modifyValue,
  52194. translated = [
  52195. 'plotOpen',
  52196. 'plotHigh',
  52197. 'plotLow',
  52198. 'plotClose',
  52199. 'yBottom'
  52200. ]; // translate OHLC for
  52201. _super.prototype.translate.apply(series);
  52202. // Do the translation
  52203. series.points.forEach(function (point) {
  52204. [point.open, point.high, point.low, point.close, point.low]
  52205. .forEach(function (value, i) {
  52206. if (value !== null) {
  52207. if (hasModifyValue) {
  52208. value = series.modifyValue(value);
  52209. }
  52210. point[translated[i]] =
  52211. yAxis.toPixels(value, true);
  52212. }
  52213. });
  52214. // Align the tooltip to the high value to avoid covering the
  52215. // point
  52216. point.tooltipPos[1] =
  52217. point.plotHigh + yAxis.pos - series.chart.plotTop;
  52218. });
  52219. };
  52220. /**
  52221. * An OHLC chart is a style of financial chart used to describe price
  52222. * movements over time. It displays open, high, low and close values per
  52223. * data point.
  52224. *
  52225. * @sample stock/demo/ohlc/
  52226. * OHLC chart
  52227. *
  52228. * @extends plotOptions.column
  52229. * @excluding borderColor, borderRadius, borderWidth, crisp, stacking,
  52230. * stack
  52231. * @product highstock
  52232. * @optionparent plotOptions.ohlc
  52233. */
  52234. OHLCSeries.defaultOptions = merge(ColumnSeries.defaultOptions, {
  52235. /**
  52236. * The approximate pixel width of each group. If for example a series
  52237. * with 30 points is displayed over a 600 pixel wide plot area, no
  52238. * grouping is performed. If however the series contains so many points
  52239. * that the spacing is less than the groupPixelWidth, Highcharts will
  52240. * try to group it into appropriate groups so that each is more or less
  52241. * two pixels wide. Defaults to `5`.
  52242. *
  52243. * @type {number}
  52244. * @default 5
  52245. * @product highstock
  52246. * @apioption plotOptions.ohlc.dataGrouping.groupPixelWidth
  52247. */
  52248. /**
  52249. * The pixel width of the line/border. Defaults to `1`.
  52250. *
  52251. * @sample {highstock} stock/plotoptions/ohlc-linewidth/
  52252. * A greater line width
  52253. *
  52254. * @type {number}
  52255. * @default 1
  52256. * @product highstock
  52257. *
  52258. * @private
  52259. */
  52260. lineWidth: 1,
  52261. tooltip: {
  52262. pointFormat: '<span style="color:{point.color}">\u25CF</span> ' +
  52263. '<b> {series.name}</b><br/>' +
  52264. 'Open: {point.open}<br/>' +
  52265. 'High: {point.high}<br/>' +
  52266. 'Low: {point.low}<br/>' +
  52267. 'Close: {point.close}<br/>'
  52268. },
  52269. threshold: null,
  52270. states: {
  52271. /**
  52272. * @extends plotOptions.column.states.hover
  52273. * @product highstock
  52274. */
  52275. hover: {
  52276. /**
  52277. * The pixel width of the line representing the OHLC point.
  52278. *
  52279. * @type {number}
  52280. * @default 3
  52281. * @product highstock
  52282. */
  52283. lineWidth: 3
  52284. }
  52285. },
  52286. /**
  52287. * Determines which one of `open`, `high`, `low`, `close` values should
  52288. * be represented as `point.y`, which is later used to set dataLabel
  52289. * position and [compare](#plotOptions.series.compare).
  52290. *
  52291. * @sample {highstock} stock/plotoptions/ohlc-pointvalkey/
  52292. * Possible values
  52293. *
  52294. * @type {string}
  52295. * @default close
  52296. * @validvalue ["open", "high", "low", "close"]
  52297. * @product highstock
  52298. * @apioption plotOptions.ohlc.pointValKey
  52299. */
  52300. /**
  52301. * @default close
  52302. * @apioption plotOptions.ohlc.colorKey
  52303. */
  52304. /**
  52305. * Line color for up points.
  52306. *
  52307. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  52308. * @product highstock
  52309. * @apioption plotOptions.ohlc.upColor
  52310. */
  52311. stickyTracking: true
  52312. });
  52313. return OHLCSeries;
  52314. }(ColumnSeries));
  52315. extend(OHLCSeries.prototype, {
  52316. animate: null,
  52317. directTouch: false,
  52318. pointArrayMap: ['open', 'high', 'low', 'close'],
  52319. pointAttrToOptions: {
  52320. stroke: 'color',
  52321. 'stroke-width': 'lineWidth'
  52322. },
  52323. pointValKey: 'close'
  52324. });
  52325. OHLCSeries.prototype.pointClass = OHLCPoint;
  52326. SeriesRegistry.registerSeriesType('ohlc', OHLCSeries);
  52327. /* *
  52328. *
  52329. * Default Export
  52330. *
  52331. * */
  52332. /* *
  52333. *
  52334. * API Options
  52335. *
  52336. * */
  52337. /**
  52338. * A `ohlc` series. If the [type](#series.ohlc.type) option is not
  52339. * specified, it is inherited from [chart.type](#chart.type).
  52340. *
  52341. * @extends series,plotOptions.ohlc
  52342. * @excluding dataParser, dataURL
  52343. * @product highstock
  52344. * @apioption series.ohlc
  52345. */
  52346. /**
  52347. * An array of data points for the series. For the `ohlc` series type,
  52348. * points can be given in the following ways:
  52349. *
  52350. * 1. An array of arrays with 5 or 4 values. In this case, the values correspond
  52351. * to `x,open,high,low,close`. If the first value is a string, it is applied
  52352. * as the name of the point, and the `x` value is inferred. The `x` value can
  52353. * also be omitted, in which case the inner arrays should be of length 4\.
  52354. * Then the `x` value is automatically calculated, either starting at 0 and
  52355. * incremented by 1, or from `pointStart` and `pointInterval` given in the
  52356. * series options.
  52357. * ```js
  52358. * data: [
  52359. * [0, 6, 5, 6, 7],
  52360. * [1, 9, 4, 8, 2],
  52361. * [2, 6, 3, 4, 10]
  52362. * ]
  52363. * ```
  52364. *
  52365. * 2. An array of objects with named values. The following snippet shows only a
  52366. * few settings, see the complete options set below. If the total number of
  52367. * data points exceeds the series'
  52368. * [turboThreshold](#series.ohlc.turboThreshold), this option is not
  52369. * available.
  52370. * ```js
  52371. * data: [{
  52372. * x: 1,
  52373. * open: 3,
  52374. * high: 4,
  52375. * low: 5,
  52376. * close: 2,
  52377. * name: "Point2",
  52378. * color: "#00FF00"
  52379. * }, {
  52380. * x: 1,
  52381. * open: 4,
  52382. * high: 3,
  52383. * low: 6,
  52384. * close: 7,
  52385. * name: "Point1",
  52386. * color: "#FF00FF"
  52387. * }]
  52388. * ```
  52389. *
  52390. * @type {Array<Array<(number|string),number,number,number>|Array<(number|string),number,number,number,number>|*>}
  52391. * @extends series.arearange.data
  52392. * @excluding y, marker
  52393. * @product highstock
  52394. * @apioption series.ohlc.data
  52395. */
  52396. /**
  52397. * The closing value of each data point.
  52398. *
  52399. * @type {number}
  52400. * @product highstock
  52401. * @apioption series.ohlc.data.close
  52402. */
  52403. /**
  52404. * The opening value of each data point.
  52405. *
  52406. * @type {number}
  52407. * @product highstock
  52408. * @apioption series.ohlc.data.open
  52409. */
  52410. ''; // adds doclets above to transpilat
  52411. return OHLCSeries;
  52412. });
  52413. _registerModule(_modules, 'Series/Candlestick/CandlestickSeries.js', [_modules['Core/Options.js'], _modules['Core/Color/Palette.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (O, palette, SeriesRegistry, U) {
  52414. /* *
  52415. *
  52416. * (c) 2010-2021 Torstein Honsi
  52417. *
  52418. * License: www.highcharts.com/license
  52419. *
  52420. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  52421. *
  52422. * */
  52423. var __extends = (this && this.__extends) || (function () {
  52424. var extendStatics = function (d,
  52425. b) {
  52426. extendStatics = Object.setPrototypeOf ||
  52427. ({ __proto__: [] } instanceof Array && function (d,
  52428. b) { d.__proto__ = b; }) ||
  52429. function (d,
  52430. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  52431. return extendStatics(d, b);
  52432. };
  52433. return function (d, b) {
  52434. extendStatics(d, b);
  52435. function __() { this.constructor = d; }
  52436. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  52437. };
  52438. })();
  52439. var defaultOptions = O.defaultOptions;
  52440. var _a = SeriesRegistry.seriesTypes,
  52441. ColumnSeries = _a.column,
  52442. OHLCSeries = _a.ohlc;
  52443. var merge = U.merge;
  52444. /* *
  52445. *
  52446. * Code
  52447. *
  52448. * */
  52449. /**
  52450. * A candlestick chart is a style of financial chart used to describe price
  52451. * movements over time.
  52452. *
  52453. * @sample stock/demo/candlestick/
  52454. * Candlestick chart
  52455. *
  52456. * @extends plotOptions.ohlc
  52457. * @excluding borderColor,borderRadius,borderWidth
  52458. * @product highstock
  52459. * @optionparent plotOptions.candlestick
  52460. */
  52461. /**
  52462. * The candlestick series type.
  52463. *
  52464. * @private
  52465. * @class
  52466. * @name Highcharts.seriesTypes.candlestick
  52467. *
  52468. * @augments Highcharts.seriesTypes.ohlc
  52469. */
  52470. var CandlestickSeries = /** @class */ (function (_super) {
  52471. __extends(CandlestickSeries, _super);
  52472. function CandlestickSeries() {
  52473. var _this = _super !== null && _super.apply(this,
  52474. arguments) || this;
  52475. /* *
  52476. *
  52477. * Properties
  52478. *
  52479. * */
  52480. _this.data = void 0;
  52481. _this.options = void 0;
  52482. _this.points = void 0;
  52483. return _this;
  52484. }
  52485. /* *
  52486. *
  52487. * Functions
  52488. *
  52489. * */
  52490. /* eslint-disable valid-jsdoc */
  52491. /**
  52492. * Postprocess mapping between options and SVG attributes
  52493. *
  52494. * @private
  52495. * @function Highcharts.seriesTypes.candlestick#pointAttribs
  52496. */
  52497. CandlestickSeries.prototype.pointAttribs = function (point, state) {
  52498. var attribs = ColumnSeries.prototype.pointAttribs.call(this,
  52499. point,
  52500. state),
  52501. options = this.options,
  52502. isUp = point.open < point.close,
  52503. stroke = options.lineColor || this.color,
  52504. color = point.color || this.color, // (#14826)
  52505. stateOptions;
  52506. attribs['stroke-width'] = options.lineWidth;
  52507. attribs.fill = point.options.color ||
  52508. (isUp ? (options.upColor || color) : color);
  52509. attribs.stroke = point.options.lineColor ||
  52510. (isUp ? (options.upLineColor || stroke) : stroke);
  52511. // Select or hover states
  52512. if (state) {
  52513. stateOptions = options.states[state];
  52514. attribs.fill = stateOptions.color || attribs.fill;
  52515. attribs.stroke = stateOptions.lineColor || attribs.stroke;
  52516. attribs['stroke-width'] =
  52517. stateOptions.lineWidth || attribs['stroke-width'];
  52518. }
  52519. return attribs;
  52520. };
  52521. /**
  52522. * Draw the data points.
  52523. *
  52524. * @private
  52525. * @function Highcharts.seriesTypes.candlestick#drawPoints
  52526. * @return {void}
  52527. */
  52528. CandlestickSeries.prototype.drawPoints = function () {
  52529. var series = this,
  52530. points = series.points,
  52531. chart = series.chart,
  52532. reversedYAxis = series.yAxis.reversed;
  52533. points.forEach(function (point) {
  52534. var graphic = point.graphic,
  52535. plotOpen,
  52536. plotClose,
  52537. topBox,
  52538. bottomBox,
  52539. hasTopWhisker,
  52540. hasBottomWhisker,
  52541. crispCorr,
  52542. crispX,
  52543. path,
  52544. halfWidth,
  52545. isNew = !graphic;
  52546. if (typeof point.plotY !== 'undefined') {
  52547. if (!graphic) {
  52548. point.graphic = graphic = chart.renderer.path()
  52549. .add(series.group);
  52550. }
  52551. if (!series.chart.styledMode) {
  52552. graphic
  52553. .attr(series.pointAttribs(point, (point.selected && 'select'))) // #3897
  52554. .shadow(series.options.shadow);
  52555. }
  52556. // Crisp vector coordinates
  52557. crispCorr = (graphic.strokeWidth() % 2) / 2;
  52558. // #2596:
  52559. crispX = Math.round(point.plotX) - crispCorr;
  52560. plotOpen = point.plotOpen;
  52561. plotClose = point.plotClose;
  52562. topBox = Math.min(plotOpen, plotClose);
  52563. bottomBox = Math.max(plotOpen, plotClose);
  52564. halfWidth = Math.round(point.shapeArgs.width / 2);
  52565. hasTopWhisker = reversedYAxis ?
  52566. bottomBox !== point.yBottom :
  52567. Math.round(topBox) !==
  52568. Math.round(point.plotHigh);
  52569. hasBottomWhisker = reversedYAxis ?
  52570. Math.round(topBox) !==
  52571. Math.round(point.plotHigh) :
  52572. bottomBox !== point.yBottom;
  52573. topBox = Math.round(topBox) + crispCorr;
  52574. bottomBox = Math.round(bottomBox) + crispCorr;
  52575. // Create the path. Due to a bug in Chrome 49, the path is
  52576. // first instanciated with no values, then the values
  52577. // pushed. For unknown reasons, instanciating the path array
  52578. // with all the values would lead to a crash when updating
  52579. // frequently (#5193).
  52580. path = [];
  52581. path.push(['M', crispX - halfWidth, bottomBox], ['L', crispX - halfWidth, topBox], ['L', crispX + halfWidth, topBox], ['L', crispX + halfWidth, bottomBox], ['Z'], // Ensure a nice rectangle #2602
  52582. ['M', crispX, topBox], [
  52583. 'L',
  52584. // #460, #2094
  52585. crispX,
  52586. hasTopWhisker ?
  52587. Math.round(reversedYAxis ?
  52588. point.yBottom :
  52589. point.plotHigh) :
  52590. topBox
  52591. ], ['M', crispX, bottomBox], [
  52592. 'L',
  52593. // #460, #2094
  52594. crispX,
  52595. hasBottomWhisker ?
  52596. Math.round(reversedYAxis ?
  52597. point.plotHigh :
  52598. point.yBottom) :
  52599. bottomBox
  52600. ]);
  52601. graphic[isNew ? 'attr' : 'animate']({ d: path })
  52602. .addClass(point.getClassName(), true);
  52603. }
  52604. });
  52605. /* eslint-enable valid-jsdoc */
  52606. };
  52607. /* *
  52608. *
  52609. * Static properties
  52610. *
  52611. * */
  52612. CandlestickSeries.defaultOptions = merge(OHLCSeries.defaultOptions, defaultOptions.plotOptions, {
  52613. /**
  52614. * The specific line color for up candle sticks. The default is to
  52615. * inherit the general `lineColor` setting.
  52616. *
  52617. * @sample {highstock} stock/plotoptions/candlestick-linecolor/
  52618. * Candlestick line colors
  52619. *
  52620. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  52621. * @since 1.3.6
  52622. * @product highstock
  52623. * @apioption plotOptions.candlestick.upLineColor
  52624. */
  52625. /**
  52626. * @type {Highcharts.DataGroupingApproximationValue|Function}
  52627. * @default ohlc
  52628. * @product highstock
  52629. * @apioption plotOptions.candlestick.dataGrouping.approximation
  52630. */
  52631. states: {
  52632. /**
  52633. * @extends plotOptions.column.states.hover
  52634. * @product highstock
  52635. */
  52636. hover: {
  52637. /**
  52638. * The pixel width of the line/border around the candlestick.
  52639. *
  52640. * @product highstock
  52641. */
  52642. lineWidth: 2
  52643. }
  52644. },
  52645. /**
  52646. * @extends plotOptions.ohlc.tooltip
  52647. */
  52648. tooltip: defaultOptions.plotOptions.ohlc.tooltip,
  52649. /**
  52650. * @type {number|null}
  52651. * @product highstock
  52652. */
  52653. threshold: null,
  52654. /**
  52655. * The color of the line/border of the candlestick.
  52656. *
  52657. * In styled mode, the line stroke can be set with the
  52658. * `.highcharts-candlestick-series .highcahrts-point` rule.
  52659. *
  52660. * @see [upLineColor](#plotOptions.candlestick.upLineColor)
  52661. *
  52662. * @sample {highstock} stock/plotoptions/candlestick-linecolor/
  52663. * Candlestick line colors
  52664. *
  52665. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  52666. * @default #000000
  52667. * @product highstock
  52668. */
  52669. lineColor: palette.neutralColor100,
  52670. /**
  52671. * The pixel width of the candlestick line/border. Defaults to `1`.
  52672. *
  52673. *
  52674. * In styled mode, the line stroke width can be set with the
  52675. * `.highcharts-candlestick-series .highcahrts-point` rule.
  52676. *
  52677. * @product highstock
  52678. */
  52679. lineWidth: 1,
  52680. /**
  52681. * The fill color of the candlestick when values are rising.
  52682. *
  52683. * In styled mode, the up color can be set with the
  52684. * `.highcharts-candlestick-series .highcharts-point-up` rule.
  52685. *
  52686. * @sample {highstock} stock/plotoptions/candlestick-color/
  52687. * Custom colors
  52688. * @sample {highstock} highcharts/css/candlestick/
  52689. * Colors in styled mode
  52690. *
  52691. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  52692. * @default #ffffff
  52693. * @product highstock
  52694. */
  52695. upColor: palette.backgroundColor,
  52696. /**
  52697. * @product highstock
  52698. */
  52699. stickyTracking: true
  52700. });
  52701. return CandlestickSeries;
  52702. }(OHLCSeries));
  52703. SeriesRegistry.registerSeriesType('candlestick', CandlestickSeries);
  52704. /* *
  52705. *
  52706. * Default Export
  52707. *
  52708. * */
  52709. /* *
  52710. *
  52711. * API Options
  52712. *
  52713. * */
  52714. /**
  52715. * A `candlestick` series. If the [type](#series.candlestick.type)
  52716. * option is not specified, it is inherited from [chart.type](
  52717. * #chart.type).
  52718. *
  52719. * @type {*}
  52720. * @extends series,plotOptions.candlestick
  52721. * @excluding dataParser, dataURL
  52722. * @product highstock
  52723. * @apioption series.candlestick
  52724. */
  52725. /**
  52726. * An array of data points for the series. For the `candlestick` series
  52727. * type, points can be given in the following ways:
  52728. *
  52729. * 1. An array of arrays with 5 or 4 values. In this case, the values correspond
  52730. * to `x,open,high,low,close`. If the first value is a string, it is applied
  52731. * as the name of the point, and the `x` value is inferred. The `x` value can
  52732. * also be omitted, in which case the inner arrays should be of length 4.
  52733. * Then the `x` value is automatically calculated, either starting at 0 and
  52734. * incremented by 1, or from `pointStart` and `pointInterval` given in the
  52735. * series options.
  52736. * ```js
  52737. * data: [
  52738. * [0, 7, 2, 0, 4],
  52739. * [1, 1, 4, 2, 8],
  52740. * [2, 3, 3, 9, 3]
  52741. * ]
  52742. * ```
  52743. *
  52744. * 2. An array of objects with named values. The following snippet shows only a
  52745. * few settings, see the complete options set below. If the total number of
  52746. * data points exceeds the series'
  52747. * [turboThreshold](#series.candlestick.turboThreshold), this option is not
  52748. * available.
  52749. * ```js
  52750. * data: [{
  52751. * x: 1,
  52752. * open: 9,
  52753. * high: 2,
  52754. * low: 4,
  52755. * close: 6,
  52756. * name: "Point2",
  52757. * color: "#00FF00"
  52758. * }, {
  52759. * x: 1,
  52760. * open: 1,
  52761. * high: 4,
  52762. * low: 7,
  52763. * close: 7,
  52764. * name: "Point1",
  52765. * color: "#FF00FF"
  52766. * }]
  52767. * ```
  52768. *
  52769. * @type {Array<Array<(number|string),number,number,number>|Array<(number|string),number,number,number,number>|*>}
  52770. * @extends series.ohlc.data
  52771. * @excluding y
  52772. * @product highstock
  52773. * @apioption series.candlestick.data
  52774. */
  52775. ''; // adds doclets above to transpilat
  52776. return CandlestickSeries;
  52777. });
  52778. _registerModule(_modules, 'Series/Flags/FlagsPoint.js', [_modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (SeriesRegistry, U) {
  52779. /* *
  52780. *
  52781. * (c) 2010-2021 Torstein Honsi
  52782. *
  52783. * License: www.highcharts.com/license
  52784. *
  52785. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  52786. *
  52787. * */
  52788. var __extends = (this && this.__extends) || (function () {
  52789. var extendStatics = function (d,
  52790. b) {
  52791. extendStatics = Object.setPrototypeOf ||
  52792. ({ __proto__: [] } instanceof Array && function (d,
  52793. b) { d.__proto__ = b; }) ||
  52794. function (d,
  52795. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  52796. return extendStatics(d, b);
  52797. };
  52798. return function (d, b) {
  52799. extendStatics(d, b);
  52800. function __() { this.constructor = d; }
  52801. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  52802. };
  52803. })();
  52804. var ColumnSeries = SeriesRegistry.seriesTypes.column;
  52805. var isNumber = U.isNumber;
  52806. /* *
  52807. *
  52808. * Class
  52809. *
  52810. * */
  52811. var FlagsPoint = /** @class */ (function (_super) {
  52812. __extends(FlagsPoint, _super);
  52813. function FlagsPoint() {
  52814. /* *
  52815. *
  52816. * Properties
  52817. *
  52818. * */
  52819. var _this = _super !== null && _super.apply(this,
  52820. arguments) || this;
  52821. _this.options = void 0;
  52822. _this.series = void 0;
  52823. return _this;
  52824. }
  52825. /* *
  52826. *
  52827. * Functions
  52828. *
  52829. * */
  52830. /* eslint-disable valid-jsdoc */
  52831. /**
  52832. * @private
  52833. */
  52834. FlagsPoint.prototype.isValid = function () {
  52835. // #9233 - Prevent from treating flags as null points (even if
  52836. // they have no y values defined).
  52837. return isNumber(this.y) || typeof this.y === 'undefined';
  52838. };
  52839. return FlagsPoint;
  52840. }(ColumnSeries.prototype.pointClass));
  52841. /* *
  52842. *
  52843. * Default Export
  52844. *
  52845. * */
  52846. return FlagsPoint;
  52847. });
  52848. _registerModule(_modules, 'Mixins/OnSeries.js', [_modules['Series/Column/ColumnSeries.js'], _modules['Core/Series/Series.js'], _modules['Core/Utilities.js']], function (ColumnSeries, Series, U) {
  52849. /* *
  52850. *
  52851. * (c) 2010-2021 Torstein Honsi
  52852. *
  52853. * License: www.highcharts.com/license
  52854. *
  52855. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  52856. *
  52857. * */
  52858. var columnProto = ColumnSeries.prototype;
  52859. var seriesProto = Series.prototype;
  52860. var defined = U.defined,
  52861. stableSort = U.stableSort;
  52862. /**
  52863. * @private
  52864. * @mixin onSeriesMixin
  52865. */
  52866. var onSeriesMixin = {
  52867. /* eslint-disable valid-jsdoc */
  52868. /**
  52869. * Override getPlotBox. If the onSeries option is valid,
  52870. return the plot box
  52871. * of the onSeries,
  52872. otherwise proceed as usual.
  52873. *
  52874. * @private
  52875. * @function onSeriesMixin.getPlotBox
  52876. * @return {Highcharts.SeriesPlotBoxObject}
  52877. */
  52878. getPlotBox: function () {
  52879. return seriesProto.getPlotBox.call((this.options.onSeries &&
  52880. this.chart.get(this.options.onSeries)) || this);
  52881. },
  52882. /**
  52883. * Extend the translate method by placing the point on the related series
  52884. *
  52885. * @private
  52886. * @function onSeriesMixin.translate
  52887. * @return {void}
  52888. */
  52889. translate: function () {
  52890. columnProto.translate.apply(this);
  52891. var series = this,
  52892. options = series.options,
  52893. chart = series.chart,
  52894. points = series.points,
  52895. cursor = points.length - 1,
  52896. point,
  52897. lastPoint,
  52898. optionsOnSeries = options.onSeries,
  52899. onSeries = (optionsOnSeries &&
  52900. chart.get(optionsOnSeries)),
  52901. onKey = options.onKey || 'y',
  52902. step = onSeries && onSeries.options.step,
  52903. onData = (onSeries && onSeries.points),
  52904. i = onData && onData.length,
  52905. inverted = chart.inverted,
  52906. xAxis = series.xAxis,
  52907. yAxis = series.yAxis,
  52908. xOffset = 0,
  52909. leftPoint,
  52910. lastX,
  52911. rightPoint,
  52912. currentDataGrouping,
  52913. distanceRatio;
  52914. // relate to a master series
  52915. if (onSeries && onSeries.visible && i) {
  52916. xOffset = (onSeries.pointXOffset || 0) + (onSeries.barW || 0) / 2;
  52917. currentDataGrouping = onSeries.currentDataGrouping;
  52918. lastX = (onData[i - 1].x +
  52919. (currentDataGrouping ? currentDataGrouping.totalRange : 0)); // #2374
  52920. // sort the data points
  52921. stableSort(points, function (a, b) {
  52922. return (a.x - b.x);
  52923. });
  52924. onKey = 'plot' + onKey[0].toUpperCase() + onKey.substr(1);
  52925. while (i-- && points[cursor]) {
  52926. leftPoint = onData[i];
  52927. point = points[cursor];
  52928. point.y = leftPoint.y;
  52929. if (leftPoint.x <= point.x &&
  52930. typeof leftPoint[onKey] !== 'undefined') {
  52931. if (point.x <= lastX) { // #803
  52932. point.plotY = leftPoint[onKey];
  52933. // interpolate between points, #666
  52934. if (leftPoint.x < point.x &&
  52935. !step) {
  52936. rightPoint = onData[i + 1];
  52937. if (rightPoint &&
  52938. typeof rightPoint[onKey] !== 'undefined') {
  52939. // the distance ratio, between 0 and 1
  52940. distanceRatio =
  52941. (point.x - leftPoint.x) /
  52942. (rightPoint.x - leftPoint.x);
  52943. point.plotY +=
  52944. distanceRatio *
  52945. // the plotY distance
  52946. (rightPoint[onKey] - leftPoint[onKey]);
  52947. point.y +=
  52948. distanceRatio *
  52949. (rightPoint.y - leftPoint.y);
  52950. }
  52951. }
  52952. }
  52953. cursor--;
  52954. i++; // check again for points in the same x position
  52955. if (cursor < 0) {
  52956. break;
  52957. }
  52958. }
  52959. }
  52960. }
  52961. // Add plotY position and handle stacking
  52962. points.forEach(function (point, i) {
  52963. var stackIndex;
  52964. point.plotX += xOffset; // #2049
  52965. // Undefined plotY means the point is either on axis, outside series
  52966. // range or hidden series. If the series is outside the range of the
  52967. // x axis it should fall through with an undefined plotY, but then
  52968. // we must remove the shapeArgs (#847). For inverted charts, we need
  52969. // to calculate position anyway, because series.invertGroups is not
  52970. // defined
  52971. if (typeof point.plotY === 'undefined' || inverted) {
  52972. if (point.plotX >= 0 &&
  52973. point.plotX <= xAxis.len) {
  52974. // We're inside xAxis range
  52975. if (inverted) {
  52976. point.plotY = xAxis.translate(point.x, 0, 1, 0, 1);
  52977. point.plotX = defined(point.y) ?
  52978. yAxis.translate(point.y, 0, 0, 0, 1) :
  52979. 0;
  52980. }
  52981. else {
  52982. point.plotY = (xAxis.opposite ? 0 : series.yAxis.len) +
  52983. xAxis.offset; // For the windbarb demo
  52984. }
  52985. }
  52986. else {
  52987. point.shapeArgs = {}; // 847
  52988. }
  52989. }
  52990. // if multiple flags appear at the same x, order them into a stack
  52991. lastPoint = points[i - 1];
  52992. if (lastPoint && lastPoint.plotX === point.plotX) {
  52993. if (typeof lastPoint.stackIndex === 'undefined') {
  52994. lastPoint.stackIndex = 0;
  52995. }
  52996. stackIndex = lastPoint.stackIndex + 1;
  52997. }
  52998. point.stackIndex = stackIndex; // #3639
  52999. });
  53000. this.onSeries = onSeries;
  53001. }
  53002. /* eslint-enable valid-jsdoc */
  53003. };
  53004. return onSeriesMixin;
  53005. });
  53006. _registerModule(_modules, 'Series/Flags/FlagsSymbols.js', [_modules['Core/Globals.js'], _modules['Core/Renderer/SVG/SVGRenderer.js']], function (H, SVGRenderer) {
  53007. /* *
  53008. *
  53009. * Imports
  53010. *
  53011. * */
  53012. var Renderer = H.Renderer,
  53013. VMLRenderer = H.VMLRenderer;
  53014. var symbols = SVGRenderer.prototype.symbols;
  53015. /* *
  53016. *
  53017. * Symbols
  53018. *
  53019. * */
  53020. // create the flag icon with anchor
  53021. symbols.flag = function (x, y, w, h, options) {
  53022. var anchorX = (options && options.anchorX) || x,
  53023. anchorY = (options && options.anchorY) || y;
  53024. // To do: unwanted any cast because symbols.circle has wrong type, it
  53025. // actually returns an SVGPathArray
  53026. var path = symbols.circle(anchorX - 1,
  53027. anchorY - 1, 2, 2);
  53028. path.push(['M', anchorX, anchorY], ['L', x, y + h], ['L', x, y], ['L', x + w, y], ['L', x + w, y + h], ['L', x, y + h], ['Z']);
  53029. return path;
  53030. };
  53031. /**
  53032. * Create the circlepin and squarepin icons with anchor.
  53033. * @private
  53034. * @param {string} shape - circle or square
  53035. * @return {void}
  53036. */
  53037. function createPinSymbol(shape) {
  53038. symbols[shape + 'pin'] = function (x, y, w, h, options) {
  53039. var anchorX = options && options.anchorX,
  53040. anchorY = options && options.anchorY,
  53041. path;
  53042. // For single-letter flags, make sure circular flags are not taller
  53043. // than their width
  53044. if (shape === 'circle' && h > w) {
  53045. x -= Math.round((h - w) / 2);
  53046. w = h;
  53047. }
  53048. path = (symbols[shape])(x, y, w, h);
  53049. if (anchorX && anchorY) {
  53050. /**
  53051. * If the label is below the anchor, draw the connecting line from
  53052. * the top edge of the label, otherwise start drawing from the
  53053. * bottom edge
  53054. */
  53055. var labelX = anchorX;
  53056. if (shape === 'circle') {
  53057. labelX = x + w / 2;
  53058. }
  53059. else {
  53060. var startSeg = path[0];
  53061. var endSeg = path[1];
  53062. if (startSeg[0] === 'M' && endSeg[0] === 'L') {
  53063. labelX = (startSeg[1] + endSeg[1]) / 2;
  53064. }
  53065. }
  53066. var labelY = (y > anchorY) ? y : y + h;
  53067. path.push([
  53068. 'M',
  53069. labelX,
  53070. labelY
  53071. ], [
  53072. 'L',
  53073. anchorX,
  53074. anchorY
  53075. ]);
  53076. path = path.concat(symbols.circle(anchorX - 1, anchorY - 1, 2, 2));
  53077. }
  53078. return path;
  53079. };
  53080. }
  53081. createPinSymbol('circle');
  53082. createPinSymbol('square');
  53083. /**
  53084. * The symbol callbacks are generated on the SVGRenderer object in all browsers.
  53085. * Even VML browsers need this in order to generate shapes in export. Now share
  53086. * them with the VMLRenderer.
  53087. */
  53088. if (Renderer === VMLRenderer) {
  53089. ['circlepin', 'flag', 'squarepin'].forEach(function (shape) {
  53090. VMLRenderer.prototype.symbols[shape] = symbols[shape];
  53091. });
  53092. }
  53093. /* *
  53094. *
  53095. * Default Export
  53096. *
  53097. * */
  53098. return symbols;
  53099. });
  53100. _registerModule(_modules, 'Series/Flags/FlagsSeries.js', [_modules['Series/Flags/FlagsPoint.js'], _modules['Core/Globals.js'], _modules['Mixins/OnSeries.js'], _modules['Core/Color/Palette.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Utilities.js']], function (FlagsPoint, H, OnSeriesMixin, palette, SeriesRegistry, SVGElement, U) {
  53101. /* *
  53102. *
  53103. * (c) 2010-2021 Torstein Honsi
  53104. *
  53105. * License: www.highcharts.com/license
  53106. *
  53107. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  53108. *
  53109. * */
  53110. var __extends = (this && this.__extends) || (function () {
  53111. var extendStatics = function (d,
  53112. b) {
  53113. extendStatics = Object.setPrototypeOf ||
  53114. ({ __proto__: [] } instanceof Array && function (d,
  53115. b) { d.__proto__ = b; }) ||
  53116. function (d,
  53117. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  53118. return extendStatics(d, b);
  53119. };
  53120. return function (d, b) {
  53121. extendStatics(d, b);
  53122. function __() { this.constructor = d; }
  53123. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  53124. };
  53125. })();
  53126. var noop = H.noop;
  53127. var Series = SeriesRegistry.series,
  53128. ColumnSeries = SeriesRegistry.seriesTypes.column;
  53129. var addEvent = U.addEvent,
  53130. defined = U.defined,
  53131. extend = U.extend,
  53132. merge = U.merge,
  53133. objectEach = U.objectEach,
  53134. wrap = U.wrap;
  53135. /**
  53136. * The Flags series.
  53137. *
  53138. * @private
  53139. * @class
  53140. * @name Highcharts.seriesTypes.flags
  53141. *
  53142. * @augments Highcharts.Series
  53143. */
  53144. var FlagsSeries = /** @class */ (function (_super) {
  53145. __extends(FlagsSeries, _super);
  53146. function FlagsSeries() {
  53147. /* *
  53148. *
  53149. * Static Properties
  53150. *
  53151. * */
  53152. var _this = _super !== null && _super.apply(this,
  53153. arguments) || this;
  53154. /* *
  53155. *
  53156. * Properties
  53157. *
  53158. * */
  53159. _this.data = void 0;
  53160. _this.options = void 0;
  53161. _this.points = void 0;
  53162. return _this;
  53163. /* eslint-enable valid-jsdoc */
  53164. }
  53165. /* *
  53166. *
  53167. * Functions
  53168. *
  53169. * */
  53170. /* eslint-disable valid-jsdoc */
  53171. /**
  53172. * Disable animation, but keep clipping (#8546).
  53173. * @private
  53174. */
  53175. FlagsSeries.prototype.animate = function (init) {
  53176. if (init) {
  53177. this.setClip();
  53178. }
  53179. };
  53180. /**
  53181. * Draw the markers.
  53182. * @private
  53183. */
  53184. FlagsSeries.prototype.drawPoints = function () {
  53185. var series = this,
  53186. points = series.points,
  53187. chart = series.chart,
  53188. renderer = chart.renderer,
  53189. plotX,
  53190. plotY,
  53191. inverted = chart.inverted,
  53192. options = series.options,
  53193. optionsY = options.y,
  53194. shape,
  53195. i,
  53196. point,
  53197. graphic,
  53198. stackIndex,
  53199. anchorY,
  53200. attribs,
  53201. outsideRight,
  53202. yAxis = series.yAxis,
  53203. boxesMap = {},
  53204. boxes = [],
  53205. centered;
  53206. i = points.length;
  53207. while (i--) {
  53208. point = points[i];
  53209. outsideRight =
  53210. (inverted ? point.plotY : point.plotX) >
  53211. series.xAxis.len;
  53212. plotX = point.plotX;
  53213. stackIndex = point.stackIndex;
  53214. shape = point.options.shape || options.shape;
  53215. plotY = point.plotY;
  53216. if (typeof plotY !== 'undefined') {
  53217. plotY = point.plotY + optionsY -
  53218. (typeof stackIndex !== 'undefined' &&
  53219. (stackIndex * options.stackDistance));
  53220. }
  53221. // skip connectors for higher level stacked points
  53222. point.anchorX = stackIndex ? void 0 : point.plotX;
  53223. anchorY = stackIndex ? void 0 : point.plotY;
  53224. centered = shape !== 'flag';
  53225. graphic = point.graphic;
  53226. // Only draw the point if y is defined and the flag is within
  53227. // the visible area
  53228. if (typeof plotY !== 'undefined' &&
  53229. plotX >= 0 &&
  53230. !outsideRight) {
  53231. // Create the flag
  53232. if (!graphic) {
  53233. graphic = point.graphic = renderer.label('', null, null, shape, null, null, options.useHTML)
  53234. .addClass('highcharts-point')
  53235. .add(series.markerGroup);
  53236. // Add reference to the point for tracker (#6303)
  53237. if (point.graphic.div) {
  53238. point.graphic.div.point = point;
  53239. }
  53240. graphic.isNew = true;
  53241. }
  53242. graphic.attr({
  53243. align: centered ? 'center' : 'left',
  53244. width: options.width,
  53245. height: options.height,
  53246. 'text-align': options.textAlign
  53247. });
  53248. if (!chart.styledMode) {
  53249. graphic
  53250. .attr(series.pointAttribs(point))
  53251. .css(merge(options.style, point.style))
  53252. .shadow(options.shadow);
  53253. }
  53254. if (plotX > 0) { // #3119
  53255. plotX -= graphic.strokeWidth() % 2; // #4285
  53256. }
  53257. // Plant the flag
  53258. attribs = {
  53259. y: plotY,
  53260. anchorY: anchorY
  53261. };
  53262. if (options.allowOverlapX) {
  53263. attribs.x = plotX;
  53264. attribs.anchorX = point.anchorX;
  53265. }
  53266. graphic.attr({
  53267. text: point.options.title || options.title || 'A'
  53268. })[graphic.isNew ? 'attr' : 'animate'](attribs);
  53269. // Rig for the distribute function
  53270. if (!options.allowOverlapX) {
  53271. if (!boxesMap[point.plotX]) {
  53272. boxesMap[point.plotX] = {
  53273. align: centered ? 0.5 : 0,
  53274. size: graphic.width,
  53275. target: plotX,
  53276. anchorX: plotX
  53277. };
  53278. }
  53279. else {
  53280. boxesMap[point.plotX].size = Math.max(boxesMap[point.plotX].size, graphic.width);
  53281. }
  53282. }
  53283. // Set the tooltip anchor position
  53284. point.tooltipPos = [
  53285. plotX,
  53286. plotY + yAxis.pos - chart.plotTop
  53287. ]; // #6327
  53288. }
  53289. else if (graphic) {
  53290. point.graphic = graphic.destroy();
  53291. }
  53292. }
  53293. // Handle X-dimension overlapping
  53294. if (!options.allowOverlapX) {
  53295. objectEach(boxesMap, function (box) {
  53296. box.plotX = box.anchorX;
  53297. boxes.push(box);
  53298. });
  53299. H.distribute(boxes, inverted ? yAxis.len : this.xAxis.len, 100);
  53300. points.forEach(function (point) {
  53301. var box = point.graphic && boxesMap[point.plotX];
  53302. if (box) {
  53303. point.graphic[point.graphic.isNew ? 'attr' : 'animate']({
  53304. x: box.pos + box.align * box.size,
  53305. anchorX: point.anchorX
  53306. });
  53307. // Hide flag when its box position is not specified
  53308. // (#8573, #9299)
  53309. if (!defined(box.pos)) {
  53310. point.graphic.attr({
  53311. x: -9999,
  53312. anchorX: -9999
  53313. });
  53314. point.graphic.isNew = true;
  53315. }
  53316. else {
  53317. point.graphic.isNew = false;
  53318. }
  53319. }
  53320. });
  53321. }
  53322. // Can be a mix of SVG and HTML and we need events for both (#6303)
  53323. if (options.useHTML) {
  53324. wrap(series.markerGroup, 'on', function (proceed) {
  53325. return SVGElement.prototype.on.apply(
  53326. // for HTML
  53327. // eslint-disable-next-line no-invalid-this
  53328. proceed.apply(this, [].slice.call(arguments, 1)),
  53329. // and for SVG
  53330. [].slice.call(arguments, 1));
  53331. });
  53332. }
  53333. };
  53334. /**
  53335. * Extend the column trackers with listeners to expand and contract
  53336. * stacks.
  53337. * @private
  53338. */
  53339. FlagsSeries.prototype.drawTracker = function () {
  53340. var series = this,
  53341. points = series.points;
  53342. _super.prototype.drawTracker.call(this);
  53343. /* *
  53344. * Bring each stacked flag up on mouse over, this allows readability
  53345. * of vertically stacked elements as well as tight points on the x
  53346. * axis. #1924.
  53347. */
  53348. points.forEach(function (point) {
  53349. var graphic = point.graphic;
  53350. if (graphic) {
  53351. addEvent(graphic.element, 'mouseover', function () {
  53352. // Raise this point
  53353. if (point.stackIndex > 0 &&
  53354. !point.raised) {
  53355. point._y = graphic.y;
  53356. graphic.attr({
  53357. y: point._y - 8
  53358. });
  53359. point.raised = true;
  53360. }
  53361. // Revert other raised points
  53362. points.forEach(function (otherPoint) {
  53363. if (otherPoint !== point &&
  53364. otherPoint.raised &&
  53365. otherPoint.graphic) {
  53366. otherPoint.graphic.attr({
  53367. y: otherPoint._y
  53368. });
  53369. otherPoint.raised = false;
  53370. }
  53371. });
  53372. });
  53373. }
  53374. });
  53375. };
  53376. /**
  53377. * Get presentational attributes
  53378. * @private
  53379. */
  53380. FlagsSeries.prototype.pointAttribs = function (point, state) {
  53381. var options = this.options,
  53382. color = (point && point.color) || this.color,
  53383. lineColor = options.lineColor,
  53384. lineWidth = (point && point.lineWidth),
  53385. fill = (point && point.fillColor) || options.fillColor;
  53386. if (state) {
  53387. fill = options.states[state].fillColor;
  53388. lineColor = options.states[state].lineColor;
  53389. lineWidth = options.states[state].lineWidth;
  53390. }
  53391. return {
  53392. fill: fill || color,
  53393. stroke: lineColor || color,
  53394. 'stroke-width': lineWidth || options.lineWidth || 0
  53395. };
  53396. };
  53397. /**
  53398. * @private
  53399. */
  53400. FlagsSeries.prototype.setClip = function () {
  53401. Series.prototype.setClip.apply(this, arguments);
  53402. if (this.options.clip !== false && this.sharedClipKey) {
  53403. this.markerGroup
  53404. .clip(this.chart[this.sharedClipKey]);
  53405. }
  53406. };
  53407. /**
  53408. * Flags are used to mark events in stock charts. They can be added on the
  53409. * timeline, or attached to a specific series.
  53410. *
  53411. * @sample stock/demo/flags-general/
  53412. * Flags on a line series
  53413. *
  53414. * @extends plotOptions.column
  53415. * @excluding animation, borderColor, borderRadius, borderWidth,
  53416. * colorByPoint, dataGrouping, pointPadding, pointWidth,
  53417. * turboThreshold
  53418. * @product highstock
  53419. * @optionparent plotOptions.flags
  53420. */
  53421. FlagsSeries.defaultOptions = merge(ColumnSeries.defaultOptions, {
  53422. /**
  53423. * In case the flag is placed on a series, on what point key to place
  53424. * it. Line and columns have one key, `y`. In range or OHLC-type series,
  53425. * however, the flag can optionally be placed on the `open`, `high`,
  53426. * `low` or `close` key.
  53427. *
  53428. * @sample {highstock} stock/plotoptions/flags-onkey/
  53429. * Range series, flag on high
  53430. *
  53431. * @type {string}
  53432. * @default y
  53433. * @since 4.2.2
  53434. * @product highstock
  53435. * @validvalue ["y", "open", "high", "low", "close"]
  53436. * @apioption plotOptions.flags.onKey
  53437. */
  53438. /**
  53439. * The id of the series that the flags should be drawn on. If no id
  53440. * is given, the flags are drawn on the x axis.
  53441. *
  53442. * @sample {highstock} stock/plotoptions/flags/
  53443. * Flags on series and on x axis
  53444. *
  53445. * @type {string}
  53446. * @product highstock
  53447. * @apioption plotOptions.flags.onSeries
  53448. */
  53449. pointRange: 0,
  53450. /**
  53451. * Whether the flags are allowed to overlap sideways. If `false`, the
  53452. * flags are moved sideways using an algorithm that seeks to place every
  53453. * flag as close as possible to its original position.
  53454. *
  53455. * @sample {highstock} stock/plotoptions/flags-allowoverlapx
  53456. * Allow sideways overlap
  53457. *
  53458. * @since 6.0.4
  53459. */
  53460. allowOverlapX: false,
  53461. /**
  53462. * The shape of the marker. Can be one of "flag", "circlepin",
  53463. * "squarepin", or an image of the format `url(/path-to-image.jpg)`.
  53464. * Individual shapes can also be set for each point.
  53465. *
  53466. * @sample {highstock} stock/plotoptions/flags/
  53467. * Different shapes
  53468. *
  53469. * @type {Highcharts.FlagsShapeValue}
  53470. * @product highstock
  53471. */
  53472. shape: 'flag',
  53473. /**
  53474. * When multiple flags in the same series fall on the same value, this
  53475. * number determines the vertical offset between them.
  53476. *
  53477. * @sample {highstock} stock/plotoptions/flags-stackdistance/
  53478. * A greater stack distance
  53479. *
  53480. * @product highstock
  53481. */
  53482. stackDistance: 12,
  53483. /**
  53484. * Text alignment for the text inside the flag.
  53485. *
  53486. * @since 5.0.0
  53487. * @product highstock
  53488. * @validvalue ["left", "center", "right"]
  53489. */
  53490. textAlign: 'center',
  53491. /**
  53492. * Specific tooltip options for flag series. Flag series tooltips are
  53493. * different from most other types in that a flag doesn't have a data
  53494. * value, so the tooltip rather displays the `text` option for each
  53495. * point.
  53496. *
  53497. * @extends plotOptions.series.tooltip
  53498. * @excluding changeDecimals, valueDecimals, valuePrefix, valueSuffix
  53499. * @product highstock
  53500. */
  53501. tooltip: {
  53502. pointFormat: '{point.text}<br/>'
  53503. },
  53504. threshold: null,
  53505. /**
  53506. * The text to display on each flag. This can be defined on series
  53507. * level, or individually for each point. Defaults to `"A"`.
  53508. *
  53509. * @type {string}
  53510. * @default A
  53511. * @product highstock
  53512. * @apioption plotOptions.flags.title
  53513. */
  53514. /**
  53515. * The y position of the top left corner of the flag relative to either
  53516. * the series (if onSeries is defined), or the x axis. Defaults to
  53517. * `-30`.
  53518. *
  53519. * @product highstock
  53520. */
  53521. y: -30,
  53522. /**
  53523. * Whether to use HTML to render the flag texts. Using HTML allows for
  53524. * advanced formatting, images and reliable bi-directional text
  53525. * rendering. Note that exported images won't respect the HTML, and that
  53526. * HTML won't respect Z-index settings.
  53527. *
  53528. * @type {boolean}
  53529. * @default false
  53530. * @since 1.3
  53531. * @product highstock
  53532. * @apioption plotOptions.flags.useHTML
  53533. */
  53534. /**
  53535. * Fixed width of the flag's shape. By default, width is autocalculated
  53536. * according to the flag's title.
  53537. *
  53538. * @sample {highstock} stock/demo/flags-shapes/
  53539. * Flags with fixed width
  53540. *
  53541. * @type {number}
  53542. * @product highstock
  53543. * @apioption plotOptions.flags.width
  53544. */
  53545. /**
  53546. * Fixed height of the flag's shape. By default, height is
  53547. * autocalculated according to the flag's title.
  53548. *
  53549. * @type {number}
  53550. * @product highstock
  53551. * @apioption plotOptions.flags.height
  53552. */
  53553. /**
  53554. * The fill color for the flags.
  53555. *
  53556. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  53557. * @product highstock
  53558. */
  53559. fillColor: palette.backgroundColor,
  53560. /**
  53561. * The color of the line/border of the flag.
  53562. *
  53563. * In styled mode, the stroke is set in the
  53564. * `.highcharts-flag-series.highcharts-point` rule.
  53565. *
  53566. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  53567. * @default #000000
  53568. * @product highstock
  53569. * @apioption plotOptions.flags.lineColor
  53570. */
  53571. /**
  53572. * The pixel width of the flag's line/border.
  53573. *
  53574. * @product highstock
  53575. */
  53576. lineWidth: 1,
  53577. states: {
  53578. /**
  53579. * @extends plotOptions.column.states.hover
  53580. * @product highstock
  53581. */
  53582. hover: {
  53583. /**
  53584. * The color of the line/border of the flag.
  53585. *
  53586. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  53587. * @product highstock
  53588. */
  53589. lineColor: palette.neutralColor100,
  53590. /**
  53591. * The fill or background color of the flag.
  53592. *
  53593. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  53594. * @product highstock
  53595. */
  53596. fillColor: palette.highlightColor20
  53597. }
  53598. },
  53599. /**
  53600. * The text styles of the flag.
  53601. *
  53602. * In styled mode, the styles are set in the
  53603. * `.highcharts-flag-series .highcharts-point` rule.
  53604. *
  53605. * @type {Highcharts.CSSObject}
  53606. * @default {"fontSize": "11px", "fontWeight": "bold"}
  53607. * @product highstock
  53608. */
  53609. style: {
  53610. /** @ignore-option */
  53611. fontSize: '11px',
  53612. /** @ignore-option */
  53613. fontWeight: 'bold'
  53614. }
  53615. });
  53616. return FlagsSeries;
  53617. }(ColumnSeries));
  53618. extend(FlagsSeries.prototype, {
  53619. allowDG: false,
  53620. /**
  53621. * @private
  53622. * @function Highcharts.seriesTypes.flags#buildKDTree
  53623. */
  53624. buildKDTree: noop,
  53625. forceCrop: true,
  53626. getPlotBox: OnSeriesMixin.getPlotBox,
  53627. /**
  53628. * Inherit the initialization from base Series.
  53629. *
  53630. * @private
  53631. * @borrows Highcharts.Series#init as Highcharts.seriesTypes.flags#init
  53632. */
  53633. init: Series.prototype.init,
  53634. /**
  53635. * Don't invert the flag marker group (#4960).
  53636. *
  53637. * @private
  53638. * @function Highcharts.seriesTypes.flags#invertGroups
  53639. */
  53640. invertGroups: noop,
  53641. // Flags series group should not be invertible (#14063).
  53642. invertible: false,
  53643. noSharedTooltip: true,
  53644. pointClass: FlagsPoint,
  53645. sorted: false,
  53646. takeOrdinalPosition: false,
  53647. trackerGroups: ['markerGroup'],
  53648. translate: OnSeriesMixin.translate
  53649. });
  53650. SeriesRegistry.registerSeriesType('flags', FlagsSeries);
  53651. /* *
  53652. *
  53653. * Default Export
  53654. *
  53655. * */
  53656. /* *
  53657. *
  53658. * API Declarations
  53659. *
  53660. * */
  53661. /**
  53662. * @typedef {"circlepin"|"flag"|"squarepin"} Highcharts.FlagsShapeValue
  53663. */
  53664. ''; // detach doclets above
  53665. /* *
  53666. *
  53667. * API Option
  53668. *
  53669. * */
  53670. /**
  53671. * A `flags` series. If the [type](#series.flags.type) option is not
  53672. * specified, it is inherited from [chart.type](#chart.type).
  53673. *
  53674. * @extends series,plotOptions.flags
  53675. * @excluding animation, borderColor, borderRadius, borderWidth, colorByPoint,
  53676. * connectNulls, dashStyle, dataGrouping, dataParser, dataURL,
  53677. * gapSize, gapUnit, linecap, lineWidth, marker, pointPadding,
  53678. * pointWidth, step, turboThreshold, useOhlcData
  53679. * @product highstock
  53680. * @apioption series.flags
  53681. */
  53682. /**
  53683. * An array of data points for the series. For the `flags` series type,
  53684. * points can be given in the following ways:
  53685. *
  53686. * 1. An array of objects with named values. The following snippet shows only a
  53687. * few settings, see the complete options set below. If the total number of
  53688. * data points exceeds the series'
  53689. * [turboThreshold](#series.flags.turboThreshold), this option is not
  53690. * available.
  53691. * ```js
  53692. * data: [{
  53693. * x: 1,
  53694. * title: "A",
  53695. * text: "First event"
  53696. * }, {
  53697. * x: 1,
  53698. * title: "B",
  53699. * text: "Second event"
  53700. * }]
  53701. * ```
  53702. *
  53703. * @type {Array<*>}
  53704. * @extends series.line.data
  53705. * @excluding dataLabels, marker, name, y
  53706. * @product highstock
  53707. * @apioption series.flags.data
  53708. */
  53709. /**
  53710. * The fill color of an individual flag. By default it inherits from
  53711. * the series color.
  53712. *
  53713. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  53714. * @product highstock
  53715. * @apioption series.flags.data.fillColor
  53716. */
  53717. /**
  53718. * The longer text to be shown in the flag's tooltip.
  53719. *
  53720. * @type {string}
  53721. * @product highstock
  53722. * @apioption series.flags.data.text
  53723. */
  53724. /**
  53725. * The short text to be shown on the flag.
  53726. *
  53727. * @type {string}
  53728. * @product highstock
  53729. * @apioption series.flags.data.title
  53730. */
  53731. ''; // adds doclets above to transpiled file
  53732. return FlagsSeries;
  53733. });
  53734. _registerModule(_modules, 'Extensions/RangeSelector.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Chart/Chart.js'], _modules['Core/Globals.js'], _modules['Core/Options.js'], _modules['Core/Color/Palette.js'], _modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Utilities.js']], function (Axis, Chart, H, O, palette, SVGElement, U) {
  53735. /* *
  53736. *
  53737. * (c) 2010-2021 Torstein Honsi
  53738. *
  53739. * License: www.highcharts.com/license
  53740. *
  53741. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  53742. *
  53743. * */
  53744. var defaultOptions = O.defaultOptions;
  53745. var addEvent = U.addEvent,
  53746. createElement = U.createElement,
  53747. css = U.css,
  53748. defined = U.defined,
  53749. destroyObjectProperties = U.destroyObjectProperties,
  53750. discardElement = U.discardElement,
  53751. extend = U.extend,
  53752. find = U.find,
  53753. fireEvent = U.fireEvent,
  53754. isNumber = U.isNumber,
  53755. merge = U.merge,
  53756. objectEach = U.objectEach,
  53757. pad = U.pad,
  53758. pick = U.pick,
  53759. pInt = U.pInt,
  53760. splat = U.splat;
  53761. /**
  53762. * Define the time span for the button
  53763. *
  53764. * @typedef {"all"|"day"|"hour"|"millisecond"|"minute"|"month"|"second"|"week"|"year"|"ytd"} Highcharts.RangeSelectorButtonTypeValue
  53765. */
  53766. /**
  53767. * Callback function to react on button clicks.
  53768. *
  53769. * @callback Highcharts.RangeSelectorClickCallbackFunction
  53770. *
  53771. * @param {global.Event} e
  53772. * Event arguments.
  53773. *
  53774. * @param {boolean|undefined}
  53775. * Return false to cancel the default button event.
  53776. */
  53777. /**
  53778. * Callback function to parse values entered in the input boxes and return a
  53779. * valid JavaScript time as milliseconds since 1970.
  53780. *
  53781. * @callback Highcharts.RangeSelectorParseCallbackFunction
  53782. *
  53783. * @param {string} value
  53784. * Input value to parse.
  53785. *
  53786. * @return {number}
  53787. * Parsed JavaScript time value.
  53788. */
  53789. /* ************************************************************************** *
  53790. * Start Range Selector code *
  53791. * ************************************************************************** */
  53792. extend(defaultOptions, {
  53793. /**
  53794. * The range selector is a tool for selecting ranges to display within
  53795. * the chart. It provides buttons to select preconfigured ranges in
  53796. * the chart, like 1 day, 1 week, 1 month etc. It also provides input
  53797. * boxes where min and max dates can be manually input.
  53798. *
  53799. * @product highstock gantt
  53800. * @optionparent rangeSelector
  53801. */
  53802. rangeSelector: {
  53803. /**
  53804. * Whether to enable all buttons from the start. By default buttons are
  53805. * only enabled if the corresponding time range exists on the X axis,
  53806. * but enabling all buttons allows for dynamically loading different
  53807. * time ranges.
  53808. *
  53809. * @sample {highstock} stock/rangeselector/allbuttonsenabled-true/
  53810. * All buttons enabled
  53811. *
  53812. * @since 2.0.3
  53813. */
  53814. allButtonsEnabled: false,
  53815. /**
  53816. * An array of configuration objects for the buttons.
  53817. *
  53818. * Defaults to:
  53819. * ```js
  53820. * buttons: [{
  53821. * type: 'month',
  53822. * count: 1,
  53823. * text: '1m',
  53824. * title: 'View 1 month'
  53825. * }, {
  53826. * type: 'month',
  53827. * count: 3,
  53828. * text: '3m',
  53829. * title: 'View 3 months'
  53830. * }, {
  53831. * type: 'month',
  53832. * count: 6,
  53833. * text: '6m',
  53834. * title: 'View 6 months'
  53835. * }, {
  53836. * type: 'ytd',
  53837. * text: 'YTD',
  53838. * title: 'View year to date'
  53839. * }, {
  53840. * type: 'year',
  53841. * count: 1,
  53842. * text: '1y',
  53843. * title: 'View 1 year'
  53844. * }, {
  53845. * type: 'all',
  53846. * text: 'All',
  53847. * title: 'View all'
  53848. * }]
  53849. * ```
  53850. *
  53851. * @sample {highstock} stock/rangeselector/datagrouping/
  53852. * Data grouping by buttons
  53853. *
  53854. * @type {Array<*>}
  53855. */
  53856. buttons: void 0,
  53857. /**
  53858. * How many units of the defined type the button should span. If `type`
  53859. * is "month" and `count` is 3, the button spans three months.
  53860. *
  53861. * @type {number}
  53862. * @default 1
  53863. * @apioption rangeSelector.buttons.count
  53864. */
  53865. /**
  53866. * Fires when clicking on the rangeSelector button. One parameter,
  53867. * event, is passed to the function, containing common event
  53868. * information.
  53869. *
  53870. * ```js
  53871. * click: function(e) {
  53872. * console.log(this);
  53873. * }
  53874. * ```
  53875. *
  53876. * Return false to stop default button's click action.
  53877. *
  53878. * @sample {highstock} stock/rangeselector/button-click/
  53879. * Click event on the button
  53880. *
  53881. * @type {Highcharts.RangeSelectorClickCallbackFunction}
  53882. * @apioption rangeSelector.buttons.events.click
  53883. */
  53884. /**
  53885. * Additional range (in milliseconds) added to the end of the calculated
  53886. * time span.
  53887. *
  53888. * @sample {highstock} stock/rangeselector/min-max-offsets/
  53889. * Button offsets
  53890. *
  53891. * @type {number}
  53892. * @default 0
  53893. * @since 6.0.0
  53894. * @apioption rangeSelector.buttons.offsetMax
  53895. */
  53896. /**
  53897. * Additional range (in milliseconds) added to the start of the
  53898. * calculated time span.
  53899. *
  53900. * @sample {highstock} stock/rangeselector/min-max-offsets/
  53901. * Button offsets
  53902. *
  53903. * @type {number}
  53904. * @default 0
  53905. * @since 6.0.0
  53906. * @apioption rangeSelector.buttons.offsetMin
  53907. */
  53908. /**
  53909. * When buttons apply dataGrouping on a series, by default zooming
  53910. * in/out will deselect buttons and unset dataGrouping. Enable this
  53911. * option to keep buttons selected when extremes change.
  53912. *
  53913. * @sample {highstock} stock/rangeselector/preserve-datagrouping/
  53914. * Different preserveDataGrouping settings
  53915. *
  53916. * @type {boolean}
  53917. * @default false
  53918. * @since 6.1.2
  53919. * @apioption rangeSelector.buttons.preserveDataGrouping
  53920. */
  53921. /**
  53922. * A custom data grouping object for each button.
  53923. *
  53924. * @see [series.dataGrouping](#plotOptions.series.dataGrouping)
  53925. *
  53926. * @sample {highstock} stock/rangeselector/datagrouping/
  53927. * Data grouping by range selector buttons
  53928. *
  53929. * @type {*}
  53930. * @extends plotOptions.series.dataGrouping
  53931. * @apioption rangeSelector.buttons.dataGrouping
  53932. */
  53933. /**
  53934. * The text for the button itself.
  53935. *
  53936. * @type {string}
  53937. * @apioption rangeSelector.buttons.text
  53938. */
  53939. /**
  53940. * Explanation for the button, shown as a tooltip on hover, and used by
  53941. * assistive technology.
  53942. *
  53943. * @type {string}
  53944. * @apioption rangeSelector.buttons.title
  53945. */
  53946. /**
  53947. * Defined the time span for the button. Can be one of `millisecond`,
  53948. * `second`, `minute`, `hour`, `day`, `week`, `month`, `year`, `ytd`,
  53949. * and `all`.
  53950. *
  53951. * @type {Highcharts.RangeSelectorButtonTypeValue}
  53952. * @apioption rangeSelector.buttons.type
  53953. */
  53954. /**
  53955. * The space in pixels between the buttons in the range selector.
  53956. */
  53957. buttonSpacing: 5,
  53958. /**
  53959. * Whether to collapse the range selector buttons into a dropdown when
  53960. * there is not enough room to show everything in a single row, instead
  53961. * of dividing the range selector into multiple rows.
  53962. * Can be one of the following:
  53963. * - `always`: Always collapse
  53964. * - `responsive`: Only collapse when there is not enough room
  53965. * - `never`: Never collapse
  53966. *
  53967. * @sample {highstock} stock/rangeselector/dropdown/
  53968. * Dropdown option
  53969. *
  53970. * @validvalue ["always", "responsive", "never"]
  53971. * @since 9.0.0
  53972. */
  53973. dropdown: 'responsive',
  53974. /**
  53975. * Enable or disable the range selector. Default to `true` for stock
  53976. * charts, using the `stockChart` factory.
  53977. *
  53978. * @sample {highstock} stock/rangeselector/enabled/
  53979. * Disable the range selector
  53980. *
  53981. * @type {boolean|undefined}
  53982. * @default {highstock} true
  53983. */
  53984. enabled: void 0,
  53985. /**
  53986. * The vertical alignment of the rangeselector box. Allowed properties
  53987. * are `top`, `middle`, `bottom`.
  53988. *
  53989. * @sample {highstock} stock/rangeselector/vertical-align-middle/
  53990. * Middle
  53991. * @sample {highstock} stock/rangeselector/vertical-align-bottom/
  53992. * Bottom
  53993. *
  53994. * @type {Highcharts.VerticalAlignValue}
  53995. * @since 6.0.0
  53996. */
  53997. verticalAlign: 'top',
  53998. /**
  53999. * A collection of attributes for the buttons. The object takes SVG
  54000. * attributes like `fill`, `stroke`, `stroke-width`, as well as `style`,
  54001. * a collection of CSS properties for the text.
  54002. *
  54003. * The object can also be extended with states, so you can set
  54004. * presentational options for `hover`, `select` or `disabled` button
  54005. * states.
  54006. *
  54007. * CSS styles for the text label.
  54008. *
  54009. * In styled mode, the buttons are styled by the
  54010. * `.highcharts-range-selector-buttons .highcharts-button` rule with its
  54011. * different states.
  54012. *
  54013. * @sample {highstock} stock/rangeselector/styling/
  54014. * Styling the buttons and inputs
  54015. *
  54016. * @type {Highcharts.SVGAttributes}
  54017. */
  54018. buttonTheme: {
  54019. /** @ignore */
  54020. width: 28,
  54021. /** @ignore */
  54022. height: 18,
  54023. /** @ignore */
  54024. padding: 2,
  54025. /** @ignore */
  54026. zIndex: 7 // #484, #852
  54027. },
  54028. /**
  54029. * When the rangeselector is floating, the plot area does not reserve
  54030. * space for it. This opens for positioning anywhere on the chart.
  54031. *
  54032. * @sample {highstock} stock/rangeselector/floating/
  54033. * Placing the range selector between the plot area and the
  54034. * navigator
  54035. *
  54036. * @since 6.0.0
  54037. */
  54038. floating: false,
  54039. /**
  54040. * The x offset of the range selector relative to its horizontal
  54041. * alignment within `chart.spacingLeft` and `chart.spacingRight`.
  54042. *
  54043. * @since 6.0.0
  54044. */
  54045. x: 0,
  54046. /**
  54047. * The y offset of the range selector relative to its horizontal
  54048. * alignment within `chart.spacingLeft` and `chart.spacingRight`.
  54049. *
  54050. * @since 6.0.0
  54051. */
  54052. y: 0,
  54053. /**
  54054. * Deprecated. The height of the range selector. Currently it is
  54055. * calculated dynamically.
  54056. *
  54057. * @deprecated
  54058. * @type {number|undefined}
  54059. * @since 2.1.9
  54060. */
  54061. height: void 0,
  54062. /**
  54063. * The border color of the date input boxes.
  54064. *
  54065. * @sample {highstock} stock/rangeselector/styling/
  54066. * Styling the buttons and inputs
  54067. *
  54068. * @type {Highcharts.ColorString}
  54069. * @since 1.3.7
  54070. */
  54071. inputBoxBorderColor: 'none',
  54072. /**
  54073. * The pixel height of the date input boxes.
  54074. *
  54075. * @sample {highstock} stock/rangeselector/styling/
  54076. * Styling the buttons and inputs
  54077. *
  54078. * @since 1.3.7
  54079. */
  54080. inputBoxHeight: 17,
  54081. /**
  54082. * The pixel width of the date input boxes. When `undefined`, the width
  54083. * is fitted to the rendered content.
  54084. *
  54085. * @sample {highstock} stock/rangeselector/styling/
  54086. * Styling the buttons and inputs
  54087. *
  54088. * @type {number|undefined}
  54089. * @since 1.3.7
  54090. */
  54091. inputBoxWidth: void 0,
  54092. /**
  54093. * The date format in the input boxes when not selected for editing.
  54094. * Defaults to `%b %e, %Y`.
  54095. *
  54096. * This is used to determine which type of input to show,
  54097. * `datetime-local`, `date` or `time` and falling back to `text` when
  54098. * the browser does not support the input type or the format contains
  54099. * milliseconds.
  54100. *
  54101. * @sample {highstock} stock/rangeselector/input-type/
  54102. * Input types
  54103. * @sample {highstock} stock/rangeselector/input-format/
  54104. * Milliseconds in the range selector
  54105. *
  54106. */
  54107. inputDateFormat: '%b %e, %Y',
  54108. /**
  54109. * A custom callback function to parse values entered in the input boxes
  54110. * and return a valid JavaScript time as milliseconds since 1970.
  54111. * The first argument passed is a value to parse,
  54112. * second is a boolean indicating use of the UTC time.
  54113. *
  54114. * This will only get called for inputs of type `text`. Since v8.2.3,
  54115. * the input type is dynamically determined based on the granularity
  54116. * of the `inputDateFormat` and the browser support.
  54117. *
  54118. * @sample {highstock} stock/rangeselector/input-format/
  54119. * Milliseconds in the range selector
  54120. *
  54121. * @type {Highcharts.RangeSelectorParseCallbackFunction}
  54122. * @since 1.3.3
  54123. */
  54124. inputDateParser: void 0,
  54125. /**
  54126. * The date format in the input boxes when they are selected for
  54127. * editing. This must be a format that is recognized by JavaScript
  54128. * Date.parse.
  54129. *
  54130. * This will only be used for inputs of type `text`. Since v8.2.3,
  54131. * the input type is dynamically determined based on the granularity
  54132. * of the `inputDateFormat` and the browser support.
  54133. *
  54134. * @sample {highstock} stock/rangeselector/input-format/
  54135. * Milliseconds in the range selector
  54136. *
  54137. */
  54138. inputEditDateFormat: '%Y-%m-%d',
  54139. /**
  54140. * Enable or disable the date input boxes.
  54141. */
  54142. inputEnabled: true,
  54143. /**
  54144. * Positioning for the input boxes. Allowed properties are `align`,
  54145. * `x` and `y`.
  54146. *
  54147. * @since 1.2.4
  54148. */
  54149. inputPosition: {
  54150. /**
  54151. * The alignment of the input box. Allowed properties are `left`,
  54152. * `center`, `right`.
  54153. *
  54154. * @sample {highstock} stock/rangeselector/input-button-position/
  54155. * Alignment
  54156. *
  54157. * @type {Highcharts.AlignValue}
  54158. * @since 6.0.0
  54159. */
  54160. align: 'right',
  54161. /**
  54162. * X offset of the input row.
  54163. */
  54164. x: 0,
  54165. /**
  54166. * Y offset of the input row.
  54167. */
  54168. y: 0
  54169. },
  54170. /**
  54171. * The space in pixels between the labels and the date input boxes in
  54172. * the range selector.
  54173. *
  54174. * @since 9.0.0
  54175. */
  54176. inputSpacing: 5,
  54177. /**
  54178. * The index of the button to appear pre-selected.
  54179. *
  54180. * @type {number}
  54181. */
  54182. selected: void 0,
  54183. /**
  54184. * Positioning for the button row.
  54185. *
  54186. * @since 1.2.4
  54187. */
  54188. buttonPosition: {
  54189. /**
  54190. * The alignment of the input box. Allowed properties are `left`,
  54191. * `center`, `right`.
  54192. *
  54193. * @sample {highstock} stock/rangeselector/input-button-position/
  54194. * Alignment
  54195. *
  54196. * @type {Highcharts.AlignValue}
  54197. * @since 6.0.0
  54198. */
  54199. align: 'left',
  54200. /**
  54201. * X offset of the button row.
  54202. */
  54203. x: 0,
  54204. /**
  54205. * Y offset of the button row.
  54206. */
  54207. y: 0
  54208. },
  54209. /**
  54210. * CSS for the HTML inputs in the range selector.
  54211. *
  54212. * In styled mode, the inputs are styled by the
  54213. * `.highcharts-range-input text` rule in SVG mode, and
  54214. * `input.highcharts-range-selector` when active.
  54215. *
  54216. * @sample {highstock} stock/rangeselector/styling/
  54217. * Styling the buttons and inputs
  54218. *
  54219. * @type {Highcharts.CSSObject}
  54220. * @apioption rangeSelector.inputStyle
  54221. */
  54222. inputStyle: {
  54223. /** @ignore */
  54224. color: palette.highlightColor80,
  54225. /** @ignore */
  54226. cursor: 'pointer'
  54227. },
  54228. /**
  54229. * CSS styles for the labels - the Zoom, From and To texts.
  54230. *
  54231. * In styled mode, the labels are styled by the
  54232. * `.highcharts-range-label` class.
  54233. *
  54234. * @sample {highstock} stock/rangeselector/styling/
  54235. * Styling the buttons and inputs
  54236. *
  54237. * @type {Highcharts.CSSObject}
  54238. */
  54239. labelStyle: {
  54240. /** @ignore */
  54241. color: palette.neutralColor60
  54242. }
  54243. }
  54244. });
  54245. extend(defaultOptions.lang,
  54246. /**
  54247. * Language object. The language object is global and it can't be set
  54248. * on each chart initialization. Instead, use `Highcharts.setOptions` to
  54249. * set it before any chart is initialized.
  54250. *
  54251. * ```js
  54252. * Highcharts.setOptions({
  54253. * lang: {
  54254. * months: [
  54255. * 'Janvier', 'Février', 'Mars', 'Avril',
  54256. * 'Mai', 'Juin', 'Juillet', 'Août',
  54257. * 'Septembre', 'Octobre', 'Novembre', 'Décembre'
  54258. * ],
  54259. * weekdays: [
  54260. * 'Dimanche', 'Lundi', 'Mardi', 'Mercredi',
  54261. * 'Jeudi', 'Vendredi', 'Samedi'
  54262. * ]
  54263. * }
  54264. * });
  54265. * ```
  54266. *
  54267. * @optionparent lang
  54268. */
  54269. {
  54270. /**
  54271. * The text for the label for the range selector buttons.
  54272. *
  54273. * @product highstock gantt
  54274. */
  54275. rangeSelectorZoom: 'Zoom',
  54276. /**
  54277. * The text for the label for the "from" input box in the range
  54278. * selector. Since v9.0, this string is empty as the label is not
  54279. * rendered by default.
  54280. *
  54281. * @product highstock gantt
  54282. */
  54283. rangeSelectorFrom: '',
  54284. /**
  54285. * The text for the label for the "to" input box in the range selector.
  54286. *
  54287. * @product highstock gantt
  54288. */
  54289. rangeSelectorTo: '→'
  54290. });
  54291. /* eslint-disable no-invalid-this, valid-jsdoc */
  54292. /**
  54293. * The range selector.
  54294. *
  54295. * @private
  54296. * @class
  54297. * @name Highcharts.RangeSelector
  54298. * @param {Highcharts.Chart} chart
  54299. */
  54300. var RangeSelector = /** @class */ (function () {
  54301. function RangeSelector(chart) {
  54302. /* *
  54303. *
  54304. * Properties
  54305. *
  54306. * */
  54307. this.buttons = void 0;
  54308. this.buttonOptions = RangeSelector.prototype.defaultButtons;
  54309. this.initialButtonGroupWidth = 0;
  54310. this.options = void 0;
  54311. this.chart = chart;
  54312. // Run RangeSelector
  54313. this.init(chart);
  54314. }
  54315. /**
  54316. * The method to run when one of the buttons in the range selectors is
  54317. * clicked
  54318. *
  54319. * @private
  54320. * @function Highcharts.RangeSelector#clickButton
  54321. * @param {number} i
  54322. * The index of the button
  54323. * @param {boolean} [redraw]
  54324. * @return {void}
  54325. */
  54326. RangeSelector.prototype.clickButton = function (i, redraw) {
  54327. var rangeSelector = this,
  54328. chart = rangeSelector.chart,
  54329. rangeOptions = rangeSelector.buttonOptions[i],
  54330. baseAxis = chart.xAxis[0],
  54331. unionExtremes = (chart.scroller && chart.scroller.getUnionExtremes()) || baseAxis || {},
  54332. dataMin = unionExtremes.dataMin,
  54333. dataMax = unionExtremes.dataMax,
  54334. newMin,
  54335. newMax = baseAxis && Math.round(Math.min(baseAxis.max,
  54336. pick(dataMax,
  54337. baseAxis.max))), // #1568
  54338. type = rangeOptions.type,
  54339. baseXAxisOptions,
  54340. range = rangeOptions._range,
  54341. rangeMin,
  54342. minSetting,
  54343. rangeSetting,
  54344. ctx,
  54345. ytdExtremes,
  54346. dataGrouping = rangeOptions.dataGrouping;
  54347. // chart has no data, base series is removed
  54348. if (dataMin === null || dataMax === null) {
  54349. return;
  54350. }
  54351. // Set the fixed range before range is altered
  54352. chart.fixedRange = range;
  54353. // Apply dataGrouping associated to button
  54354. if (dataGrouping) {
  54355. this.forcedDataGrouping = true;
  54356. Axis.prototype.setDataGrouping.call(baseAxis || { chart: this.chart }, dataGrouping, false);
  54357. this.frozenStates = rangeOptions.preserveDataGrouping;
  54358. }
  54359. // Apply range
  54360. if (type === 'month' || type === 'year') {
  54361. if (!baseAxis) {
  54362. // This is set to the user options and picked up later when the
  54363. // axis is instantiated so that we know the min and max.
  54364. range = rangeOptions;
  54365. }
  54366. else {
  54367. ctx = {
  54368. range: rangeOptions,
  54369. max: newMax,
  54370. chart: chart,
  54371. dataMin: dataMin,
  54372. dataMax: dataMax
  54373. };
  54374. newMin = baseAxis.minFromRange.call(ctx);
  54375. if (isNumber(ctx.newMax)) {
  54376. newMax = ctx.newMax;
  54377. }
  54378. }
  54379. // Fixed times like minutes, hours, days
  54380. }
  54381. else if (range) {
  54382. newMin = Math.max(newMax - range, dataMin);
  54383. newMax = Math.min(newMin + range, dataMax);
  54384. }
  54385. else if (type === 'ytd') {
  54386. // On user clicks on the buttons, or a delayed action running from
  54387. // the beforeRender event (below), the baseAxis is defined.
  54388. if (baseAxis) {
  54389. // When "ytd" is the pre-selected button for the initial view,
  54390. // its calculation is delayed and rerun in the beforeRender
  54391. // event (below). When the series are initialized, but before
  54392. // the chart is rendered, we have access to the xData array
  54393. // (#942).
  54394. if (typeof dataMax === 'undefined') {
  54395. dataMin = Number.MAX_VALUE;
  54396. dataMax = Number.MIN_VALUE;
  54397. chart.series.forEach(function (series) {
  54398. // reassign it to the last item
  54399. var xData = series.xData;
  54400. dataMin = Math.min(xData[0], dataMin);
  54401. dataMax = Math.max(xData[xData.length - 1], dataMax);
  54402. });
  54403. redraw = false;
  54404. }
  54405. ytdExtremes = rangeSelector.getYTDExtremes(dataMax, dataMin, chart.time.useUTC);
  54406. newMin = rangeMin = ytdExtremes.min;
  54407. newMax = ytdExtremes.max;
  54408. // "ytd" is pre-selected. We don't yet have access to processed
  54409. // point and extremes data (things like pointStart and pointInterval
  54410. // are missing), so we delay the process (#942)
  54411. }
  54412. else {
  54413. rangeSelector.deferredYTDClick = i;
  54414. return;
  54415. }
  54416. }
  54417. else if (type === 'all' && baseAxis) {
  54418. newMin = dataMin;
  54419. newMax = dataMax;
  54420. }
  54421. if (defined(newMin)) {
  54422. newMin += rangeOptions._offsetMin;
  54423. }
  54424. if (defined(newMax)) {
  54425. newMax += rangeOptions._offsetMax;
  54426. }
  54427. rangeSelector.setSelected(i);
  54428. if (this.dropdown) {
  54429. this.dropdown.selectedIndex = i + 1;
  54430. }
  54431. // Update the chart
  54432. if (!baseAxis) {
  54433. // Axis not yet instanciated. Temporarily set min and range
  54434. // options and remove them on chart load (#4317).
  54435. baseXAxisOptions = splat(chart.options.xAxis)[0];
  54436. rangeSetting = baseXAxisOptions.range;
  54437. baseXAxisOptions.range = range;
  54438. minSetting = baseXAxisOptions.min;
  54439. baseXAxisOptions.min = rangeMin;
  54440. addEvent(chart, 'load', function resetMinAndRange() {
  54441. baseXAxisOptions.range = rangeSetting;
  54442. baseXAxisOptions.min = minSetting;
  54443. });
  54444. }
  54445. else {
  54446. // Existing axis object. Set extremes after render time.
  54447. baseAxis.setExtremes(newMin, newMax, pick(redraw, true), void 0, // auto animation
  54448. {
  54449. trigger: 'rangeSelectorButton',
  54450. rangeSelectorButton: rangeOptions
  54451. });
  54452. }
  54453. fireEvent(this, 'afterBtnClick');
  54454. };
  54455. /**
  54456. * Set the selected option. This method only sets the internal flag, it
  54457. * doesn't update the buttons or the actual zoomed range.
  54458. *
  54459. * @private
  54460. * @function Highcharts.RangeSelector#setSelected
  54461. * @param {number} [selected]
  54462. * @return {void}
  54463. */
  54464. RangeSelector.prototype.setSelected = function (selected) {
  54465. this.selected = this.options.selected = selected;
  54466. };
  54467. /**
  54468. * Initialize the range selector
  54469. *
  54470. * @private
  54471. * @function Highcharts.RangeSelector#init
  54472. * @param {Highcharts.Chart} chart
  54473. * @return {void}
  54474. */
  54475. RangeSelector.prototype.init = function (chart) {
  54476. var rangeSelector = this,
  54477. options = chart.options.rangeSelector,
  54478. buttonOptions = options.buttons || rangeSelector.defaultButtons.slice(),
  54479. selectedOption = options.selected,
  54480. blurInputs = function () {
  54481. var minInput = rangeSelector.minInput,
  54482. maxInput = rangeSelector.maxInput;
  54483. // #3274 in some case blur is not defined
  54484. if (minInput && minInput.blur) {
  54485. fireEvent(minInput, 'blur');
  54486. }
  54487. if (maxInput && maxInput.blur) {
  54488. fireEvent(maxInput, 'blur');
  54489. }
  54490. };
  54491. rangeSelector.chart = chart;
  54492. rangeSelector.options = options;
  54493. rangeSelector.buttons = [];
  54494. rangeSelector.buttonOptions = buttonOptions;
  54495. this.eventsToUnbind = [];
  54496. this.eventsToUnbind.push(addEvent(chart.container, 'mousedown', blurInputs));
  54497. this.eventsToUnbind.push(addEvent(chart, 'resize', blurInputs));
  54498. // Extend the buttonOptions with actual range
  54499. buttonOptions.forEach(rangeSelector.computeButtonRange);
  54500. // zoomed range based on a pre-selected button index
  54501. if (typeof selectedOption !== 'undefined' &&
  54502. buttonOptions[selectedOption]) {
  54503. this.clickButton(selectedOption, false);
  54504. }
  54505. this.eventsToUnbind.push(addEvent(chart, 'load', function () {
  54506. // If a data grouping is applied to the current button, release it
  54507. // when extremes change
  54508. if (chart.xAxis && chart.xAxis[0]) {
  54509. addEvent(chart.xAxis[0], 'setExtremes', function (e) {
  54510. if (this.max - this.min !==
  54511. chart.fixedRange &&
  54512. e.trigger !== 'rangeSelectorButton' &&
  54513. e.trigger !== 'updatedData' &&
  54514. rangeSelector.forcedDataGrouping &&
  54515. !rangeSelector.frozenStates) {
  54516. this.setDataGrouping(false, false);
  54517. }
  54518. });
  54519. }
  54520. }));
  54521. };
  54522. /**
  54523. * Dynamically update the range selector buttons after a new range has been
  54524. * set
  54525. *
  54526. * @private
  54527. * @function Highcharts.RangeSelector#updateButtonStates
  54528. * @return {void}
  54529. */
  54530. RangeSelector.prototype.updateButtonStates = function () {
  54531. var rangeSelector = this,
  54532. chart = this.chart,
  54533. dropdown = this.dropdown,
  54534. baseAxis = chart.xAxis[0],
  54535. actualRange = Math.round(baseAxis.max - baseAxis.min),
  54536. hasNoData = !baseAxis.hasVisibleSeries,
  54537. day = 24 * 36e5, // A single day in milliseconds
  54538. unionExtremes = (chart.scroller &&
  54539. chart.scroller.getUnionExtremes()) || baseAxis,
  54540. dataMin = unionExtremes.dataMin,
  54541. dataMax = unionExtremes.dataMax,
  54542. ytdExtremes = rangeSelector.getYTDExtremes(dataMax,
  54543. dataMin,
  54544. chart.time.useUTC),
  54545. ytdMin = ytdExtremes.min,
  54546. ytdMax = ytdExtremes.max,
  54547. selected = rangeSelector.selected,
  54548. selectedExists = isNumber(selected),
  54549. allButtonsEnabled = rangeSelector.options.allButtonsEnabled,
  54550. buttons = rangeSelector.buttons;
  54551. rangeSelector.buttonOptions.forEach(function (rangeOptions, i) {
  54552. var range = rangeOptions._range,
  54553. type = rangeOptions.type,
  54554. count = rangeOptions.count || 1,
  54555. button = buttons[i],
  54556. state = 0,
  54557. disable,
  54558. select,
  54559. offsetRange = rangeOptions._offsetMax -
  54560. rangeOptions._offsetMin,
  54561. isSelected = i === selected,
  54562. // Disable buttons where the range exceeds what is allowed in
  54563. // the current view
  54564. isTooGreatRange = range >
  54565. dataMax - dataMin,
  54566. // Disable buttons where the range is smaller than the minimum
  54567. // range
  54568. isTooSmallRange = range < baseAxis.minRange,
  54569. // Do not select the YTD button if not explicitly told so
  54570. isYTDButNotSelected = false,
  54571. // Disable the All button if we're already showing all
  54572. isAllButAlreadyShowingAll = false,
  54573. isSameRange = range === actualRange;
  54574. // Months and years have a variable range so we check the extremes
  54575. if ((type === 'month' || type === 'year') &&
  54576. (actualRange + 36e5 >=
  54577. { month: 28, year: 365 }[type] * day * count - offsetRange) &&
  54578. (actualRange - 36e5 <=
  54579. { month: 31, year: 366 }[type] * day * count + offsetRange)) {
  54580. isSameRange = true;
  54581. }
  54582. else if (type === 'ytd') {
  54583. isSameRange = (ytdMax - ytdMin + offsetRange) === actualRange;
  54584. isYTDButNotSelected = !isSelected;
  54585. }
  54586. else if (type === 'all') {
  54587. isSameRange = (baseAxis.max - baseAxis.min >=
  54588. dataMax - dataMin);
  54589. isAllButAlreadyShowingAll = (!isSelected &&
  54590. selectedExists &&
  54591. isSameRange);
  54592. }
  54593. // The new zoom area happens to match the range for a button - mark
  54594. // it selected. This happens when scrolling across an ordinal gap.
  54595. // It can be seen in the intraday demos when selecting 1h and scroll
  54596. // across the night gap.
  54597. disable = (!allButtonsEnabled &&
  54598. (isTooGreatRange ||
  54599. isTooSmallRange ||
  54600. isAllButAlreadyShowingAll ||
  54601. hasNoData));
  54602. select = ((isSelected && isSameRange) ||
  54603. (isSameRange && !selectedExists && !isYTDButNotSelected) ||
  54604. (isSelected && rangeSelector.frozenStates));
  54605. if (disable) {
  54606. state = 3;
  54607. }
  54608. else if (select) {
  54609. selectedExists = true; // Only one button can be selected
  54610. state = 2;
  54611. }
  54612. // If state has changed, update the button
  54613. if (button.state !== state) {
  54614. button.setState(state);
  54615. if (dropdown) {
  54616. dropdown.options[i + 1].disabled = disable;
  54617. if (state === 2) {
  54618. dropdown.selectedIndex = i + 1;
  54619. }
  54620. }
  54621. // Reset (#9209)
  54622. if (state === 0 && selected === i) {
  54623. rangeSelector.setSelected();
  54624. }
  54625. }
  54626. });
  54627. };
  54628. /**
  54629. * Compute and cache the range for an individual button
  54630. *
  54631. * @private
  54632. * @function Highcharts.RangeSelector#computeButtonRange
  54633. * @param {Highcharts.RangeSelectorButtonsOptions} rangeOptions
  54634. * @return {void}
  54635. */
  54636. RangeSelector.prototype.computeButtonRange = function (rangeOptions) {
  54637. var type = rangeOptions.type,
  54638. count = rangeOptions.count || 1,
  54639. // these time intervals have a fixed number of milliseconds, as
  54640. // opposed to month, ytd and year
  54641. fixedTimes = {
  54642. millisecond: 1,
  54643. second: 1000,
  54644. minute: 60 * 1000,
  54645. hour: 3600 * 1000,
  54646. day: 24 * 3600 * 1000,
  54647. week: 7 * 24 * 3600 * 1000
  54648. };
  54649. // Store the range on the button object
  54650. if (fixedTimes[type]) {
  54651. rangeOptions._range = fixedTimes[type] * count;
  54652. }
  54653. else if (type === 'month' || type === 'year') {
  54654. rangeOptions._range = {
  54655. month: 30,
  54656. year: 365
  54657. }[type] * 24 * 36e5 * count;
  54658. }
  54659. rangeOptions._offsetMin = pick(rangeOptions.offsetMin, 0);
  54660. rangeOptions._offsetMax = pick(rangeOptions.offsetMax, 0);
  54661. rangeOptions._range +=
  54662. rangeOptions._offsetMax - rangeOptions._offsetMin;
  54663. };
  54664. /**
  54665. * Get the unix timestamp of a HTML input for the dates
  54666. *
  54667. * @private
  54668. * @function Highcharts.RangeSelector#getInputValue
  54669. * @param {string} name
  54670. * @return {number}
  54671. */
  54672. RangeSelector.prototype.getInputValue = function (name) {
  54673. var input = name === 'min' ? this.minInput : this.maxInput;
  54674. var options = this.chart.options.rangeSelector;
  54675. var time = this.chart.time;
  54676. if (input) {
  54677. return ((input.type === 'text' && options.inputDateParser) ||
  54678. this.defaultInputDateParser)(input.value, time.useUTC, time);
  54679. }
  54680. return 0;
  54681. };
  54682. /**
  54683. * Set the internal and displayed value of a HTML input for the dates
  54684. *
  54685. * @private
  54686. * @function Highcharts.RangeSelector#setInputValue
  54687. * @param {string} name
  54688. * @param {number} [inputTime]
  54689. * @return {void}
  54690. */
  54691. RangeSelector.prototype.setInputValue = function (name, inputTime) {
  54692. var options = this.options, time = this.chart.time, input = name === 'min' ? this.minInput : this.maxInput, dateBox = name === 'min' ? this.minDateBox : this.maxDateBox;
  54693. if (input) {
  54694. var hcTimeAttr = input.getAttribute('data-hc-time');
  54695. var updatedTime = defined(hcTimeAttr) ? Number(hcTimeAttr) : void 0;
  54696. if (defined(inputTime)) {
  54697. var previousTime = updatedTime;
  54698. if (defined(previousTime)) {
  54699. input.setAttribute('data-hc-time-previous', previousTime);
  54700. }
  54701. input.setAttribute('data-hc-time', inputTime);
  54702. updatedTime = inputTime;
  54703. }
  54704. input.value = time.dateFormat(this.inputTypeFormats[input.type] || options.inputEditDateFormat, updatedTime);
  54705. if (dateBox) {
  54706. dateBox.attr({
  54707. text: time.dateFormat(options.inputDateFormat, updatedTime)
  54708. });
  54709. }
  54710. }
  54711. };
  54712. /**
  54713. * Set the min and max value of a HTML input for the dates
  54714. *
  54715. * @private
  54716. * @function Highcharts.RangeSelector#setInputExtremes
  54717. * @param {string} name
  54718. * @param {number} min
  54719. * @param {number} max
  54720. * @return {void}
  54721. */
  54722. RangeSelector.prototype.setInputExtremes = function (name, min, max) {
  54723. var input = name === 'min' ? this.minInput : this.maxInput;
  54724. if (input) {
  54725. var format = this.inputTypeFormats[input.type];
  54726. var time = this.chart.time;
  54727. if (format) {
  54728. var newMin = time.dateFormat(format,
  54729. min);
  54730. if (input.min !== newMin) {
  54731. input.min = newMin;
  54732. }
  54733. var newMax = time.dateFormat(format,
  54734. max);
  54735. if (input.max !== newMax) {
  54736. input.max = newMax;
  54737. }
  54738. }
  54739. }
  54740. };
  54741. /**
  54742. * @private
  54743. * @function Highcharts.RangeSelector#showInput
  54744. * @param {string} name
  54745. * @return {void}
  54746. */
  54747. RangeSelector.prototype.showInput = function (name) {
  54748. var dateBox = name === 'min' ? this.minDateBox : this.maxDateBox;
  54749. var input = name === 'min' ? this.minInput : this.maxInput;
  54750. if (input && dateBox && this.inputGroup) {
  54751. var isTextInput = input.type === 'text';
  54752. var _a = this.inputGroup,
  54753. translateX = _a.translateX,
  54754. translateY = _a.translateY;
  54755. css(input, {
  54756. width: isTextInput ? ((dateBox.width - 2) + 'px') : 'auto',
  54757. height: isTextInput ? ((dateBox.height - 2) + 'px') : 'auto',
  54758. border: '2px solid silver'
  54759. });
  54760. if (isTextInput) {
  54761. css(input, {
  54762. left: (translateX + dateBox.x) + 'px',
  54763. top: translateY + 'px'
  54764. });
  54765. // Inputs of types date, time or datetime-local should be centered
  54766. // on top of the dateBox
  54767. }
  54768. else {
  54769. css(input, {
  54770. left: Math.min(Math.round(dateBox.x +
  54771. translateX -
  54772. (input.offsetWidth - dateBox.width) / 2), this.chart.chartWidth - input.offsetWidth) + 'px',
  54773. top: (translateY - (input.offsetHeight - dateBox.height) / 2) + 'px'
  54774. });
  54775. }
  54776. }
  54777. };
  54778. /**
  54779. * @private
  54780. * @function Highcharts.RangeSelector#hideInput
  54781. * @param {string} name
  54782. * @return {void}
  54783. */
  54784. RangeSelector.prototype.hideInput = function (name) {
  54785. var input = name === 'min' ? this.minInput : this.maxInput;
  54786. if (input) {
  54787. css(input, {
  54788. top: '-9999em',
  54789. border: 0,
  54790. width: '1px',
  54791. height: '1px'
  54792. });
  54793. }
  54794. };
  54795. /**
  54796. * @private
  54797. * @function Highcharts.RangeSelector#defaultInputDateParser
  54798. */
  54799. RangeSelector.prototype.defaultInputDateParser = function (inputDate, useUTC, time) {
  54800. var hasTimezone = function (str) {
  54801. return str.length > 6 &&
  54802. (str.lastIndexOf('-') === str.length - 6 ||
  54803. str.lastIndexOf('+') === str.length - 6);
  54804. };
  54805. var input = inputDate.split('/').join('-').split(' ').join('T');
  54806. if (input.indexOf('T') === -1) {
  54807. input += 'T00:00';
  54808. }
  54809. if (useUTC) {
  54810. input += 'Z';
  54811. }
  54812. else if (H.isSafari && !hasTimezone(input)) {
  54813. var offset = new Date(input).getTimezoneOffset() / 60;
  54814. input += offset <= 0 ? "+" + pad(-offset) + ":00" : "-" + pad(offset) + ":00";
  54815. }
  54816. var date = Date.parse(input);
  54817. // If the value isn't parsed directly to a value by the
  54818. // browser's Date.parse method, like YYYY-MM-DD in IE8, try
  54819. // parsing it a different way
  54820. if (!isNumber(date)) {
  54821. var parts = inputDate.split('-');
  54822. date = Date.UTC(pInt(parts[0]), pInt(parts[1]) - 1, pInt(parts[2]));
  54823. }
  54824. if (time && useUTC) {
  54825. date += time.getTimezoneOffset(date);
  54826. }
  54827. return date;
  54828. };
  54829. /**
  54830. * Draw either the 'from' or the 'to' HTML input box of the range selector
  54831. *
  54832. * @private
  54833. * @function Highcharts.RangeSelector#drawInput
  54834. * @param {string} name
  54835. * @return {RangeSelectorInputElements}
  54836. */
  54837. RangeSelector.prototype.drawInput = function (name) {
  54838. var _a = this,
  54839. chart = _a.chart,
  54840. div = _a.div,
  54841. inputGroup = _a.inputGroup;
  54842. var rangeSelector = this,
  54843. chartStyle = chart.renderer.style || {},
  54844. renderer = chart.renderer,
  54845. options = chart.options.rangeSelector,
  54846. lang = defaultOptions.lang,
  54847. isMin = name === 'min';
  54848. /**
  54849. * @private
  54850. */
  54851. function updateExtremes() {
  54852. var value = rangeSelector.getInputValue(name),
  54853. chartAxis = chart.xAxis[0],
  54854. dataAxis = chart.scroller && chart.scroller.xAxis ?
  54855. chart.scroller.xAxis :
  54856. chartAxis,
  54857. dataMin = dataAxis.dataMin,
  54858. dataMax = dataAxis.dataMax;
  54859. var maxInput = rangeSelector.maxInput,
  54860. minInput = rangeSelector.minInput;
  54861. if (value !== Number(input.getAttribute('data-hc-time-previous')) &&
  54862. isNumber(value)) {
  54863. input.setAttribute('data-hc-time-previous', value);
  54864. // Validate the extremes. If it goes beyound the data min or
  54865. // max, use the actual data extreme (#2438).
  54866. if (isMin && maxInput && isNumber(dataMin)) {
  54867. if (value > Number(maxInput.getAttribute('data-hc-time'))) {
  54868. value = void 0;
  54869. }
  54870. else if (value < dataMin) {
  54871. value = dataMin;
  54872. }
  54873. }
  54874. else if (minInput && isNumber(dataMax)) {
  54875. if (value < Number(minInput.getAttribute('data-hc-time'))) {
  54876. value = void 0;
  54877. }
  54878. else if (value > dataMax) {
  54879. value = dataMax;
  54880. }
  54881. }
  54882. // Set the extremes
  54883. if (typeof value !== 'undefined') { // @todo typof undefined
  54884. chartAxis.setExtremes(isMin ? value : chartAxis.min, isMin ? chartAxis.max : value, void 0, void 0, { trigger: 'rangeSelectorInput' });
  54885. }
  54886. }
  54887. }
  54888. // Create the text label
  54889. var text = lang[isMin ? 'rangeSelectorFrom' : 'rangeSelectorTo'];
  54890. var label = renderer
  54891. .label(text, 0)
  54892. .addClass('highcharts-range-label')
  54893. .attr({
  54894. padding: text ? 2 : 0
  54895. })
  54896. .add(inputGroup);
  54897. // Create an SVG label that shows updated date ranges and and records
  54898. // click events that bring in the HTML input.
  54899. var dateBox = renderer
  54900. .label('', 0)
  54901. .addClass('highcharts-range-input')
  54902. .attr({
  54903. padding: 2,
  54904. width: options.inputBoxWidth,
  54905. height: options.inputBoxHeight,
  54906. 'text-align': 'center'
  54907. })
  54908. .on('click',
  54909. function () {
  54910. // If it is already focused, the onfocus event doesn't fire
  54911. // (#3713)
  54912. rangeSelector.showInput(name);
  54913. rangeSelector[name + 'Input'].focus();
  54914. });
  54915. if (!chart.styledMode) {
  54916. dateBox.attr({
  54917. stroke: options.inputBoxBorderColor,
  54918. 'stroke-width': 1
  54919. });
  54920. }
  54921. dateBox.add(inputGroup);
  54922. // Create the HTML input element. This is rendered as 1x1 pixel then set
  54923. // to the right size when focused.
  54924. var input = createElement('input', {
  54925. name: name,
  54926. className: 'highcharts-range-selector'
  54927. },
  54928. void 0,
  54929. div);
  54930. // #14788: Setting input.type to an unsupported type throws in IE, so
  54931. // we need to use setAttribute instead
  54932. input.setAttribute('type', preferredInputType(options.inputDateFormat || '%b %e, %Y'));
  54933. if (!chart.styledMode) {
  54934. // Styles
  54935. label.css(merge(chartStyle, options.labelStyle));
  54936. dateBox.css(merge({
  54937. color: palette.neutralColor80
  54938. }, chartStyle, options.inputStyle));
  54939. css(input, extend({
  54940. position: 'absolute',
  54941. border: 0,
  54942. boxShadow: '0 0 15px rgba(0,0,0,0.3)',
  54943. width: '1px',
  54944. height: '1px',
  54945. padding: 0,
  54946. textAlign: 'center',
  54947. fontSize: chartStyle.fontSize,
  54948. fontFamily: chartStyle.fontFamily,
  54949. top: '-9999em' // #4798
  54950. }, options.inputStyle));
  54951. }
  54952. // Blow up the input box
  54953. input.onfocus = function () {
  54954. rangeSelector.showInput(name);
  54955. };
  54956. // Hide away the input box
  54957. input.onblur = function () {
  54958. // update extermes only when inputs are active
  54959. if (input === H.doc.activeElement) { // Only when focused
  54960. // Update also when no `change` event is triggered, like when
  54961. // clicking inside the SVG (#4710)
  54962. updateExtremes();
  54963. }
  54964. // #10404 - move hide and blur outside focus
  54965. rangeSelector.hideInput(name);
  54966. rangeSelector.setInputValue(name);
  54967. input.blur(); // #4606
  54968. };
  54969. var keyDown = false;
  54970. // handle changes in the input boxes
  54971. input.onchange = function () {
  54972. updateExtremes();
  54973. // Blur input when clicking date input calendar
  54974. if (!keyDown) {
  54975. rangeSelector.hideInput(name);
  54976. input.blur();
  54977. }
  54978. };
  54979. input.onkeypress = function (event) {
  54980. // IE does not fire onchange on enter
  54981. if (event.keyCode === 13) {
  54982. updateExtremes();
  54983. }
  54984. };
  54985. input.onkeydown = function () {
  54986. keyDown = true;
  54987. };
  54988. input.onkeyup = function () {
  54989. keyDown = false;
  54990. };
  54991. return { dateBox: dateBox, input: input, label: label };
  54992. };
  54993. /**
  54994. * Get the position of the range selector buttons and inputs. This can be
  54995. * overridden from outside for custom positioning.
  54996. *
  54997. * @private
  54998. * @function Highcharts.RangeSelector#getPosition
  54999. *
  55000. * @return {Highcharts.Dictionary<number>}
  55001. */
  55002. RangeSelector.prototype.getPosition = function () {
  55003. var chart = this.chart,
  55004. options = chart.options.rangeSelector,
  55005. top = options.verticalAlign === 'top' ?
  55006. chart.plotTop - chart.axisOffset[0] :
  55007. 0; // set offset only for varticalAlign top
  55008. return {
  55009. buttonTop: top + options.buttonPosition.y,
  55010. inputTop: top + options.inputPosition.y - 10
  55011. };
  55012. };
  55013. /**
  55014. * Get the extremes of YTD. Will choose dataMax if its value is lower than
  55015. * the current timestamp. Will choose dataMin if its value is higher than
  55016. * the timestamp for the start of current year.
  55017. *
  55018. * @private
  55019. * @function Highcharts.RangeSelector#getYTDExtremes
  55020. *
  55021. * @param {number} dataMax
  55022. *
  55023. * @param {number} dataMin
  55024. *
  55025. * @return {*}
  55026. * Returns min and max for the YTD
  55027. */
  55028. RangeSelector.prototype.getYTDExtremes = function (dataMax, dataMin, useUTC) {
  55029. var time = this.chart.time,
  55030. min,
  55031. now = new time.Date(dataMax),
  55032. year = time.get('FullYear',
  55033. now),
  55034. startOfYear = useUTC ?
  55035. time.Date.UTC(year, 0, 1) : // eslint-disable-line new-cap
  55036. +new time.Date(year, 0, 1);
  55037. min = Math.max(dataMin, startOfYear);
  55038. var ts = now.getTime();
  55039. return {
  55040. max: Math.min(dataMax || ts, ts),
  55041. min: min
  55042. };
  55043. };
  55044. /**
  55045. * Render the range selector including the buttons and the inputs. The first
  55046. * time render is called, the elements are created and positioned. On
  55047. * subsequent calls, they are moved and updated.
  55048. *
  55049. * @private
  55050. * @function Highcharts.RangeSelector#render
  55051. * @param {number} [min]
  55052. * X axis minimum
  55053. * @param {number} [max]
  55054. * X axis maximum
  55055. * @return {void}
  55056. */
  55057. RangeSelector.prototype.render = function (min, max) {
  55058. var chart = this.chart,
  55059. renderer = chart.renderer,
  55060. container = chart.container,
  55061. chartOptions = chart.options,
  55062. options = chartOptions.rangeSelector,
  55063. // Place inputs above the container
  55064. inputsZIndex = pick(chartOptions.chart.style &&
  55065. chartOptions.chart.style.zIndex, 0) + 1,
  55066. inputEnabled = options.inputEnabled,
  55067. rendered = this.rendered;
  55068. if (options.enabled === false) {
  55069. return;
  55070. }
  55071. // create the elements
  55072. if (!rendered) {
  55073. this.group = renderer.g('range-selector-group')
  55074. .attr({
  55075. zIndex: 7
  55076. })
  55077. .add();
  55078. this.div = createElement('div', void 0, {
  55079. position: 'relative',
  55080. height: 0,
  55081. zIndex: inputsZIndex
  55082. });
  55083. if (this.buttonOptions.length) {
  55084. this.renderButtons();
  55085. }
  55086. // First create a wrapper outside the container in order to make
  55087. // the inputs work and make export correct
  55088. if (container.parentNode) {
  55089. container.parentNode.insertBefore(this.div, container);
  55090. }
  55091. if (inputEnabled) {
  55092. // Create the group to keep the inputs
  55093. this.inputGroup = renderer.g('input-group').add(this.group);
  55094. var minElems = this.drawInput('min');
  55095. this.minDateBox = minElems.dateBox;
  55096. this.minLabel = minElems.label;
  55097. this.minInput = minElems.input;
  55098. var maxElems = this.drawInput('max');
  55099. this.maxDateBox = maxElems.dateBox;
  55100. this.maxLabel = maxElems.label;
  55101. this.maxInput = maxElems.input;
  55102. }
  55103. }
  55104. if (inputEnabled) {
  55105. // Set or reset the input values
  55106. this.setInputValue('min', min);
  55107. this.setInputValue('max', max);
  55108. var unionExtremes = (chart.scroller && chart.scroller.getUnionExtremes()) || chart.xAxis[0] || {};
  55109. if (defined(unionExtremes.dataMin) && defined(unionExtremes.dataMax)) {
  55110. var minRange = chart.xAxis[0].minRange || 0;
  55111. this.setInputExtremes('min', unionExtremes.dataMin, Math.min(unionExtremes.dataMax, this.getInputValue('max')) - minRange);
  55112. this.setInputExtremes('max', Math.max(unionExtremes.dataMin, this.getInputValue('min')) + minRange, unionExtremes.dataMax);
  55113. }
  55114. // Reflow
  55115. if (this.inputGroup) {
  55116. var x_1 = 0;
  55117. [
  55118. this.minLabel,
  55119. this.minDateBox,
  55120. this.maxLabel,
  55121. this.maxDateBox
  55122. ].forEach(function (label) {
  55123. if (label && label.width) {
  55124. label.attr({ x: x_1 });
  55125. x_1 += label.width + options.inputSpacing;
  55126. }
  55127. });
  55128. }
  55129. }
  55130. this.alignElements();
  55131. this.rendered = true;
  55132. };
  55133. /**
  55134. * Render the range buttons. This only runs the first time, later the
  55135. * positioning is laid out in alignElements.
  55136. *
  55137. * @private
  55138. * @function Highcharts.RangeSelector#renderButtons
  55139. * @return {void}
  55140. */
  55141. RangeSelector.prototype.renderButtons = function () {
  55142. var _this = this;
  55143. var _a = this,
  55144. buttons = _a.buttons,
  55145. chart = _a.chart,
  55146. options = _a.options;
  55147. var lang = defaultOptions.lang;
  55148. var renderer = chart.renderer;
  55149. var buttonTheme = merge(options.buttonTheme);
  55150. var states = buttonTheme && buttonTheme.states;
  55151. // Prevent the button from resetting the width when the button state
  55152. // changes since we need more control over the width when collapsing
  55153. // the buttons
  55154. var width = buttonTheme.width || 28;
  55155. delete buttonTheme.width;
  55156. this.buttonGroup = renderer.g('range-selector-buttons').add(this.group);
  55157. var dropdown = this.dropdown = createElement('select',
  55158. void 0, {
  55159. position: 'absolute',
  55160. width: '1px',
  55161. height: '1px',
  55162. padding: 0,
  55163. border: 0,
  55164. top: '-9999em',
  55165. cursor: 'pointer',
  55166. opacity: 0.0001
  55167. },
  55168. this.div);
  55169. // Prevent page zoom on iPhone
  55170. addEvent(dropdown, 'touchstart', function () {
  55171. dropdown.style.fontSize = '16px';
  55172. });
  55173. // Forward events from select to button
  55174. [
  55175. [H.isMS ? 'mouseover' : 'mouseenter'],
  55176. [H.isMS ? 'mouseout' : 'mouseleave'],
  55177. ['change', 'click']
  55178. ].forEach(function (_a) {
  55179. var from = _a[0],
  55180. to = _a[1];
  55181. addEvent(dropdown, from, function () {
  55182. var button = buttons[_this.currentButtonIndex()];
  55183. if (button) {
  55184. fireEvent(button.element, to || from);
  55185. }
  55186. });
  55187. });
  55188. this.zoomText = renderer
  55189. .text(lang.rangeSelectorZoom, 0, 15)
  55190. .add(this.buttonGroup);
  55191. if (!this.chart.styledMode) {
  55192. this.zoomText.css(options.labelStyle);
  55193. buttonTheme['stroke-width'] = pick(buttonTheme['stroke-width'], 0);
  55194. }
  55195. createElement('option', {
  55196. textContent: this.zoomText.textStr,
  55197. disabled: true
  55198. }, void 0, dropdown);
  55199. this.buttonOptions.forEach(function (rangeOptions, i) {
  55200. createElement('option', {
  55201. textContent: rangeOptions.title || rangeOptions.text
  55202. }, void 0, dropdown);
  55203. buttons[i] = renderer
  55204. .button(rangeOptions.text, 0, 0, function (e) {
  55205. // extract events from button object and call
  55206. var buttonEvents = (rangeOptions.events &&
  55207. rangeOptions.events.click),
  55208. callDefaultEvent;
  55209. if (buttonEvents) {
  55210. callDefaultEvent =
  55211. buttonEvents.call(rangeOptions, e);
  55212. }
  55213. if (callDefaultEvent !== false) {
  55214. _this.clickButton(i);
  55215. }
  55216. _this.isActive = true;
  55217. }, buttonTheme, states && states.hover, states && states.select, states && states.disabled)
  55218. .attr({
  55219. 'text-align': 'center',
  55220. width: width
  55221. })
  55222. .add(_this.buttonGroup);
  55223. if (rangeOptions.title) {
  55224. buttons[i].attr('title', rangeOptions.title);
  55225. }
  55226. });
  55227. };
  55228. /**
  55229. * Align the elements horizontally and vertically.
  55230. *
  55231. * @private
  55232. * @function Highcharts.RangeSelector#alignElements
  55233. * @return {void}
  55234. */
  55235. RangeSelector.prototype.alignElements = function () {
  55236. var _this = this;
  55237. var _a = this,
  55238. buttonGroup = _a.buttonGroup,
  55239. buttons = _a.buttons,
  55240. chart = _a.chart,
  55241. group = _a.group,
  55242. inputGroup = _a.inputGroup,
  55243. options = _a.options,
  55244. zoomText = _a.zoomText;
  55245. var chartOptions = chart.options;
  55246. var navButtonOptions = (chartOptions.exporting &&
  55247. chartOptions.exporting.enabled !== false &&
  55248. chartOptions.navigation &&
  55249. chartOptions.navigation.buttonOptions);
  55250. var buttonPosition = options.buttonPosition,
  55251. inputPosition = options.inputPosition,
  55252. verticalAlign = options.verticalAlign;
  55253. // Get the X offset required to avoid overlapping with the exporting
  55254. // button. This is is used both by the buttonGroup and the inputGroup.
  55255. var getXOffsetForExportButton = function (group,
  55256. position) {
  55257. if (navButtonOptions &&
  55258. _this.titleCollision(chart) &&
  55259. verticalAlign === 'top' &&
  55260. position.align === 'right' && ((position.y -
  55261. group.getBBox().height - 12) <
  55262. ((navButtonOptions.y || 0) +
  55263. (navButtonOptions.height || 0) +
  55264. chart.spacing[0]))) {
  55265. return -40;
  55266. }
  55267. return 0;
  55268. };
  55269. var plotLeft = chart.plotLeft;
  55270. if (group && buttonPosition && inputPosition) {
  55271. var translateX = buttonPosition.x - chart.spacing[3];
  55272. if (buttonGroup) {
  55273. this.positionButtons();
  55274. if (!this.initialButtonGroupWidth) {
  55275. var width_1 = 0;
  55276. if (zoomText) {
  55277. width_1 += zoomText.getBBox().width + 5;
  55278. }
  55279. buttons.forEach(function (button, i) {
  55280. width_1 += button.width;
  55281. if (i !== buttons.length - 1) {
  55282. width_1 += options.buttonSpacing;
  55283. }
  55284. });
  55285. this.initialButtonGroupWidth = width_1;
  55286. }
  55287. plotLeft -= chart.spacing[3];
  55288. this.updateButtonStates();
  55289. // Detect collision between button group and exporting
  55290. var xOffsetForExportButton_1 = getXOffsetForExportButton(buttonGroup,
  55291. buttonPosition);
  55292. this.alignButtonGroup(xOffsetForExportButton_1);
  55293. // Skip animation
  55294. group.placed = buttonGroup.placed = chart.hasLoaded;
  55295. }
  55296. var xOffsetForExportButton = 0;
  55297. if (inputGroup) {
  55298. // Detect collision between the input group and exporting button
  55299. xOffsetForExportButton = getXOffsetForExportButton(inputGroup, inputPosition);
  55300. if (inputPosition.align === 'left') {
  55301. translateX = plotLeft;
  55302. }
  55303. else if (inputPosition.align === 'right') {
  55304. translateX = -Math.max(chart.axisOffset[1], -xOffsetForExportButton);
  55305. }
  55306. // Update the alignment to the updated spacing box
  55307. inputGroup.align({
  55308. y: inputPosition.y,
  55309. width: inputGroup.getBBox().width,
  55310. align: inputPosition.align,
  55311. // fix wrong getBBox() value on right align
  55312. x: inputPosition.x + translateX - 2
  55313. }, true, chart.spacingBox);
  55314. // Skip animation
  55315. inputGroup.placed = chart.hasLoaded;
  55316. }
  55317. this.handleCollision(xOffsetForExportButton);
  55318. // Vertical align
  55319. group.align({
  55320. verticalAlign: verticalAlign
  55321. }, true, chart.spacingBox);
  55322. var alignTranslateY = group.alignAttr.translateY;
  55323. // Set position
  55324. var groupHeight = group.getBBox().height + 20; // # 20 padding
  55325. var translateY = 0;
  55326. // Calculate bottom position
  55327. if (verticalAlign === 'bottom') {
  55328. var legendOptions = chart.legend && chart.legend.options;
  55329. var legendHeight = (legendOptions &&
  55330. legendOptions.verticalAlign === 'bottom' &&
  55331. legendOptions.enabled &&
  55332. !legendOptions.floating ?
  55333. (chart.legend.legendHeight +
  55334. pick(legendOptions.margin, 10)) :
  55335. 0);
  55336. groupHeight = groupHeight + legendHeight - 20;
  55337. translateY = (alignTranslateY -
  55338. groupHeight -
  55339. (options.floating ? 0 : options.y) -
  55340. (chart.titleOffset ? chart.titleOffset[2] : 0) -
  55341. 10 // 10 spacing
  55342. );
  55343. }
  55344. if (verticalAlign === 'top') {
  55345. if (options.floating) {
  55346. translateY = 0;
  55347. }
  55348. if (chart.titleOffset && chart.titleOffset[0]) {
  55349. translateY = chart.titleOffset[0];
  55350. }
  55351. translateY += ((chart.margin[0] - chart.spacing[0]) || 0);
  55352. }
  55353. else if (verticalAlign === 'middle') {
  55354. if (inputPosition.y === buttonPosition.y) {
  55355. translateY = alignTranslateY;
  55356. }
  55357. else if (inputPosition.y || buttonPosition.y) {
  55358. if (inputPosition.y < 0 ||
  55359. buttonPosition.y < 0) {
  55360. translateY -= Math.min(inputPosition.y, buttonPosition.y);
  55361. }
  55362. else {
  55363. translateY = alignTranslateY - groupHeight;
  55364. }
  55365. }
  55366. }
  55367. group.translate(options.x, options.y + Math.floor(translateY));
  55368. // Translate HTML inputs
  55369. var _b = this,
  55370. minInput = _b.minInput,
  55371. maxInput = _b.maxInput,
  55372. dropdown = _b.dropdown;
  55373. if (options.inputEnabled && minInput && maxInput) {
  55374. minInput.style.marginTop = group.translateY + 'px';
  55375. maxInput.style.marginTop = group.translateY + 'px';
  55376. }
  55377. if (dropdown) {
  55378. dropdown.style.marginTop = group.translateY + 'px';
  55379. }
  55380. }
  55381. };
  55382. /**
  55383. * Align the button group horizontally and vertically.
  55384. *
  55385. * @private
  55386. * @function Highcharts.RangeSelector#alignButtonGroup
  55387. * @param {number} xOffsetForExportButton
  55388. * @param {number} [width]
  55389. * @return {void}
  55390. */
  55391. RangeSelector.prototype.alignButtonGroup = function (xOffsetForExportButton, width) {
  55392. var _a = this,
  55393. chart = _a.chart,
  55394. options = _a.options,
  55395. buttonGroup = _a.buttonGroup,
  55396. buttons = _a.buttons;
  55397. var buttonPosition = options.buttonPosition;
  55398. var plotLeft = chart.plotLeft - chart.spacing[3];
  55399. var translateX = buttonPosition.x - chart.spacing[3];
  55400. if (buttonPosition.align === 'right') {
  55401. translateX += xOffsetForExportButton - plotLeft; // #13014
  55402. }
  55403. else if (buttonPosition.align === 'center') {
  55404. translateX -= plotLeft / 2;
  55405. }
  55406. if (buttonGroup) {
  55407. // Align button group
  55408. buttonGroup.align({
  55409. y: buttonPosition.y,
  55410. width: pick(width, this.initialButtonGroupWidth),
  55411. align: buttonPosition.align,
  55412. x: translateX
  55413. }, true, chart.spacingBox);
  55414. }
  55415. };
  55416. /**
  55417. * @private
  55418. * @function Highcharts.RangeSelector#positionButtons
  55419. * @return {void}
  55420. */
  55421. RangeSelector.prototype.positionButtons = function () {
  55422. var _a = this,
  55423. buttons = _a.buttons,
  55424. chart = _a.chart,
  55425. options = _a.options,
  55426. zoomText = _a.zoomText;
  55427. var verb = chart.hasLoaded ? 'animate' : 'attr';
  55428. var buttonPosition = options.buttonPosition;
  55429. var plotLeft = chart.plotLeft;
  55430. var buttonLeft = plotLeft;
  55431. if (zoomText && zoomText.visibility !== 'hidden') {
  55432. // #8769, allow dynamically updating margins
  55433. zoomText[verb]({
  55434. x: pick(plotLeft + buttonPosition.x, plotLeft)
  55435. });
  55436. // Button start position
  55437. buttonLeft += buttonPosition.x +
  55438. zoomText.getBBox().width + 5;
  55439. }
  55440. this.buttonOptions.forEach(function (rangeOptions, i) {
  55441. if (buttons[i].visibility !== 'hidden') {
  55442. buttons[i][verb]({ x: buttonLeft });
  55443. // increase button position for the next button
  55444. buttonLeft += buttons[i].width + options.buttonSpacing;
  55445. }
  55446. else {
  55447. buttons[i][verb]({ x: plotLeft });
  55448. }
  55449. });
  55450. };
  55451. /**
  55452. * Handle collision between the button group and the input group
  55453. *
  55454. * @private
  55455. * @function Highcharts.RangeSelector#handleCollision
  55456. *
  55457. * @param {number} xOffsetForExportButton
  55458. * The X offset of the group required to make room for the
  55459. * exporting button
  55460. * @return {void}
  55461. */
  55462. RangeSelector.prototype.handleCollision = function (xOffsetForExportButton) {
  55463. var _this = this;
  55464. var _a = this,
  55465. chart = _a.chart,
  55466. buttonGroup = _a.buttonGroup,
  55467. inputGroup = _a.inputGroup;
  55468. var _b = this.options,
  55469. buttonPosition = _b.buttonPosition,
  55470. dropdown = _b.dropdown,
  55471. inputPosition = _b.inputPosition;
  55472. var maxButtonWidth = function () {
  55473. var buttonWidth = 0;
  55474. _this.buttons.forEach(function (button) {
  55475. var bBox = button.getBBox();
  55476. if (bBox.width > buttonWidth) {
  55477. buttonWidth = bBox.width;
  55478. }
  55479. });
  55480. return buttonWidth;
  55481. };
  55482. var groupsOverlap = function (buttonGroupWidth) {
  55483. if (inputGroup && buttonGroup) {
  55484. var inputGroupX = (inputGroup.alignAttr.translateX +
  55485. inputGroup.alignOptions.x -
  55486. xOffsetForExportButton +
  55487. // getBBox for detecing left margin
  55488. inputGroup.getBBox().x +
  55489. // 2px padding to not overlap input and label
  55490. 2);
  55491. var inputGroupWidth = inputGroup.alignOptions.width;
  55492. var buttonGroupX = buttonGroup.alignAttr.translateX +
  55493. buttonGroup.getBBox().x;
  55494. return (buttonGroupX + buttonGroupWidth > inputGroupX) &&
  55495. (inputGroupX + inputGroupWidth > buttonGroupX) &&
  55496. (buttonPosition.y <
  55497. (inputPosition.y +
  55498. inputGroup.getBBox().height));
  55499. }
  55500. return false;
  55501. };
  55502. var moveInputsDown = function () {
  55503. if (inputGroup && buttonGroup) {
  55504. inputGroup.attr({
  55505. translateX: inputGroup.alignAttr.translateX + (chart.axisOffset[1] >= -xOffsetForExportButton ?
  55506. 0 :
  55507. -xOffsetForExportButton),
  55508. translateY: inputGroup.alignAttr.translateY +
  55509. buttonGroup.getBBox().height + 10
  55510. });
  55511. }
  55512. };
  55513. if (buttonGroup) {
  55514. if (dropdown === 'always') {
  55515. this.collapseButtons(xOffsetForExportButton);
  55516. if (groupsOverlap(maxButtonWidth())) {
  55517. // Move the inputs down if there is still a collision
  55518. // after collapsing the buttons
  55519. moveInputsDown();
  55520. }
  55521. return;
  55522. }
  55523. if (dropdown === 'never') {
  55524. this.expandButtons();
  55525. }
  55526. }
  55527. // Detect collision
  55528. if (inputGroup && buttonGroup) {
  55529. if ((inputPosition.align === buttonPosition.align) ||
  55530. // 20 is minimal spacing between elements
  55531. groupsOverlap(this.initialButtonGroupWidth + 20)) {
  55532. if (dropdown === 'responsive') {
  55533. this.collapseButtons(xOffsetForExportButton);
  55534. if (groupsOverlap(maxButtonWidth())) {
  55535. moveInputsDown();
  55536. }
  55537. }
  55538. else {
  55539. moveInputsDown();
  55540. }
  55541. }
  55542. else if (dropdown === 'responsive') {
  55543. this.expandButtons();
  55544. }
  55545. }
  55546. else if (buttonGroup && dropdown === 'responsive') {
  55547. if (this.initialButtonGroupWidth > chart.plotWidth) {
  55548. this.collapseButtons(xOffsetForExportButton);
  55549. }
  55550. else {
  55551. this.expandButtons();
  55552. }
  55553. }
  55554. };
  55555. /**
  55556. * Collapse the buttons and put the select element on top.
  55557. *
  55558. * @private
  55559. * @function Highcharts.RangeSelector#collapseButtons
  55560. * @param {number} xOffsetForExportButton
  55561. * @return {void}
  55562. */
  55563. RangeSelector.prototype.collapseButtons = function (xOffsetForExportButton) {
  55564. var _a;
  55565. var _b = this,
  55566. buttons = _b.buttons,
  55567. buttonOptions = _b.buttonOptions,
  55568. dropdown = _b.dropdown,
  55569. options = _b.options,
  55570. zoomText = _b.zoomText;
  55571. var getAttribs = function (text) { return ({
  55572. text: text ? text + " \u25BE" : '▾',
  55573. width: 'auto',
  55574. paddingLeft: 8,
  55575. paddingRight: 8
  55576. }); };
  55577. if (zoomText) {
  55578. zoomText.hide();
  55579. }
  55580. var hasActiveButton = false;
  55581. buttonOptions.forEach(function (rangeOptions, i) {
  55582. var button = buttons[i];
  55583. if (button.state !== 2) {
  55584. button.hide();
  55585. }
  55586. else {
  55587. button.show();
  55588. button.attr(getAttribs(rangeOptions.text));
  55589. hasActiveButton = true;
  55590. }
  55591. });
  55592. if (!hasActiveButton) {
  55593. if (dropdown) {
  55594. dropdown.selectedIndex = 0;
  55595. }
  55596. buttons[0].show();
  55597. buttons[0].attr(getAttribs((_a = this.zoomText) === null || _a === void 0 ? void 0 : _a.textStr));
  55598. }
  55599. var align = options.buttonPosition.align;
  55600. this.positionButtons();
  55601. if (align === 'right' || align === 'center') {
  55602. this.alignButtonGroup(xOffsetForExportButton, buttons[this.currentButtonIndex()].getBBox().width);
  55603. }
  55604. this.showDropdown();
  55605. };
  55606. /**
  55607. * Show all the buttons and hide the select element.
  55608. *
  55609. * @private
  55610. * @function Highcharts.RangeSelector#expandButtons
  55611. * @return {void}
  55612. */
  55613. RangeSelector.prototype.expandButtons = function () {
  55614. var _a = this,
  55615. buttons = _a.buttons,
  55616. buttonOptions = _a.buttonOptions,
  55617. options = _a.options,
  55618. zoomText = _a.zoomText;
  55619. this.hideDropdown();
  55620. if (zoomText) {
  55621. zoomText.show();
  55622. }
  55623. buttonOptions.forEach(function (rangeOptions, i) {
  55624. var button = buttons[i];
  55625. button.show();
  55626. button.attr({
  55627. text: rangeOptions.text,
  55628. width: options.buttonTheme.width || 28,
  55629. paddingLeft: 'unset',
  55630. paddingRight: 'unset'
  55631. });
  55632. if (button.state < 2) {
  55633. button.setState(0);
  55634. }
  55635. });
  55636. this.positionButtons();
  55637. };
  55638. /**
  55639. * Get the index of the visible button when the buttons are collapsed.
  55640. *
  55641. * @private
  55642. * @function Highcharts.RangeSelector#currentButtonIndex
  55643. * @return {number}
  55644. */
  55645. RangeSelector.prototype.currentButtonIndex = function () {
  55646. var dropdown = this.dropdown;
  55647. if (dropdown && dropdown.selectedIndex > 0) {
  55648. return dropdown.selectedIndex - 1;
  55649. }
  55650. return 0;
  55651. };
  55652. /**
  55653. * Position the select element on top of the button.
  55654. *
  55655. * @private
  55656. * @function Highcharts.RangeSelector#showDropdown
  55657. * @return {void}
  55658. */
  55659. RangeSelector.prototype.showDropdown = function () {
  55660. var _a = this,
  55661. buttonGroup = _a.buttonGroup,
  55662. buttons = _a.buttons,
  55663. chart = _a.chart,
  55664. dropdown = _a.dropdown;
  55665. if (buttonGroup && dropdown) {
  55666. var translateX = buttonGroup.translateX,
  55667. translateY = buttonGroup.translateY;
  55668. var bBox = buttons[this.currentButtonIndex()].getBBox();
  55669. css(dropdown, {
  55670. left: (chart.plotLeft + translateX) + 'px',
  55671. top: (translateY + 0.5) + 'px',
  55672. width: bBox.width + 'px',
  55673. height: bBox.height + 'px'
  55674. });
  55675. this.hasVisibleDropdown = true;
  55676. }
  55677. };
  55678. /**
  55679. * @private
  55680. * @function Highcharts.RangeSelector#hideDropdown
  55681. * @return {void}
  55682. */
  55683. RangeSelector.prototype.hideDropdown = function () {
  55684. var dropdown = this.dropdown;
  55685. if (dropdown) {
  55686. css(dropdown, {
  55687. top: '-9999em',
  55688. width: '1px',
  55689. height: '1px'
  55690. });
  55691. this.hasVisibleDropdown = false;
  55692. }
  55693. };
  55694. /**
  55695. * Extracts height of range selector
  55696. *
  55697. * @private
  55698. * @function Highcharts.RangeSelector#getHeight
  55699. * @return {number}
  55700. * Returns rangeSelector height
  55701. */
  55702. RangeSelector.prototype.getHeight = function () {
  55703. var rangeSelector = this,
  55704. options = rangeSelector.options,
  55705. rangeSelectorGroup = rangeSelector.group,
  55706. inputPosition = options.inputPosition,
  55707. buttonPosition = options.buttonPosition,
  55708. yPosition = options.y,
  55709. buttonPositionY = buttonPosition.y,
  55710. inputPositionY = inputPosition.y,
  55711. rangeSelectorHeight = 0,
  55712. minPosition;
  55713. if (options.height) {
  55714. return options.height;
  55715. }
  55716. // Align the elements before we read the height in case we're switching
  55717. // between wrapped and non-wrapped layout
  55718. this.alignElements();
  55719. rangeSelectorHeight = rangeSelectorGroup ?
  55720. // 13px to keep back compatibility
  55721. (rangeSelectorGroup.getBBox(true).height) + 13 +
  55722. yPosition :
  55723. 0;
  55724. minPosition = Math.min(inputPositionY, buttonPositionY);
  55725. if ((inputPositionY < 0 && buttonPositionY < 0) ||
  55726. (inputPositionY > 0 && buttonPositionY > 0)) {
  55727. rangeSelectorHeight += Math.abs(minPosition);
  55728. }
  55729. return rangeSelectorHeight;
  55730. };
  55731. /**
  55732. * Detect collision with title or subtitle
  55733. *
  55734. * @private
  55735. * @function Highcharts.RangeSelector#titleCollision
  55736. *
  55737. * @param {Highcharts.Chart} chart
  55738. *
  55739. * @return {boolean}
  55740. * Returns collision status
  55741. */
  55742. RangeSelector.prototype.titleCollision = function (chart) {
  55743. return !(chart.options.title.text ||
  55744. chart.options.subtitle.text);
  55745. };
  55746. /**
  55747. * Update the range selector with new options
  55748. *
  55749. * @private
  55750. * @function Highcharts.RangeSelector#update
  55751. * @param {Highcharts.RangeSelectorOptions} options
  55752. * @return {void}
  55753. */
  55754. RangeSelector.prototype.update = function (options) {
  55755. var chart = this.chart;
  55756. merge(true, chart.options.rangeSelector, options);
  55757. this.destroy();
  55758. this.init(chart);
  55759. this.render();
  55760. };
  55761. /**
  55762. * Destroys allocated elements.
  55763. *
  55764. * @private
  55765. * @function Highcharts.RangeSelector#destroy
  55766. */
  55767. RangeSelector.prototype.destroy = function () {
  55768. var rSelector = this,
  55769. minInput = rSelector.minInput,
  55770. maxInput = rSelector.maxInput;
  55771. if (rSelector.eventsToUnbind) {
  55772. rSelector.eventsToUnbind.forEach(function (unbind) { return unbind(); });
  55773. rSelector.eventsToUnbind = void 0;
  55774. }
  55775. // Destroy elements in collections
  55776. destroyObjectProperties(rSelector.buttons);
  55777. // Clear input element events
  55778. if (minInput) {
  55779. minInput.onfocus = minInput.onblur = minInput.onchange = null;
  55780. }
  55781. if (maxInput) {
  55782. maxInput.onfocus = maxInput.onblur = maxInput.onchange = null;
  55783. }
  55784. // Destroy HTML and SVG elements
  55785. objectEach(rSelector, function (val, key) {
  55786. if (val && key !== 'chart') {
  55787. if (val instanceof SVGElement) {
  55788. // SVGElement
  55789. val.destroy();
  55790. }
  55791. else if (val instanceof window.HTMLElement) {
  55792. // HTML element
  55793. discardElement(val);
  55794. }
  55795. }
  55796. if (val !== RangeSelector.prototype[key]) {
  55797. rSelector[key] = null;
  55798. }
  55799. }, this);
  55800. };
  55801. return RangeSelector;
  55802. }());
  55803. /**
  55804. * The default buttons for pre-selecting time frames
  55805. */
  55806. RangeSelector.prototype.defaultButtons = [{
  55807. type: 'month',
  55808. count: 1,
  55809. text: '1m',
  55810. title: 'View 1 month'
  55811. }, {
  55812. type: 'month',
  55813. count: 3,
  55814. text: '3m',
  55815. title: 'View 3 months'
  55816. }, {
  55817. type: 'month',
  55818. count: 6,
  55819. text: '6m',
  55820. title: 'View 6 months'
  55821. }, {
  55822. type: 'ytd',
  55823. text: 'YTD',
  55824. title: 'View year to date'
  55825. }, {
  55826. type: 'year',
  55827. count: 1,
  55828. text: '1y',
  55829. title: 'View 1 year'
  55830. }, {
  55831. type: 'all',
  55832. text: 'All',
  55833. title: 'View all'
  55834. }];
  55835. /**
  55836. * The date formats to use when setting min, max and value on date inputs
  55837. */
  55838. RangeSelector.prototype.inputTypeFormats = {
  55839. 'datetime-local': '%Y-%m-%dT%H:%M:%S',
  55840. 'date': '%Y-%m-%d',
  55841. 'time': '%H:%M:%S'
  55842. };
  55843. /**
  55844. * Get the preferred input type based on a date format string.
  55845. *
  55846. * @private
  55847. * @function preferredInputType
  55848. * @param {string} format
  55849. * @return {string}
  55850. */
  55851. function preferredInputType(format) {
  55852. var ms = format.indexOf('%L') !== -1;
  55853. if (ms) {
  55854. return 'text';
  55855. }
  55856. var date = ['a', 'A', 'd', 'e', 'w', 'b', 'B', 'm', 'o', 'y', 'Y'].some(function (char) {
  55857. return format.indexOf('%' + char) !== -1;
  55858. });
  55859. var time = ['H', 'k', 'I', 'l', 'M', 'S'].some(function (char) {
  55860. return format.indexOf('%' + char) !== -1;
  55861. });
  55862. if (date && time) {
  55863. return 'datetime-local';
  55864. }
  55865. if (date) {
  55866. return 'date';
  55867. }
  55868. if (time) {
  55869. return 'time';
  55870. }
  55871. return 'text';
  55872. }
  55873. /**
  55874. * Get the axis min value based on the range option and the current max. For
  55875. * stock charts this is extended via the {@link RangeSelector} so that if the
  55876. * selected range is a multiple of months or years, it is compensated for
  55877. * various month lengths.
  55878. *
  55879. * @private
  55880. * @function Highcharts.Axis#minFromRange
  55881. * @return {number|undefined}
  55882. * The new minimum value.
  55883. */
  55884. Axis.prototype.minFromRange = function () {
  55885. var rangeOptions = this.range,
  55886. type = rangeOptions.type,
  55887. min,
  55888. max = this.max,
  55889. dataMin,
  55890. range,
  55891. time = this.chart.time,
  55892. // Get the true range from a start date
  55893. getTrueRange = function (base,
  55894. count) {
  55895. var timeName = type === 'year' ? 'FullYear' : 'Month';
  55896. var date = new time.Date(base);
  55897. var basePeriod = time.get(timeName,
  55898. date);
  55899. time.set(timeName, date, basePeriod + count);
  55900. if (basePeriod === time.get(timeName, date)) {
  55901. time.set('Date', date, 0); // #6537
  55902. }
  55903. return date.getTime() - base;
  55904. };
  55905. if (isNumber(rangeOptions)) {
  55906. min = max - rangeOptions;
  55907. range = rangeOptions;
  55908. }
  55909. else {
  55910. min = max + getTrueRange(max, -rangeOptions.count);
  55911. // Let the fixedRange reflect initial settings (#5930)
  55912. if (this.chart) {
  55913. this.chart.fixedRange = max - min;
  55914. }
  55915. }
  55916. dataMin = pick(this.dataMin, Number.MIN_VALUE);
  55917. if (!isNumber(min)) {
  55918. min = dataMin;
  55919. }
  55920. if (min <= dataMin) {
  55921. min = dataMin;
  55922. if (typeof range === 'undefined') { // #4501
  55923. range = getTrueRange(min, rangeOptions.count);
  55924. }
  55925. this.newMax = Math.min(min + range, this.dataMax);
  55926. }
  55927. if (!isNumber(max)) {
  55928. min = void 0;
  55929. }
  55930. return min;
  55931. };
  55932. if (!H.RangeSelector) {
  55933. var chartDestroyEvents_1 = [];
  55934. var initRangeSelector_1 = function (chart) {
  55935. var extremes,
  55936. rangeSelector = chart.rangeSelector,
  55937. legend,
  55938. alignTo,
  55939. verticalAlign;
  55940. /**
  55941. * @private
  55942. */
  55943. function render() {
  55944. if (rangeSelector) {
  55945. extremes = chart.xAxis[0].getExtremes();
  55946. legend = chart.legend;
  55947. verticalAlign = rangeSelector === null || rangeSelector === void 0 ? void 0 : rangeSelector.options.verticalAlign;
  55948. if (isNumber(extremes.min)) {
  55949. rangeSelector.render(extremes.min, extremes.max);
  55950. }
  55951. // Re-align the legend so that it's below the rangeselector
  55952. if (legend.display &&
  55953. verticalAlign === 'top' &&
  55954. verticalAlign === legend.options.verticalAlign) {
  55955. // Create a new alignment box for the legend.
  55956. alignTo = merge(chart.spacingBox);
  55957. if (legend.options.layout === 'vertical') {
  55958. alignTo.y = chart.plotTop;
  55959. }
  55960. else {
  55961. alignTo.y += rangeSelector.getHeight();
  55962. }
  55963. legend.group.placed = false; // Don't animate the alignment.
  55964. legend.align(alignTo);
  55965. }
  55966. }
  55967. }
  55968. if (rangeSelector) {
  55969. var events = find(chartDestroyEvents_1,
  55970. function (e) { return e[0] === chart; });
  55971. if (!events) {
  55972. chartDestroyEvents_1.push([chart, [
  55973. // redraw the scroller on setExtremes
  55974. addEvent(chart.xAxis[0], 'afterSetExtremes', function (e) {
  55975. if (rangeSelector) {
  55976. rangeSelector.render(e.min, e.max);
  55977. }
  55978. }),
  55979. // redraw the scroller chart resize
  55980. addEvent(chart, 'redraw', render)
  55981. ]]);
  55982. }
  55983. // do it now
  55984. render();
  55985. }
  55986. };
  55987. // Initialize rangeselector for stock charts
  55988. addEvent(Chart, 'afterGetContainer', function () {
  55989. var _a;
  55990. if ((_a = this.options.rangeSelector) === null || _a === void 0 ? void 0 : _a.enabled) {
  55991. this.rangeSelector = new RangeSelector(this);
  55992. }
  55993. });
  55994. addEvent(Chart, 'beforeRender', function () {
  55995. var chart = this,
  55996. axes = chart.axes,
  55997. rangeSelector = chart.rangeSelector,
  55998. verticalAlign;
  55999. if (rangeSelector) {
  56000. if (isNumber(rangeSelector.deferredYTDClick)) {
  56001. rangeSelector.clickButton(rangeSelector.deferredYTDClick);
  56002. delete rangeSelector.deferredYTDClick;
  56003. }
  56004. axes.forEach(function (axis) {
  56005. axis.updateNames();
  56006. axis.setScale();
  56007. });
  56008. chart.getAxisMargins();
  56009. rangeSelector.render();
  56010. verticalAlign = rangeSelector.options.verticalAlign;
  56011. if (!rangeSelector.options.floating) {
  56012. if (verticalAlign === 'bottom') {
  56013. this.extraBottomMargin = true;
  56014. }
  56015. else if (verticalAlign !== 'middle') {
  56016. this.extraTopMargin = true;
  56017. }
  56018. }
  56019. }
  56020. });
  56021. addEvent(Chart, 'update', function (e) {
  56022. var chart = this,
  56023. options = e.options,
  56024. optionsRangeSelector = options.rangeSelector,
  56025. rangeSelector = chart.rangeSelector,
  56026. verticalAlign,
  56027. extraBottomMarginWas = this.extraBottomMargin,
  56028. extraTopMarginWas = this.extraTopMargin;
  56029. if (optionsRangeSelector &&
  56030. optionsRangeSelector.enabled &&
  56031. !defined(rangeSelector) &&
  56032. this.options.rangeSelector) {
  56033. this.options.rangeSelector.enabled = true;
  56034. this.rangeSelector = rangeSelector = new RangeSelector(this);
  56035. }
  56036. this.extraBottomMargin = false;
  56037. this.extraTopMargin = false;
  56038. if (rangeSelector) {
  56039. initRangeSelector_1(this);
  56040. verticalAlign = (optionsRangeSelector &&
  56041. optionsRangeSelector.verticalAlign) || (rangeSelector.options && rangeSelector.options.verticalAlign);
  56042. if (!rangeSelector.options.floating) {
  56043. if (verticalAlign === 'bottom') {
  56044. this.extraBottomMargin = true;
  56045. }
  56046. else if (verticalAlign !== 'middle') {
  56047. this.extraTopMargin = true;
  56048. }
  56049. }
  56050. if (this.extraBottomMargin !== extraBottomMarginWas ||
  56051. this.extraTopMargin !== extraTopMarginWas) {
  56052. this.isDirtyBox = true;
  56053. }
  56054. }
  56055. });
  56056. addEvent(Chart, 'render', function () {
  56057. var chart = this,
  56058. rangeSelector = chart.rangeSelector,
  56059. verticalAlign;
  56060. if (rangeSelector && !rangeSelector.options.floating) {
  56061. rangeSelector.render();
  56062. verticalAlign = rangeSelector.options.verticalAlign;
  56063. if (verticalAlign === 'bottom') {
  56064. this.extraBottomMargin = true;
  56065. }
  56066. else if (verticalAlign !== 'middle') {
  56067. this.extraTopMargin = true;
  56068. }
  56069. }
  56070. });
  56071. addEvent(Chart, 'getMargins', function () {
  56072. var rangeSelector = this.rangeSelector,
  56073. rangeSelectorHeight;
  56074. if (rangeSelector) {
  56075. rangeSelectorHeight = rangeSelector.getHeight();
  56076. if (this.extraTopMargin) {
  56077. this.plotTop += rangeSelectorHeight;
  56078. }
  56079. if (this.extraBottomMargin) {
  56080. this.marginBottom += rangeSelectorHeight;
  56081. }
  56082. }
  56083. });
  56084. Chart.prototype.callbacks.push(initRangeSelector_1);
  56085. // Remove resize/afterSetExtremes at chart destroy
  56086. addEvent(Chart, 'destroy', function destroyEvents() {
  56087. for (var i = 0; i < chartDestroyEvents_1.length; i++) {
  56088. var events = chartDestroyEvents_1[i];
  56089. if (events[0] === this) {
  56090. events[1].forEach(function (unbind) { return unbind(); });
  56091. chartDestroyEvents_1.splice(i, 1);
  56092. return;
  56093. }
  56094. }
  56095. });
  56096. H.RangeSelector = RangeSelector;
  56097. }
  56098. return H.RangeSelector;
  56099. });
  56100. _registerModule(_modules, 'Core/Chart/StockChart.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Chart/Chart.js'], _modules['Core/Globals.js'], _modules['Core/Color/Palette.js'], _modules['Core/Series/Point.js'], _modules['Core/Series/Series.js'], _modules['Core/Renderer/SVG/SVGRenderer.js'], _modules['Core/Utilities.js']], function (Axis, Chart, H, palette, Point, Series, SVGRenderer, U) {
  56101. /* *
  56102. *
  56103. * (c) 2010-2021 Torstein Honsi
  56104. *
  56105. * License: www.highcharts.com/license
  56106. *
  56107. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  56108. *
  56109. * */
  56110. var pointTooltipFormatter = Point.prototype.tooltipFormatter;
  56111. var _a = Series.prototype,
  56112. seriesInit = _a.init,
  56113. seriesProcessData = _a.processData;
  56114. var addEvent = U.addEvent,
  56115. arrayMax = U.arrayMax,
  56116. arrayMin = U.arrayMin,
  56117. clamp = U.clamp,
  56118. defined = U.defined,
  56119. extend = U.extend,
  56120. find = U.find,
  56121. format = U.format,
  56122. getOptions = U.getOptions,
  56123. isNumber = U.isNumber,
  56124. isString = U.isString,
  56125. merge = U.merge,
  56126. pick = U.pick,
  56127. splat = U.splat;
  56128. // Has a dependency on Navigator due to the use of
  56129. // defaultOptions.navigator
  56130. // Has a dependency on Scrollbar due to the use of
  56131. // defaultOptions.scrollbar
  56132. // Has a dependency on RangeSelector due to the use of
  56133. // defaultOptions.rangeSelector
  56134. /* eslint-disable no-invalid-this, valid-jsdoc */
  56135. /* *
  56136. *
  56137. * Factory
  56138. *
  56139. * */
  56140. /**
  56141. * Factory function for creating new stock charts. Creates a new
  56142. * {@link Highcharts.Chart|Chart} object with different default options than the
  56143. * basic Chart.
  56144. *
  56145. * @example
  56146. * var chart = Highcharts.stockChart('container', {
  56147. * series: [{
  56148. * data: [1, 2, 3, 4, 5, 6, 7, 8, 9],
  56149. * pointInterval: 24 * 60 * 60 * 1000
  56150. * }]
  56151. * });
  56152. *
  56153. * @function Highcharts.stockChart
  56154. *
  56155. * @param {string|Highcharts.HTMLDOMElement} [renderTo]
  56156. * The DOM element to render to, or its id.
  56157. *
  56158. * @param {Highcharts.Options} options
  56159. * The chart options structure as described in the
  56160. * [options reference](https://api.highcharts.com/highstock).
  56161. *
  56162. * @param {Highcharts.ChartCallbackFunction} [callback]
  56163. * A function to execute when the chart object is finished loading and
  56164. * rendering. In most cases the chart is built in one thread, but in
  56165. * Internet Explorer version 8 or less the chart is sometimes
  56166. * initialized before the document is ready, and in these cases the
  56167. * chart object will not be finished synchronously. As a consequence,
  56168. * code that relies on the newly built Chart object should always run in
  56169. * the callback. Defining a
  56170. * [chart.events.load](https://api.highcharts.com/highstock/chart.events.load)
  56171. * handler is equivalent.
  56172. *
  56173. * @return {Highcharts.Chart}
  56174. * The chart object.
  56175. */
  56176. function stockChart(a, b, c) {
  56177. var hasRenderToArg = isString(a) || a.nodeName,
  56178. options = arguments[hasRenderToArg ? 1 : 0],
  56179. userOptions = options,
  56180. // to increase performance, don't merge the data
  56181. seriesOptions = options.series,
  56182. defaultOptions = getOptions(),
  56183. opposite,
  56184. // Always disable startOnTick:true on the main axis when the navigator
  56185. // is enabled (#1090)
  56186. navigatorEnabled = pick(options.navigator && options.navigator.enabled,
  56187. defaultOptions.navigator.enabled,
  56188. true);
  56189. // apply X axis options to both single and multi y axes
  56190. options.xAxis = splat(options.xAxis || {}).map(function (xAxisOptions, i) {
  56191. return merge({
  56192. minPadding: 0,
  56193. maxPadding: 0,
  56194. overscroll: 0,
  56195. ordinal: true,
  56196. title: {
  56197. text: null
  56198. },
  56199. labels: {
  56200. overflow: 'justify'
  56201. },
  56202. showLastLabel: true
  56203. }, defaultOptions.xAxis, // #3802
  56204. defaultOptions.xAxis && defaultOptions.xAxis[i], // #7690
  56205. xAxisOptions, // user options
  56206. {
  56207. type: 'datetime',
  56208. categories: null
  56209. }, (navigatorEnabled ? {
  56210. startOnTick: false,
  56211. endOnTick: false
  56212. } : null));
  56213. });
  56214. // apply Y axis options to both single and multi y axes
  56215. options.yAxis = splat(options.yAxis || {}).map(function (yAxisOptions, i) {
  56216. opposite = pick(yAxisOptions.opposite, true);
  56217. return merge({
  56218. labels: {
  56219. y: -2
  56220. },
  56221. opposite: opposite,
  56222. /**
  56223. * @default {highcharts} true
  56224. * @default {highstock} false
  56225. * @apioption yAxis.showLastLabel
  56226. *
  56227. * @private
  56228. */
  56229. showLastLabel: !!(
  56230. // #6104, show last label by default for category axes
  56231. yAxisOptions.categories ||
  56232. yAxisOptions.type === 'category'),
  56233. title: {
  56234. text: null
  56235. }
  56236. }, defaultOptions.yAxis, // #3802
  56237. defaultOptions.yAxis && defaultOptions.yAxis[i], // #7690
  56238. yAxisOptions // user options
  56239. );
  56240. });
  56241. options.series = null;
  56242. options = merge({
  56243. chart: {
  56244. panning: {
  56245. enabled: true,
  56246. type: 'x'
  56247. },
  56248. pinchType: 'x'
  56249. },
  56250. navigator: {
  56251. enabled: navigatorEnabled
  56252. },
  56253. scrollbar: {
  56254. // #4988 - check if setOptions was called
  56255. enabled: pick(defaultOptions.scrollbar.enabled, true)
  56256. },
  56257. rangeSelector: {
  56258. // #4988 - check if setOptions was called
  56259. enabled: pick(defaultOptions.rangeSelector.enabled, true)
  56260. },
  56261. title: {
  56262. text: null
  56263. },
  56264. tooltip: {
  56265. split: pick(defaultOptions.tooltip.split, true),
  56266. crosshairs: true
  56267. },
  56268. legend: {
  56269. enabled: false
  56270. }
  56271. }, options, // user's options
  56272. {
  56273. isStock: true // internal flag
  56274. });
  56275. options.series = userOptions.series = seriesOptions;
  56276. return hasRenderToArg ?
  56277. new Chart(a, options, c) :
  56278. new Chart(options, b);
  56279. }
  56280. /* *
  56281. *
  56282. * Compositions
  56283. *
  56284. * */
  56285. // Handle som Stock-specific series defaults, override the plotOptions before
  56286. // series options are handled.
  56287. addEvent(Series, 'setOptions', function (e) {
  56288. var overrides;
  56289. if (this.chart.options.isStock) {
  56290. if (this.is('column') || this.is('columnrange')) {
  56291. overrides = {
  56292. borderWidth: 0,
  56293. shadow: false
  56294. };
  56295. }
  56296. else if (!this.is('scatter') && !this.is('sma')) {
  56297. overrides = {
  56298. marker: {
  56299. enabled: false,
  56300. radius: 2
  56301. }
  56302. };
  56303. }
  56304. if (overrides) {
  56305. e.plotOptions[this.type] = merge(e.plotOptions[this.type], overrides);
  56306. }
  56307. }
  56308. });
  56309. // Override the automatic label alignment so that the first Y axis' labels
  56310. // are drawn on top of the grid line, and subsequent axes are drawn outside
  56311. addEvent(Axis, 'autoLabelAlign', function (e) {
  56312. var chart = this.chart,
  56313. options = this.options,
  56314. panes = chart._labelPanes = chart._labelPanes || {},
  56315. key,
  56316. labelOptions = this.options.labels;
  56317. if (this.chart.options.isStock && this.coll === 'yAxis') {
  56318. key = options.top + ',' + options.height;
  56319. // do it only for the first Y axis of each pane
  56320. if (!panes[key] && labelOptions.enabled) {
  56321. if (labelOptions.x === 15) { // default
  56322. labelOptions.x = 0;
  56323. }
  56324. if (typeof labelOptions.align === 'undefined') {
  56325. labelOptions.align = 'right';
  56326. }
  56327. panes[key] = this;
  56328. e.align = 'right';
  56329. e.preventDefault();
  56330. }
  56331. }
  56332. });
  56333. // Clear axis from label panes (#6071)
  56334. addEvent(Axis, 'destroy', function () {
  56335. var chart = this.chart, key = this.options && (this.options.top + ',' + this.options.height);
  56336. if (key && chart._labelPanes && chart._labelPanes[key] === this) {
  56337. delete chart._labelPanes[key];
  56338. }
  56339. });
  56340. // Override getPlotLinePath to allow for multipane charts
  56341. addEvent(Axis, 'getPlotLinePath', function (e) {
  56342. var axis = this,
  56343. series = (this.isLinked && !this.series ?
  56344. this.linkedParent.series :
  56345. this.series),
  56346. chart = axis.chart,
  56347. renderer = chart.renderer,
  56348. axisLeft = axis.left,
  56349. axisTop = axis.top,
  56350. x1,
  56351. y1,
  56352. x2,
  56353. y2,
  56354. result = [],
  56355. axes = [], // #3416 need a default array
  56356. axes2,
  56357. uniqueAxes,
  56358. translatedValue = e.translatedValue,
  56359. value = e.value,
  56360. force = e.force,
  56361. transVal;
  56362. /**
  56363. * Return the other axis based on either the axis option or on related
  56364. * series.
  56365. * @private
  56366. */
  56367. function getAxis(coll) {
  56368. var otherColl = coll === 'xAxis' ? 'yAxis' : 'xAxis',
  56369. opt = axis.options[otherColl];
  56370. // Other axis indexed by number
  56371. if (isNumber(opt)) {
  56372. return [chart[otherColl][opt]];
  56373. }
  56374. // Other axis indexed by id (like navigator)
  56375. if (isString(opt)) {
  56376. return [chart.get(opt)];
  56377. }
  56378. // Auto detect based on existing series
  56379. return series.map(function (s) {
  56380. return s[otherColl];
  56381. });
  56382. }
  56383. if ( // For stock chart, by default render paths across the panes
  56384. // except the case when `acrossPanes` is disabled by user (#6644)
  56385. (chart.options.isStock && e.acrossPanes !== false) &&
  56386. // Ignore in case of colorAxis or zAxis. #3360, #3524, #6720
  56387. axis.coll === 'xAxis' || axis.coll === 'yAxis') {
  56388. e.preventDefault();
  56389. // Get the related axes based on series
  56390. axes = getAxis(axis.coll);
  56391. // Get the related axes based options.*Axis setting #2810
  56392. axes2 = (axis.isXAxis ? chart.yAxis : chart.xAxis);
  56393. axes2.forEach(function (A) {
  56394. if (defined(A.options.id) ?
  56395. A.options.id.indexOf('navigator') === -1 :
  56396. true) {
  56397. var a = (A.isXAxis ? 'yAxis' : 'xAxis'),
  56398. rax = (defined(A.options[a]) ?
  56399. chart[a][A.options[a]] :
  56400. chart[a][0]);
  56401. if (axis === rax) {
  56402. axes.push(A);
  56403. }
  56404. }
  56405. });
  56406. // Remove duplicates in the axes array. If there are no axes in the axes
  56407. // array, we are adding an axis without data, so we need to populate
  56408. // this with grid lines (#2796).
  56409. uniqueAxes = axes.length ?
  56410. [] :
  56411. [axis.isXAxis ? chart.yAxis[0] : chart.xAxis[0]]; // #3742
  56412. axes.forEach(function (axis2) {
  56413. if (uniqueAxes.indexOf(axis2) === -1 &&
  56414. // Do not draw on axis which overlap completely. #5424
  56415. !find(uniqueAxes, function (unique) {
  56416. return unique.pos === axis2.pos && unique.len === axis2.len;
  56417. })) {
  56418. uniqueAxes.push(axis2);
  56419. }
  56420. });
  56421. transVal = pick(translatedValue, axis.translate(value, null, null, e.old));
  56422. if (isNumber(transVal)) {
  56423. if (axis.horiz) {
  56424. uniqueAxes.forEach(function (axis2) {
  56425. var skip;
  56426. y1 = axis2.pos;
  56427. y2 = y1 + axis2.len;
  56428. x1 = x2 = Math.round(transVal + axis.transB);
  56429. // outside plot area
  56430. if (force !== 'pass' &&
  56431. (x1 < axisLeft || x1 > axisLeft + axis.width)) {
  56432. if (force) {
  56433. x1 = x2 = clamp(x1, axisLeft, axisLeft + axis.width);
  56434. }
  56435. else {
  56436. skip = true;
  56437. }
  56438. }
  56439. if (!skip) {
  56440. result.push(['M', x1, y1], ['L', x2, y2]);
  56441. }
  56442. });
  56443. }
  56444. else {
  56445. uniqueAxes.forEach(function (axis2) {
  56446. var skip;
  56447. x1 = axis2.pos;
  56448. x2 = x1 + axis2.len;
  56449. y1 = y2 = Math.round(axisTop + axis.height - transVal);
  56450. // outside plot area
  56451. if (force !== 'pass' &&
  56452. (y1 < axisTop || y1 > axisTop + axis.height)) {
  56453. if (force) {
  56454. y1 = y2 = clamp(y1, axisTop, axisTop + axis.height);
  56455. }
  56456. else {
  56457. skip = true;
  56458. }
  56459. }
  56460. if (!skip) {
  56461. result.push(['M', x1, y1], ['L', x2, y2]);
  56462. }
  56463. });
  56464. }
  56465. }
  56466. e.path = result.length > 0 ?
  56467. renderer.crispPolyLine(result, e.lineWidth || 1) :
  56468. // #3557 getPlotLinePath in regular Highcharts also returns null
  56469. null;
  56470. }
  56471. });
  56472. /**
  56473. * Function to crisp a line with multiple segments
  56474. *
  56475. * @private
  56476. * @function Highcharts.SVGRenderer#crispPolyLine
  56477. * @param {Highcharts.SVGPathArray} points
  56478. * @param {number} width
  56479. * @return {Highcharts.SVGPathArray}
  56480. */
  56481. SVGRenderer.prototype.crispPolyLine = function (points, width) {
  56482. // points format: [['M', 0, 0], ['L', 100, 0]]
  56483. // normalize to a crisp line
  56484. for (var i = 0; i < points.length; i = i + 2) {
  56485. var start = points[i],
  56486. end = points[i + 1];
  56487. if (start[1] === end[1]) {
  56488. // Substract due to #1129. Now bottom and left axis gridlines behave
  56489. // the same.
  56490. start[1] = end[1] =
  56491. Math.round(start[1]) - (width % 2 / 2);
  56492. }
  56493. if (start[2] === end[2]) {
  56494. start[2] = end[2] =
  56495. Math.round(start[2]) + (width % 2 / 2);
  56496. }
  56497. }
  56498. return points;
  56499. };
  56500. // Wrapper to hide the label
  56501. addEvent(Axis, 'afterHideCrosshair', function () {
  56502. if (this.crossLabel) {
  56503. this.crossLabel = this.crossLabel.hide();
  56504. }
  56505. });
  56506. // Extend crosshairs to also draw the label
  56507. addEvent(Axis, 'afterDrawCrosshair', function (event) {
  56508. // Check if the label has to be drawn
  56509. if (!defined(this.crosshair.label) ||
  56510. !this.crosshair.label.enabled ||
  56511. !this.cross) {
  56512. return;
  56513. }
  56514. var chart = this.chart, log = this.logarithmic, options = this.options.crosshair.label, // the label's options
  56515. horiz = this.horiz, // axis orientation
  56516. opposite = this.opposite, // axis position
  56517. left = this.left, // left position
  56518. top = this.top, // top position
  56519. crossLabel = this.crossLabel, // the svgElement
  56520. posx, posy, crossBox, formatOption = options.format, formatFormat = '', limit, align, tickInside = this.options.tickPosition === 'inside', snap = this.crosshair.snap !== false, value, offset = 0,
  56521. // Use last available event (#5287)
  56522. e = event.e || (this.cross && this.cross.e), point = event.point, min = this.min, max = this.max;
  56523. if (log) {
  56524. min = log.lin2log(min);
  56525. max = log.lin2log(max);
  56526. }
  56527. align = (horiz ? 'center' : opposite ?
  56528. (this.labelAlign === 'right' ? 'right' : 'left') :
  56529. (this.labelAlign === 'left' ? 'left' : 'center'));
  56530. // If the label does not exist yet, create it.
  56531. if (!crossLabel) {
  56532. crossLabel = this.crossLabel = chart.renderer
  56533. .label(null, null, null, options.shape || 'callout')
  56534. .addClass('highcharts-crosshair-label' + (this.series[0] &&
  56535. ' highcharts-color-' + this.series[0].colorIndex))
  56536. .attr({
  56537. align: options.align || align,
  56538. padding: pick(options.padding, 8),
  56539. r: pick(options.borderRadius, 3),
  56540. zIndex: 2
  56541. })
  56542. .add(this.labelGroup);
  56543. // Presentational
  56544. if (!chart.styledMode) {
  56545. crossLabel
  56546. .attr({
  56547. fill: options.backgroundColor ||
  56548. (this.series[0] && this.series[0].color) ||
  56549. palette.neutralColor60,
  56550. stroke: options.borderColor || '',
  56551. 'stroke-width': options.borderWidth || 0
  56552. })
  56553. .css(extend({
  56554. color: palette.backgroundColor,
  56555. fontWeight: 'normal',
  56556. fontSize: '11px',
  56557. textAlign: 'center'
  56558. }, options.style));
  56559. }
  56560. }
  56561. if (horiz) {
  56562. posx = snap ? point.plotX + left : e.chartX;
  56563. posy = top + (opposite ? 0 : this.height);
  56564. }
  56565. else {
  56566. posx = opposite ? this.width + left : 0;
  56567. posy = snap ? point.plotY + top : e.chartY;
  56568. }
  56569. if (!formatOption && !options.formatter) {
  56570. if (this.dateTime) {
  56571. formatFormat = '%b %d, %Y';
  56572. }
  56573. formatOption =
  56574. '{value' + (formatFormat ? ':' + formatFormat : '') + '}';
  56575. }
  56576. // Show the label
  56577. value = snap ?
  56578. point[this.isXAxis ? 'x' : 'y'] :
  56579. this.toValue(horiz ? e.chartX : e.chartY);
  56580. crossLabel.attr({
  56581. text: formatOption ?
  56582. format(formatOption, { value: value }, chart) :
  56583. options.formatter.call(this, value),
  56584. x: posx,
  56585. y: posy,
  56586. // Crosshair should be rendered within Axis range (#7219)
  56587. visibility: value < min || value > max ?
  56588. 'hidden' :
  56589. 'visible'
  56590. });
  56591. crossBox = crossLabel.getBBox();
  56592. // now it is placed we can correct its position
  56593. if (isNumber(crossLabel.y)) {
  56594. if (horiz) {
  56595. if ((tickInside && !opposite) || (!tickInside && opposite)) {
  56596. posy = crossLabel.y - crossBox.height;
  56597. }
  56598. }
  56599. else {
  56600. posy = crossLabel.y - (crossBox.height / 2);
  56601. }
  56602. }
  56603. // check the edges
  56604. if (horiz) {
  56605. limit = {
  56606. left: left - crossBox.x,
  56607. right: left + this.width - crossBox.x
  56608. };
  56609. }
  56610. else {
  56611. limit = {
  56612. left: this.labelAlign === 'left' ? left : 0,
  56613. right: this.labelAlign === 'right' ?
  56614. left + this.width :
  56615. chart.chartWidth
  56616. };
  56617. }
  56618. // left edge
  56619. if (crossLabel.translateX < limit.left) {
  56620. offset = limit.left - crossLabel.translateX;
  56621. }
  56622. // right edge
  56623. if (crossLabel.translateX + crossBox.width >= limit.right) {
  56624. offset = -(crossLabel.translateX + crossBox.width - limit.right);
  56625. }
  56626. // show the crosslabel
  56627. crossLabel.attr({
  56628. x: posx + offset,
  56629. y: posy,
  56630. // First set x and y, then anchorX and anchorY, when box is actually
  56631. // calculated, #5702
  56632. anchorX: horiz ?
  56633. posx :
  56634. (this.opposite ? 0 : chart.chartWidth),
  56635. anchorY: horiz ?
  56636. (this.opposite ? chart.chartHeight : 0) :
  56637. posy + crossBox.height / 2
  56638. });
  56639. });
  56640. /* ************************************************************************** *
  56641. * Start value compare logic *
  56642. * ************************************************************************** */
  56643. /**
  56644. * Extend series.init by adding a method to modify the y value used for plotting
  56645. * on the y axis. This method is called both from the axis when finding dataMin
  56646. * and dataMax, and from the series.translate method.
  56647. *
  56648. * @ignore
  56649. * @function Highcharts.Series#init
  56650. */
  56651. Series.prototype.init = function () {
  56652. // Call base method
  56653. seriesInit.apply(this, arguments);
  56654. // Set comparison mode
  56655. this.initCompare(this.options.compare);
  56656. };
  56657. /**
  56658. * Highstock only. Set the
  56659. * [compare](https://api.highcharts.com/highstock/plotOptions.series.compare)
  56660. * mode of the series after render time. In most cases it is more useful running
  56661. * {@link Axis#setCompare} on the X axis to update all its series.
  56662. *
  56663. * @function Highcharts.Series#setCompare
  56664. *
  56665. * @param {string} [compare]
  56666. * Can be one of `null` (default), `"percent"` or `"value"`.
  56667. */
  56668. Series.prototype.setCompare = function (compare) {
  56669. this.initCompare(compare);
  56670. // Survive to export, #5485
  56671. this.userOptions.compare = compare;
  56672. };
  56673. /**
  56674. * @ignore
  56675. * @function Highcharts.Series#initCompare
  56676. *
  56677. * @param {string} [compare]
  56678. * Can be one of `null` (default), `"percent"` or `"value"`.
  56679. */
  56680. Series.prototype.initCompare = function (compare) {
  56681. // Set or unset the modifyValue method
  56682. this.modifyValue = (compare === 'value' || compare === 'percent') ?
  56683. function (value, point) {
  56684. var compareValue = this.compareValue;
  56685. if (typeof value !== 'undefined' &&
  56686. typeof compareValue !== 'undefined') { // #2601, #5814
  56687. // Get the modified value
  56688. if (compare === 'value') {
  56689. value -= compareValue;
  56690. // Compare percent
  56691. }
  56692. else {
  56693. value = 100 * (value / compareValue) -
  56694. (this.options.compareBase === 100 ? 0 : 100);
  56695. }
  56696. // record for tooltip etc.
  56697. if (point) {
  56698. point.change = value;
  56699. }
  56700. return value;
  56701. }
  56702. return 0;
  56703. } :
  56704. null;
  56705. // Mark dirty
  56706. if (this.chart.hasRendered) {
  56707. this.isDirty = true;
  56708. }
  56709. };
  56710. /**
  56711. * Extend series.processData by finding the first y value in the plot area,
  56712. * used for comparing the following values
  56713. *
  56714. * @ignore
  56715. * @function Highcharts.Series#processData
  56716. */
  56717. Series.prototype.processData = function (force) {
  56718. var series = this,
  56719. i,
  56720. keyIndex = -1,
  56721. processedXData,
  56722. processedYData,
  56723. compareStart = series.options.compareStart === true ? 0 : 1,
  56724. length,
  56725. compareValue;
  56726. // call base method
  56727. seriesProcessData.apply(this, arguments);
  56728. if (series.xAxis && series.processedYData) { // not pies
  56729. // local variables
  56730. processedXData = series.processedXData;
  56731. processedYData = series.processedYData;
  56732. length = processedYData.length;
  56733. // For series with more than one value (range, OHLC etc), compare
  56734. // against close or the pointValKey (#4922, #3112, #9854)
  56735. if (series.pointArrayMap) {
  56736. keyIndex = series.pointArrayMap.indexOf(series.options.pointValKey || series.pointValKey || 'y');
  56737. }
  56738. // find the first value for comparison
  56739. for (i = 0; i < length - compareStart; i++) {
  56740. compareValue = processedYData[i] && keyIndex > -1 ?
  56741. processedYData[i][keyIndex] :
  56742. processedYData[i];
  56743. if (isNumber(compareValue) &&
  56744. processedXData[i + compareStart] >=
  56745. series.xAxis.min &&
  56746. compareValue !== 0) {
  56747. series.compareValue = compareValue;
  56748. break;
  56749. }
  56750. }
  56751. }
  56752. return;
  56753. };
  56754. // Modify series extremes
  56755. addEvent(Series, 'afterGetExtremes', function (e) {
  56756. var dataExtremes = e.dataExtremes;
  56757. if (this.modifyValue && dataExtremes) {
  56758. var extremes = [
  56759. this.modifyValue(dataExtremes.dataMin),
  56760. this.modifyValue(dataExtremes.dataMax)
  56761. ];
  56762. dataExtremes.dataMin = arrayMin(extremes);
  56763. dataExtremes.dataMax = arrayMax(extremes);
  56764. }
  56765. });
  56766. /**
  56767. * Highstock only. Set the compare mode on all series belonging to an Y axis
  56768. * after render time.
  56769. *
  56770. * @see [series.plotOptions.compare](https://api.highcharts.com/highstock/series.plotOptions.compare)
  56771. *
  56772. * @sample stock/members/axis-setcompare/
  56773. * Set compoare
  56774. *
  56775. * @function Highcharts.Axis#setCompare
  56776. *
  56777. * @param {string} [compare]
  56778. * The compare mode. Can be one of `null` (default), `"value"` or
  56779. * `"percent"`.
  56780. *
  56781. * @param {boolean} [redraw=true]
  56782. * Whether to redraw the chart or to wait for a later call to
  56783. * {@link Chart#redraw}.
  56784. */
  56785. Axis.prototype.setCompare = function (compare, redraw) {
  56786. if (!this.isXAxis) {
  56787. this.series.forEach(function (series) {
  56788. series.setCompare(compare);
  56789. });
  56790. if (pick(redraw, true)) {
  56791. this.chart.redraw();
  56792. }
  56793. }
  56794. };
  56795. /**
  56796. * Extend the tooltip formatter by adding support for the point.change variable
  56797. * as well as the changeDecimals option.
  56798. *
  56799. * @ignore
  56800. * @function Highcharts.Point#tooltipFormatter
  56801. *
  56802. * @param {string} pointFormat
  56803. */
  56804. Point.prototype.tooltipFormatter = function (pointFormat) {
  56805. var point = this;
  56806. var numberFormatter = point.series.chart.numberFormatter;
  56807. pointFormat = pointFormat.replace('{point.change}', (point.change > 0 ? '+' : '') + numberFormatter(point.change, pick(point.series.tooltipOptions.changeDecimals, 2)));
  56808. return pointTooltipFormatter.apply(this, [pointFormat]);
  56809. };
  56810. /* ************************************************************************** *
  56811. * End value compare logic *
  56812. * ************************************************************************** */
  56813. // Extend the Series prototype to create a separate series clip box. This is
  56814. // related to using multiple panes, and a future pane logic should incorporate
  56815. // this feature (#2754).
  56816. addEvent(Series, 'render', function () {
  56817. var chart = this.chart,
  56818. clipHeight;
  56819. // Only do this on not 3d (#2939, #5904) nor polar (#6057) charts, and only
  56820. // if the series type handles clipping in the animate method (#2975).
  56821. if (!(chart.is3d && chart.is3d()) &&
  56822. !chart.polar &&
  56823. this.xAxis &&
  56824. !this.xAxis.isRadial // Gauge, #6192
  56825. ) {
  56826. clipHeight = this.yAxis.len;
  56827. // Include xAxis line width (#8031) but only if the Y axis ends on the
  56828. // edge of the X axis (#11005).
  56829. if (this.xAxis.axisLine) {
  56830. var dist = chart.plotTop + chart.plotHeight -
  56831. this.yAxis.pos - this.yAxis.len,
  56832. lineHeightCorrection = Math.floor(this.xAxis.axisLine.strokeWidth() / 2);
  56833. if (dist >= 0) {
  56834. clipHeight -= Math.max(lineHeightCorrection - dist, 0);
  56835. }
  56836. }
  56837. // First render, initial clip box
  56838. if (!this.clipBox && this.isDirty && !this.isDirtyData) {
  56839. this.clipBox = merge(chart.clipBox);
  56840. this.clipBox.width = this.xAxis.len;
  56841. this.clipBox.height = clipHeight;
  56842. // On redrawing, resizing etc, update the clip rectangle
  56843. }
  56844. else if (chart[this.sharedClipKey]) {
  56845. // animate in case resize is done during initial animation
  56846. chart[this.sharedClipKey].animate({
  56847. width: this.xAxis.len,
  56848. height: clipHeight
  56849. });
  56850. // also change markers clip animation for consistency
  56851. // (marker clip rects should exist only on chart init)
  56852. if (chart[this.sharedClipKey + 'm']) {
  56853. chart[this.sharedClipKey + 'm'].animate({
  56854. width: this.xAxis.len
  56855. });
  56856. }
  56857. }
  56858. }
  56859. });
  56860. addEvent(Chart, 'update', function (e) {
  56861. var options = e.options;
  56862. // Use case: enabling scrollbar from a disabled state.
  56863. // Scrollbar needs to be initialized from a controller, Navigator in this
  56864. // case (#6615)
  56865. if ('scrollbar' in options && this.navigator) {
  56866. merge(true, this.options.scrollbar, options.scrollbar);
  56867. this.navigator.update({}, false);
  56868. delete options.scrollbar;
  56869. }
  56870. });
  56871. /* *
  56872. *
  56873. * Compatibility
  56874. *
  56875. * */
  56876. H.StockChart = H.stockChart = stockChart;
  56877. /* *
  56878. *
  56879. * Default Export
  56880. *
  56881. * */
  56882. /* *
  56883. *
  56884. * API Options
  56885. *
  56886. * */
  56887. /**
  56888. * Compare the values of the series against the first non-null, non-
  56889. * zero value in the visible range. The y axis will show percentage
  56890. * or absolute change depending on whether `compare` is set to `"percent"`
  56891. * or `"value"`. When this is applied to multiple series, it allows
  56892. * comparing the development of the series against each other. Adds
  56893. * a `change` field to every point object.
  56894. *
  56895. * @see [compareBase](#plotOptions.series.compareBase)
  56896. * @see [Axis.setCompare()](/class-reference/Highcharts.Axis#setCompare)
  56897. *
  56898. * @sample {highstock} stock/plotoptions/series-compare-percent/
  56899. * Percent
  56900. * @sample {highstock} stock/plotoptions/series-compare-value/
  56901. * Value
  56902. *
  56903. * @type {string}
  56904. * @since 1.0.1
  56905. * @product highstock
  56906. * @apioption plotOptions.series.compare
  56907. */
  56908. /**
  56909. * Defines if comparison should start from the first point within the visible
  56910. * range or should start from the first point **before** the range.
  56911. *
  56912. * In other words, this flag determines if first point within the visible range
  56913. * will have 0% (`compareStart=true`) or should have been already calculated
  56914. * according to the previous point (`compareStart=false`).
  56915. *
  56916. * @sample {highstock} stock/plotoptions/series-comparestart/
  56917. * Calculate compare within visible range
  56918. *
  56919. * @type {boolean}
  56920. * @default false
  56921. * @since 6.0.0
  56922. * @product highstock
  56923. * @apioption plotOptions.series.compareStart
  56924. */
  56925. /**
  56926. * When [compare](#plotOptions.series.compare) is `percent`, this option
  56927. * dictates whether to use 0 or 100 as the base of comparison.
  56928. *
  56929. * @sample {highstock} stock/plotoptions/series-comparebase/
  56930. * Compare base is 100
  56931. *
  56932. * @type {number}
  56933. * @default 0
  56934. * @since 5.0.6
  56935. * @product highstock
  56936. * @validvalue [0, 100]
  56937. * @apioption plotOptions.series.compareBase
  56938. */
  56939. ''; // keeps doclets above in transpiled file
  56940. return stockChart;
  56941. });
  56942. _registerModule(_modules, 'masters/modules/stock.src.js', [], function () {
  56943. });
  56944. _registerModule(_modules, 'masters/highstock.src.js', [_modules['masters/highcharts.src.js']], function (Highcharts) {
  56945. Highcharts.product = 'Highstock';
  56946. return Highcharts;
  56947. });
  56948. _modules['masters/highstock.src.js']._modules = _modules;
  56949. return _modules['masters/highstock.src.js'];
  56950. }));