highcharts-more.src.js 435 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690
  1. /**
  2. * @license Highcharts JS v8.1.2 (2020-06-16)
  3. *
  4. * (c) 2009-2018 Torstein Honsi
  5. *
  6. * License: www.highcharts.com/license
  7. */
  8. 'use strict';
  9. (function (factory) {
  10. if (typeof module === 'object' && module.exports) {
  11. factory['default'] = factory;
  12. module.exports = factory;
  13. } else if (typeof define === 'function' && define.amd) {
  14. define('highcharts/highcharts-more', ['highcharts'], function (Highcharts) {
  15. factory(Highcharts);
  16. factory.Highcharts = Highcharts;
  17. return factory;
  18. });
  19. } else {
  20. factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);
  21. }
  22. }(function (Highcharts) {
  23. var _modules = Highcharts ? Highcharts._modules : {};
  24. function _registerModule(obj, path, args, fn) {
  25. if (!obj.hasOwnProperty(path)) {
  26. obj[path] = fn.apply(null, args);
  27. }
  28. }
  29. _registerModule(_modules, 'parts-more/Pane.js', [_modules['parts/Chart.js'], _modules['parts/Globals.js'], _modules['parts/Pointer.js'], _modules['parts/Utilities.js']], function (Chart, H, Pointer, U) {
  30. /* *
  31. *
  32. * (c) 2010-2020 Torstein Honsi
  33. *
  34. * License: www.highcharts.com/license
  35. *
  36. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  37. *
  38. * */
  39. var addEvent = U.addEvent, extend = U.extend, merge = U.merge, pick = U.pick, splat = U.splat;
  40. /**
  41. * @typedef {"arc"|"circle"|"solid"} Highcharts.PaneBackgroundShapeValue
  42. */
  43. var CenteredSeriesMixin = H.CenteredSeriesMixin;
  44. /* eslint-disable no-invalid-this, valid-jsdoc */
  45. Chart.prototype.collectionsWithUpdate.push('pane');
  46. /**
  47. * The Pane object allows options that are common to a set of X and Y axes.
  48. *
  49. * In the future, this can be extended to basic Highcharts and Highstock.
  50. *
  51. * @private
  52. * @class
  53. * @name Highcharts.Pane
  54. * @param {Highcharts.PaneOptions} options
  55. * @param {Highcharts.Chart} chart
  56. */
  57. var Pane = /** @class */ (function () {
  58. function Pane(options, chart) {
  59. this.background = void 0;
  60. this.center = void 0;
  61. this.chart = void 0;
  62. this.options = void 0;
  63. this.coll = 'pane'; // Member of chart.pane
  64. /**
  65. * The pane serves as a container for axes and backgrounds for circular
  66. * gauges and polar charts.
  67. *
  68. * @since 2.3.0
  69. * @product highcharts
  70. * @requires highcharts-more
  71. * @optionparent pane
  72. */
  73. this.defaultOptions = {
  74. /**
  75. * The end angle of the polar X axis or gauge value axis, given in
  76. * degrees where 0 is north. Defaults to [startAngle](#pane.startAngle)
  77. * + 360.
  78. *
  79. * @sample {highcharts} highcharts/demo/gauge-vu-meter/
  80. * VU-meter with custom start and end angle
  81. *
  82. * @type {number}
  83. * @since 2.3.0
  84. * @product highcharts
  85. * @apioption pane.endAngle
  86. */
  87. /**
  88. * The center of a polar chart or angular gauge, given as an array
  89. * of [x, y] positions. Positions can be given as integers that
  90. * transform to pixels, or as percentages of the plot area size.
  91. *
  92. * @sample {highcharts} highcharts/demo/gauge-vu-meter/
  93. * Two gauges with different center
  94. *
  95. * @type {Array<string|number>}
  96. * @default ["50%", "50%"]
  97. * @since 2.3.0
  98. * @product highcharts
  99. */
  100. center: ['50%', '50%'],
  101. /**
  102. * The size of the pane, either as a number defining pixels, or a
  103. * percentage defining a percentage of the available plot area (the
  104. * smallest of the plot height or plot width).
  105. *
  106. * @sample {highcharts} highcharts/demo/gauge-vu-meter/
  107. * Smaller size
  108. *
  109. * @type {number|string}
  110. * @product highcharts
  111. */
  112. size: '85%',
  113. /**
  114. * The inner size of the pane, either as a number defining pixels, or a
  115. * percentage defining a percentage of the pane's size.
  116. *
  117. * @sample {highcharts} highcharts/series-polar/column-inverted-inner
  118. * The inner size set to 20%
  119. *
  120. * @type {number|string}
  121. * @product highcharts
  122. */
  123. innerSize: '0%',
  124. /**
  125. * The start angle of the polar X axis or gauge axis, given in degrees
  126. * where 0 is north. Defaults to 0.
  127. *
  128. * @sample {highcharts} highcharts/demo/gauge-vu-meter/
  129. * VU-meter with custom start and end angle
  130. *
  131. * @since 2.3.0
  132. * @product highcharts
  133. */
  134. startAngle: 0
  135. };
  136. /**
  137. * An array of background items for the pane.
  138. *
  139. * @sample {highcharts} highcharts/demo/gauge-speedometer/
  140. * Speedometer gauge with multiple backgrounds
  141. *
  142. * @type {Array<*>}
  143. * @optionparent pane.background
  144. */
  145. this.defaultBackgroundOptions = {
  146. /**
  147. * The class name for this background.
  148. *
  149. * @sample {highcharts} highcharts/css/pane/
  150. * Panes styled by CSS
  151. * @sample {highstock} highcharts/css/pane/
  152. * Panes styled by CSS
  153. * @sample {highmaps} highcharts/css/pane/
  154. * Panes styled by CSS
  155. *
  156. * @type {string}
  157. * @default highcharts-pane
  158. * @since 5.0.0
  159. * @apioption pane.background.className
  160. */
  161. /**
  162. * The shape of the pane background. When `solid`, the background
  163. * is circular. When `arc`, the background extends only from the min
  164. * to the max of the value axis.
  165. *
  166. * @type {Highcharts.PaneBackgroundShapeValue}
  167. * @since 2.3.0
  168. * @product highcharts
  169. */
  170. shape: 'circle',
  171. /**
  172. * The pixel border width of the pane background.
  173. *
  174. * @since 2.3.0
  175. * @product highcharts
  176. */
  177. borderWidth: 1,
  178. /**
  179. * The pane background border color.
  180. *
  181. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  182. * @since 2.3.0
  183. * @product highcharts
  184. */
  185. borderColor: '#cccccc',
  186. /**
  187. * The background color or gradient for the pane.
  188. *
  189. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  190. * @default { linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, stops: [[0, #ffffff], [1, #e6e6e6]] }
  191. * @since 2.3.0
  192. * @product highcharts
  193. */
  194. backgroundColor: {
  195. /** @ignore-option */
  196. linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
  197. /** @ignore-option */
  198. stops: [
  199. [0, '#ffffff'],
  200. [1, '#e6e6e6']
  201. ]
  202. },
  203. /** @ignore-option */
  204. from: -Number.MAX_VALUE,
  205. /**
  206. * The inner radius of the pane background. Can be either numeric
  207. * (pixels) or a percentage string.
  208. *
  209. * @type {number|string}
  210. * @since 2.3.0
  211. * @product highcharts
  212. */
  213. innerRadius: 0,
  214. /** @ignore-option */
  215. to: Number.MAX_VALUE,
  216. /**
  217. * The outer radius of the circular pane background. Can be either
  218. * numeric (pixels) or a percentage string.
  219. *
  220. * @type {number|string}
  221. * @since 2.3.0
  222. * @product highcharts
  223. */
  224. outerRadius: '105%'
  225. };
  226. this.init(options, chart);
  227. }
  228. /**
  229. * Initialize the Pane object
  230. *
  231. * @private
  232. * @function Highcharts.Pane#init
  233. *
  234. * @param {Highcharts.PaneOptions} options
  235. *
  236. * @param {Highcharts.Chart} chart
  237. */
  238. Pane.prototype.init = function (options, chart) {
  239. this.chart = chart;
  240. this.background = [];
  241. chart.pane.push(this);
  242. this.setOptions(options);
  243. };
  244. /**
  245. * @private
  246. * @function Highcharts.Pane#setOptions
  247. *
  248. * @param {Highcharts.PaneOptions} options
  249. */
  250. Pane.prototype.setOptions = function (options) {
  251. // Set options. Angular charts have a default background (#3318)
  252. this.options = options = merge(this.defaultOptions, this.chart.angular ? { background: {} } : void 0, options);
  253. };
  254. /**
  255. * Render the pane with its backgrounds.
  256. *
  257. * @private
  258. * @function Highcharts.Pane#render
  259. */
  260. Pane.prototype.render = function () {
  261. var options = this.options, backgroundOption = this.options.background, renderer = this.chart.renderer, len, i;
  262. if (!this.group) {
  263. this.group = renderer.g('pane-group')
  264. .attr({ zIndex: options.zIndex || 0 })
  265. .add();
  266. }
  267. this.updateCenter();
  268. // Render the backgrounds
  269. if (backgroundOption) {
  270. backgroundOption = splat(backgroundOption);
  271. len = Math.max(backgroundOption.length, this.background.length || 0);
  272. for (i = 0; i < len; i++) {
  273. // #6641 - if axis exists, chart is circular and apply
  274. // background
  275. if (backgroundOption[i] && this.axis) {
  276. this.renderBackground(merge(this.defaultBackgroundOptions, backgroundOption[i]), i);
  277. }
  278. else if (this.background[i]) {
  279. this.background[i] = this.background[i].destroy();
  280. this.background.splice(i, 1);
  281. }
  282. }
  283. }
  284. };
  285. /**
  286. * Render an individual pane background.
  287. *
  288. * @private
  289. * @function Highcharts.Pane#renderBackground
  290. *
  291. * @param {Highcharts.PaneBackgroundOptions} backgroundOptions
  292. * Background options
  293. *
  294. * @param {number} i
  295. * The index of the background in this.backgrounds
  296. */
  297. Pane.prototype.renderBackground = function (backgroundOptions, i) {
  298. var method = 'animate', attribs = {
  299. 'class': 'highcharts-pane ' + (backgroundOptions.className || '')
  300. };
  301. if (!this.chart.styledMode) {
  302. extend(attribs, {
  303. 'fill': backgroundOptions.backgroundColor,
  304. 'stroke': backgroundOptions.borderColor,
  305. 'stroke-width': backgroundOptions.borderWidth
  306. });
  307. }
  308. if (!this.background[i]) {
  309. this.background[i] = this.chart.renderer
  310. .path()
  311. .add(this.group);
  312. method = 'attr';
  313. }
  314. this.background[i][method]({
  315. 'd': this.axis.getPlotBandPath(backgroundOptions.from, backgroundOptions.to, backgroundOptions)
  316. }).attr(attribs);
  317. };
  318. /**
  319. * Gets the center for the pane and its axis.
  320. *
  321. * @private
  322. * @function Highcharts.Pane#updateCenter
  323. * @param {Highcharts.Axis} [axis]
  324. * @return {void}
  325. */
  326. Pane.prototype.updateCenter = function (axis) {
  327. this.center = (axis ||
  328. this.axis ||
  329. {}).center = CenteredSeriesMixin.getCenter.call(this);
  330. };
  331. /**
  332. * Destroy the pane item
  333. *
  334. * @ignore
  335. * @private
  336. * @function Highcharts.Pane#destroy
  337. * /
  338. destroy: function () {
  339. erase(this.chart.pane, this);
  340. this.background.forEach(function (background) {
  341. background.destroy();
  342. });
  343. this.background.length = 0;
  344. this.group = this.group.destroy();
  345. },
  346. */
  347. /**
  348. * Update the pane item with new options
  349. *
  350. * @private
  351. * @function Highcharts.Pane#update
  352. * @param {Highcharts.PaneOptions} options
  353. * New pane options
  354. * @param {boolean} [redraw]
  355. * @return {void}
  356. */
  357. Pane.prototype.update = function (options, redraw) {
  358. merge(true, this.options, options);
  359. merge(true, this.chart.options.pane, options); // #9917
  360. this.setOptions(this.options);
  361. this.render();
  362. this.chart.axes.forEach(function (axis) {
  363. if (axis.pane === this) {
  364. axis.pane = null;
  365. axis.update({}, redraw);
  366. }
  367. }, this);
  368. };
  369. return Pane;
  370. }());
  371. /**
  372. * Check whether element is inside or outside pane.
  373. * @private
  374. * @param {number} x Element's x coordinate
  375. * @param {number} y Element's y coordinate
  376. * @param {Array<number>} center Pane's center (x, y) and diameter
  377. * @return {boolean}
  378. */
  379. function isInsidePane(x, y, center) {
  380. return Math.sqrt(Math.pow(x - center[0], 2) + Math.pow(y - center[1], 2)) < center[2] / 2;
  381. }
  382. H.Chart.prototype.getHoverPane = function (eventArgs) {
  383. var chart = this;
  384. var hoverPane;
  385. if (eventArgs) {
  386. chart.pane.forEach(function (pane) {
  387. var plotX = eventArgs.chartX - chart.plotLeft, plotY = eventArgs.chartY - chart.plotTop, x = chart.inverted ? plotY : plotX, y = chart.inverted ? plotX : plotY;
  388. if (isInsidePane(x, y, pane.center)) {
  389. hoverPane = pane;
  390. }
  391. });
  392. }
  393. return hoverPane;
  394. };
  395. addEvent(Chart, 'afterIsInsidePlot', function (e) {
  396. var chart = this;
  397. if (chart.polar) {
  398. e.isInsidePlot = chart.pane.some(function (pane) { return isInsidePane(e.x, e.y, pane.center); });
  399. }
  400. });
  401. addEvent(Pointer, 'beforeGetHoverData', function (eventArgs) {
  402. var chart = this.chart;
  403. if (chart.polar) {
  404. // Find pane we are currently hovering over.
  405. chart.hoverPane = chart.getHoverPane(eventArgs);
  406. // Edit filter method to handle polar
  407. eventArgs.filter = function (s) {
  408. return (s.visible &&
  409. !(!eventArgs.shared && s.directTouch) && // #3821
  410. pick(s.options.enableMouseTracking, true) &&
  411. (!chart.hoverPane || s.xAxis.pane === chart.hoverPane));
  412. };
  413. }
  414. });
  415. addEvent(Pointer, 'afterGetHoverData', function (eventArgs) {
  416. var chart = this.chart;
  417. if (eventArgs.hoverPoint &&
  418. eventArgs.hoverPoint.plotX &&
  419. eventArgs.hoverPoint.plotY &&
  420. chart.hoverPane &&
  421. !isInsidePane(eventArgs.hoverPoint.plotX, eventArgs.hoverPoint.plotY, chart.hoverPane.center)) {
  422. eventArgs.hoverPoint = void 0;
  423. }
  424. });
  425. H.Pane = Pane;
  426. return H.Pane;
  427. });
  428. _registerModule(_modules, 'parts-more/HiddenAxis.js', [], function () {
  429. /* *
  430. *
  431. * (c) 2010-2020 Torstein Honsi
  432. *
  433. * License: www.highcharts.com/license
  434. *
  435. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  436. *
  437. * */
  438. /**
  439. * @private
  440. * @class
  441. */
  442. var HiddenAxis = /** @class */ (function () {
  443. function HiddenAxis() {
  444. }
  445. /**
  446. * Augments methods for the x axis in order to hide it completely. Used for
  447. * the X axis in gauges
  448. *
  449. * @private
  450. *
  451. * @param {Highcharts.Axis} axis
  452. * Radial axis to augment.
  453. */
  454. HiddenAxis.init = function (axis) {
  455. axis.getOffset = function () { };
  456. axis.redraw = function () {
  457. this.isDirty = false; // prevent setting Y axis dirty
  458. };
  459. axis.render = function () {
  460. this.isDirty = false; // prevent setting Y axis dirty
  461. };
  462. axis.createLabelCollector = function () {
  463. return function () {
  464. return;
  465. };
  466. };
  467. axis.setScale = function () { };
  468. axis.setCategories = function () { };
  469. axis.setTitle = function () { };
  470. axis.isHidden = true;
  471. };
  472. return HiddenAxis;
  473. }());
  474. return HiddenAxis;
  475. });
  476. _registerModule(_modules, 'parts-more/RadialAxis.js', [_modules['parts/Axis.js'], _modules['parts/Tick.js'], _modules['parts-more/HiddenAxis.js'], _modules['parts/Utilities.js']], function (Axis, Tick, HiddenAxis, U) {
  477. /* *
  478. *
  479. * (c) 2010-2020 Torstein Honsi
  480. *
  481. * License: www.highcharts.com/license
  482. *
  483. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  484. *
  485. * */
  486. var addEvent = U.addEvent, correctFloat = U.correctFloat, defined = U.defined, extend = U.extend, fireEvent = U.fireEvent, isNumber = U.isNumber, merge = U.merge, pick = U.pick, pInt = U.pInt, relativeLength = U.relativeLength, wrap = U.wrap;
  487. /**
  488. * @private
  489. * @class
  490. */
  491. var RadialAxis = /** @class */ (function () {
  492. function RadialAxis() {
  493. }
  494. /* *
  495. *
  496. * Static Functions
  497. *
  498. * */
  499. RadialAxis.init = function (axis) {
  500. var axisProto = Axis.prototype;
  501. // Merge and set options.
  502. axis.setOptions = function (userOptions) {
  503. var options = this.options = merge(axis.constructor.defaultOptions, this.defaultPolarOptions, userOptions);
  504. // Make sure the plotBands array is instanciated for each Axis
  505. // (#2649)
  506. if (!options.plotBands) {
  507. options.plotBands = [];
  508. }
  509. fireEvent(this, 'afterSetOptions');
  510. };
  511. // Wrap the getOffset method to return zero offset for title or labels
  512. // in a radial axis.
  513. axis.getOffset = function () {
  514. // Call the Axis prototype method (the method we're in now is on the
  515. // instance)
  516. axisProto.getOffset.call(this);
  517. // Title or label offsets are not counted
  518. this.chart.axisOffset[this.side] = 0;
  519. };
  520. /**
  521. * Get the path for the axis line. This method is also referenced in the
  522. * getPlotLinePath method.
  523. *
  524. * @private
  525. *
  526. * @param {number} _lineWidth
  527. * Line width is not used.
  528. *
  529. * @param {number} [radius]
  530. * Radius of radial path.
  531. *
  532. * @param {number} [innerRadius]
  533. * Inner radius of radial path.
  534. *
  535. * @return {RadialAxisPath}
  536. */
  537. axis.getLinePath = function (_lineWidth, radius, innerRadius) {
  538. var center = this.pane.center, end, chart = this.chart, r = pick(radius, center[2] / 2 - this.offset), path;
  539. if (typeof innerRadius === 'undefined') {
  540. innerRadius = this.horiz ? 0 : this.center && -this.center[3] / 2;
  541. }
  542. // In case when innerSize of pane is set, it must be included
  543. if (innerRadius) {
  544. r += innerRadius;
  545. }
  546. if (this.isCircular || typeof radius !== 'undefined') {
  547. path = this.chart.renderer.symbols.arc(this.left + center[0], this.top + center[1], r, r, {
  548. start: this.startAngleRad,
  549. end: this.endAngleRad,
  550. open: true,
  551. innerR: 0
  552. });
  553. // Bounds used to position the plotLine label next to the line
  554. // (#7117)
  555. path.xBounds = [this.left + center[0]];
  556. path.yBounds = [this.top + center[1] - r];
  557. }
  558. else {
  559. end = this.postTranslate(this.angleRad, r);
  560. path = [
  561. ['M', this.center[0] + chart.plotLeft, this.center[1] + chart.plotTop],
  562. ['L', end.x, end.y]
  563. ];
  564. }
  565. return path;
  566. };
  567. /**
  568. * Override setAxisTranslation by setting the translation to the
  569. * difference in rotation. This allows the translate method to return
  570. * angle for any given value.
  571. *
  572. * @private
  573. */
  574. axis.setAxisTranslation = function () {
  575. // Call uber method
  576. axisProto.setAxisTranslation.call(this);
  577. // Set transA and minPixelPadding
  578. if (this.center) { // it's not defined the first time
  579. if (this.isCircular) {
  580. this.transA = (this.endAngleRad - this.startAngleRad) /
  581. ((this.max - this.min) || 1);
  582. }
  583. else {
  584. // The transA here is the length of the axis, so in case
  585. // of inner radius, the length must be decreased by it
  586. this.transA = ((this.center[2] - this.center[3]) / 2) /
  587. ((this.max - this.min) || 1);
  588. }
  589. if (this.isXAxis) {
  590. this.minPixelPadding = this.transA * this.minPointOffset;
  591. }
  592. else {
  593. // This is a workaround for regression #2593, but categories
  594. // still don't position correctly.
  595. this.minPixelPadding = 0;
  596. }
  597. }
  598. };
  599. /**
  600. * In case of auto connect, add one closestPointRange to the max value
  601. * right before tickPositions are computed, so that ticks will extend
  602. * passed the real max.
  603. * @private
  604. */
  605. axis.beforeSetTickPositions = function () {
  606. // If autoConnect is true, polygonal grid lines are connected, and
  607. // one closestPointRange is added to the X axis to prevent the last
  608. // point from overlapping the first.
  609. this.autoConnect = (this.isCircular &&
  610. typeof pick(this.userMax, this.options.max) === 'undefined' &&
  611. correctFloat(this.endAngleRad - this.startAngleRad) ===
  612. correctFloat(2 * Math.PI));
  613. // This will lead to add an extra tick to xAxis in order to display
  614. // a correct range on inverted polar
  615. if (!this.isCircular && this.chart.inverted) {
  616. this.max++;
  617. }
  618. if (this.autoConnect) {
  619. this.max += ((this.categories && 1) ||
  620. this.pointRange ||
  621. this.closestPointRange ||
  622. 0); // #1197, #2260
  623. }
  624. };
  625. /**
  626. * Override the setAxisSize method to use the arc's circumference as
  627. * length. This allows tickPixelInterval to apply to pixel lengths along
  628. * the perimeter.
  629. * @private
  630. */
  631. axis.setAxisSize = function () {
  632. var center, start;
  633. axisProto.setAxisSize.call(this);
  634. if (this.isRadial) {
  635. // Set the center array
  636. this.pane.updateCenter(this);
  637. // In case when the innerSize is set in a polar chart, the axis'
  638. // center cannot be a reference to pane's center
  639. center = this.center = extend([], this.pane.center);
  640. // The sector is used in Axis.translate to compute the
  641. // translation of reversed axis points (#2570)
  642. if (this.isCircular) {
  643. this.sector = this.endAngleRad - this.startAngleRad;
  644. }
  645. else {
  646. // When the pane's startAngle or the axis' angle is set then
  647. // new x and y values for vertical axis' center must be
  648. // calulated
  649. start = this.postTranslate(this.angleRad, center[3] / 2);
  650. center[0] = start.x - this.chart.plotLeft;
  651. center[1] = start.y - this.chart.plotTop;
  652. }
  653. // Axis len is used to lay out the ticks
  654. this.len = this.width = this.height =
  655. (center[2] - center[3]) * pick(this.sector, 1) / 2;
  656. }
  657. };
  658. /**
  659. * Returns the x, y coordinate of a point given by a value and a pixel
  660. * distance from center.
  661. *
  662. * @private
  663. *
  664. * @param {number} value
  665. * Point value.
  666. *
  667. * @param {number} [length]
  668. * Distance from center.
  669. *
  670. * @return {Highcharts.PositionObject}
  671. */
  672. axis.getPosition = function (value, length) {
  673. var translatedVal = this.translate(value);
  674. return this.postTranslate(this.isCircular ? translatedVal : this.angleRad, // #2848
  675. // In case when translatedVal is negative, the 0 value must be
  676. // used instead, in order to deal with lines and labels that
  677. // fall out of the visible range near the center of a pane
  678. pick(this.isCircular ?
  679. length :
  680. (translatedVal < 0 ? 0 : translatedVal), this.center[2] / 2) - this.offset);
  681. };
  682. /**
  683. * Translate from intermediate plotX (angle), plotY (axis.len - radius)
  684. * to final chart coordinates.
  685. *
  686. * @private
  687. *
  688. * @param {number} angle
  689. * Translation angle.
  690. *
  691. * @param {number} radius
  692. * Translation radius.
  693. *
  694. * @return {Highcharts.PositionObject}
  695. */
  696. axis.postTranslate = function (angle, radius) {
  697. var chart = this.chart, center = this.center;
  698. angle = this.startAngleRad + angle;
  699. return {
  700. x: chart.plotLeft + center[0] + Math.cos(angle) * radius,
  701. y: chart.plotTop + center[1] + Math.sin(angle) * radius
  702. };
  703. };
  704. /**
  705. * Find the path for plot bands along the radial axis.
  706. *
  707. * @private
  708. *
  709. * @param {number} from
  710. * From value.
  711. *
  712. * @param {number} to
  713. * To value.
  714. *
  715. * @param {Highcharts.AxisPlotBandsOptions} options
  716. * Band options.
  717. *
  718. * @return {RadialAxisPath}
  719. */
  720. axis.getPlotBandPath = function (from, to, options) {
  721. var radiusToPixels = function (radius) {
  722. if (typeof radius === 'string') {
  723. var r = parseInt(radius, 10);
  724. if (percentRegex.test(radius)) {
  725. r = (r * fullRadius) / 100;
  726. }
  727. return r;
  728. }
  729. return radius;
  730. };
  731. var center = this.center, startAngleRad = this.startAngleRad, fullRadius = center[2] / 2, offset = Math.min(this.offset, 0), percentRegex = /%$/, start, end, angle, xOnPerimeter, open, isCircular = this.isCircular, // X axis in a polar chart
  732. path, outerRadius = pick(radiusToPixels(options.outerRadius), fullRadius), innerRadius = radiusToPixels(options.innerRadius), thickness = pick(radiusToPixels(options.thickness), 10);
  733. // Polygonal plot bands
  734. if (this.options.gridLineInterpolation === 'polygon') {
  735. path = this.getPlotLinePath({ value: from }).concat(this.getPlotLinePath({ value: to, reverse: true }));
  736. // Circular grid bands
  737. }
  738. else {
  739. // Keep within bounds
  740. from = Math.max(from, this.min);
  741. to = Math.min(to, this.max);
  742. var transFrom = this.translate(from);
  743. var transTo = this.translate(to);
  744. // Plot bands on Y axis (radial axis) - inner and outer
  745. // radius depend on to and from
  746. if (!isCircular) {
  747. outerRadius = transFrom || 0;
  748. innerRadius = transTo || 0;
  749. }
  750. // Handle full circle
  751. if (options.shape === 'circle' || !isCircular) {
  752. start = -Math.PI / 2;
  753. end = Math.PI * 1.5;
  754. open = true;
  755. }
  756. else {
  757. start = startAngleRad + (transFrom || 0);
  758. end = startAngleRad + (transTo || 0);
  759. }
  760. outerRadius -= offset; // #5283
  761. thickness -= offset; // #5283
  762. path = this.chart.renderer.symbols.arc(this.left + center[0], this.top + center[1], outerRadius, outerRadius, {
  763. // Math is for reversed yAxis (#3606)
  764. start: Math.min(start, end),
  765. end: Math.max(start, end),
  766. innerR: pick(innerRadius, outerRadius - thickness),
  767. open: open
  768. });
  769. // Provide positioning boxes for the label (#6406)
  770. if (isCircular) {
  771. angle = (end + start) / 2;
  772. xOnPerimeter = (this.left +
  773. center[0] +
  774. (center[2] / 2) * Math.cos(angle));
  775. path.xBounds = angle > -Math.PI / 2 && angle < Math.PI / 2 ?
  776. // Right hemisphere
  777. [xOnPerimeter, this.chart.plotWidth] :
  778. // Left hemisphere
  779. [0, xOnPerimeter];
  780. path.yBounds = [
  781. this.top + center[1] + (center[2] / 2) * Math.sin(angle)
  782. ];
  783. // Shift up or down to get the label clear of the perimeter
  784. path.yBounds[0] += ((angle > -Math.PI && angle < 0) ||
  785. (angle > Math.PI)) ? -10 : 10;
  786. }
  787. }
  788. return path;
  789. };
  790. // Find the correct end values of crosshair in polar.
  791. axis.getCrosshairPosition = function (options, x1, y1) {
  792. var axis = this, value = options.value, center = axis.pane.center, shapeArgs, end, x2, y2;
  793. if (axis.isCircular) {
  794. if (!defined(value)) {
  795. // When the snap is set to false
  796. x2 = options.chartX || 0;
  797. y2 = options.chartY || 0;
  798. value = axis.translate(Math.atan2(y2 - y1, x2 - x1) - axis.startAngleRad, true);
  799. }
  800. else if (options.point) {
  801. // When the snap is set to true
  802. shapeArgs = options.point.shapeArgs || {};
  803. if (shapeArgs.start) {
  804. // Find a true value of the point based on the
  805. // angle
  806. value = axis.chart.inverted ?
  807. axis.translate(options.point.rectPlotY, true) :
  808. options.point.x;
  809. }
  810. }
  811. end = axis.getPosition(value);
  812. x2 = end.x;
  813. y2 = end.y;
  814. }
  815. else {
  816. if (!defined(value)) {
  817. x2 = options.chartX;
  818. y2 = options.chartY;
  819. }
  820. if (defined(x2) && defined(y2)) {
  821. // Calculate radius of non-circular axis' crosshair
  822. y1 = center[1] + axis.chart.plotTop;
  823. value = axis.translate(Math.min(Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)), center[2] / 2) - center[3] / 2, true);
  824. }
  825. }
  826. return [value, x2 || 0, y2 || 0];
  827. };
  828. // Find the path for plot lines perpendicular to the radial axis.
  829. axis.getPlotLinePath = function (options) {
  830. var axis = this, center = axis.pane.center, chart = axis.chart, inverted = chart.inverted, value = options.value, reverse = options.reverse, end = axis.getPosition(value), background = axis.pane.options.background ?
  831. (axis.pane.options.background[0] ||
  832. axis.pane.options.background) :
  833. {}, innerRadius = background.innerRadius || '0%', outerRadius = background.outerRadius || '100%', x1 = center[0] + chart.plotLeft, y1 = center[1] + chart.plotTop, x2 = end.x, y2 = end.y, height = axis.height, isCrosshair = options.isCrosshair, paneInnerR = center[3] / 2, innerRatio, distance, a, b, otherAxis, xy, tickPositions, crossPos, path;
  834. // Crosshair logic
  835. if (isCrosshair) {
  836. // Find crosshair's position and perform destructuring
  837. // assignment
  838. crossPos = this.getCrosshairPosition(options, x1, y1);
  839. value = crossPos[0];
  840. x2 = crossPos[1];
  841. y2 = crossPos[2];
  842. }
  843. // Spokes
  844. if (axis.isCircular) {
  845. distance =
  846. Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
  847. a = (typeof innerRadius === 'string') ?
  848. relativeLength(innerRadius, 1) : (innerRadius / distance);
  849. b = (typeof outerRadius === 'string') ?
  850. relativeLength(outerRadius, 1) : (outerRadius / distance);
  851. // To ensure that gridlines won't be displayed in area
  852. // defined by innerSize in case of custom radiuses of pane's
  853. // background
  854. if (center && paneInnerR) {
  855. innerRatio = paneInnerR / distance;
  856. if (a < innerRatio) {
  857. a = innerRatio;
  858. }
  859. if (b < innerRatio) {
  860. b = innerRatio;
  861. }
  862. }
  863. path = [
  864. ['M', x1 + a * (x2 - x1), y1 - a * (y1 - y2)],
  865. ['L', x2 - (1 - b) * (x2 - x1), y2 + (1 - b) * (y1 - y2)]
  866. ];
  867. // Concentric circles
  868. }
  869. else {
  870. // Pick the right values depending if it is grid line or
  871. // crosshair
  872. value = axis.translate(value);
  873. // This is required in case when xAxis is non-circular to
  874. // prevent grid lines (or crosshairs, if enabled) from
  875. // rendering above the center after they supposed to be
  876. // displayed below the center point
  877. if (value) {
  878. if (value < 0 || value > height) {
  879. value = 0;
  880. }
  881. }
  882. if (axis.options.gridLineInterpolation === 'circle') {
  883. // A value of 0 is in the center, so it won't be
  884. // visible, but draw it anyway for update and animation
  885. // (#2366)
  886. path = axis.getLinePath(0, value, paneInnerR);
  887. // Concentric polygons
  888. }
  889. else {
  890. path = [];
  891. // Find the other axis (a circular one) in the same pane
  892. chart[inverted ? 'yAxis' : 'xAxis'].forEach(function (a) {
  893. if (a.pane === axis.pane) {
  894. otherAxis = a;
  895. }
  896. });
  897. if (otherAxis) {
  898. tickPositions = otherAxis.tickPositions;
  899. if (otherAxis.autoConnect) {
  900. tickPositions =
  901. tickPositions.concat([tickPositions[0]]);
  902. }
  903. // Reverse the positions for concatenation of polygonal
  904. // plot bands
  905. if (reverse) {
  906. tickPositions = tickPositions.slice().reverse();
  907. }
  908. if (value) {
  909. value += paneInnerR;
  910. }
  911. for (var i = 0; i < tickPositions.length; i++) {
  912. xy = otherAxis.getPosition(tickPositions[i], value);
  913. path.push(i ? ['L', xy.x, xy.y] : ['M', xy.x, xy.y]);
  914. }
  915. }
  916. }
  917. }
  918. return path;
  919. };
  920. // Find the position for the axis title, by default inside the gauge.
  921. axis.getTitlePosition = function () {
  922. var center = this.center, chart = this.chart, titleOptions = this.options.title;
  923. return {
  924. x: chart.plotLeft + center[0] + (titleOptions.x || 0),
  925. y: (chart.plotTop +
  926. center[1] -
  927. ({
  928. high: 0.5,
  929. middle: 0.25,
  930. low: 0
  931. }[titleOptions.align] *
  932. center[2]) +
  933. (titleOptions.y || 0))
  934. };
  935. };
  936. /**
  937. * Attach and return collecting function for labels in radial axis for
  938. * anti-collision.
  939. *
  940. * @private
  941. *
  942. * @return {Highcharts.ChartLabelCollectorFunction}
  943. */
  944. axis.createLabelCollector = function () {
  945. var axis = this;
  946. return function () {
  947. if (axis.isRadial &&
  948. axis.tickPositions &&
  949. // undocumented option for now, but working
  950. axis.options.labels.allowOverlap !== true) {
  951. return axis.tickPositions
  952. .map(function (pos) {
  953. return axis.ticks[pos] && axis.ticks[pos].label;
  954. })
  955. .filter(function (label) {
  956. return Boolean(label);
  957. });
  958. }
  959. };
  960. };
  961. };
  962. /**
  963. * Augments methods for the value axis.
  964. *
  965. * @private
  966. *
  967. * @param {Highcharts.Axis} AxisClass
  968. * Axis class to extend.
  969. *
  970. * @param {Highcharts.Tick} TickClass
  971. * Tick class to use.
  972. */
  973. RadialAxis.compose = function (AxisClass, TickClass) {
  974. /* eslint-disable no-invalid-this */
  975. // Actions before axis init.
  976. addEvent(AxisClass, 'init', function (e) {
  977. var axis = this;
  978. var chart = axis.chart;
  979. var inverted = chart.inverted, angular = chart.angular, polar = chart.polar, isX = axis.isXAxis, coll = axis.coll, isHidden = angular && isX, isCircular, chartOptions = chart.options, paneIndex = e.userOptions.pane || 0, pane = this.pane =
  980. chart.pane && chart.pane[paneIndex];
  981. // Prevent changes for colorAxis
  982. if (coll === 'colorAxis') {
  983. this.isRadial = false;
  984. return;
  985. }
  986. // Before prototype.init
  987. if (angular) {
  988. if (isHidden) {
  989. HiddenAxis.init(axis);
  990. }
  991. else {
  992. RadialAxis.init(axis);
  993. }
  994. isCircular = !isX;
  995. if (isCircular) {
  996. axis.defaultPolarOptions = RadialAxis.defaultRadialGaugeOptions;
  997. }
  998. }
  999. else if (polar) {
  1000. RadialAxis.init(axis);
  1001. // Check which axis is circular
  1002. isCircular = axis.horiz;
  1003. axis.defaultPolarOptions = isCircular ?
  1004. RadialAxis.defaultCircularOptions :
  1005. merge(coll === 'xAxis' ?
  1006. AxisClass.defaultOptions :
  1007. AxisClass.defaultYAxisOptions, RadialAxis.defaultRadialOptions);
  1008. // Apply the stack labels for yAxis in case of inverted chart
  1009. if (inverted && coll === 'yAxis') {
  1010. axis.defaultPolarOptions.stackLabels = AxisClass.defaultYAxisOptions.stackLabels;
  1011. }
  1012. }
  1013. // Disable certain features on angular and polar axes
  1014. if (angular || polar) {
  1015. axis.isRadial = true;
  1016. chartOptions.chart.zoomType = null;
  1017. if (!axis.labelCollector) {
  1018. axis.labelCollector = axis.createLabelCollector();
  1019. }
  1020. if (axis.labelCollector) {
  1021. // Prevent overlapping axis labels (#9761)
  1022. chart.labelCollectors.push(axis.labelCollector);
  1023. }
  1024. }
  1025. else {
  1026. this.isRadial = false;
  1027. }
  1028. // A pointer back to this axis to borrow geometry
  1029. if (pane && isCircular) {
  1030. pane.axis = axis;
  1031. }
  1032. axis.isCircular = isCircular;
  1033. });
  1034. addEvent(AxisClass, 'afterInit', function () {
  1035. var axis = this;
  1036. var chart = axis.chart, options = axis.options, isHidden = chart.angular && axis.isXAxis, pane = axis.pane, paneOptions = pane && pane.options;
  1037. if (!isHidden && pane && (chart.angular || chart.polar)) {
  1038. // Start and end angle options are given in degrees relative to
  1039. // top, while internal computations are in radians relative to
  1040. // right (like SVG).
  1041. // Y axis in polar charts
  1042. axis.angleRad = (options.angle || 0) * Math.PI / 180;
  1043. // Gauges
  1044. axis.startAngleRad =
  1045. (paneOptions.startAngle - 90) * Math.PI / 180;
  1046. axis.endAngleRad = (pick(paneOptions.endAngle, paneOptions.startAngle + 360) - 90) * Math.PI / 180; // Gauges
  1047. axis.offset = options.offset || 0;
  1048. }
  1049. });
  1050. // Wrap auto label align to avoid setting axis-wide rotation on radial
  1051. // axes. (#4920)
  1052. addEvent(AxisClass, 'autoLabelAlign', function (e) {
  1053. if (this.isRadial) {
  1054. e.align = void 0;
  1055. e.preventDefault();
  1056. }
  1057. });
  1058. // Remove label collector function on axis remove/update
  1059. addEvent(AxisClass, 'destroy', function () {
  1060. var axis = this;
  1061. if (axis.chart &&
  1062. axis.chart.labelCollectors) {
  1063. var index = (axis.labelCollector ?
  1064. axis.chart.labelCollectors.indexOf(axis.labelCollector) :
  1065. -1);
  1066. if (index >= 0) {
  1067. axis.chart.labelCollectors.splice(index, 1);
  1068. }
  1069. }
  1070. });
  1071. addEvent(AxisClass, 'initialAxisTranslation', function () {
  1072. var axis = this;
  1073. if (axis.isRadial) {
  1074. axis.beforeSetTickPositions();
  1075. }
  1076. });
  1077. // Add special cases within the Tick class' methods for radial axes.
  1078. addEvent(TickClass, 'afterGetPosition', function (e) {
  1079. var tick = this;
  1080. if (tick.axis.getPosition) {
  1081. extend(e.pos, tick.axis.getPosition(this.pos));
  1082. }
  1083. });
  1084. // Find the center position of the label based on the distance option.
  1085. addEvent(TickClass, 'afterGetLabelPosition', function (e) {
  1086. var tick = this;
  1087. var axis = tick.axis;
  1088. var label = tick.label;
  1089. if (!label) {
  1090. return;
  1091. }
  1092. var labelBBox = label.getBBox(), labelOptions = axis.options.labels, optionsY = labelOptions.y, ret, centerSlot = 20, // 20 degrees to each side at the top and bottom
  1093. align = labelOptions.align, angle = ((axis.translate(this.pos) + axis.startAngleRad +
  1094. Math.PI / 2) / Math.PI * 180) % 360, correctAngle = Math.round(angle), labelDir = 'end', // Direction of the label 'start' or 'end'
  1095. reducedAngle1 = correctAngle < 0 ?
  1096. correctAngle + 360 : correctAngle, reducedAngle2 = reducedAngle1, translateY = 0, translateX = 0, labelYPosCorrection = labelOptions.y === null ? -labelBBox.height * 0.3 : 0;
  1097. if (axis.isRadial) { // Both X and Y axes in a polar chart
  1098. ret = axis.getPosition(this.pos, (axis.center[2] / 2) +
  1099. relativeLength(pick(labelOptions.distance, -25), axis.center[2] / 2, -axis.center[2] / 2));
  1100. // Automatically rotated
  1101. if (labelOptions.rotation === 'auto') {
  1102. label.attr({
  1103. rotation: angle
  1104. });
  1105. // Vertically centered
  1106. }
  1107. else if (optionsY === null) {
  1108. optionsY = (axis.chart.renderer
  1109. .fontMetrics(label.styles && label.styles.fontSize).b -
  1110. labelBBox.height / 2);
  1111. }
  1112. // Automatic alignment
  1113. if (align === null) {
  1114. if (axis.isCircular) { // Y axis
  1115. if (labelBBox.width >
  1116. axis.len * axis.tickInterval / (axis.max - axis.min)) { // #3506
  1117. centerSlot = 0;
  1118. }
  1119. if (angle > centerSlot && angle < 180 - centerSlot) {
  1120. align = 'left'; // right hemisphere
  1121. }
  1122. else if (angle > 180 + centerSlot &&
  1123. angle < 360 - centerSlot) {
  1124. align = 'right'; // left hemisphere
  1125. }
  1126. else {
  1127. align = 'center'; // top or bottom
  1128. }
  1129. }
  1130. else {
  1131. align = 'center';
  1132. }
  1133. label.attr({
  1134. align: align
  1135. });
  1136. }
  1137. // Auto alignment for solid-gauges with two labels (#10635)
  1138. if (align === 'auto' &&
  1139. axis.tickPositions.length === 2 &&
  1140. axis.isCircular) {
  1141. // Angles reduced to 0 - 90 or 180 - 270
  1142. if (reducedAngle1 > 90 && reducedAngle1 < 180) {
  1143. reducedAngle1 = 180 - reducedAngle1;
  1144. }
  1145. else if (reducedAngle1 > 270 && reducedAngle1 <= 360) {
  1146. reducedAngle1 = 540 - reducedAngle1;
  1147. }
  1148. // Angles reduced to 0 - 180
  1149. if (reducedAngle2 > 180 && reducedAngle2 <= 360) {
  1150. reducedAngle2 = 360 - reducedAngle2;
  1151. }
  1152. if ((axis.pane.options.startAngle === correctAngle) ||
  1153. (axis.pane.options.startAngle === correctAngle + 360) ||
  1154. (axis.pane.options.startAngle === correctAngle - 360)) {
  1155. labelDir = 'start';
  1156. }
  1157. if ((correctAngle >= -90 && correctAngle <= 90) ||
  1158. (correctAngle >= -360 && correctAngle <= -270) ||
  1159. (correctAngle >= 270 && correctAngle <= 360)) {
  1160. align = (labelDir === 'start') ? 'right' : 'left';
  1161. }
  1162. else {
  1163. align = (labelDir === 'start') ? 'left' : 'right';
  1164. }
  1165. // For angles beetwen (90 + n * 180) +- 20
  1166. if (reducedAngle2 > 70 && reducedAngle2 < 110) {
  1167. align = 'center';
  1168. }
  1169. // auto Y translation
  1170. if (reducedAngle1 < 15 ||
  1171. (reducedAngle1 >= 180 && reducedAngle1 < 195)) {
  1172. translateY = labelBBox.height * 0.3;
  1173. }
  1174. else if (reducedAngle1 >= 15 && reducedAngle1 <= 35) {
  1175. translateY = labelDir === 'start' ?
  1176. 0 : labelBBox.height * 0.75;
  1177. }
  1178. else if (reducedAngle1 >= 195 && reducedAngle1 <= 215) {
  1179. translateY = labelDir === 'start' ?
  1180. labelBBox.height * 0.75 : 0;
  1181. }
  1182. else if (reducedAngle1 > 35 && reducedAngle1 <= 90) {
  1183. translateY = labelDir === 'start' ?
  1184. -labelBBox.height * 0.25 : labelBBox.height;
  1185. }
  1186. else if (reducedAngle1 > 215 && reducedAngle1 <= 270) {
  1187. translateY = labelDir === 'start' ?
  1188. labelBBox.height : -labelBBox.height * 0.25;
  1189. }
  1190. // auto X translation
  1191. if (reducedAngle2 < 15) {
  1192. translateX = labelDir === 'start' ?
  1193. -labelBBox.height * 0.15 : labelBBox.height * 0.15;
  1194. }
  1195. else if (reducedAngle2 > 165 && reducedAngle2 <= 180) {
  1196. translateX = labelDir === 'start' ?
  1197. labelBBox.height * 0.15 : -labelBBox.height * 0.15;
  1198. }
  1199. label.attr({ align: align });
  1200. label.translate(translateX, translateY + labelYPosCorrection);
  1201. }
  1202. e.pos.x = ret.x + labelOptions.x;
  1203. e.pos.y = ret.y + optionsY;
  1204. }
  1205. });
  1206. // Wrap the getMarkPath function to return the path of the radial marker
  1207. wrap(TickClass.prototype, 'getMarkPath', function (proceed, x, y, tickLength, tickWidth, horiz, renderer) {
  1208. var tick = this;
  1209. var axis = tick.axis;
  1210. var endPoint, ret;
  1211. if (axis.isRadial) {
  1212. endPoint = axis.getPosition(this.pos, axis.center[2] / 2 + tickLength);
  1213. ret = [
  1214. 'M',
  1215. x,
  1216. y,
  1217. 'L',
  1218. endPoint.x,
  1219. endPoint.y
  1220. ];
  1221. }
  1222. else {
  1223. ret = proceed.call(this, x, y, tickLength, tickWidth, horiz, renderer);
  1224. }
  1225. return ret;
  1226. });
  1227. };
  1228. /* *
  1229. *
  1230. * Static Properties
  1231. *
  1232. * */
  1233. /**
  1234. * Circular axis around the perimeter of a polar chart.
  1235. * @private
  1236. */
  1237. RadialAxis.defaultCircularOptions = {
  1238. gridLineWidth: 1,
  1239. labels: {
  1240. align: null,
  1241. distance: 15,
  1242. x: 0,
  1243. y: null,
  1244. style: {
  1245. textOverflow: 'none' // wrap lines by default (#7248)
  1246. }
  1247. },
  1248. maxPadding: 0,
  1249. minPadding: 0,
  1250. showLastLabel: false,
  1251. tickLength: 0
  1252. };
  1253. /**
  1254. * The default options extend defaultYAxisOptions.
  1255. * @private
  1256. */
  1257. RadialAxis.defaultRadialGaugeOptions = {
  1258. labels: {
  1259. align: 'center',
  1260. x: 0,
  1261. y: null // auto
  1262. },
  1263. minorGridLineWidth: 0,
  1264. minorTickInterval: 'auto',
  1265. minorTickLength: 10,
  1266. minorTickPosition: 'inside',
  1267. minorTickWidth: 1,
  1268. tickLength: 10,
  1269. tickPosition: 'inside',
  1270. tickWidth: 2,
  1271. title: {
  1272. rotation: 0
  1273. },
  1274. zIndex: 2 // behind dials, points in the series group
  1275. };
  1276. /**
  1277. * Radial axis, like a spoke in a polar chart.
  1278. * @private
  1279. */
  1280. RadialAxis.defaultRadialOptions = {
  1281. /**
  1282. * In a polar chart, this is the angle of the Y axis in degrees, where
  1283. * 0 is up and 90 is right. The angle determines the position of the
  1284. * axis line and the labels, though the coordinate system is unaffected.
  1285. * Since v8.0.0 this option is also applicable for X axis (inverted
  1286. * polar).
  1287. *
  1288. * @sample {highcharts} highcharts/xaxis/angle/
  1289. * Custom X axis' angle on inverted polar chart
  1290. * @sample {highcharts} highcharts/yaxis/angle/
  1291. * Dual axis polar chart
  1292. *
  1293. * @type {number}
  1294. * @default 0
  1295. * @since 4.2.7
  1296. * @product highcharts
  1297. * @apioption xAxis.angle
  1298. */
  1299. /**
  1300. * Polar charts only. Whether the grid lines should draw as a polygon
  1301. * with straight lines between categories, or as circles. Can be either
  1302. * `circle` or `polygon`. Since v8.0.0 this option is also applicable
  1303. * for X axis (inverted polar).
  1304. *
  1305. * @sample {highcharts} highcharts/demo/polar-spider/
  1306. * Polygon grid lines
  1307. * @sample {highcharts} highcharts/xaxis/gridlineinterpolation/
  1308. * Circle and polygon on inverted polar
  1309. * @sample {highcharts} highcharts/yaxis/gridlineinterpolation/
  1310. * Circle and polygon
  1311. *
  1312. * @type {string}
  1313. * @product highcharts
  1314. * @validvalue ["circle", "polygon"]
  1315. * @apioption xAxis.gridLineInterpolation
  1316. */
  1317. gridLineInterpolation: 'circle',
  1318. gridLineWidth: 1,
  1319. labels: {
  1320. align: 'right',
  1321. x: -3,
  1322. y: -2
  1323. },
  1324. showLastLabel: false,
  1325. title: {
  1326. x: 4,
  1327. text: null,
  1328. rotation: 90
  1329. }
  1330. };
  1331. return RadialAxis;
  1332. }());
  1333. RadialAxis.compose(Axis, Tick); // @todo move outside
  1334. return RadialAxis;
  1335. });
  1336. _registerModule(_modules, 'parts-more/AreaRangeSeries.js', [_modules['parts/Globals.js'], _modules['parts/Point.js'], _modules['parts/Utilities.js']], function (H, Point, U) {
  1337. /* *
  1338. *
  1339. * (c) 2010-2020 Torstein Honsi
  1340. *
  1341. * License: www.highcharts.com/license
  1342. *
  1343. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1344. *
  1345. * */
  1346. var defined = U.defined, extend = U.extend, isArray = U.isArray, isNumber = U.isNumber, pick = U.pick, seriesType = U.seriesType;
  1347. var noop = H.noop, Series = H.Series, seriesTypes = H.seriesTypes, seriesProto = Series.prototype, pointProto = Point.prototype;
  1348. /**
  1349. * The area range series is a carteseian series with higher and lower values for
  1350. * each point along an X axis, where the area between the values is shaded.
  1351. *
  1352. * @sample {highcharts} highcharts/demo/arearange/
  1353. * Area range chart
  1354. * @sample {highstock} stock/demo/arearange/
  1355. * Area range chart
  1356. *
  1357. * @extends plotOptions.area
  1358. * @product highcharts highstock
  1359. * @excluding stack, stacking
  1360. * @requires highcharts-more
  1361. * @optionparent plotOptions.arearange
  1362. */
  1363. seriesType('arearange', 'area', {
  1364. /**
  1365. * Whether to apply a drop shadow to the graph line. Since 2.3 the shadow
  1366. * can be an object configuration containing `color`, `offsetX`, `offsetY`,
  1367. * `opacity` and `width`.
  1368. *
  1369. * @type {boolean|Highcharts.ShadowOptionsObject}
  1370. * @product highcharts
  1371. * @apioption plotOptions.arearange.shadow
  1372. */
  1373. /**
  1374. * @default low
  1375. * @apioption plotOptions.arearange.colorKey
  1376. */
  1377. /**
  1378. * Pixel width of the arearange graph line.
  1379. *
  1380. * @since 2.3.0
  1381. *
  1382. * @private
  1383. */
  1384. lineWidth: 1,
  1385. threshold: null,
  1386. tooltip: {
  1387. pointFormat: '<span style="color:{series.color}">\u25CF</span> ' +
  1388. '{series.name}: <b>{point.low}</b> - <b>{point.high}</b><br/>'
  1389. },
  1390. /**
  1391. * Whether the whole area or just the line should respond to mouseover
  1392. * tooltips and other mouse or touch events.
  1393. *
  1394. * @since 2.3.0
  1395. *
  1396. * @private
  1397. */
  1398. trackByArea: true,
  1399. /**
  1400. * Extended data labels for range series types. Range series data labels use
  1401. * no `x` and `y` options. Instead, they have `xLow`, `xHigh`, `yLow` and
  1402. * `yHigh` options to allow the higher and lower data label sets
  1403. * individually.
  1404. *
  1405. * @declare Highcharts.SeriesAreaRangeDataLabelsOptionsObject
  1406. * @exclude x, y
  1407. * @since 2.3.0
  1408. * @product highcharts highstock
  1409. *
  1410. * @private
  1411. */
  1412. dataLabels: {
  1413. align: void 0,
  1414. verticalAlign: void 0,
  1415. /**
  1416. * X offset of the lower data labels relative to the point value.
  1417. *
  1418. * @sample highcharts/plotoptions/arearange-datalabels/
  1419. * Data labels on range series
  1420. * @sample highcharts/plotoptions/arearange-datalabels/
  1421. * Data labels on range series
  1422. */
  1423. xLow: 0,
  1424. /**
  1425. * X offset of the higher data labels relative to the point value.
  1426. *
  1427. * @sample highcharts/plotoptions/arearange-datalabels/
  1428. * Data labels on range series
  1429. */
  1430. xHigh: 0,
  1431. /**
  1432. * Y offset of the lower data labels relative to the point value.
  1433. *
  1434. * @sample highcharts/plotoptions/arearange-datalabels/
  1435. * Data labels on range series
  1436. */
  1437. yLow: 0,
  1438. /**
  1439. * Y offset of the higher data labels relative to the point value.
  1440. *
  1441. * @sample highcharts/plotoptions/arearange-datalabels/
  1442. * Data labels on range series
  1443. */
  1444. yHigh: 0
  1445. }
  1446. // Prototype members
  1447. }, {
  1448. pointArrayMap: ['low', 'high'],
  1449. pointValKey: 'low',
  1450. deferTranslatePolar: true,
  1451. /* eslint-disable valid-jsdoc */
  1452. /**
  1453. * @private
  1454. */
  1455. toYData: function (point) {
  1456. return [point.low, point.high];
  1457. },
  1458. /**
  1459. * Translate a point's plotHigh from the internal angle and radius measures
  1460. * to true plotHigh coordinates. This is an addition of the toXY method
  1461. * found in Polar.js, because it runs too early for arearanges to be
  1462. * considered (#3419).
  1463. * @private
  1464. */
  1465. highToXY: function (point) {
  1466. // Find the polar plotX and plotY
  1467. var chart = this.chart, xy = this.xAxis.postTranslate(point.rectPlotX, this.yAxis.len - point.plotHigh);
  1468. point.plotHighX = xy.x - chart.plotLeft;
  1469. point.plotHigh = xy.y - chart.plotTop;
  1470. point.plotLowX = point.plotX;
  1471. },
  1472. /**
  1473. * Translate data points from raw values x and y to plotX and plotY.
  1474. * @private
  1475. */
  1476. translate: function () {
  1477. var series = this, yAxis = series.yAxis, hasModifyValue = !!series.modifyValue;
  1478. seriesTypes.area.prototype.translate.apply(series);
  1479. // Set plotLow and plotHigh
  1480. series.points.forEach(function (point) {
  1481. var high = point.high, plotY = point.plotY;
  1482. if (point.isNull) {
  1483. point.plotY = null;
  1484. }
  1485. else {
  1486. point.plotLow = plotY;
  1487. point.plotHigh = yAxis.translate(hasModifyValue ?
  1488. series.modifyValue(high, point) :
  1489. high, 0, 1, 0, 1);
  1490. if (hasModifyValue) {
  1491. point.yBottom = point.plotHigh;
  1492. }
  1493. }
  1494. });
  1495. // Postprocess plotHigh
  1496. if (this.chart.polar) {
  1497. this.points.forEach(function (point) {
  1498. series.highToXY(point);
  1499. point.tooltipPos = [
  1500. (point.plotHighX + point.plotLowX) / 2,
  1501. (point.plotHigh + point.plotLow) / 2
  1502. ];
  1503. });
  1504. }
  1505. },
  1506. /**
  1507. * Extend the line series' getSegmentPath method by applying the segment
  1508. * path to both lower and higher values of the range.
  1509. * @private
  1510. */
  1511. getGraphPath: function (points) {
  1512. var highPoints = [], highAreaPoints = [], i, getGraphPath = seriesTypes.area.prototype.getGraphPath, point, pointShim, linePath, lowerPath, options = this.options, connectEnds = this.chart.polar && options.connectEnds !== false, connectNulls = options.connectNulls, step = options.step, higherPath, higherAreaPath;
  1513. points = points || this.points;
  1514. i = points.length;
  1515. // Create the top line and the top part of the area fill. The area fill
  1516. // compensates for null points by drawing down to the lower graph,
  1517. // moving across the null gap and starting again at the lower graph.
  1518. i = points.length;
  1519. while (i--) {
  1520. point = points[i];
  1521. if (!point.isNull &&
  1522. !connectEnds &&
  1523. !connectNulls &&
  1524. (!points[i + 1] || points[i + 1].isNull)) {
  1525. highAreaPoints.push({
  1526. plotX: point.plotX,
  1527. plotY: point.plotY,
  1528. doCurve: false // #5186, gaps in areasplinerange fill
  1529. });
  1530. }
  1531. pointShim = {
  1532. polarPlotY: point.polarPlotY,
  1533. rectPlotX: point.rectPlotX,
  1534. yBottom: point.yBottom,
  1535. // plotHighX is for polar charts
  1536. plotX: pick(point.plotHighX, point.plotX),
  1537. plotY: point.plotHigh,
  1538. isNull: point.isNull
  1539. };
  1540. highAreaPoints.push(pointShim);
  1541. highPoints.push(pointShim);
  1542. if (!point.isNull &&
  1543. !connectEnds &&
  1544. !connectNulls &&
  1545. (!points[i - 1] || points[i - 1].isNull)) {
  1546. highAreaPoints.push({
  1547. plotX: point.plotX,
  1548. plotY: point.plotY,
  1549. doCurve: false // #5186, gaps in areasplinerange fill
  1550. });
  1551. }
  1552. }
  1553. // Get the paths
  1554. lowerPath = getGraphPath.call(this, points);
  1555. if (step) {
  1556. if (step === true) {
  1557. step = 'left';
  1558. }
  1559. options.step = {
  1560. left: 'right',
  1561. center: 'center',
  1562. right: 'left'
  1563. }[step]; // swap for reading in getGraphPath
  1564. }
  1565. higherPath = getGraphPath.call(this, highPoints);
  1566. higherAreaPath = getGraphPath.call(this, highAreaPoints);
  1567. options.step = step;
  1568. // Create a line on both top and bottom of the range
  1569. linePath = []
  1570. .concat(lowerPath, higherPath);
  1571. // For the area path, we need to change the 'move' statement
  1572. // into 'lineTo'
  1573. if (!this.chart.polar && higherAreaPath[0] && higherAreaPath[0][0] === 'M') {
  1574. // This probably doesn't work for spline
  1575. higherAreaPath[0] = ['L', higherAreaPath[0][1], higherAreaPath[0][2]];
  1576. }
  1577. this.graphPath = linePath;
  1578. this.areaPath = lowerPath.concat(higherAreaPath);
  1579. // Prepare for sideways animation
  1580. linePath.isArea = true;
  1581. linePath.xMap = lowerPath.xMap;
  1582. this.areaPath.xMap = lowerPath.xMap;
  1583. return linePath;
  1584. },
  1585. /**
  1586. * Extend the basic drawDataLabels method by running it for both lower and
  1587. * higher values.
  1588. * @private
  1589. */
  1590. drawDataLabels: function () {
  1591. var data = this.points, length = data.length, i, originalDataLabels = [], dataLabelOptions = this.options.dataLabels, point, up, inverted = this.chart.inverted, upperDataLabelOptions, lowerDataLabelOptions;
  1592. // Split into upper and lower options. If data labels is an array, the
  1593. // first element is the upper label, the second is the lower.
  1594. //
  1595. // TODO: We want to change this and allow multiple labels for both upper
  1596. // and lower values in the future - introducing some options for which
  1597. // point value to use as Y for the dataLabel, so that this could be
  1598. // handled in Series.drawDataLabels. This would also improve performance
  1599. // since we now have to loop over all the points multiple times to work
  1600. // around the data label logic.
  1601. if (isArray(dataLabelOptions)) {
  1602. if (dataLabelOptions.length > 1) {
  1603. upperDataLabelOptions = dataLabelOptions[0];
  1604. lowerDataLabelOptions = dataLabelOptions[1];
  1605. }
  1606. else {
  1607. upperDataLabelOptions = dataLabelOptions[0];
  1608. lowerDataLabelOptions = { enabled: false };
  1609. }
  1610. }
  1611. else {
  1612. // Make copies
  1613. upperDataLabelOptions = extend({}, dataLabelOptions);
  1614. upperDataLabelOptions.x = dataLabelOptions.xHigh;
  1615. upperDataLabelOptions.y = dataLabelOptions.yHigh;
  1616. lowerDataLabelOptions = extend({}, dataLabelOptions);
  1617. lowerDataLabelOptions.x = dataLabelOptions.xLow;
  1618. lowerDataLabelOptions.y = dataLabelOptions.yLow;
  1619. }
  1620. // Draw upper labels
  1621. if (upperDataLabelOptions.enabled || this._hasPointLabels) {
  1622. // Set preliminary values for plotY and dataLabel
  1623. // and draw the upper labels
  1624. i = length;
  1625. while (i--) {
  1626. point = data[i];
  1627. if (point) {
  1628. up = upperDataLabelOptions.inside ?
  1629. point.plotHigh < point.plotLow :
  1630. point.plotHigh > point.plotLow;
  1631. point.y = point.high;
  1632. point._plotY = point.plotY;
  1633. point.plotY = point.plotHigh;
  1634. // Store original data labels and set preliminary label
  1635. // objects to be picked up in the uber method
  1636. originalDataLabels[i] = point.dataLabel;
  1637. point.dataLabel = point.dataLabelUpper;
  1638. // Set the default offset
  1639. point.below = up;
  1640. if (inverted) {
  1641. if (!upperDataLabelOptions.align) {
  1642. upperDataLabelOptions.align = up ? 'right' : 'left';
  1643. }
  1644. }
  1645. else {
  1646. if (!upperDataLabelOptions.verticalAlign) {
  1647. upperDataLabelOptions.verticalAlign = up ?
  1648. 'top' :
  1649. 'bottom';
  1650. }
  1651. }
  1652. }
  1653. }
  1654. this.options.dataLabels = upperDataLabelOptions;
  1655. if (seriesProto.drawDataLabels) {
  1656. // #1209:
  1657. seriesProto.drawDataLabels.apply(this, arguments);
  1658. }
  1659. // Reset state after the upper labels were created. Move
  1660. // it to point.dataLabelUpper and reassign the originals.
  1661. // We do this here to support not drawing a lower label.
  1662. i = length;
  1663. while (i--) {
  1664. point = data[i];
  1665. if (point) {
  1666. point.dataLabelUpper = point.dataLabel;
  1667. point.dataLabel = originalDataLabels[i];
  1668. delete point.dataLabels;
  1669. point.y = point.low;
  1670. point.plotY = point._plotY;
  1671. }
  1672. }
  1673. }
  1674. // Draw lower labels
  1675. if (lowerDataLabelOptions.enabled || this._hasPointLabels) {
  1676. i = length;
  1677. while (i--) {
  1678. point = data[i];
  1679. if (point) {
  1680. up = lowerDataLabelOptions.inside ?
  1681. point.plotHigh < point.plotLow :
  1682. point.plotHigh > point.plotLow;
  1683. // Set the default offset
  1684. point.below = !up;
  1685. if (inverted) {
  1686. if (!lowerDataLabelOptions.align) {
  1687. lowerDataLabelOptions.align = up ? 'left' : 'right';
  1688. }
  1689. }
  1690. else {
  1691. if (!lowerDataLabelOptions.verticalAlign) {
  1692. lowerDataLabelOptions.verticalAlign = up ?
  1693. 'bottom' :
  1694. 'top';
  1695. }
  1696. }
  1697. }
  1698. }
  1699. this.options.dataLabels = lowerDataLabelOptions;
  1700. if (seriesProto.drawDataLabels) {
  1701. seriesProto.drawDataLabels.apply(this, arguments);
  1702. }
  1703. }
  1704. // Merge upper and lower into point.dataLabels for later destroying
  1705. if (upperDataLabelOptions.enabled) {
  1706. i = length;
  1707. while (i--) {
  1708. point = data[i];
  1709. if (point) {
  1710. point.dataLabels = [
  1711. point.dataLabelUpper,
  1712. point.dataLabel
  1713. ].filter(function (label) {
  1714. return !!label;
  1715. });
  1716. }
  1717. }
  1718. }
  1719. // Reset options
  1720. this.options.dataLabels = dataLabelOptions;
  1721. },
  1722. alignDataLabel: function () {
  1723. seriesTypes.column.prototype.alignDataLabel
  1724. .apply(this, arguments);
  1725. },
  1726. drawPoints: function () {
  1727. var series = this, pointLength = series.points.length, point, i;
  1728. // Draw bottom points
  1729. seriesProto.drawPoints
  1730. .apply(series, arguments);
  1731. // Prepare drawing top points
  1732. i = 0;
  1733. while (i < pointLength) {
  1734. point = series.points[i];
  1735. // Save original props to be overridden by temporary props for top
  1736. // points
  1737. point.origProps = {
  1738. plotY: point.plotY,
  1739. plotX: point.plotX,
  1740. isInside: point.isInside,
  1741. negative: point.negative,
  1742. zone: point.zone,
  1743. y: point.y
  1744. };
  1745. point.lowerGraphic = point.graphic;
  1746. point.graphic = point.upperGraphic;
  1747. point.plotY = point.plotHigh;
  1748. if (defined(point.plotHighX)) {
  1749. point.plotX = point.plotHighX;
  1750. }
  1751. point.y = point.high;
  1752. point.negative = point.high < (series.options.threshold || 0);
  1753. point.zone = (series.zones.length && point.getZone());
  1754. if (!series.chart.polar) {
  1755. point.isInside = point.isTopInside = (typeof point.plotY !== 'undefined' &&
  1756. point.plotY >= 0 &&
  1757. point.plotY <= series.yAxis.len && // #3519
  1758. point.plotX >= 0 &&
  1759. point.plotX <= series.xAxis.len);
  1760. }
  1761. i++;
  1762. }
  1763. // Draw top points
  1764. seriesProto.drawPoints.apply(series, arguments);
  1765. // Reset top points preliminary modifications
  1766. i = 0;
  1767. while (i < pointLength) {
  1768. point = series.points[i];
  1769. point.upperGraphic = point.graphic;
  1770. point.graphic = point.lowerGraphic;
  1771. extend(point, point.origProps);
  1772. delete point.origProps;
  1773. i++;
  1774. }
  1775. },
  1776. /* eslint-enable valid-jsdoc */
  1777. setStackedPoints: noop
  1778. }, {
  1779. /**
  1780. * Range series only. The high or maximum value for each data point.
  1781. * @name Highcharts.Point#high
  1782. * @type {number|undefined}
  1783. */
  1784. /**
  1785. * Range series only. The low or minimum value for each data point.
  1786. * @name Highcharts.Point#low
  1787. * @type {number|undefined}
  1788. */
  1789. /* eslint-disable valid-jsdoc */
  1790. /**
  1791. * @private
  1792. */
  1793. setState: function () {
  1794. var prevState = this.state, series = this.series, isPolar = series.chart.polar;
  1795. if (!defined(this.plotHigh)) {
  1796. // Boost doesn't calculate plotHigh
  1797. this.plotHigh = series.yAxis.toPixels(this.high, true);
  1798. }
  1799. if (!defined(this.plotLow)) {
  1800. // Boost doesn't calculate plotLow
  1801. this.plotLow = this.plotY = series.yAxis.toPixels(this.low, true);
  1802. }
  1803. if (series.stateMarkerGraphic) {
  1804. series.lowerStateMarkerGraphic = series.stateMarkerGraphic;
  1805. series.stateMarkerGraphic = series.upperStateMarkerGraphic;
  1806. }
  1807. // Change state also for the top marker
  1808. this.graphic = this.upperGraphic;
  1809. this.plotY = this.plotHigh;
  1810. if (isPolar) {
  1811. this.plotX = this.plotHighX;
  1812. }
  1813. // Top state:
  1814. pointProto.setState.apply(this, arguments);
  1815. this.state = prevState;
  1816. // Now restore defaults
  1817. this.plotY = this.plotLow;
  1818. this.graphic = this.lowerGraphic;
  1819. if (isPolar) {
  1820. this.plotX = this.plotLowX;
  1821. }
  1822. if (series.stateMarkerGraphic) {
  1823. series.upperStateMarkerGraphic = series.stateMarkerGraphic;
  1824. series.stateMarkerGraphic = series.lowerStateMarkerGraphic;
  1825. // Lower marker is stored at stateMarkerGraphic
  1826. // to avoid reference duplication (#7021)
  1827. series.lowerStateMarkerGraphic = void 0;
  1828. }
  1829. pointProto.setState.apply(this, arguments);
  1830. },
  1831. haloPath: function () {
  1832. var isPolar = this.series.chart.polar, path = [];
  1833. // Bottom halo
  1834. this.plotY = this.plotLow;
  1835. if (isPolar) {
  1836. this.plotX = this.plotLowX;
  1837. }
  1838. if (this.isInside) {
  1839. path = pointProto.haloPath.apply(this, arguments);
  1840. }
  1841. // Top halo
  1842. this.plotY = this.plotHigh;
  1843. if (isPolar) {
  1844. this.plotX = this.plotHighX;
  1845. }
  1846. if (this.isTopInside) {
  1847. path = path.concat(pointProto.haloPath.apply(this, arguments));
  1848. }
  1849. return path;
  1850. },
  1851. destroyElements: function () {
  1852. var graphics = ['lowerGraphic', 'upperGraphic'];
  1853. graphics.forEach(function (graphicName) {
  1854. if (this[graphicName]) {
  1855. this[graphicName] =
  1856. this[graphicName].destroy();
  1857. }
  1858. }, this);
  1859. // Clear graphic for states, removed in the above each:
  1860. this.graphic = null;
  1861. return pointProto.destroyElements.apply(this, arguments);
  1862. },
  1863. isValid: function () {
  1864. return isNumber(this.low) && isNumber(this.high);
  1865. }
  1866. /* eslint-enable valid-jsdoc */
  1867. });
  1868. /**
  1869. * A `arearange` series. If the [type](#series.arearange.type) option is not
  1870. * specified, it is inherited from [chart.type](#chart.type).
  1871. *
  1872. *
  1873. * @extends series,plotOptions.arearange
  1874. * @excluding dataParser, dataURL, stack, stacking
  1875. * @product highcharts highstock
  1876. * @requires highcharts-more
  1877. * @apioption series.arearange
  1878. */
  1879. /**
  1880. * An array of data points for the series. For the `arearange` series type,
  1881. * points can be given in the following ways:
  1882. *
  1883. * 1. An array of arrays with 3 or 2 values. In this case, the values
  1884. * correspond to `x,low,high`. If the first value is a string, it is
  1885. * applied as the name of the point, and the `x` value is inferred.
  1886. * The `x` value can also be omitted, in which case the inner arrays
  1887. * should be of length 2\. Then the `x` value is automatically calculated,
  1888. * either starting at 0 and incremented by 1, or from `pointStart`
  1889. * and `pointInterval` given in the series options.
  1890. * ```js
  1891. * data: [
  1892. * [0, 8, 3],
  1893. * [1, 1, 1],
  1894. * [2, 6, 8]
  1895. * ]
  1896. * ```
  1897. *
  1898. * 2. An array of objects with named values. The following snippet shows only a
  1899. * few settings, see the complete options set below. If the total number of
  1900. * data points exceeds the series'
  1901. * [turboThreshold](#series.arearange.turboThreshold),
  1902. * this option is not available.
  1903. * ```js
  1904. * data: [{
  1905. * x: 1,
  1906. * low: 9,
  1907. * high: 0,
  1908. * name: "Point2",
  1909. * color: "#00FF00"
  1910. * }, {
  1911. * x: 1,
  1912. * low: 3,
  1913. * high: 4,
  1914. * name: "Point1",
  1915. * color: "#FF00FF"
  1916. * }]
  1917. * ```
  1918. *
  1919. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  1920. * Arrays of numeric x and y
  1921. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  1922. * Arrays of datetime x and y
  1923. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  1924. * Arrays of point.name and y
  1925. * @sample {highcharts} highcharts/series/data-array-of-objects/
  1926. * Config objects
  1927. *
  1928. * @type {Array<Array<(number|string),number>|Array<(number|string),number,number>|*>}
  1929. * @extends series.line.data
  1930. * @excluding marker, y
  1931. * @product highcharts highstock
  1932. * @apioption series.arearange.data
  1933. */
  1934. /**
  1935. * @extends series.arearange.dataLabels
  1936. * @product highcharts highstock
  1937. * @apioption series.arearange.data.dataLabels
  1938. */
  1939. /**
  1940. * The high or maximum value for each data point.
  1941. *
  1942. * @type {number}
  1943. * @product highcharts highstock
  1944. * @apioption series.arearange.data.high
  1945. */
  1946. /**
  1947. * The low or minimum value for each data point.
  1948. *
  1949. * @type {number}
  1950. * @product highcharts highstock
  1951. * @apioption series.arearange.data.low
  1952. */
  1953. ''; // adds doclets above to tranpiled file
  1954. });
  1955. _registerModule(_modules, 'parts-more/AreaSplineRangeSeries.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
  1956. /* *
  1957. *
  1958. * (c) 2010-2020 Torstein Honsi
  1959. *
  1960. * License: www.highcharts.com/license
  1961. *
  1962. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1963. *
  1964. * */
  1965. var seriesType = U.seriesType;
  1966. var seriesTypes = H.seriesTypes;
  1967. /**
  1968. * The area spline range is a cartesian series type with higher and
  1969. * lower Y values along an X axis. The area inside the range is colored, and
  1970. * the graph outlining the area is a smoothed spline.
  1971. *
  1972. * @sample {highstock|highstock} stock/demo/areasplinerange/
  1973. * Area spline range
  1974. *
  1975. * @extends plotOptions.arearange
  1976. * @since 2.3.0
  1977. * @excluding step
  1978. * @product highcharts highstock
  1979. * @requires highcharts-more
  1980. * @apioption plotOptions.areasplinerange
  1981. */
  1982. seriesType('areasplinerange', 'arearange', null, {
  1983. getPointSpline: seriesTypes.spline.prototype.getPointSpline
  1984. });
  1985. /**
  1986. * A `areasplinerange` series. If the [type](#series.areasplinerange.type)
  1987. * option is not specified, it is inherited from [chart.type](#chart.type).
  1988. *
  1989. * @extends series,plotOptions.areasplinerange
  1990. * @excluding dataParser, dataURL, stack, step
  1991. * @product highcharts highstock
  1992. * @requires highcharts-more
  1993. * @apioption series.areasplinerange
  1994. */
  1995. /**
  1996. * An array of data points for the series. For the `areasplinerange`
  1997. * series type, points can be given in the following ways:
  1998. *
  1999. * 1. An array of arrays with 3 or 2 values. In this case, the values correspond
  2000. * to `x,low,high`. If the first value is a string, it is applied as the name
  2001. * of the point, and the `x` value is inferred. The `x` value can also be
  2002. * omitted, in which case the inner arrays should be of length 2\. Then the
  2003. * `x` value is automatically calculated, either starting at 0 and
  2004. * incremented by 1, or from `pointStart` and `pointInterval` given in the
  2005. * series options.
  2006. * ```js
  2007. * data: [
  2008. * [0, 0, 5],
  2009. * [1, 9, 1],
  2010. * [2, 5, 2]
  2011. * ]
  2012. * ```
  2013. *
  2014. * 2. An array of objects with named values. The following snippet shows only a
  2015. * few settings, see the complete options set below. If the total number of
  2016. * data points exceeds the series'
  2017. * [turboThreshold](#series.areasplinerange.turboThreshold), this option is
  2018. * not available.
  2019. * ```js
  2020. * data: [{
  2021. * x: 1,
  2022. * low: 5,
  2023. * high: 0,
  2024. * name: "Point2",
  2025. * color: "#00FF00"
  2026. * }, {
  2027. * x: 1,
  2028. * low: 4,
  2029. * high: 1,
  2030. * name: "Point1",
  2031. * color: "#FF00FF"
  2032. * }]
  2033. * ```
  2034. *
  2035. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  2036. * Arrays of numeric x and y
  2037. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  2038. * Arrays of datetime x and y
  2039. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  2040. * Arrays of point.name and y
  2041. * @sample {highcharts} highcharts/series/data-array-of-objects/
  2042. * Config objects
  2043. *
  2044. * @type {Array<Array<(number|string),number>|Array<(number|string),number,number>|*>}
  2045. * @extends series.arearange.data
  2046. * @product highcharts highstock
  2047. * @apioption series.areasplinerange.data
  2048. */
  2049. ''; // adds doclets above to transpiled file
  2050. });
  2051. _registerModule(_modules, 'parts-more/ColumnRangeSeries.js', [_modules['parts/Globals.js'], _modules['parts/Options.js'], _modules['parts/Utilities.js']], function (H, O, U) {
  2052. /* *
  2053. *
  2054. * (c) 2010-2020 Torstein Honsi
  2055. *
  2056. * License: www.highcharts.com/license
  2057. *
  2058. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  2059. *
  2060. * */
  2061. var defaultOptions = O.defaultOptions;
  2062. var clamp = U.clamp, merge = U.merge, pick = U.pick, seriesType = U.seriesType;
  2063. var noop = H.noop, seriesTypes = H.seriesTypes;
  2064. var colProto = seriesTypes.column.prototype;
  2065. /**
  2066. * The column range is a cartesian series type with higher and lower
  2067. * Y values along an X axis. To display horizontal bars, set
  2068. * [chart.inverted](#chart.inverted) to `true`.
  2069. *
  2070. * @sample {highcharts|highstock} highcharts/demo/columnrange/
  2071. * Inverted column range
  2072. *
  2073. * @extends plotOptions.column
  2074. * @since 2.3.0
  2075. * @excluding negativeColor, stacking, softThreshold, threshold
  2076. * @product highcharts highstock
  2077. * @requires highcharts-more
  2078. * @optionparent plotOptions.columnrange
  2079. */
  2080. var columnRangeOptions = {
  2081. /**
  2082. * Extended data labels for range series types. Range series data labels
  2083. * have no `x` and `y` options. Instead, they have `xLow`, `xHigh`,
  2084. * `yLow` and `yHigh` options to allow the higher and lower data label
  2085. * sets individually.
  2086. *
  2087. * @declare Highcharts.SeriesAreaRangeDataLabelsOptionsObject
  2088. * @extends plotOptions.arearange.dataLabels
  2089. * @since 2.3.0
  2090. * @product highcharts highstock
  2091. * @apioption plotOptions.columnrange.dataLabels
  2092. */
  2093. pointRange: null,
  2094. /** @ignore-option */
  2095. marker: null,
  2096. states: {
  2097. hover: {
  2098. /** @ignore-option */
  2099. halo: false
  2100. }
  2101. }
  2102. };
  2103. /**
  2104. * The ColumnRangeSeries class
  2105. *
  2106. * @private
  2107. * @class
  2108. * @name Highcharts.seriesTypes.columnrange
  2109. *
  2110. * @augments Highcharts.Series
  2111. */
  2112. seriesType('columnrange', 'arearange', merge(defaultOptions.plotOptions.column, defaultOptions.plotOptions.arearange, columnRangeOptions), {
  2113. // eslint-disable-next-line valid-jsdoc
  2114. /**
  2115. * Translate data points from raw values x and y to plotX and plotY
  2116. * @private
  2117. */
  2118. translate: function () {
  2119. var series = this, yAxis = series.yAxis, xAxis = series.xAxis, startAngleRad = xAxis.startAngleRad, start, chart = series.chart, isRadial = series.xAxis.isRadial, safeDistance = Math.max(chart.chartWidth, chart.chartHeight) + 999, plotHigh;
  2120. // eslint-disable-next-line valid-jsdoc
  2121. /**
  2122. * Don't draw too far outside plot area (#6835)
  2123. * @private
  2124. */
  2125. function safeBounds(pixelPos) {
  2126. return clamp(pixelPos, -safeDistance, safeDistance);
  2127. }
  2128. colProto.translate.apply(series);
  2129. // Set plotLow and plotHigh
  2130. series.points.forEach(function (point) {
  2131. var shapeArgs = point.shapeArgs, minPointLength = series.options.minPointLength, heightDifference, height, y;
  2132. point.plotHigh = plotHigh = safeBounds(yAxis.translate(point.high, 0, 1, 0, 1));
  2133. point.plotLow = safeBounds(point.plotY);
  2134. // adjust shape
  2135. y = plotHigh;
  2136. height = pick(point.rectPlotY, point.plotY) - plotHigh;
  2137. // Adjust for minPointLength
  2138. if (Math.abs(height) < minPointLength) {
  2139. heightDifference = (minPointLength - height);
  2140. height += heightDifference;
  2141. y -= heightDifference / 2;
  2142. // Adjust for negative ranges or reversed Y axis (#1457)
  2143. }
  2144. else if (height < 0) {
  2145. height *= -1;
  2146. y -= height;
  2147. }
  2148. if (isRadial) {
  2149. start = point.barX + startAngleRad;
  2150. point.shapeType = 'arc';
  2151. point.shapeArgs = series.polarArc(y + height, y, start, start + point.pointWidth);
  2152. }
  2153. else {
  2154. shapeArgs.height = height;
  2155. shapeArgs.y = y;
  2156. point.tooltipPos = chart.inverted ?
  2157. [
  2158. yAxis.len + yAxis.pos - chart.plotLeft - y -
  2159. height / 2,
  2160. xAxis.len + xAxis.pos - chart.plotTop -
  2161. shapeArgs.x - shapeArgs.width / 2,
  2162. height
  2163. ] : [
  2164. xAxis.left - chart.plotLeft + shapeArgs.x +
  2165. shapeArgs.width / 2,
  2166. yAxis.pos - chart.plotTop + y + height / 2,
  2167. height
  2168. ]; // don't inherit from column tooltip position - #3372
  2169. }
  2170. });
  2171. },
  2172. directTouch: true,
  2173. trackerGroups: ['group', 'dataLabelsGroup'],
  2174. drawGraph: noop,
  2175. getSymbol: noop,
  2176. // Overrides from modules that may be loaded after this module
  2177. crispCol: function () {
  2178. return colProto.crispCol.apply(this, arguments);
  2179. },
  2180. drawPoints: function () {
  2181. return colProto.drawPoints.apply(this, arguments);
  2182. },
  2183. drawTracker: function () {
  2184. return colProto.drawTracker.apply(this, arguments);
  2185. },
  2186. getColumnMetrics: function () {
  2187. return colProto.getColumnMetrics.apply(this, arguments);
  2188. },
  2189. pointAttribs: function () {
  2190. return colProto.pointAttribs.apply(this, arguments);
  2191. },
  2192. animate: function () {
  2193. return colProto.animate.apply(this, arguments);
  2194. },
  2195. polarArc: function () {
  2196. return colProto.polarArc.apply(this, arguments);
  2197. },
  2198. translate3dPoints: function () {
  2199. return colProto.translate3dPoints.apply(this, arguments);
  2200. },
  2201. translate3dShapes: function () {
  2202. return colProto.translate3dShapes.apply(this, arguments);
  2203. }
  2204. }, {
  2205. setState: colProto.pointClass.prototype.setState
  2206. });
  2207. /**
  2208. * A `columnrange` series. If the [type](#series.columnrange.type)
  2209. * option is not specified, it is inherited from
  2210. * [chart.type](#chart.type).
  2211. *
  2212. * @extends series,plotOptions.columnrange
  2213. * @excluding dataParser, dataURL, stack, stacking
  2214. * @product highcharts highstock
  2215. * @requires highcharts-more
  2216. * @apioption series.columnrange
  2217. */
  2218. /**
  2219. * An array of data points for the series. For the `columnrange` series
  2220. * type, points can be given in the following ways:
  2221. *
  2222. * 1. An array of arrays with 3 or 2 values. In this case, the values correspond
  2223. * to `x,low,high`. If the first value is a string, it is applied as the name
  2224. * of the point, and the `x` value is inferred. The `x` value can also be
  2225. * omitted, in which case the inner arrays should be of length 2\. Then the
  2226. * `x` value is automatically calculated, either starting at 0 and
  2227. * incremented by 1, or from `pointStart` and `pointInterval` given in the
  2228. * series options.
  2229. * ```js
  2230. * data: [
  2231. * [0, 4, 2],
  2232. * [1, 2, 1],
  2233. * [2, 9, 10]
  2234. * ]
  2235. * ```
  2236. *
  2237. * 2. An array of objects with named values. The following snippet shows only a
  2238. * few settings, see the complete options set below. If the total number of
  2239. * data points exceeds the series'
  2240. * [turboThreshold](#series.columnrange.turboThreshold), this option is not
  2241. * available.
  2242. * ```js
  2243. * data: [{
  2244. * x: 1,
  2245. * low: 0,
  2246. * high: 4,
  2247. * name: "Point2",
  2248. * color: "#00FF00"
  2249. * }, {
  2250. * x: 1,
  2251. * low: 5,
  2252. * high: 3,
  2253. * name: "Point1",
  2254. * color: "#FF00FF"
  2255. * }]
  2256. * ```
  2257. *
  2258. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  2259. * Arrays of numeric x and y
  2260. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  2261. * Arrays of datetime x and y
  2262. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  2263. * Arrays of point.name and y
  2264. * @sample {highcharts} highcharts/series/data-array-of-objects/
  2265. * Config objects
  2266. *
  2267. * @type {Array<Array<(number|string),number>|Array<(number|string),number,number>|*>}
  2268. * @extends series.arearange.data
  2269. * @excluding marker
  2270. * @product highcharts highstock
  2271. * @apioption series.columnrange.data
  2272. */
  2273. /**
  2274. * @extends series.columnrange.dataLabels
  2275. * @product highcharts highstock
  2276. * @apioption series.columnrange.data.dataLabels
  2277. */
  2278. /**
  2279. * @excluding halo, lineWidth, lineWidthPlus, marker
  2280. * @product highcharts highstock
  2281. * @apioption series.columnrange.states.hover
  2282. */
  2283. /**
  2284. * @excluding halo, lineWidth, lineWidthPlus, marker
  2285. * @product highcharts highstock
  2286. * @apioption series.columnrange.states.select
  2287. */
  2288. ''; // adds doclets above into transpiled
  2289. });
  2290. _registerModule(_modules, 'parts-more/ColumnPyramidSeries.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
  2291. /* *
  2292. *
  2293. * (c) 2010-2020 Sebastian Bochan
  2294. *
  2295. * License: www.highcharts.com/license
  2296. *
  2297. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  2298. *
  2299. * */
  2300. var clamp = U.clamp, pick = U.pick, seriesType = U.seriesType;
  2301. var seriesTypes = H.seriesTypes;
  2302. var colProto = seriesTypes.column.prototype;
  2303. /**
  2304. * The ColumnPyramidSeries class
  2305. *
  2306. * @private
  2307. * @class
  2308. * @name Highcharts.seriesTypes.columnpyramid
  2309. *
  2310. * @augments Highcharts.Series
  2311. */
  2312. seriesType('columnpyramid', 'column',
  2313. /**
  2314. * Column pyramid series display one pyramid per value along an X axis.
  2315. * To display horizontal pyramids, set [chart.inverted](#chart.inverted) to
  2316. * `true`.
  2317. *
  2318. * @sample {highcharts|highstock} highcharts/demo/column-pyramid/
  2319. * Column pyramid
  2320. * @sample {highcharts|highstock} highcharts/plotoptions/columnpyramid-stacked/
  2321. * Column pyramid stacked
  2322. * @sample {highcharts|highstock} highcharts/plotoptions/columnpyramid-inverted/
  2323. * Column pyramid inverted
  2324. *
  2325. * @extends plotOptions.column
  2326. * @since 7.0.0
  2327. * @product highcharts highstock
  2328. * @excluding boostThreshold, borderRadius, crisp, depth, edgeColor,
  2329. * edgeWidth, groupZPadding, negativeColor, softThreshold,
  2330. * threshold, zoneAxis, zones
  2331. * @requires highcharts-more
  2332. * @optionparent plotOptions.columnpyramid
  2333. */
  2334. {
  2335. // no additions
  2336. }, {
  2337. /* eslint-disable-next-line valid-jsdoc */
  2338. /**
  2339. * Overrides the column translate method
  2340. * @private
  2341. */
  2342. translate: function () {
  2343. var series = this, chart = series.chart, options = series.options, dense = series.dense =
  2344. series.closestPointRange * series.xAxis.transA < 2, borderWidth = series.borderWidth = pick(options.borderWidth, dense ? 0 : 1 // #3635
  2345. ), yAxis = series.yAxis, threshold = options.threshold, translatedThreshold = series.translatedThreshold =
  2346. yAxis.getThreshold(threshold), minPointLength = pick(options.minPointLength, 5), metrics = series.getColumnMetrics(), pointWidth = metrics.width,
  2347. // postprocessed for border width
  2348. seriesBarW = series.barW =
  2349. Math.max(pointWidth, 1 + 2 * borderWidth), pointXOffset = series.pointXOffset = metrics.offset;
  2350. if (chart.inverted) {
  2351. translatedThreshold -= 0.5; // #3355
  2352. }
  2353. // When the pointPadding is 0,
  2354. // we want the pyramids to be packed tightly,
  2355. // so we allow individual pyramids to have individual sizes.
  2356. // When pointPadding is greater,
  2357. // we strive for equal-width columns (#2694).
  2358. if (options.pointPadding) {
  2359. seriesBarW = Math.ceil(seriesBarW);
  2360. }
  2361. colProto.translate.apply(series);
  2362. // Record the new values
  2363. series.points.forEach(function (point) {
  2364. var yBottom = pick(point.yBottom, translatedThreshold), safeDistance = 999 + Math.abs(yBottom), plotY = clamp(point.plotY, -safeDistance, yAxis.len + safeDistance),
  2365. // Don't draw too far outside plot area
  2366. // (#1303, #2241, #4264)
  2367. barX = point.plotX + pointXOffset, barW = seriesBarW / 2, barY = Math.min(plotY, yBottom), barH = Math.max(plotY, yBottom) - barY, stackTotal, stackHeight, topPointY, topXwidth, bottomXwidth, invBarPos, x1, x2, x3, x4, y1, y2;
  2368. point.barX = barX;
  2369. point.pointWidth = pointWidth;
  2370. // Fix the tooltip on center of grouped pyramids
  2371. // (#1216, #424, #3648)
  2372. point.tooltipPos = chart.inverted ?
  2373. [
  2374. yAxis.len + yAxis.pos - chart.plotLeft - plotY,
  2375. series.xAxis.len - barX - barW,
  2376. barH
  2377. ] :
  2378. [
  2379. barX + barW,
  2380. plotY + yAxis.pos - chart.plotTop,
  2381. barH
  2382. ];
  2383. stackTotal =
  2384. threshold + (point.total || point.y);
  2385. // overwrite stacktotal (always 100 / -100)
  2386. if (options.stacking === 'percent') {
  2387. stackTotal =
  2388. threshold + (point.y < 0) ?
  2389. -100 :
  2390. 100;
  2391. }
  2392. // get the highest point (if stack, extract from total)
  2393. topPointY = yAxis.toPixels((stackTotal), true);
  2394. // calculate height of stack (in pixels)
  2395. stackHeight =
  2396. chart.plotHeight - topPointY -
  2397. (chart.plotHeight - translatedThreshold);
  2398. // topXwidth and bottomXwidth = width of lines from the center
  2399. // calculated from tanges proportion.
  2400. // Can not be a NaN #12514
  2401. topXwidth = stackHeight ? (barW * (barY - topPointY)) / stackHeight : 0;
  2402. // like topXwidth, but with height of point
  2403. bottomXwidth = stackHeight ? (barW * (barY + barH - topPointY)) / stackHeight : 0;
  2404. /*
  2405. /\
  2406. / \
  2407. x1,y1,------ x2,y1
  2408. / \
  2409. ----------
  2410. x4,y2 x3,y2
  2411. */
  2412. x1 = barX - topXwidth + barW;
  2413. x2 = barX + topXwidth + barW;
  2414. x3 = barX + bottomXwidth + barW;
  2415. x4 = barX - bottomXwidth + barW;
  2416. y1 = barY - minPointLength;
  2417. y2 = barY + barH;
  2418. if (point.y < 0) {
  2419. y1 = barY;
  2420. y2 = barY + barH + minPointLength;
  2421. }
  2422. // inverted chart
  2423. if (chart.inverted) {
  2424. invBarPos = chart.plotWidth - barY;
  2425. stackHeight = (topPointY -
  2426. (chart.plotWidth - translatedThreshold));
  2427. // proportion tanges
  2428. topXwidth = (barW *
  2429. (topPointY - invBarPos)) / stackHeight;
  2430. bottomXwidth = (barW *
  2431. (topPointY - (invBarPos - barH))) / stackHeight;
  2432. x1 = barX + barW + topXwidth; // top bottom
  2433. x2 = x1 - 2 * topXwidth; // top top
  2434. x3 = barX - bottomXwidth + barW; // bottom top
  2435. x4 = barX + bottomXwidth + barW; // bottom bottom
  2436. y1 = barY;
  2437. y2 = barY + barH - minPointLength;
  2438. if (point.y < 0) {
  2439. y2 = barY + barH + minPointLength;
  2440. }
  2441. }
  2442. // Register shape type and arguments to be used in drawPoints
  2443. point.shapeType = 'path';
  2444. point.shapeArgs = {
  2445. // args for datalabels positioning
  2446. x: x1,
  2447. y: y1,
  2448. width: x2 - x1,
  2449. height: barH,
  2450. // path of pyramid
  2451. d: [
  2452. ['M', x1, y1],
  2453. ['L', x2, y1],
  2454. ['L', x3, y2],
  2455. ['L', x4, y2],
  2456. ['Z']
  2457. ]
  2458. };
  2459. });
  2460. }
  2461. });
  2462. /**
  2463. * A `columnpyramid` series. If the [type](#series.columnpyramid.type) option is
  2464. * not specified, it is inherited from [chart.type](#chart.type).
  2465. *
  2466. * @extends series,plotOptions.columnpyramid
  2467. * @excluding connectEnds, connectNulls, dashStyle, dataParser, dataURL,
  2468. * gapSize, gapUnit, linecap, lineWidth, marker, step
  2469. * @product highcharts highstock
  2470. * @requires highcharts-more
  2471. * @apioption series.columnpyramid
  2472. */
  2473. /**
  2474. * @excluding halo, lineWidth, lineWidthPlus, marker
  2475. * @product highcharts highstock
  2476. * @apioption series.columnpyramid.states.hover
  2477. */
  2478. /**
  2479. * @excluding halo, lineWidth, lineWidthPlus, marker
  2480. * @product highcharts highstock
  2481. * @apioption series.columnpyramid.states.select
  2482. */
  2483. /**
  2484. * An array of data points for the series. For the `columnpyramid` series type,
  2485. * points can be given in the following ways:
  2486. *
  2487. * 1. An array of numerical values. In this case, the numerical values will be
  2488. * interpreted as `y` options. The `x` values will be automatically
  2489. * calculated, either starting at 0 and incremented by 1, or from
  2490. * `pointStart` and `pointInterval` given in the series options. If the axis
  2491. * has categories, these will be used. Example:
  2492. * ```js
  2493. * data: [0, 5, 3, 5]
  2494. * ```
  2495. *
  2496. * 2. An array of arrays with 2 values. In this case, the values correspond to
  2497. * `x,y`. If the first value is a string, it is applied as the name of the
  2498. * point, and the `x` value is inferred.
  2499. * ```js
  2500. * data: [
  2501. * [0, 6],
  2502. * [1, 2],
  2503. * [2, 6]
  2504. * ]
  2505. * ```
  2506. *
  2507. * 3. An array of objects with named values. The objects are point configuration
  2508. * objects as seen below. If the total number of data points exceeds the
  2509. * series' [turboThreshold](#series.columnpyramid.turboThreshold), this
  2510. * option is not available.
  2511. * ```js
  2512. * data: [{
  2513. * x: 1,
  2514. * y: 9,
  2515. * name: "Point2",
  2516. * color: "#00FF00"
  2517. * }, {
  2518. * x: 1,
  2519. * y: 6,
  2520. * name: "Point1",
  2521. * color: "#FF00FF"
  2522. * }]
  2523. * ```
  2524. *
  2525. * @sample {highcharts} highcharts/chart/reflow-true/
  2526. * Numerical values
  2527. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  2528. * Arrays of numeric x and y
  2529. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  2530. * Arrays of datetime x and y
  2531. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  2532. * Arrays of point.name and y
  2533. * @sample {highcharts} highcharts/series/data-array-of-objects/
  2534. * Config objects
  2535. *
  2536. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  2537. * @extends series.line.data
  2538. * @excluding marker
  2539. * @product highcharts highstock
  2540. * @apioption series.columnpyramid.data
  2541. */
  2542. ''; // adds doclets above to transpiled file;
  2543. });
  2544. _registerModule(_modules, 'parts-more/GaugeSeries.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
  2545. /* *
  2546. *
  2547. * (c) 2010-2020 Torstein Honsi
  2548. *
  2549. * License: www.highcharts.com/license
  2550. *
  2551. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  2552. *
  2553. * */
  2554. var clamp = U.clamp, isNumber = U.isNumber, merge = U.merge, pick = U.pick, pInt = U.pInt, seriesType = U.seriesType;
  2555. var noop = H.noop, Series = H.Series, TrackerMixin = H.TrackerMixin;
  2556. /**
  2557. * Gauges are circular plots displaying one or more values with a dial pointing
  2558. * to values along the perimeter.
  2559. *
  2560. * @sample highcharts/demo/gauge-speedometer/
  2561. * Gauge chart
  2562. *
  2563. * @extends plotOptions.line
  2564. * @excluding animationLimit, boostThreshold, colorAxis, colorKey,
  2565. * connectEnds, connectNulls, cropThreshold, dashStyle, dragDrop,
  2566. * findNearestPointBy, getExtremesFromAll, marker, negativeColor,
  2567. * pointPlacement, shadow, softThreshold, stacking, states, step,
  2568. * threshold, turboThreshold, xAxis, zoneAxis, zones, dataSorting
  2569. * @product highcharts
  2570. * @requires highcharts-more
  2571. * @optionparent plotOptions.gauge
  2572. */
  2573. seriesType('gauge', 'line', {
  2574. /**
  2575. * When this option is `true`, the dial will wrap around the axes. For
  2576. * instance, in a full-range gauge going from 0 to 360, a value of 400
  2577. * will point to 40\. When `wrap` is `false`, the dial stops at 360.
  2578. *
  2579. * @see [overshoot](#plotOptions.gauge.overshoot)
  2580. *
  2581. * @type {boolean}
  2582. * @default true
  2583. * @since 3.0
  2584. * @product highcharts
  2585. * @apioption plotOptions.gauge.wrap
  2586. */
  2587. /**
  2588. * Data labels for the gauge. For gauges, the data labels are enabled
  2589. * by default and shown in a bordered box below the point.
  2590. *
  2591. * @since 2.3.0
  2592. * @product highcharts
  2593. */
  2594. dataLabels: {
  2595. borderColor: '#cccccc',
  2596. borderRadius: 3,
  2597. borderWidth: 1,
  2598. crop: false,
  2599. defer: false,
  2600. enabled: true,
  2601. verticalAlign: 'top',
  2602. y: 15,
  2603. zIndex: 2
  2604. },
  2605. /**
  2606. * Options for the dial or arrow pointer of the gauge.
  2607. *
  2608. * In styled mode, the dial is styled with the
  2609. * `.highcharts-gauge-series .highcharts-dial` rule.
  2610. *
  2611. * @sample {highcharts} highcharts/css/gauge/
  2612. * Styled mode
  2613. *
  2614. * @type {*}
  2615. * @since 2.3.0
  2616. * @product highcharts
  2617. */
  2618. dial: {},
  2619. /**
  2620. * The length of the dial's base part, relative to the total radius
  2621. * or length of the dial.
  2622. *
  2623. * @sample {highcharts} highcharts/plotoptions/gauge-dial/
  2624. * Dial options demonstrated
  2625. *
  2626. * @type {string}
  2627. * @default 70%
  2628. * @since 2.3.0
  2629. * @product highcharts
  2630. * @apioption plotOptions.gauge.dial.baseLength
  2631. */
  2632. /**
  2633. * The pixel width of the base of the gauge dial. The base is the part
  2634. * closest to the pivot, defined by baseLength.
  2635. *
  2636. * @sample {highcharts} highcharts/plotoptions/gauge-dial/
  2637. * Dial options demonstrated
  2638. *
  2639. * @type {number}
  2640. * @default 3
  2641. * @since 2.3.0
  2642. * @product highcharts
  2643. * @apioption plotOptions.gauge.dial.baseWidth
  2644. */
  2645. /**
  2646. * The radius or length of the dial, in percentages relative to the
  2647. * radius of the gauge itself.
  2648. *
  2649. * @sample {highcharts} highcharts/plotoptions/gauge-dial/
  2650. * Dial options demonstrated
  2651. *
  2652. * @type {string}
  2653. * @default 80%
  2654. * @since 2.3.0
  2655. * @product highcharts
  2656. * @apioption plotOptions.gauge.dial.radius
  2657. */
  2658. /**
  2659. * The length of the dial's rear end, the part that extends out on the
  2660. * other side of the pivot. Relative to the dial's length.
  2661. *
  2662. * @sample {highcharts} highcharts/plotoptions/gauge-dial/
  2663. * Dial options demonstrated
  2664. *
  2665. * @type {string}
  2666. * @default 10%
  2667. * @since 2.3.0
  2668. * @product highcharts
  2669. * @apioption plotOptions.gauge.dial.rearLength
  2670. */
  2671. /**
  2672. * The width of the top of the dial, closest to the perimeter. The pivot
  2673. * narrows in from the base to the top.
  2674. *
  2675. * @sample {highcharts} highcharts/plotoptions/gauge-dial/
  2676. * Dial options demonstrated
  2677. *
  2678. * @type {number}
  2679. * @default 1
  2680. * @since 2.3.0
  2681. * @product highcharts
  2682. * @apioption plotOptions.gauge.dial.topWidth
  2683. */
  2684. /**
  2685. * The background or fill color of the gauge's dial.
  2686. *
  2687. * @sample {highcharts} highcharts/plotoptions/gauge-dial/
  2688. * Dial options demonstrated
  2689. *
  2690. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  2691. * @default #000000
  2692. * @since 2.3.0
  2693. * @product highcharts
  2694. * @apioption plotOptions.gauge.dial.backgroundColor
  2695. */
  2696. /**
  2697. * The border color or stroke of the gauge's dial. By default, the
  2698. * borderWidth is 0, so this must be set in addition to a custom border
  2699. * color.
  2700. *
  2701. * @sample {highcharts} highcharts/plotoptions/gauge-dial/
  2702. * Dial options demonstrated
  2703. *
  2704. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  2705. * @default #cccccc
  2706. * @since 2.3.0
  2707. * @product highcharts
  2708. * @apioption plotOptions.gauge.dial.borderColor
  2709. */
  2710. /**
  2711. * The width of the gauge dial border in pixels.
  2712. *
  2713. * @sample {highcharts} highcharts/plotoptions/gauge-dial/
  2714. * Dial options demonstrated
  2715. *
  2716. * @type {number}
  2717. * @default 0
  2718. * @since 2.3.0
  2719. * @product highcharts
  2720. * @apioption plotOptions.gauge.dial.borderWidth
  2721. */
  2722. /**
  2723. * Allow the dial to overshoot the end of the perimeter axis by this
  2724. * many degrees. Say if the gauge axis goes from 0 to 60, a value of
  2725. * 100, or 1000, will show 5 degrees beyond the end of the axis when this
  2726. * option is set to 5.
  2727. *
  2728. * @see [wrap](#plotOptions.gauge.wrap)
  2729. *
  2730. * @sample {highcharts} highcharts/plotoptions/gauge-overshoot/
  2731. * Allow 5 degrees overshoot
  2732. *
  2733. * @type {number}
  2734. * @since 3.0.10
  2735. * @product highcharts
  2736. * @apioption plotOptions.gauge.overshoot
  2737. */
  2738. /**
  2739. * Options for the pivot or the center point of the gauge.
  2740. *
  2741. * In styled mode, the pivot is styled with the
  2742. * `.highcharts-gauge-series .highcharts-pivot` rule.
  2743. *
  2744. * @sample {highcharts} highcharts/css/gauge/
  2745. * Styled mode
  2746. *
  2747. * @type {*}
  2748. * @since 2.3.0
  2749. * @product highcharts
  2750. */
  2751. pivot: {},
  2752. /**
  2753. * The pixel radius of the pivot.
  2754. *
  2755. * @sample {highcharts} highcharts/plotoptions/gauge-pivot/
  2756. * Pivot options demonstrated
  2757. *
  2758. * @type {number}
  2759. * @default 5
  2760. * @since 2.3.0
  2761. * @product highcharts
  2762. * @apioption plotOptions.gauge.pivot.radius
  2763. */
  2764. /**
  2765. * The border or stroke width of the pivot.
  2766. *
  2767. * @sample {highcharts} highcharts/plotoptions/gauge-pivot/
  2768. * Pivot options demonstrated
  2769. *
  2770. * @type {number}
  2771. * @default 0
  2772. * @since 2.3.0
  2773. * @product highcharts
  2774. * @apioption plotOptions.gauge.pivot.borderWidth
  2775. */
  2776. /**
  2777. * The border or stroke color of the pivot. In able to change this,
  2778. * the borderWidth must also be set to something other than the default
  2779. * 0.
  2780. *
  2781. * @sample {highcharts} highcharts/plotoptions/gauge-pivot/
  2782. * Pivot options demonstrated
  2783. *
  2784. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  2785. * @default #cccccc
  2786. * @since 2.3.0
  2787. * @product highcharts
  2788. * @apioption plotOptions.gauge.pivot.borderColor
  2789. */
  2790. /**
  2791. * The background color or fill of the pivot.
  2792. *
  2793. * @sample {highcharts} highcharts/plotoptions/gauge-pivot/
  2794. * Pivot options demonstrated
  2795. *
  2796. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  2797. * @default #000000
  2798. * @since 2.3.0
  2799. * @product highcharts
  2800. * @apioption plotOptions.gauge.pivot.backgroundColor
  2801. */
  2802. tooltip: {
  2803. headerFormat: ''
  2804. },
  2805. /**
  2806. * Whether to display this particular series or series type in the
  2807. * legend. Defaults to false for gauge series.
  2808. *
  2809. * @since 2.3.0
  2810. * @product highcharts
  2811. */
  2812. showInLegend: false
  2813. // Prototype members
  2814. }, {
  2815. // chart.angular will be set to true when a gauge series is present,
  2816. // and this will be used on the axes
  2817. angular: true,
  2818. directTouch: true,
  2819. drawGraph: noop,
  2820. fixedBox: true,
  2821. forceDL: true,
  2822. noSharedTooltip: true,
  2823. trackerGroups: ['group', 'dataLabelsGroup'],
  2824. /* eslint-disable valid-jsdoc */
  2825. /**
  2826. * Calculate paths etc
  2827. * @private
  2828. */
  2829. translate: function () {
  2830. var series = this, yAxis = series.yAxis, options = series.options, center = yAxis.center;
  2831. series.generatePoints();
  2832. series.points.forEach(function (point) {
  2833. var dialOptions = merge(options.dial, point.dial), radius = ((pInt(pick(dialOptions.radius, '80%')) * center[2]) /
  2834. 200), baseLength = ((pInt(pick(dialOptions.baseLength, '70%')) * radius) /
  2835. 100), rearLength = ((pInt(pick(dialOptions.rearLength, '10%')) * radius) /
  2836. 100), baseWidth = dialOptions.baseWidth || 3, topWidth = dialOptions.topWidth || 1, overshoot = options.overshoot, rotation = yAxis.startAngleRad + yAxis.translate(point.y, null, null, null, true);
  2837. // Handle the wrap and overshoot options
  2838. if (isNumber(overshoot) || options.wrap === false) {
  2839. overshoot = isNumber(overshoot) ?
  2840. (overshoot / 180 * Math.PI) : 0;
  2841. rotation = clamp(rotation, yAxis.startAngleRad - overshoot, yAxis.endAngleRad + overshoot);
  2842. }
  2843. rotation = rotation * 180 / Math.PI;
  2844. point.shapeType = 'path';
  2845. var d = dialOptions.path || [
  2846. ['M', -rearLength, -baseWidth / 2],
  2847. ['L', baseLength, -baseWidth / 2],
  2848. ['L', radius, -topWidth / 2],
  2849. ['L', radius, topWidth / 2],
  2850. ['L', baseLength, baseWidth / 2],
  2851. ['L', -rearLength, baseWidth / 2],
  2852. ['Z']
  2853. ];
  2854. point.shapeArgs = {
  2855. d: d,
  2856. translateX: center[0],
  2857. translateY: center[1],
  2858. rotation: rotation
  2859. };
  2860. // Positions for data label
  2861. point.plotX = center[0];
  2862. point.plotY = center[1];
  2863. });
  2864. },
  2865. /**
  2866. * Draw the points where each point is one needle
  2867. * @private
  2868. */
  2869. drawPoints: function () {
  2870. var series = this, chart = series.chart, center = series.yAxis.center, pivot = series.pivot, options = series.options, pivotOptions = options.pivot, renderer = chart.renderer;
  2871. series.points.forEach(function (point) {
  2872. var graphic = point.graphic, shapeArgs = point.shapeArgs, d = shapeArgs.d, dialOptions = merge(options.dial, point.dial); // #1233
  2873. if (graphic) {
  2874. graphic.animate(shapeArgs);
  2875. shapeArgs.d = d; // animate alters it
  2876. }
  2877. else {
  2878. point.graphic =
  2879. renderer[point.shapeType](shapeArgs)
  2880. .attr({
  2881. // required by VML when animation is false
  2882. rotation: shapeArgs.rotation,
  2883. zIndex: 1
  2884. })
  2885. .addClass('highcharts-dial')
  2886. .add(series.group);
  2887. }
  2888. // Presentational attributes
  2889. if (!chart.styledMode) {
  2890. point.graphic[graphic ? 'animate' : 'attr']({
  2891. stroke: dialOptions.borderColor || 'none',
  2892. 'stroke-width': dialOptions.borderWidth || 0,
  2893. fill: dialOptions.backgroundColor ||
  2894. '#000000'
  2895. });
  2896. }
  2897. });
  2898. // Add or move the pivot
  2899. if (pivot) {
  2900. pivot.animate({
  2901. translateX: center[0],
  2902. translateY: center[1]
  2903. });
  2904. }
  2905. else {
  2906. series.pivot =
  2907. renderer.circle(0, 0, pick(pivotOptions.radius, 5))
  2908. .attr({
  2909. zIndex: 2
  2910. })
  2911. .addClass('highcharts-pivot')
  2912. .translate(center[0], center[1])
  2913. .add(series.group);
  2914. // Presentational attributes
  2915. if (!chart.styledMode) {
  2916. series.pivot.attr({
  2917. 'stroke-width': pivotOptions.borderWidth || 0,
  2918. stroke: pivotOptions.borderColor ||
  2919. '#cccccc',
  2920. fill: pivotOptions.backgroundColor ||
  2921. '#000000'
  2922. });
  2923. }
  2924. }
  2925. },
  2926. /**
  2927. * Animate the arrow up from startAngle
  2928. * @private
  2929. */
  2930. animate: function (init) {
  2931. var series = this;
  2932. if (!init) {
  2933. series.points.forEach(function (point) {
  2934. var graphic = point.graphic;
  2935. if (graphic) {
  2936. // start value
  2937. graphic.attr({
  2938. rotation: series.yAxis.startAngleRad * 180 / Math.PI
  2939. });
  2940. // animate
  2941. graphic.animate({
  2942. rotation: point.shapeArgs.rotation
  2943. }, series.options.animation);
  2944. }
  2945. });
  2946. }
  2947. },
  2948. /**
  2949. * @private
  2950. */
  2951. render: function () {
  2952. this.group = this.plotGroup('group', 'series', this.visible ? 'visible' : 'hidden', this.options.zIndex, this.chart.seriesGroup);
  2953. Series.prototype.render.call(this);
  2954. this.group.clip(this.chart.clipRect);
  2955. },
  2956. /**
  2957. * Extend the basic setData method by running processData and generatePoints
  2958. * immediately, in order to access the points from the legend.
  2959. * @private
  2960. */
  2961. setData: function (data, redraw) {
  2962. Series.prototype.setData.call(this, data, false);
  2963. this.processData();
  2964. this.generatePoints();
  2965. if (pick(redraw, true)) {
  2966. this.chart.redraw();
  2967. }
  2968. },
  2969. /**
  2970. * Define hasData function for non-cartesian series.
  2971. * Returns true if the series has points at all.
  2972. * @private
  2973. */
  2974. hasData: function () {
  2975. return !!this.points.length; // != 0
  2976. },
  2977. // If the tracking module is loaded, add the point tracker
  2978. drawTracker: TrackerMixin && TrackerMixin.drawTrackerPoint
  2979. /* eslint-enable valid-jsdoc */
  2980. }, {
  2981. // Point members
  2982. /* eslint-disable valid-jsdoc */
  2983. /**
  2984. * Don't do any hover colors or anything
  2985. * @private
  2986. */
  2987. setState: function (state) {
  2988. this.state = state;
  2989. }
  2990. /* eslint-enable valid-jsdoc */
  2991. });
  2992. /**
  2993. * A `gauge` series. If the [type](#series.gauge.type) option is not
  2994. * specified, it is inherited from [chart.type](#chart.type).
  2995. *
  2996. * @extends series,plotOptions.gauge
  2997. * @excluding animationLimit, boostThreshold, connectEnds, connectNulls,
  2998. * cropThreshold, dashStyle, dataParser, dataURL, findNearestPointBy,
  2999. * getExtremesFromAll, marker, negativeColor, pointPlacement, shadow,
  3000. * softThreshold, stack, stacking, states, step, threshold,
  3001. * turboThreshold, zoneAxis, zones, dataSorting
  3002. * @product highcharts
  3003. * @requires highcharts-more
  3004. * @apioption series.gauge
  3005. */
  3006. /**
  3007. * An array of data points for the series. For the `gauge` series type,
  3008. * points can be given in the following ways:
  3009. *
  3010. * 1. An array of numerical values. In this case, the numerical values will be
  3011. * interpreted as `y` options. Example:
  3012. * ```js
  3013. * data: [0, 5, 3, 5]
  3014. * ```
  3015. *
  3016. * 2. An array of objects with named values. The following snippet shows only a
  3017. * few settings, see the complete options set below. If the total number of
  3018. * data points exceeds the series'
  3019. * [turboThreshold](#series.gauge.turboThreshold), this option is not
  3020. * available.
  3021. * ```js
  3022. * data: [{
  3023. * y: 6,
  3024. * name: "Point2",
  3025. * color: "#00FF00"
  3026. * }, {
  3027. * y: 8,
  3028. * name: "Point1",
  3029. * color: "#FF00FF"
  3030. * }]
  3031. * ```
  3032. *
  3033. * The typical gauge only contains a single data value.
  3034. *
  3035. * @sample {highcharts} highcharts/chart/reflow-true/
  3036. * Numerical values
  3037. * @sample {highcharts} highcharts/series/data-array-of-objects/
  3038. * Config objects
  3039. *
  3040. * @type {Array<number|null|*>}
  3041. * @extends series.line.data
  3042. * @excluding drilldown, marker, x
  3043. * @product highcharts
  3044. * @apioption series.gauge.data
  3045. */
  3046. ''; // adds the doclets above in the transpiled file
  3047. });
  3048. _registerModule(_modules, 'parts-more/BoxPlotSeries.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
  3049. /* *
  3050. *
  3051. * (c) 2010-2020 Torstein Honsi
  3052. *
  3053. * License: www.highcharts.com/license
  3054. *
  3055. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  3056. *
  3057. * */
  3058. var pick = U.pick, seriesType = U.seriesType;
  3059. var noop = H.noop, seriesTypes = H.seriesTypes;
  3060. /**
  3061. * The boxplot series type.
  3062. *
  3063. * @private
  3064. * @class
  3065. * @name Highcharts.seriesTypes#boxplot
  3066. *
  3067. * @augments Highcharts.Series
  3068. */
  3069. /**
  3070. * A box plot is a convenient way of depicting groups of data through their
  3071. * five-number summaries: the smallest observation (sample minimum), lower
  3072. * quartile (Q1), median (Q2), upper quartile (Q3), and largest observation
  3073. * (sample maximum).
  3074. *
  3075. * @sample highcharts/demo/box-plot/
  3076. * Box plot
  3077. *
  3078. * @extends plotOptions.column
  3079. * @excluding borderColor, borderRadius, borderWidth, groupZPadding, states
  3080. * @product highcharts
  3081. * @requires highcharts-more
  3082. * @optionparent plotOptions.boxplot
  3083. */
  3084. seriesType('boxplot', 'column', {
  3085. threshold: null,
  3086. tooltip: {
  3087. pointFormat: '<span style="color:{point.color}">\u25CF</span> <b> ' +
  3088. '{series.name}</b><br/>' +
  3089. 'Maximum: {point.high}<br/>' +
  3090. 'Upper quartile: {point.q3}<br/>' +
  3091. 'Median: {point.median}<br/>' +
  3092. 'Lower quartile: {point.q1}<br/>' +
  3093. 'Minimum: {point.low}<br/>'
  3094. },
  3095. /**
  3096. * The length of the whiskers, the horizontal lines marking low and
  3097. * high values. It can be a numerical pixel value, or a percentage
  3098. * value of the box width. Set `0` to disable whiskers.
  3099. *
  3100. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3101. * True by default
  3102. *
  3103. * @type {number|string}
  3104. * @since 3.0
  3105. * @product highcharts
  3106. */
  3107. whiskerLength: '50%',
  3108. /**
  3109. * The fill color of the box.
  3110. *
  3111. * In styled mode, the fill color can be set with the
  3112. * `.highcharts-boxplot-box` class.
  3113. *
  3114. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3115. * Box plot styling
  3116. *
  3117. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  3118. * @default #ffffff
  3119. * @since 3.0
  3120. * @product highcharts
  3121. */
  3122. fillColor: '#ffffff',
  3123. /**
  3124. * The width of the line surrounding the box. If any of
  3125. * [stemWidth](#plotOptions.boxplot.stemWidth),
  3126. * [medianWidth](#plotOptions.boxplot.medianWidth)
  3127. * or [whiskerWidth](#plotOptions.boxplot.whiskerWidth) are `null`,
  3128. * the lineWidth also applies to these lines.
  3129. *
  3130. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3131. * Box plot styling
  3132. * @sample {highcharts} highcharts/plotoptions/error-bar-styling/
  3133. * Error bar styling
  3134. *
  3135. * @since 3.0
  3136. * @product highcharts
  3137. */
  3138. lineWidth: 1,
  3139. /**
  3140. * The color of the median line. If `undefined`, the general series color
  3141. * applies.
  3142. *
  3143. * In styled mode, the median stroke width can be set with the
  3144. * `.highcharts-boxplot-median` class.
  3145. *
  3146. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3147. * Box plot styling
  3148. * @sample {highcharts} highcharts/css/boxplot/
  3149. * Box plot in styled mode
  3150. * @sample {highcharts} highcharts/plotoptions/error-bar-styling/
  3151. * Error bar styling
  3152. *
  3153. * @type {Highcharts.ColorString|Highcharts.GradientColorObject}
  3154. * @since 3.0
  3155. * @product highcharts
  3156. * @apioption plotOptions.boxplot.medianColor
  3157. */
  3158. /**
  3159. * The pixel width of the median line. If `null`, the
  3160. * [lineWidth](#plotOptions.boxplot.lineWidth) is used.
  3161. *
  3162. * In styled mode, the median stroke width can be set with the
  3163. * `.highcharts-boxplot-median` class.
  3164. *
  3165. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3166. * Box plot styling
  3167. * @sample {highcharts} highcharts/css/boxplot/
  3168. * Box plot in styled mode
  3169. *
  3170. * @type {number|null}
  3171. * @since 3.0
  3172. * @product highcharts
  3173. */
  3174. medianWidth: 2,
  3175. /*
  3176. // States are not working and are removed from docs.
  3177. // Refer to: #2340
  3178. states: {
  3179. hover: {
  3180. brightness: -0.3
  3181. }
  3182. },
  3183. /**
  3184. * The color of the stem, the vertical line extending from the box to
  3185. * the whiskers. If `undefined`, the series color is used.
  3186. *
  3187. * In styled mode, the stem stroke can be set with the
  3188. * `.highcharts-boxplot-stem` class.
  3189. *
  3190. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3191. * Box plot styling
  3192. * @sample {highcharts} highcharts/css/boxplot/
  3193. * Box plot in styled mode
  3194. * @sample {highcharts} highcharts/plotoptions/error-bar-styling/
  3195. * Error bar styling
  3196. *
  3197. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  3198. * @since 3.0
  3199. * @product highcharts
  3200. * @apioption plotOptions.boxplot.stemColor
  3201. */
  3202. /**
  3203. * The dash style of the box.
  3204. *
  3205. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3206. * Box plot styling
  3207. * @sample {highcharts} highcharts/css/boxplot/
  3208. * Box plot in styled mode
  3209. *
  3210. * @type {Highcharts.DashStyleValue}
  3211. * @default Solid
  3212. * @since 8.1.0
  3213. * @product highcharts
  3214. * @apioption plotOptions.boxplot.boxDashStyle
  3215. */
  3216. /**
  3217. * The dash style of the median.
  3218. *
  3219. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3220. * Box plot styling
  3221. * @sample {highcharts} highcharts/css/boxplot/
  3222. * Box plot in styled mode
  3223. *
  3224. * @type {Highcharts.DashStyleValue}
  3225. * @default Solid
  3226. * @since 8.1.0
  3227. * @product highcharts
  3228. * @apioption plotOptions.boxplot.medianDashStyle
  3229. */
  3230. /**
  3231. * The dash style of the stem, the vertical line extending from the
  3232. * box to the whiskers.
  3233. *
  3234. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3235. * Box plot styling
  3236. * @sample {highcharts} highcharts/css/boxplot/
  3237. * Box plot in styled mode
  3238. * @sample {highcharts} highcharts/plotoptions/error-bar-styling/
  3239. * Error bar styling
  3240. *
  3241. * @type {Highcharts.DashStyleValue}
  3242. * @default Solid
  3243. * @since 3.0
  3244. * @product highcharts
  3245. * @apioption plotOptions.boxplot.stemDashStyle
  3246. */
  3247. /**
  3248. * The dash style of the whiskers.
  3249. *
  3250. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3251. * Box plot styling
  3252. * @sample {highcharts} highcharts/css/boxplot/
  3253. * Box plot in styled mode
  3254. *
  3255. * @type {Highcharts.DashStyleValue}
  3256. * @default Solid
  3257. * @since 8.1.0
  3258. * @product highcharts
  3259. * @apioption plotOptions.boxplot.whiskerDashStyle
  3260. */
  3261. /**
  3262. * The width of the stem, the vertical line extending from the box to
  3263. * the whiskers. If `undefined`, the width is inherited from the
  3264. * [lineWidth](#plotOptions.boxplot.lineWidth) option.
  3265. *
  3266. * In styled mode, the stem stroke width can be set with the
  3267. * `.highcharts-boxplot-stem` class.
  3268. *
  3269. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3270. * Box plot styling
  3271. * @sample {highcharts} highcharts/css/boxplot/
  3272. * Box plot in styled mode
  3273. * @sample {highcharts} highcharts/plotoptions/error-bar-styling/
  3274. * Error bar styling
  3275. *
  3276. * @type {number}
  3277. * @since 3.0
  3278. * @product highcharts
  3279. * @apioption plotOptions.boxplot.stemWidth
  3280. */
  3281. /**
  3282. * @default high
  3283. * @apioption plotOptions.boxplot.colorKey
  3284. */
  3285. /**
  3286. * The color of the whiskers, the horizontal lines marking low and high
  3287. * values. When `undefined`, the general series color is used.
  3288. *
  3289. * In styled mode, the whisker stroke can be set with the
  3290. * `.highcharts-boxplot-whisker` class .
  3291. *
  3292. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3293. * Box plot styling
  3294. * @sample {highcharts} highcharts/css/boxplot/
  3295. * Box plot in styled mode
  3296. *
  3297. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  3298. * @since 3.0
  3299. * @product highcharts
  3300. * @apioption plotOptions.boxplot.whiskerColor
  3301. */
  3302. /**
  3303. * The line width of the whiskers, the horizontal lines marking low and
  3304. * high values. When `undefined`, the general
  3305. * [lineWidth](#plotOptions.boxplot.lineWidth) applies.
  3306. *
  3307. * In styled mode, the whisker stroke width can be set with the
  3308. * `.highcharts-boxplot-whisker` class.
  3309. *
  3310. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3311. * Box plot styling
  3312. * @sample {highcharts} highcharts/css/boxplot/
  3313. * Box plot in styled mode
  3314. *
  3315. * @since 3.0
  3316. * @product highcharts
  3317. */
  3318. whiskerWidth: 2
  3319. }, /** @lends Highcharts.seriesTypes.boxplot */ {
  3320. // array point configs are mapped to this
  3321. pointArrayMap: ['low', 'q1', 'median', 'q3', 'high'],
  3322. // return a plain array for speedy calculation
  3323. toYData: function (point) {
  3324. return [point.low, point.q1, point.median, point.q3, point.high];
  3325. },
  3326. // defines the top of the tracker
  3327. pointValKey: 'high',
  3328. // Get presentational attributes
  3329. pointAttribs: function () {
  3330. // No attributes should be set on point.graphic which is the group
  3331. return {};
  3332. },
  3333. // Disable data labels for box plot
  3334. drawDataLabels: noop,
  3335. // Translate data points from raw values x and y to plotX and plotY
  3336. translate: function () {
  3337. var series = this, yAxis = series.yAxis, pointArrayMap = series.pointArrayMap;
  3338. seriesTypes.column.prototype.translate.apply(series);
  3339. // do the translation on each point dimension
  3340. series.points.forEach(function (point) {
  3341. pointArrayMap.forEach(function (key) {
  3342. if (point[key] !== null) {
  3343. point[key + 'Plot'] = yAxis.translate(point[key], 0, 1, 0, 1);
  3344. }
  3345. });
  3346. point.plotHigh = point.highPlot; // For data label validation
  3347. });
  3348. },
  3349. // eslint-disable-next-line valid-jsdoc
  3350. /**
  3351. * Draw the data points
  3352. * @private
  3353. */
  3354. drawPoints: function () {
  3355. var series = this, points = series.points, options = series.options, chart = series.chart, renderer = chart.renderer, q1Plot, q3Plot, highPlot, lowPlot, medianPlot, medianPath, crispCorr, crispX = 0, boxPath, width, left, right, halfWidth,
  3356. // error bar inherits this series type but doesn't do quartiles
  3357. doQuartiles = series.doQuartiles !== false, pointWiskerLength, whiskerLength = series.options.whiskerLength;
  3358. points.forEach(function (point) {
  3359. var graphic = point.graphic, verb = graphic ? 'animate' : 'attr', shapeArgs = point.shapeArgs, boxAttr = {}, stemAttr = {}, whiskersAttr = {}, medianAttr = {}, color = point.color || series.color;
  3360. if (typeof point.plotY !== 'undefined') {
  3361. // crisp vector coordinates
  3362. width = Math.round(shapeArgs.width);
  3363. left = Math.floor(shapeArgs.x);
  3364. right = left + width;
  3365. halfWidth = Math.round(width / 2);
  3366. q1Plot = Math.floor(doQuartiles ? point.q1Plot : point.lowPlot);
  3367. q3Plot = Math.floor(doQuartiles ? point.q3Plot : point.lowPlot);
  3368. highPlot = Math.floor(point.highPlot);
  3369. lowPlot = Math.floor(point.lowPlot);
  3370. if (!graphic) {
  3371. point.graphic = graphic = renderer.g('point')
  3372. .add(series.group);
  3373. point.stem = renderer.path()
  3374. .addClass('highcharts-boxplot-stem')
  3375. .add(graphic);
  3376. if (whiskerLength) {
  3377. point.whiskers = renderer.path()
  3378. .addClass('highcharts-boxplot-whisker')
  3379. .add(graphic);
  3380. }
  3381. if (doQuartiles) {
  3382. point.box = renderer.path(boxPath)
  3383. .addClass('highcharts-boxplot-box')
  3384. .add(graphic);
  3385. }
  3386. point.medianShape = renderer.path(medianPath)
  3387. .addClass('highcharts-boxplot-median')
  3388. .add(graphic);
  3389. }
  3390. if (!chart.styledMode) {
  3391. // Stem attributes
  3392. stemAttr.stroke =
  3393. point.stemColor || options.stemColor || color;
  3394. stemAttr['stroke-width'] = pick(point.stemWidth, options.stemWidth, options.lineWidth);
  3395. stemAttr.dashstyle = (point.stemDashStyle ||
  3396. options.stemDashStyle ||
  3397. options.dashStyle);
  3398. point.stem.attr(stemAttr);
  3399. // Whiskers attributes
  3400. if (whiskerLength) {
  3401. whiskersAttr.stroke = (point.whiskerColor ||
  3402. options.whiskerColor ||
  3403. color);
  3404. whiskersAttr['stroke-width'] = pick(point.whiskerWidth, options.whiskerWidth, options.lineWidth);
  3405. whiskersAttr.dashstyle = (point.whiskerDashStyle ||
  3406. options.whiskerDashStyle ||
  3407. options.dashStyle);
  3408. point.whiskers.attr(whiskersAttr);
  3409. }
  3410. if (doQuartiles) {
  3411. boxAttr.fill = (point.fillColor ||
  3412. options.fillColor ||
  3413. color);
  3414. boxAttr.stroke = options.lineColor || color;
  3415. boxAttr['stroke-width'] = options.lineWidth || 0;
  3416. boxAttr.dashstyle = (point.boxDashStyle ||
  3417. options.boxDashStyle ||
  3418. options.dashStyle);
  3419. point.box.attr(boxAttr);
  3420. }
  3421. // Median attributes
  3422. medianAttr.stroke = (point.medianColor ||
  3423. options.medianColor ||
  3424. color);
  3425. medianAttr['stroke-width'] = pick(point.medianWidth, options.medianWidth, options.lineWidth);
  3426. medianAttr.dashstyle = (point.medianDashStyle ||
  3427. options.medianDashStyle ||
  3428. options.dashStyle);
  3429. point.medianShape.attr(medianAttr);
  3430. }
  3431. var d = void 0;
  3432. // The stem
  3433. crispCorr = (point.stem.strokeWidth() % 2) / 2;
  3434. crispX = left + halfWidth + crispCorr;
  3435. d = [
  3436. // stem up
  3437. ['M', crispX, q3Plot],
  3438. ['L', crispX, highPlot],
  3439. // stem down
  3440. ['M', crispX, q1Plot],
  3441. ['L', crispX, lowPlot]
  3442. ];
  3443. point.stem[verb]({ d: d });
  3444. // The box
  3445. if (doQuartiles) {
  3446. crispCorr = (point.box.strokeWidth() % 2) / 2;
  3447. q1Plot = Math.floor(q1Plot) + crispCorr;
  3448. q3Plot = Math.floor(q3Plot) + crispCorr;
  3449. left += crispCorr;
  3450. right += crispCorr;
  3451. d = [
  3452. ['M', left, q3Plot],
  3453. ['L', left, q1Plot],
  3454. ['L', right, q1Plot],
  3455. ['L', right, q3Plot],
  3456. ['L', left, q3Plot],
  3457. ['Z']
  3458. ];
  3459. point.box[verb]({ d: d });
  3460. }
  3461. // The whiskers
  3462. if (whiskerLength) {
  3463. crispCorr = (point.whiskers.strokeWidth() % 2) / 2;
  3464. highPlot = highPlot + crispCorr;
  3465. lowPlot = lowPlot + crispCorr;
  3466. pointWiskerLength = (/%$/).test(whiskerLength) ?
  3467. halfWidth * parseFloat(whiskerLength) / 100 :
  3468. whiskerLength / 2;
  3469. d = [
  3470. // High whisker
  3471. ['M', crispX - pointWiskerLength, highPlot],
  3472. ['L', crispX + pointWiskerLength, highPlot],
  3473. // Low whisker
  3474. ['M', crispX - pointWiskerLength, lowPlot],
  3475. ['L', crispX + pointWiskerLength, lowPlot]
  3476. ];
  3477. point.whiskers[verb]({ d: d });
  3478. }
  3479. // The median
  3480. medianPlot = Math.round(point.medianPlot);
  3481. crispCorr = (point.medianShape.strokeWidth() % 2) / 2;
  3482. medianPlot = medianPlot + crispCorr;
  3483. d = [
  3484. ['M', left, medianPlot],
  3485. ['L', right, medianPlot]
  3486. ];
  3487. point.medianShape[verb]({ d: d });
  3488. }
  3489. });
  3490. },
  3491. setStackedPoints: noop // #3890
  3492. });
  3493. /**
  3494. * A `boxplot` series. If the [type](#series.boxplot.type) option is
  3495. * not specified, it is inherited from [chart.type](#chart.type).
  3496. *
  3497. * @extends series,plotOptions.boxplot
  3498. * @excluding dataParser, dataURL, marker, stack, stacking, states
  3499. * @product highcharts
  3500. * @requires highcharts-more
  3501. * @apioption series.boxplot
  3502. */
  3503. /**
  3504. * An array of data points for the series. For the `boxplot` series
  3505. * type, points can be given in the following ways:
  3506. *
  3507. * 1. An array of arrays with 6 or 5 values. In this case, the values correspond
  3508. * to `x,low,q1,median,q3,high`. If the first value is a string, it is
  3509. * applied as the name of the point, and the `x` value is inferred. The `x`
  3510. * value can also be omitted, in which case the inner arrays should be of
  3511. * length 5. Then the `x` value is automatically calculated, either starting
  3512. * at 0 and incremented by 1, or from `pointStart` and `pointInterval` given
  3513. * in the series options.
  3514. * ```js
  3515. * data: [
  3516. * [0, 3, 0, 10, 3, 5],
  3517. * [1, 7, 8, 7, 2, 9],
  3518. * [2, 6, 9, 5, 1, 3]
  3519. * ]
  3520. * ```
  3521. *
  3522. * 2. An array of objects with named values. The following snippet shows only a
  3523. * few settings, see the complete options set below. If the total number of
  3524. * data points exceeds the series'
  3525. * [turboThreshold](#series.boxplot.turboThreshold), this option is not
  3526. * available.
  3527. * ```js
  3528. * data: [{
  3529. * x: 1,
  3530. * low: 4,
  3531. * q1: 9,
  3532. * median: 9,
  3533. * q3: 1,
  3534. * high: 10,
  3535. * name: "Point2",
  3536. * color: "#00FF00"
  3537. * }, {
  3538. * x: 1,
  3539. * low: 5,
  3540. * q1: 7,
  3541. * median: 3,
  3542. * q3: 6,
  3543. * high: 2,
  3544. * name: "Point1",
  3545. * color: "#FF00FF"
  3546. * }]
  3547. * ```
  3548. *
  3549. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  3550. * Arrays of numeric x and y
  3551. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  3552. * Arrays of datetime x and y
  3553. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  3554. * Arrays of point.name and y
  3555. * @sample {highcharts} highcharts/series/data-array-of-objects/
  3556. * Config objects
  3557. *
  3558. * @type {Array<Array<(number|string),number,number,number,number>|Array<(number|string),number,number,number,number,number>|*>}
  3559. * @extends series.line.data
  3560. * @excluding marker
  3561. * @product highcharts
  3562. * @apioption series.boxplot.data
  3563. */
  3564. /**
  3565. * The `high` value for each data point, signifying the highest value
  3566. * in the sample set. The top whisker is drawn here.
  3567. *
  3568. * @type {number}
  3569. * @product highcharts
  3570. * @apioption series.boxplot.data.high
  3571. */
  3572. /**
  3573. * The `low` value for each data point, signifying the lowest value
  3574. * in the sample set. The bottom whisker is drawn here.
  3575. *
  3576. * @type {number}
  3577. * @product highcharts
  3578. * @apioption series.boxplot.data.low
  3579. */
  3580. /**
  3581. * The median for each data point. This is drawn as a line through the
  3582. * middle area of the box.
  3583. *
  3584. * @type {number}
  3585. * @product highcharts
  3586. * @apioption series.boxplot.data.median
  3587. */
  3588. /**
  3589. * The lower quartile for each data point. This is the bottom of the
  3590. * box.
  3591. *
  3592. * @type {number}
  3593. * @product highcharts
  3594. * @apioption series.boxplot.data.q1
  3595. */
  3596. /**
  3597. * The higher quartile for each data point. This is the top of the box.
  3598. *
  3599. * @type {number}
  3600. * @product highcharts
  3601. * @apioption series.boxplot.data.q3
  3602. */
  3603. /**
  3604. * The dash style of the box.
  3605. *
  3606. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3607. * Box plot styling
  3608. * @sample {highcharts} highcharts/css/boxplot/
  3609. * Box plot in styled mode
  3610. *
  3611. * @type {Highcharts.DashStyleValue}
  3612. * @default Solid
  3613. * @since 8.1.0
  3614. * @product highcharts
  3615. * @apioption series.boxplot.data.boxDashStyle
  3616. */
  3617. /**
  3618. * The dash style of the median.
  3619. *
  3620. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3621. * Box plot styling
  3622. * @sample {highcharts} highcharts/css/boxplot/
  3623. * Box plot in styled mode
  3624. *
  3625. * @type {Highcharts.DashStyleValue}
  3626. * @default Solid
  3627. * @since 8.1.0
  3628. * @product highcharts
  3629. * @apioption series.boxplot.data.medianDashStyle
  3630. */
  3631. /**
  3632. * The dash style of the stem.
  3633. *
  3634. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3635. * Box plot styling
  3636. * @sample {highcharts} highcharts/css/boxplot/
  3637. * Box plot in styled mode
  3638. *
  3639. * @type {Highcharts.DashStyleValue}
  3640. * @default Solid
  3641. * @since 8.1.0
  3642. * @product highcharts
  3643. * @apioption series.boxplot.data.stemDashStyle
  3644. */
  3645. /**
  3646. * The dash style of the whiskers.
  3647. *
  3648. * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
  3649. * Box plot styling
  3650. * @sample {highcharts} highcharts/css/boxplot/
  3651. * Box plot in styled mode
  3652. *
  3653. * @type {Highcharts.DashStyleValue}
  3654. * @default Solid
  3655. * @since 8.1.0
  3656. * @product highcharts
  3657. * @apioption series.boxplot.data.whiskerDashStyle
  3658. */
  3659. ''; // adds doclets above to transpiled file
  3660. });
  3661. _registerModule(_modules, 'parts-more/ErrorBarSeries.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
  3662. /* *
  3663. *
  3664. * (c) 2010-2020 Torstein Honsi
  3665. *
  3666. * License: www.highcharts.com/license
  3667. *
  3668. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  3669. *
  3670. * */
  3671. var seriesType = U.seriesType;
  3672. var noop = H.noop, seriesTypes = H.seriesTypes;
  3673. /**
  3674. * Error bars are a graphical representation of the variability of data and are
  3675. * used on graphs to indicate the error, or uncertainty in a reported
  3676. * measurement.
  3677. *
  3678. * @sample highcharts/demo/error-bar/
  3679. * Error bars on a column series
  3680. * @sample highcharts/series-errorbar/on-scatter/
  3681. * Error bars on a scatter series
  3682. *
  3683. * @extends plotOptions.boxplot
  3684. * @product highcharts highstock
  3685. * @requires highcharts-more
  3686. * @optionparent plotOptions.errorbar
  3687. */
  3688. seriesType('errorbar', 'boxplot', {
  3689. /**
  3690. * The main color of the bars. This can be overridden by
  3691. * [stemColor](#plotOptions.errorbar.stemColor) and
  3692. * [whiskerColor](#plotOptions.errorbar.whiskerColor) individually.
  3693. *
  3694. * @sample {highcharts} highcharts/plotoptions/error-bar-styling/
  3695. * Error bar styling
  3696. *
  3697. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  3698. * @default #000000
  3699. * @since 3.0
  3700. * @product highcharts
  3701. */
  3702. color: '#000000',
  3703. grouping: false,
  3704. /**
  3705. * The parent series of the error bar. The default value links it to
  3706. * the previous series. Otherwise, use the id of the parent series.
  3707. *
  3708. * @since 3.0
  3709. * @product highcharts
  3710. */
  3711. linkedTo: ':previous',
  3712. tooltip: {
  3713. pointFormat: '<span style="color:{point.color}">\u25CF</span> {series.name}: <b>{point.low}</b> - <b>{point.high}</b><br/>'
  3714. },
  3715. /**
  3716. * The line width of the whiskers, the horizontal lines marking low
  3717. * and high values. When `null`, the general
  3718. * [lineWidth](#plotOptions.errorbar.lineWidth) applies.
  3719. *
  3720. * @sample {highcharts} highcharts/plotoptions/error-bar-styling/
  3721. * Error bar styling
  3722. *
  3723. * @type {number}
  3724. * @since 3.0
  3725. * @product highcharts
  3726. */
  3727. whiskerWidth: null
  3728. // Prototype members
  3729. }, {
  3730. type: 'errorbar',
  3731. // array point configs are mapped to this
  3732. pointArrayMap: ['low', 'high'],
  3733. // return a plain array for speedy calculation
  3734. toYData: function (point) {
  3735. return [point.low, point.high];
  3736. },
  3737. pointValKey: 'high',
  3738. doQuartiles: false,
  3739. drawDataLabels: seriesTypes.arearange ?
  3740. function () {
  3741. var valKey = this.pointValKey;
  3742. seriesTypes.arearange.prototype.drawDataLabels.call(this);
  3743. // Arearange drawDataLabels does not reset point.y to high,
  3744. // but to low after drawing (#4133)
  3745. this.data.forEach(function (point) {
  3746. point.y = point[valKey];
  3747. });
  3748. } :
  3749. noop,
  3750. // Get the width and X offset, either on top of the linked series column or
  3751. // standalone
  3752. getColumnMetrics: function () {
  3753. return ((this.linkedParent && this.linkedParent.columnMetrics) ||
  3754. seriesTypes.column.prototype.getColumnMetrics.call(this));
  3755. }
  3756. });
  3757. /**
  3758. * A `errorbar` series. If the [type](#series.errorbar.type) option
  3759. * is not specified, it is inherited from [chart.type](#chart.type).
  3760. *
  3761. * @extends series,plotOptions.errorbar
  3762. * @excluding dataParser, dataURL, stack, stacking
  3763. * @product highcharts
  3764. * @requires highcharts-more
  3765. * @apioption series.errorbar
  3766. */
  3767. /**
  3768. * An array of data points for the series. For the `errorbar` series
  3769. * type, points can be given in the following ways:
  3770. *
  3771. * 1. An array of arrays with 3 or 2 values. In this case, the values correspond
  3772. * to `x,low,high`. If the first value is a string, it is applied as the name
  3773. * of the point, and the `x` value is inferred. The `x` value can also be
  3774. * omitted, in which case the inner arrays should be of length 2\. Then the
  3775. * `x` value is automatically calculated, either starting at 0 and
  3776. * incremented by 1, or from `pointStart` and `pointInterval` given in the
  3777. * series options.
  3778. * ```js
  3779. * data: [
  3780. * [0, 10, 2],
  3781. * [1, 1, 8],
  3782. * [2, 4, 5]
  3783. * ]
  3784. * ```
  3785. *
  3786. * 2. An array of objects with named values. The following snippet shows only a
  3787. * few settings, see the complete options set below. If the total number of
  3788. * data points exceeds the series'
  3789. * [turboThreshold](#series.errorbar.turboThreshold), this option is not
  3790. * available.
  3791. * ```js
  3792. * data: [{
  3793. * x: 1,
  3794. * low: 0,
  3795. * high: 0,
  3796. * name: "Point2",
  3797. * color: "#00FF00"
  3798. * }, {
  3799. * x: 1,
  3800. * low: 5,
  3801. * high: 5,
  3802. * name: "Point1",
  3803. * color: "#FF00FF"
  3804. * }]
  3805. * ```
  3806. *
  3807. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  3808. * Arrays of numeric x and y
  3809. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  3810. * Arrays of datetime x and y
  3811. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  3812. * Arrays of point.name and y
  3813. * @sample {highcharts} highcharts/series/data-array-of-objects/
  3814. * Config objects
  3815. *
  3816. * @type {Array<Array<(number|string),number>|Array<(number|string),number,number>|*>}
  3817. * @extends series.arearange.data
  3818. * @excluding dataLabels, drilldown, marker, states
  3819. * @product highcharts
  3820. * @apioption series.errorbar.data
  3821. */
  3822. ''; // adds doclets above to transpiled file
  3823. });
  3824. _registerModule(_modules, 'parts-more/WaterfallSeries.js', [_modules['parts/Axis.js'], _modules['parts/Chart.js'], _modules['parts/Globals.js'], _modules['parts/Point.js'], _modules['parts/Stacking.js'], _modules['parts/Utilities.js']], function (Axis, Chart, H, Point, StackItem, U) {
  3825. /* *
  3826. *
  3827. * (c) 2010-2020 Torstein Honsi
  3828. *
  3829. * License: www.highcharts.com/license
  3830. *
  3831. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  3832. *
  3833. * */
  3834. var addEvent = U.addEvent, arrayMax = U.arrayMax, arrayMin = U.arrayMin, correctFloat = U.correctFloat, isNumber = U.isNumber, objectEach = U.objectEach, pick = U.pick, seriesType = U.seriesType;
  3835. var Series = H.Series, seriesTypes = H.seriesTypes;
  3836. /**
  3837. * Returns true if the key is a direct property of the object.
  3838. * @private
  3839. * @param {*} obj - Object with property to test
  3840. * @param {string} key - Property key to test
  3841. * @return {boolean} - Whether it is a direct property
  3842. */
  3843. function ownProp(obj, key) {
  3844. return Object.hasOwnProperty.call(obj, key);
  3845. }
  3846. /**
  3847. * @private
  3848. */
  3849. var WaterfallAxis;
  3850. (function (WaterfallAxis) {
  3851. /* *
  3852. *
  3853. * Interfaces
  3854. *
  3855. * */
  3856. /* *
  3857. *
  3858. * Classes
  3859. *
  3860. * */
  3861. /**
  3862. * @private
  3863. */
  3864. var Composition = /** @class */ (function () {
  3865. /* *
  3866. *
  3867. * Constructors
  3868. *
  3869. * */
  3870. /**
  3871. * @private
  3872. */
  3873. function Composition(axis) {
  3874. this.axis = axis;
  3875. this.stacks = {
  3876. changed: false
  3877. };
  3878. }
  3879. /* *
  3880. *
  3881. * Functions
  3882. *
  3883. * */
  3884. /**
  3885. * Calls StackItem.prototype.render function that creates and renders
  3886. * stack total label for each waterfall stack item.
  3887. *
  3888. * @private
  3889. * @function Highcharts.Axis#renderWaterfallStackTotals
  3890. */
  3891. Composition.prototype.renderStackTotals = function () {
  3892. var yAxis = this.axis, waterfallStacks = yAxis.waterfall.stacks, stackTotalGroup = yAxis.stacking && yAxis.stacking.stackTotalGroup, dummyStackItem = new StackItem(yAxis, yAxis.options.stackLabels, false, 0, void 0);
  3893. this.dummyStackItem = dummyStackItem;
  3894. // Render each waterfall stack total
  3895. objectEach(waterfallStacks, function (type) {
  3896. objectEach(type, function (stackItem) {
  3897. dummyStackItem.total = stackItem.stackTotal;
  3898. if (stackItem.label) {
  3899. dummyStackItem.label = stackItem.label;
  3900. }
  3901. StackItem.prototype.render.call(dummyStackItem, stackTotalGroup);
  3902. stackItem.label = dummyStackItem.label;
  3903. delete dummyStackItem.label;
  3904. });
  3905. });
  3906. dummyStackItem.total = null;
  3907. };
  3908. return Composition;
  3909. }());
  3910. WaterfallAxis.Composition = Composition;
  3911. /* *
  3912. *
  3913. * Functions
  3914. *
  3915. * */
  3916. /**
  3917. * @private
  3918. */
  3919. function compose(AxisClass, ChartClass) {
  3920. addEvent(AxisClass, 'init', onInit);
  3921. addEvent(AxisClass, 'afterBuildStacks', onAfterBuildStacks);
  3922. addEvent(AxisClass, 'afterRender', onAfterRender);
  3923. addEvent(ChartClass, 'beforeRedraw', onBeforeRedraw);
  3924. }
  3925. WaterfallAxis.compose = compose;
  3926. /**
  3927. * @private
  3928. */
  3929. function onAfterBuildStacks() {
  3930. var axis = this;
  3931. var stacks = axis.waterfall.stacks;
  3932. if (stacks) {
  3933. stacks.changed = false;
  3934. delete stacks.alreadyChanged;
  3935. }
  3936. }
  3937. /**
  3938. * @private
  3939. */
  3940. function onAfterRender() {
  3941. var axis = this;
  3942. var stackLabelOptions = axis.options.stackLabels;
  3943. if (stackLabelOptions && stackLabelOptions.enabled &&
  3944. axis.waterfall.stacks) {
  3945. axis.waterfall.renderStackTotals();
  3946. }
  3947. }
  3948. /**
  3949. * @private
  3950. */
  3951. function onBeforeRedraw() {
  3952. var axes = this.axes, series = this.series, i = series.length;
  3953. while (i--) {
  3954. if (series[i].options.stacking) {
  3955. axes.forEach(function (axis) {
  3956. if (!axis.isXAxis) {
  3957. axis.waterfall.stacks.changed = true;
  3958. }
  3959. });
  3960. i = 0;
  3961. }
  3962. }
  3963. }
  3964. /**
  3965. * @private
  3966. */
  3967. function onInit() {
  3968. var axis = this;
  3969. if (!axis.waterfall) {
  3970. axis.waterfall = new Composition(axis);
  3971. }
  3972. }
  3973. })(WaterfallAxis || (WaterfallAxis = {}));
  3974. // eslint-disable-next-line valid-jsdoc
  3975. /**
  3976. * A waterfall chart displays sequentially introduced positive or negative
  3977. * values in cumulative columns.
  3978. *
  3979. * @sample highcharts/demo/waterfall/
  3980. * Waterfall chart
  3981. * @sample highcharts/plotoptions/waterfall-inverted/
  3982. * Horizontal (inverted) waterfall
  3983. * @sample highcharts/plotoptions/waterfall-stacked/
  3984. * Stacked waterfall chart
  3985. *
  3986. * @extends plotOptions.column
  3987. * @product highcharts
  3988. * @requires highcharts-more
  3989. * @optionparent plotOptions.waterfall
  3990. */
  3991. seriesType('waterfall', 'column', {
  3992. /**
  3993. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  3994. * @apioption plotOptions.waterfall.color
  3995. */
  3996. /**
  3997. * The color used specifically for positive point columns. When not
  3998. * specified, the general series color is used.
  3999. *
  4000. * In styled mode, the waterfall colors can be set with the
  4001. * `.highcharts-point-negative`, `.highcharts-sum` and
  4002. * `.highcharts-intermediate-sum` classes.
  4003. *
  4004. * @sample {highcharts} highcharts/demo/waterfall/
  4005. * Waterfall
  4006. *
  4007. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  4008. * @product highcharts
  4009. * @apioption plotOptions.waterfall.upColor
  4010. */
  4011. dataLabels: {
  4012. inside: true
  4013. },
  4014. /**
  4015. * The width of the line connecting waterfall columns.
  4016. *
  4017. * @product highcharts
  4018. */
  4019. lineWidth: 1,
  4020. /**
  4021. * The color of the line that connects columns in a waterfall series.
  4022. *
  4023. * In styled mode, the stroke can be set with the `.highcharts-graph` class.
  4024. *
  4025. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  4026. * @since 3.0
  4027. * @product highcharts
  4028. */
  4029. lineColor: '#333333',
  4030. /**
  4031. * A name for the dash style to use for the line connecting the columns
  4032. * of the waterfall series. Possible values: Dash, DashDot, Dot, LongDash,
  4033. * LongDashDot, LongDashDotDot, ShortDash, ShortDashDot, ShortDashDotDot,
  4034. * ShortDot, Solid
  4035. *
  4036. * In styled mode, the stroke dash-array can be set with the
  4037. * `.highcharts-graph` class.
  4038. *
  4039. * @type {Highcharts.DashStyleValue}
  4040. * @since 3.0
  4041. * @product highcharts
  4042. */
  4043. dashStyle: 'Dot',
  4044. /**
  4045. * The color of the border of each waterfall column.
  4046. *
  4047. * In styled mode, the border stroke can be set with the
  4048. * `.highcharts-point` class.
  4049. *
  4050. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  4051. * @since 3.0
  4052. * @product highcharts
  4053. */
  4054. borderColor: '#333333',
  4055. states: {
  4056. hover: {
  4057. lineWidthPlus: 0 // #3126
  4058. }
  4059. }
  4060. // Prototype members
  4061. }, {
  4062. pointValKey: 'y',
  4063. // Property needed to prevent lines between the columns from disappearing
  4064. // when negativeColor is used.
  4065. showLine: true,
  4066. // After generating points, set y-values for all sums.
  4067. generatePoints: function () {
  4068. var point, len, i, y;
  4069. // Parent call:
  4070. seriesTypes.column.prototype.generatePoints.apply(this);
  4071. for (i = 0, len = this.points.length; i < len; i++) {
  4072. point = this.points[i];
  4073. y = this.processedYData[i];
  4074. // override point value for sums
  4075. // #3710 Update point does not propagate to sum
  4076. if (point.isIntermediateSum || point.isSum) {
  4077. point.y = correctFloat(y);
  4078. }
  4079. }
  4080. },
  4081. // Translate data points from raw values
  4082. translate: function () {
  4083. var series = this, options = series.options, yAxis = series.yAxis, len, i, points, point, shapeArgs, y, yValue, previousY, previousIntermediate, range, minPointLength = pick(options.minPointLength, 5), halfMinPointLength = minPointLength / 2, threshold = options.threshold, stacking = options.stacking, tooltipY, actualStack = yAxis.waterfall.stacks[series.stackKey], actualStackX, dummyStackItem, total, pointY, yPos, hPos;
  4084. // run column series translate
  4085. seriesTypes.column.prototype.translate.apply(series);
  4086. previousY = previousIntermediate = threshold;
  4087. points = series.points;
  4088. for (i = 0, len = points.length; i < len; i++) {
  4089. // cache current point object
  4090. point = points[i];
  4091. yValue = series.processedYData[i];
  4092. shapeArgs = point.shapeArgs;
  4093. range = [0, yValue];
  4094. pointY = point.y;
  4095. // code responsible for correct positions of stacked points
  4096. // starts here
  4097. if (stacking) {
  4098. if (actualStack) {
  4099. actualStackX = actualStack[i];
  4100. if (stacking === 'overlap') {
  4101. total =
  4102. actualStackX.stackState[actualStackX.stateIndex--];
  4103. y = pointY >= 0 ? total : total - pointY;
  4104. if (ownProp(actualStackX, 'absolutePos')) {
  4105. delete actualStackX.absolutePos;
  4106. }
  4107. if (ownProp(actualStackX, 'absoluteNeg')) {
  4108. delete actualStackX.absoluteNeg;
  4109. }
  4110. }
  4111. else {
  4112. if (pointY >= 0) {
  4113. total = actualStackX.threshold +
  4114. actualStackX.posTotal;
  4115. actualStackX.posTotal -= pointY;
  4116. y = total;
  4117. }
  4118. else {
  4119. total = actualStackX.threshold +
  4120. actualStackX.negTotal;
  4121. actualStackX.negTotal -= pointY;
  4122. y = total - pointY;
  4123. }
  4124. if (!actualStackX.posTotal) {
  4125. if (ownProp(actualStackX, 'absolutePos')) {
  4126. actualStackX.posTotal =
  4127. actualStackX.absolutePos;
  4128. delete actualStackX.absolutePos;
  4129. }
  4130. }
  4131. if (!actualStackX.negTotal) {
  4132. if (ownProp(actualStackX, 'absoluteNeg')) {
  4133. actualStackX.negTotal =
  4134. actualStackX.absoluteNeg;
  4135. delete actualStackX.absoluteNeg;
  4136. }
  4137. }
  4138. }
  4139. if (!point.isSum) {
  4140. // the connectorThreshold property is later used in
  4141. // getCrispPath function to draw a connector line in a
  4142. // correct place
  4143. actualStackX.connectorThreshold =
  4144. actualStackX.threshold + actualStackX.stackTotal;
  4145. }
  4146. if (yAxis.reversed) {
  4147. yPos = (pointY >= 0) ? (y - pointY) : (y + pointY);
  4148. hPos = y;
  4149. }
  4150. else {
  4151. yPos = y;
  4152. hPos = y - pointY;
  4153. }
  4154. point.below = yPos <= pick(threshold, 0);
  4155. shapeArgs.y = yAxis.translate(yPos, 0, 1, 0, 1);
  4156. shapeArgs.height = Math.abs(shapeArgs.y -
  4157. yAxis.translate(hPos, 0, 1, 0, 1));
  4158. }
  4159. dummyStackItem = yAxis.waterfall.dummyStackItem;
  4160. if (dummyStackItem) {
  4161. dummyStackItem.x = i;
  4162. dummyStackItem.label = actualStack[i].label;
  4163. dummyStackItem.setOffset(series.pointXOffset || 0, series.barW || 0, series.stackedYNeg[i], series.stackedYPos[i]);
  4164. }
  4165. }
  4166. else {
  4167. // up points
  4168. y =
  4169. Math.max(previousY, previousY + pointY) + range[0];
  4170. shapeArgs.y =
  4171. yAxis.translate(y, 0, 1, 0, 1);
  4172. // sum points
  4173. if (point.isSum) {
  4174. shapeArgs.y = yAxis.translate(range[1], 0, 1, 0, 1);
  4175. shapeArgs.height = Math.min(yAxis.translate(range[0], 0, 1, 0, 1), yAxis.len) - shapeArgs.y; // #4256
  4176. }
  4177. else if (point.isIntermediateSum) {
  4178. if (pointY >= 0) {
  4179. yPos = range[1] + previousIntermediate;
  4180. hPos = previousIntermediate;
  4181. }
  4182. else {
  4183. yPos = previousIntermediate;
  4184. hPos = range[1] + previousIntermediate;
  4185. }
  4186. if (yAxis.reversed) {
  4187. // swapping values
  4188. yPos ^= hPos;
  4189. hPos ^= yPos;
  4190. yPos ^= hPos;
  4191. }
  4192. shapeArgs.y = yAxis.translate(yPos, 0, 1, 0, 1);
  4193. shapeArgs.height = Math.abs(shapeArgs.y -
  4194. Math.min(yAxis.translate(hPos, 0, 1, 0, 1), yAxis.len));
  4195. previousIntermediate += range[1];
  4196. // If it's not the sum point, update previous stack end position
  4197. // and get shape height (#3886)
  4198. }
  4199. else {
  4200. shapeArgs.height = yValue > 0 ?
  4201. yAxis.translate(previousY, 0, 1, 0, 1) - shapeArgs.y :
  4202. yAxis.translate(previousY, 0, 1, 0, 1) - yAxis.translate(previousY - yValue, 0, 1, 0, 1);
  4203. previousY += yValue;
  4204. point.below = previousY < pick(threshold, 0);
  4205. }
  4206. // #3952 Negative sum or intermediate sum not rendered correctly
  4207. if (shapeArgs.height < 0) {
  4208. shapeArgs.y += shapeArgs.height;
  4209. shapeArgs.height *= -1;
  4210. }
  4211. }
  4212. point.plotY = shapeArgs.y =
  4213. Math.round(shapeArgs.y) - (series.borderWidth % 2) / 2;
  4214. // #3151
  4215. shapeArgs.height =
  4216. Math.max(Math.round(shapeArgs.height), 0.001);
  4217. point.yBottom = shapeArgs.y + shapeArgs.height;
  4218. if (shapeArgs.height <= minPointLength && !point.isNull) {
  4219. shapeArgs.height = minPointLength;
  4220. shapeArgs.y -= halfMinPointLength;
  4221. point.plotY = shapeArgs.y;
  4222. if (point.y < 0) {
  4223. point.minPointLengthOffset = -halfMinPointLength;
  4224. }
  4225. else {
  4226. point.minPointLengthOffset = halfMinPointLength;
  4227. }
  4228. }
  4229. else {
  4230. if (point.isNull) {
  4231. shapeArgs.width = 0;
  4232. }
  4233. point.minPointLengthOffset = 0;
  4234. }
  4235. // Correct tooltip placement (#3014)
  4236. tooltipY =
  4237. point.plotY + (point.negative ? shapeArgs.height : 0);
  4238. if (series.chart.inverted) {
  4239. point.tooltipPos[0] = yAxis.len - tooltipY;
  4240. }
  4241. else {
  4242. point.tooltipPos[1] = tooltipY;
  4243. }
  4244. }
  4245. },
  4246. // Call default processData then override yData to reflect waterfall's
  4247. // extremes on yAxis
  4248. processData: function (force) {
  4249. var series = this, options = series.options, yData = series.yData,
  4250. // #3710 Update point does not propagate to sum
  4251. points = options.data, point, dataLength = yData.length, threshold = options.threshold || 0, subSum, sum, dataMin, dataMax, y, i;
  4252. sum = subSum = dataMin = dataMax = 0;
  4253. for (i = 0; i < dataLength; i++) {
  4254. y = yData[i];
  4255. point = points && points[i] ? points[i] : {};
  4256. if (y === 'sum' || point.isSum) {
  4257. yData[i] = correctFloat(sum);
  4258. }
  4259. else if (y === 'intermediateSum' ||
  4260. point.isIntermediateSum) {
  4261. yData[i] = correctFloat(subSum);
  4262. subSum = 0;
  4263. }
  4264. else {
  4265. sum += y;
  4266. subSum += y;
  4267. }
  4268. dataMin = Math.min(sum, dataMin);
  4269. dataMax = Math.max(sum, dataMax);
  4270. }
  4271. Series.prototype.processData.call(this, force);
  4272. // Record extremes only if stacking was not set:
  4273. if (!options.stacking) {
  4274. series.dataMin = dataMin + threshold;
  4275. series.dataMax = dataMax;
  4276. }
  4277. return;
  4278. },
  4279. // Return y value or string if point is sum
  4280. toYData: function (pt) {
  4281. if (pt.isSum) {
  4282. return 'sum';
  4283. }
  4284. if (pt.isIntermediateSum) {
  4285. return 'intermediateSum';
  4286. }
  4287. return pt.y;
  4288. },
  4289. updateParallelArrays: function (point, i) {
  4290. Series.prototype.updateParallelArrays.call(this, point, i);
  4291. // Prevent initial sums from triggering an error (#3245, #7559)
  4292. if (this.yData[0] === 'sum' || this.yData[0] === 'intermediateSum') {
  4293. this.yData[0] = null;
  4294. }
  4295. },
  4296. // Postprocess mapping between options and SVG attributes
  4297. pointAttribs: function (point, state) {
  4298. var upColor = this.options.upColor, attr;
  4299. // Set or reset up color (#3710, update to negative)
  4300. if (upColor && !point.options.color) {
  4301. point.color = point.y > 0 ? upColor : null;
  4302. }
  4303. attr = seriesTypes.column.prototype.pointAttribs.call(this, point, state);
  4304. // The dashStyle option in waterfall applies to the graph, not
  4305. // the points
  4306. delete attr.dashstyle;
  4307. return attr;
  4308. },
  4309. // Return an empty path initially, because we need to know the stroke-width
  4310. // in order to set the final path.
  4311. getGraphPath: function () {
  4312. return [['M', 0, 0]];
  4313. },
  4314. // Draw columns' connector lines
  4315. getCrispPath: function () {
  4316. var data = this.data, yAxis = this.yAxis, length = data.length, graphNormalizer = Math.round(this.graph.strokeWidth()) % 2 / 2, borderNormalizer = Math.round(this.borderWidth) % 2 / 2, reversedXAxis = this.xAxis.reversed, reversedYAxis = this.yAxis.reversed, stacking = this.options.stacking, path = [], connectorThreshold, prevStack, prevStackX, prevPoint, yPos, isPos, prevArgs, pointArgs, i;
  4317. for (i = 1; i < length; i++) {
  4318. pointArgs = data[i].shapeArgs;
  4319. prevPoint = data[i - 1];
  4320. prevArgs = data[i - 1].shapeArgs;
  4321. prevStack = yAxis.waterfall.stacks[this.stackKey];
  4322. isPos = prevPoint.y > 0 ? -prevArgs.height : 0;
  4323. if (prevStack && prevArgs && pointArgs) {
  4324. prevStackX = prevStack[i - 1];
  4325. // y position of the connector is different when series are
  4326. // stacked, yAxis is reversed and it also depends on point's
  4327. // value
  4328. if (stacking) {
  4329. connectorThreshold = prevStackX.connectorThreshold;
  4330. yPos = Math.round((yAxis.translate(connectorThreshold, 0, 1, 0, 1) +
  4331. (reversedYAxis ? isPos : 0))) - graphNormalizer;
  4332. }
  4333. else {
  4334. yPos =
  4335. prevArgs.y + prevPoint.minPointLengthOffset +
  4336. borderNormalizer - graphNormalizer;
  4337. }
  4338. path.push([
  4339. 'M',
  4340. (prevArgs.x || 0) + (reversedXAxis ?
  4341. 0 :
  4342. (prevArgs.width || 0)),
  4343. yPos
  4344. ], [
  4345. 'L',
  4346. (pointArgs.x || 0) + (reversedXAxis ?
  4347. (pointArgs.width || 0) :
  4348. 0),
  4349. yPos
  4350. ]);
  4351. }
  4352. if (!stacking &&
  4353. path.length &&
  4354. prevArgs &&
  4355. ((prevPoint.y < 0 && !reversedYAxis) ||
  4356. (prevPoint.y > 0 && reversedYAxis))) {
  4357. path[path.length - 2][2] += prevArgs.height;
  4358. path[path.length - 1][2] += prevArgs.height;
  4359. }
  4360. }
  4361. return path;
  4362. },
  4363. // The graph is initially drawn with an empty definition, then updated with
  4364. // crisp rendering.
  4365. drawGraph: function () {
  4366. Series.prototype.drawGraph.call(this);
  4367. this.graph.attr({
  4368. d: this.getCrispPath()
  4369. });
  4370. },
  4371. // Waterfall has stacking along the x-values too.
  4372. setStackedPoints: function () {
  4373. var series = this, options = series.options, waterfallStacks = series.yAxis.waterfall.stacks, seriesThreshold = options.threshold, stackThreshold = seriesThreshold || 0, interSum = stackThreshold, stackKey = series.stackKey, xData = series.xData, xLength = xData.length, actualStack, actualStackX, totalYVal, actualSum, prevSum, statesLen, posTotal, negTotal, xPoint, yVal, x, alreadyChanged, changed;
  4374. // function responsible for calculating correct values for stackState
  4375. // array of each stack item. The arguments are: firstS - the value for
  4376. // the first state, nextS - the difference between the previous and the
  4377. // newest state, sInx - counter used in the for that updates each state
  4378. // when necessary, sOff - offset that must be added to each state when
  4379. // they need to be updated (if point isn't a total sum)
  4380. // eslint-disable-next-line require-jsdoc
  4381. function calculateStackState(firstS, nextS, sInx, sOff) {
  4382. if (!statesLen) {
  4383. actualStackX.stackState[0] = firstS;
  4384. statesLen = actualStackX.stackState.length;
  4385. }
  4386. else {
  4387. for (sInx; sInx < statesLen; sInx++) {
  4388. actualStackX.stackState[sInx] += sOff;
  4389. }
  4390. }
  4391. actualStackX.stackState.push(actualStackX.stackState[statesLen - 1] + nextS);
  4392. }
  4393. series.yAxis.stacking.usePercentage = false;
  4394. totalYVal = actualSum = prevSum = stackThreshold;
  4395. // code responsible for creating stacks for waterfall series
  4396. if (series.visible ||
  4397. !series.chart.options.chart.ignoreHiddenSeries) {
  4398. changed = waterfallStacks.changed;
  4399. alreadyChanged = waterfallStacks.alreadyChanged;
  4400. // in case of a redraw, stack for each x value must be
  4401. // emptied (only for the first series in a specific stack)
  4402. // and recalculated once more
  4403. if (alreadyChanged &&
  4404. alreadyChanged.indexOf(stackKey) < 0) {
  4405. changed = true;
  4406. }
  4407. if (!waterfallStacks[stackKey]) {
  4408. waterfallStacks[stackKey] = {};
  4409. }
  4410. actualStack = waterfallStacks[stackKey];
  4411. for (var i = 0; i < xLength; i++) {
  4412. x = xData[i];
  4413. if (!actualStack[x] || changed) {
  4414. actualStack[x] = {
  4415. negTotal: 0,
  4416. posTotal: 0,
  4417. stackTotal: 0,
  4418. threshold: 0,
  4419. stateIndex: 0,
  4420. stackState: [],
  4421. label: ((changed &&
  4422. actualStack[x]) ?
  4423. actualStack[x].label :
  4424. void 0)
  4425. };
  4426. }
  4427. actualStackX = actualStack[x];
  4428. yVal = series.yData[i];
  4429. if (yVal >= 0) {
  4430. actualStackX.posTotal += yVal;
  4431. }
  4432. else {
  4433. actualStackX.negTotal += yVal;
  4434. }
  4435. // points do not exist yet, so raw data is used
  4436. xPoint = options.data[i];
  4437. posTotal = actualStackX.absolutePos =
  4438. actualStackX.posTotal;
  4439. negTotal = actualStackX.absoluteNeg =
  4440. actualStackX.negTotal;
  4441. actualStackX.stackTotal = posTotal + negTotal;
  4442. statesLen = actualStackX.stackState.length;
  4443. if (xPoint && xPoint.isIntermediateSum) {
  4444. calculateStackState(prevSum, actualSum, 0, prevSum);
  4445. prevSum = actualSum;
  4446. actualSum = seriesThreshold;
  4447. // swapping values
  4448. stackThreshold ^= interSum;
  4449. interSum ^= stackThreshold;
  4450. stackThreshold ^= interSum;
  4451. }
  4452. else if (xPoint && xPoint.isSum) {
  4453. calculateStackState(seriesThreshold, totalYVal, statesLen);
  4454. stackThreshold = seriesThreshold;
  4455. }
  4456. else {
  4457. calculateStackState(stackThreshold, yVal, 0, totalYVal);
  4458. if (xPoint) {
  4459. totalYVal += yVal;
  4460. actualSum += yVal;
  4461. }
  4462. }
  4463. actualStackX.stateIndex++;
  4464. actualStackX.threshold = stackThreshold;
  4465. stackThreshold += actualStackX.stackTotal;
  4466. }
  4467. waterfallStacks.changed = false;
  4468. if (!waterfallStacks.alreadyChanged) {
  4469. waterfallStacks.alreadyChanged = [];
  4470. }
  4471. waterfallStacks.alreadyChanged.push(stackKey);
  4472. }
  4473. },
  4474. // Extremes for a non-stacked series are recorded in processData.
  4475. // In case of stacking, use Series.stackedYData to calculate extremes.
  4476. getExtremes: function () {
  4477. var stacking = this.options.stacking, yAxis, waterfallStacks, stackedYNeg, stackedYPos;
  4478. if (stacking) {
  4479. yAxis = this.yAxis;
  4480. waterfallStacks = yAxis.waterfall.stacks;
  4481. stackedYNeg = this.stackedYNeg = [];
  4482. stackedYPos = this.stackedYPos = [];
  4483. // the visible y range can be different when stacking is set to
  4484. // overlap and different when it's set to normal
  4485. if (stacking === 'overlap') {
  4486. objectEach(waterfallStacks[this.stackKey], function (stackX) {
  4487. stackedYNeg.push(arrayMin(stackX.stackState));
  4488. stackedYPos.push(arrayMax(stackX.stackState));
  4489. });
  4490. }
  4491. else {
  4492. objectEach(waterfallStacks[this.stackKey], function (stackX) {
  4493. stackedYNeg.push(stackX.negTotal + stackX.threshold);
  4494. stackedYPos.push(stackX.posTotal + stackX.threshold);
  4495. });
  4496. }
  4497. return {
  4498. dataMin: arrayMin(stackedYNeg),
  4499. dataMax: arrayMax(stackedYPos)
  4500. };
  4501. }
  4502. // When not stacking, data extremes have already been computed in the
  4503. // processData function.
  4504. return {
  4505. dataMin: this.dataMin,
  4506. dataMax: this.dataMax
  4507. };
  4508. }
  4509. // Point members
  4510. }, {
  4511. getClassName: function () {
  4512. var className = Point.prototype.getClassName.call(this);
  4513. if (this.isSum) {
  4514. className += ' highcharts-sum';
  4515. }
  4516. else if (this.isIntermediateSum) {
  4517. className += ' highcharts-intermediate-sum';
  4518. }
  4519. return className;
  4520. },
  4521. // Pass the null test in ColumnSeries.translate.
  4522. isValid: function () {
  4523. return (isNumber(this.y) ||
  4524. this.isSum ||
  4525. Boolean(this.isIntermediateSum));
  4526. }
  4527. });
  4528. /**
  4529. * A `waterfall` series. If the [type](#series.waterfall.type) option
  4530. * is not specified, it is inherited from [chart.type](#chart.type).
  4531. *
  4532. * @extends series,plotOptions.waterfall
  4533. * @excluding dataParser, dataURL
  4534. * @product highcharts
  4535. * @requires highcharts-more
  4536. * @apioption series.waterfall
  4537. */
  4538. /**
  4539. * An array of data points for the series. For the `waterfall` series
  4540. * type, points can be given in the following ways:
  4541. *
  4542. * 1. An array of numerical values. In this case, the numerical values will be
  4543. * interpreted as `y` options. The `x` values will be automatically
  4544. * calculated, either starting at 0 and incremented by 1, or from
  4545. * `pointStart` and `pointInterval` given in the series options. If the axis
  4546. * has categories, these will be used. Example:
  4547. * ```js
  4548. * data: [0, 5, 3, 5]
  4549. * ```
  4550. *
  4551. * 2. An array of arrays with 2 values. In this case, the values correspond to
  4552. * `x,y`. If the first value is a string, it is applied as the name of the
  4553. * point, and the `x` value is inferred.
  4554. * ```js
  4555. * data: [
  4556. * [0, 7],
  4557. * [1, 8],
  4558. * [2, 3]
  4559. * ]
  4560. * ```
  4561. *
  4562. * 3. An array of objects with named values. The following snippet shows only a
  4563. * few settings, see the complete options set below. If the total number of
  4564. * data points exceeds the series'
  4565. * [turboThreshold](#series.waterfall.turboThreshold), this option is not
  4566. * available.
  4567. * ```js
  4568. * data: [{
  4569. * x: 1,
  4570. * y: 8,
  4571. * name: "Point2",
  4572. * color: "#00FF00"
  4573. * }, {
  4574. * x: 1,
  4575. * y: 8,
  4576. * name: "Point1",
  4577. * color: "#FF00FF"
  4578. * }]
  4579. * ```
  4580. *
  4581. * @sample {highcharts} highcharts/chart/reflow-true/
  4582. * Numerical values
  4583. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  4584. * Arrays of numeric x and y
  4585. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  4586. * Arrays of datetime x and y
  4587. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  4588. * Arrays of point.name and y
  4589. * @sample {highcharts} highcharts/series/data-array-of-objects/
  4590. * Config objects
  4591. *
  4592. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  4593. * @extends series.line.data
  4594. * @excluding marker
  4595. * @product highcharts
  4596. * @apioption series.waterfall.data
  4597. */
  4598. /**
  4599. * When this property is true, the points acts as a summary column for
  4600. * the values added or substracted since the last intermediate sum,
  4601. * or since the start of the series. The `y` value is ignored.
  4602. *
  4603. * @sample {highcharts} highcharts/demo/waterfall/
  4604. * Waterfall
  4605. *
  4606. * @type {boolean}
  4607. * @default false
  4608. * @product highcharts
  4609. * @apioption series.waterfall.data.isIntermediateSum
  4610. */
  4611. /**
  4612. * When this property is true, the point display the total sum across
  4613. * the entire series. The `y` value is ignored.
  4614. *
  4615. * @sample {highcharts} highcharts/demo/waterfall/
  4616. * Waterfall
  4617. *
  4618. * @type {boolean}
  4619. * @default false
  4620. * @product highcharts
  4621. * @apioption series.waterfall.data.isSum
  4622. */
  4623. ''; // adds doclets above to transpiled file
  4624. WaterfallAxis.compose(Axis, Chart);
  4625. return WaterfallAxis;
  4626. });
  4627. _registerModule(_modules, 'parts-more/PolygonSeries.js', [_modules['parts/Globals.js'], _modules['mixins/legend-symbol.js'], _modules['parts/Utilities.js']], function (H, LegendSymbolMixin, U) {
  4628. /* *
  4629. *
  4630. * (c) 2010-2020 Torstein Honsi
  4631. *
  4632. * License: www.highcharts.com/license
  4633. *
  4634. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  4635. *
  4636. * */
  4637. var seriesType = U.seriesType;
  4638. var noop = H.noop, Series = H.Series, seriesTypes = H.seriesTypes;
  4639. /**
  4640. * A polygon series can be used to draw any freeform shape in the cartesian
  4641. * coordinate system. A fill is applied with the `color` option, and
  4642. * stroke is applied through `lineWidth` and `lineColor` options.
  4643. *
  4644. * @sample {highcharts} highcharts/demo/polygon/
  4645. * Polygon
  4646. * @sample {highstock} highcharts/demo/polygon/
  4647. * Polygon
  4648. *
  4649. * @extends plotOptions.scatter
  4650. * @since 4.1.0
  4651. * @excluding jitter, softThreshold, threshold, cluster
  4652. * @product highcharts highstock
  4653. * @requires highcharts-more
  4654. * @optionparent plotOptions.polygon
  4655. */
  4656. seriesType('polygon', 'scatter', {
  4657. marker: {
  4658. enabled: false,
  4659. states: {
  4660. hover: {
  4661. enabled: false
  4662. }
  4663. }
  4664. },
  4665. stickyTracking: false,
  4666. tooltip: {
  4667. followPointer: true,
  4668. pointFormat: ''
  4669. },
  4670. trackByArea: true
  4671. // Prototype members
  4672. }, {
  4673. type: 'polygon',
  4674. getGraphPath: function () {
  4675. var graphPath = Series.prototype.getGraphPath.call(this), i = graphPath.length + 1;
  4676. // Close all segments
  4677. while (i--) {
  4678. if ((i === graphPath.length || graphPath[i][0] === 'M') && i > 0) {
  4679. graphPath.splice(i, 0, ['Z']);
  4680. }
  4681. }
  4682. this.areaPath = graphPath;
  4683. return graphPath;
  4684. },
  4685. drawGraph: function () {
  4686. // Hack into the fill logic in area.drawGraph
  4687. this.options.fillColor = this.color;
  4688. seriesTypes.area.prototype.drawGraph.call(this);
  4689. },
  4690. drawLegendSymbol: LegendSymbolMixin.drawRectangle,
  4691. drawTracker: Series.prototype.drawTracker,
  4692. setStackedPoints: noop // No stacking points on polygons (#5310)
  4693. });
  4694. /**
  4695. * A `polygon` series. If the [type](#series.polygon.type) option is
  4696. * not specified, it is inherited from [chart.type](#chart.type).
  4697. *
  4698. * @extends series,plotOptions.polygon
  4699. * @excluding dataParser, dataURL, stack
  4700. * @product highcharts highstock
  4701. * @requires highcharts-more
  4702. * @apioption series.polygon
  4703. */
  4704. /**
  4705. * An array of data points for the series. For the `polygon` series
  4706. * type, points can be given in the following ways:
  4707. *
  4708. * 1. An array of numerical values. In this case, the numerical values will be
  4709. * interpreted as `y` options. The `x` values will be automatically
  4710. * calculated, either starting at 0 and incremented by 1, or from
  4711. * `pointStart` and `pointInterval` given in the series options. If the axis
  4712. * has categories, these will be used. Example:
  4713. * ```js
  4714. * data: [0, 5, 3, 5]
  4715. * ```
  4716. *
  4717. * 2. An array of arrays with 2 values. In this case, the values correspond to
  4718. * `x,y`. If the first value is a string, it is applied as the name of the
  4719. * point, and the `x` value is inferred.
  4720. * ```js
  4721. * data: [
  4722. * [0, 10],
  4723. * [1, 3],
  4724. * [2, 1]
  4725. * ]
  4726. * ```
  4727. *
  4728. * 3. An array of objects with named values. The following snippet shows only a
  4729. * few settings, see the complete options set below. If the total number of
  4730. * data points exceeds the series'
  4731. * [turboThreshold](#series.polygon.turboThreshold), this option is not
  4732. * available.
  4733. * ```js
  4734. * data: [{
  4735. * x: 1,
  4736. * y: 1,
  4737. * name: "Point2",
  4738. * color: "#00FF00"
  4739. * }, {
  4740. * x: 1,
  4741. * y: 8,
  4742. * name: "Point1",
  4743. * color: "#FF00FF"
  4744. * }]
  4745. * ```
  4746. *
  4747. * @sample {highcharts} highcharts/chart/reflow-true/
  4748. * Numerical values
  4749. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  4750. * Arrays of numeric x and y
  4751. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  4752. * Arrays of datetime x and y
  4753. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  4754. * Arrays of point.name and y
  4755. * @sample {highcharts} highcharts/series/data-array-of-objects/
  4756. * Config objects
  4757. *
  4758. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  4759. * @extends series.line.data
  4760. * @product highcharts highstock
  4761. * @apioption series.polygon.data
  4762. */
  4763. ''; // adds doclets above to transpiled file
  4764. });
  4765. _registerModule(_modules, 'parts-more/BubbleLegend.js', [_modules['parts/Chart.js'], _modules['parts/Color.js'], _modules['parts/Globals.js'], _modules['parts/Legend.js'], _modules['parts/Utilities.js']], function (Chart, Color, H, Legend, U) {
  4766. /* *
  4767. *
  4768. * (c) 2010-2020 Highsoft AS
  4769. *
  4770. * Author: Paweł Potaczek
  4771. *
  4772. * License: www.highcharts.com/license
  4773. *
  4774. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  4775. *
  4776. * */
  4777. var color = Color.parse;
  4778. var addEvent = U.addEvent, arrayMax = U.arrayMax, arrayMin = U.arrayMin, isNumber = U.isNumber, merge = U.merge, objectEach = U.objectEach, pick = U.pick, setOptions = U.setOptions, stableSort = U.stableSort, wrap = U.wrap;
  4779. /**
  4780. * @interface Highcharts.BubbleLegendFormatterContextObject
  4781. */ /**
  4782. * The center y position of the range.
  4783. * @name Highcharts.BubbleLegendFormatterContextObject#center
  4784. * @type {number}
  4785. */ /**
  4786. * The radius of the bubble range.
  4787. * @name Highcharts.BubbleLegendFormatterContextObject#radius
  4788. * @type {number}
  4789. */ /**
  4790. * The bubble value.
  4791. * @name Highcharts.BubbleLegendFormatterContextObject#value
  4792. * @type {number}
  4793. */
  4794. ''; // detach doclets above
  4795. var Series = H.Series, noop = H.noop;
  4796. setOptions({
  4797. legend: {
  4798. /**
  4799. * The bubble legend is an additional element in legend which
  4800. * presents the scale of the bubble series. Individual bubble ranges
  4801. * can be defined by user or calculated from series. In the case of
  4802. * automatically calculated ranges, a 1px margin of error is
  4803. * permitted.
  4804. *
  4805. * @since 7.0.0
  4806. * @product highcharts highstock highmaps
  4807. * @requires highcharts-more
  4808. * @optionparent legend.bubbleLegend
  4809. */
  4810. bubbleLegend: {
  4811. /**
  4812. * The color of the ranges borders, can be also defined for an
  4813. * individual range.
  4814. *
  4815. * @sample highcharts/bubble-legend/similartoseries/
  4816. * Similat look to the bubble series
  4817. * @sample highcharts/bubble-legend/bordercolor/
  4818. * Individual bubble border color
  4819. *
  4820. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  4821. */
  4822. borderColor: void 0,
  4823. /**
  4824. * The width of the ranges borders in pixels, can be also
  4825. * defined for an individual range.
  4826. */
  4827. borderWidth: 2,
  4828. /**
  4829. * An additional class name to apply to the bubble legend'
  4830. * circle graphical elements. This option does not replace
  4831. * default class names of the graphical element.
  4832. *
  4833. * @sample {highcharts} highcharts/css/bubble-legend/
  4834. * Styling by CSS
  4835. *
  4836. * @type {string}
  4837. */
  4838. className: void 0,
  4839. /**
  4840. * The main color of the bubble legend. Applies to ranges, if
  4841. * individual color is not defined.
  4842. *
  4843. * @sample highcharts/bubble-legend/similartoseries/
  4844. * Similat look to the bubble series
  4845. * @sample highcharts/bubble-legend/color/
  4846. * Individual bubble color
  4847. *
  4848. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  4849. */
  4850. color: void 0,
  4851. /**
  4852. * An additional class name to apply to the bubble legend's
  4853. * connector graphical elements. This option does not replace
  4854. * default class names of the graphical element.
  4855. *
  4856. * @sample {highcharts} highcharts/css/bubble-legend/
  4857. * Styling by CSS
  4858. *
  4859. * @type {string}
  4860. */
  4861. connectorClassName: void 0,
  4862. /**
  4863. * The color of the connector, can be also defined
  4864. * for an individual range.
  4865. *
  4866. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  4867. */
  4868. connectorColor: void 0,
  4869. /**
  4870. * The length of the connectors in pixels. If labels are
  4871. * centered, the distance is reduced to 0.
  4872. *
  4873. * @sample highcharts/bubble-legend/connectorandlabels/
  4874. * Increased connector length
  4875. */
  4876. connectorDistance: 60,
  4877. /**
  4878. * The width of the connectors in pixels.
  4879. *
  4880. * @sample highcharts/bubble-legend/connectorandlabels/
  4881. * Increased connector width
  4882. */
  4883. connectorWidth: 1,
  4884. /**
  4885. * Enable or disable the bubble legend.
  4886. */
  4887. enabled: false,
  4888. /**
  4889. * Options for the bubble legend labels.
  4890. */
  4891. labels: {
  4892. /**
  4893. * An additional class name to apply to the bubble legend
  4894. * label graphical elements. This option does not replace
  4895. * default class names of the graphical element.
  4896. *
  4897. * @sample {highcharts} highcharts/css/bubble-legend/
  4898. * Styling by CSS
  4899. *
  4900. * @type {string}
  4901. */
  4902. className: void 0,
  4903. /**
  4904. * Whether to allow data labels to overlap.
  4905. */
  4906. allowOverlap: false,
  4907. /**
  4908. * A format string for the bubble legend labels. Available
  4909. * variables are the same as for `formatter`.
  4910. *
  4911. * @sample highcharts/bubble-legend/format/
  4912. * Add a unit
  4913. *
  4914. * @type {string}
  4915. */
  4916. format: '',
  4917. /**
  4918. * Available `this` properties are:
  4919. *
  4920. * - `this.value`: The bubble value.
  4921. *
  4922. * - `this.radius`: The radius of the bubble range.
  4923. *
  4924. * - `this.center`: The center y position of the range.
  4925. *
  4926. * @type {Highcharts.FormatterCallbackFunction<Highcharts.BubbleLegendFormatterContextObject>}
  4927. */
  4928. formatter: void 0,
  4929. /**
  4930. * The alignment of the labels compared to the bubble
  4931. * legend. Can be one of `left`, `center` or `right`.
  4932. *
  4933. * @sample highcharts/bubble-legend/connectorandlabels/
  4934. * Labels on left
  4935. *
  4936. * @type {Highcharts.AlignValue}
  4937. */
  4938. align: 'right',
  4939. /**
  4940. * CSS styles for the labels.
  4941. *
  4942. * @type {Highcharts.CSSObject}
  4943. */
  4944. style: {
  4945. /** @ignore-option */
  4946. fontSize: 10,
  4947. /** @ignore-option */
  4948. color: void 0
  4949. },
  4950. /**
  4951. * The x position offset of the label relative to the
  4952. * connector.
  4953. */
  4954. x: 0,
  4955. /**
  4956. * The y position offset of the label relative to the
  4957. * connector.
  4958. */
  4959. y: 0
  4960. },
  4961. /**
  4962. * Miximum bubble legend range size. If values for ranges are
  4963. * not specified, the `minSize` and the `maxSize` are calculated
  4964. * from bubble series.
  4965. */
  4966. maxSize: 60,
  4967. /**
  4968. * Minimum bubble legend range size. If values for ranges are
  4969. * not specified, the `minSize` and the `maxSize` are calculated
  4970. * from bubble series.
  4971. */
  4972. minSize: 10,
  4973. /**
  4974. * The position of the bubble legend in the legend.
  4975. * @sample highcharts/bubble-legend/connectorandlabels/
  4976. * Bubble legend as last item in legend
  4977. */
  4978. legendIndex: 0,
  4979. /**
  4980. * Options for specific range. One range consists of bubble,
  4981. * label and connector.
  4982. *
  4983. * @sample highcharts/bubble-legend/ranges/
  4984. * Manually defined ranges
  4985. * @sample highcharts/bubble-legend/autoranges/
  4986. * Auto calculated ranges
  4987. *
  4988. * @type {Array<*>}
  4989. */
  4990. ranges: {
  4991. /**
  4992. * Range size value, similar to bubble Z data.
  4993. * @type {number}
  4994. */
  4995. value: void 0,
  4996. /**
  4997. * The color of the border for individual range.
  4998. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  4999. */
  5000. borderColor: void 0,
  5001. /**
  5002. * The color of the bubble for individual range.
  5003. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  5004. */
  5005. color: void 0,
  5006. /**
  5007. * The color of the connector for individual range.
  5008. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  5009. */
  5010. connectorColor: void 0
  5011. },
  5012. /**
  5013. * Whether the bubble legend range value should be represented
  5014. * by the area or the width of the bubble. The default, area,
  5015. * corresponds best to the human perception of the size of each
  5016. * bubble.
  5017. *
  5018. * @sample highcharts/bubble-legend/ranges/
  5019. * Size by width
  5020. *
  5021. * @type {Highcharts.BubbleSizeByValue}
  5022. */
  5023. sizeBy: 'area',
  5024. /**
  5025. * When this is true, the absolute value of z determines the
  5026. * size of the bubble. This means that with the default
  5027. * zThreshold of 0, a bubble of value -1 will have the same size
  5028. * as a bubble of value 1, while a bubble of value 0 will have a
  5029. * smaller size according to minSize.
  5030. */
  5031. sizeByAbsoluteValue: false,
  5032. /**
  5033. * Define the visual z index of the bubble legend.
  5034. */
  5035. zIndex: 1,
  5036. /**
  5037. * Ranges with with lower value than zThreshold, are skipped.
  5038. */
  5039. zThreshold: 0
  5040. }
  5041. }
  5042. });
  5043. /* eslint-disable no-invalid-this, valid-jsdoc */
  5044. /**
  5045. * BubbleLegend class.
  5046. *
  5047. * @private
  5048. * @class
  5049. * @name Highcharts.BubbleLegend
  5050. * @param {Highcharts.LegendBubbleLegendOptions} options
  5051. * Bubble legend options
  5052. * @param {Highcharts.Legend} legend
  5053. * Legend
  5054. */
  5055. var BubbleLegend = /** @class */ (function () {
  5056. function BubbleLegend(options, legend) {
  5057. this.chart = void 0;
  5058. this.fontMetrics = void 0;
  5059. this.legend = void 0;
  5060. this.legendGroup = void 0;
  5061. this.legendItem = void 0;
  5062. this.legendItemHeight = void 0;
  5063. this.legendItemWidth = void 0;
  5064. this.legendSymbol = void 0;
  5065. this.maxLabel = void 0;
  5066. this.movementX = void 0;
  5067. this.ranges = void 0;
  5068. this.visible = void 0;
  5069. this.symbols = void 0;
  5070. this.options = void 0;
  5071. this.setState = noop;
  5072. this.init(options, legend);
  5073. }
  5074. /**
  5075. * Create basic bubbleLegend properties similar to item in legend.
  5076. *
  5077. * @private
  5078. * @function Highcharts.BubbleLegend#init
  5079. * @param {Highcharts.LegendBubbleLegendOptions} options
  5080. * Bubble legend options
  5081. * @param {Highcharts.Legend} legend
  5082. * Legend
  5083. * @return {void}
  5084. */
  5085. BubbleLegend.prototype.init = function (options, legend) {
  5086. this.options = options;
  5087. this.visible = true;
  5088. this.chart = legend.chart;
  5089. this.legend = legend;
  5090. };
  5091. /**
  5092. * Depending on the position option, add bubbleLegend to legend items.
  5093. *
  5094. * @private
  5095. * @function Highcharts.BubbleLegend#addToLegend
  5096. * @param {Array<(Highcharts.Point|Highcharts.Series)>}
  5097. * All legend items
  5098. * @return {void}
  5099. */
  5100. BubbleLegend.prototype.addToLegend = function (items) {
  5101. // Insert bubbleLegend into legend items
  5102. items.splice(this.options.legendIndex, 0, this);
  5103. };
  5104. /**
  5105. * Calculate ranges, sizes and call the next steps of bubbleLegend
  5106. * creation.
  5107. *
  5108. * @private
  5109. * @function Highcharts.BubbleLegend#drawLegendSymbol
  5110. * @param {Highcharts.Legend} legend
  5111. * Legend instance
  5112. * @return {void}
  5113. */
  5114. BubbleLegend.prototype.drawLegendSymbol = function (legend) {
  5115. var chart = this.chart, options = this.options, size, itemDistance = pick(legend.options.itemDistance, 20), connectorSpace, ranges = options.ranges, radius, maxLabel, connectorDistance = options.connectorDistance;
  5116. // Predict label dimensions
  5117. this.fontMetrics = chart.renderer.fontMetrics(options.labels.style.fontSize.toString() + 'px');
  5118. // Do not create bubbleLegend now if ranges or ranges valeus are not
  5119. // specified or if are empty array.
  5120. if (!ranges || !ranges.length || !isNumber(ranges[0].value)) {
  5121. legend.options.bubbleLegend.autoRanges = true;
  5122. return;
  5123. }
  5124. // Sort ranges to right render order
  5125. stableSort(ranges, function (a, b) {
  5126. return b.value - a.value;
  5127. });
  5128. this.ranges = ranges;
  5129. this.setOptions();
  5130. this.render();
  5131. // Get max label size
  5132. maxLabel = this.getMaxLabelSize();
  5133. radius = this.ranges[0].radius;
  5134. size = radius * 2;
  5135. // Space for connectors and labels.
  5136. connectorSpace =
  5137. connectorDistance - radius + maxLabel.width;
  5138. connectorSpace = connectorSpace > 0 ? connectorSpace : 0;
  5139. this.maxLabel = maxLabel;
  5140. this.movementX = options.labels.align === 'left' ?
  5141. connectorSpace : 0;
  5142. this.legendItemWidth = size + connectorSpace + itemDistance;
  5143. this.legendItemHeight = size + this.fontMetrics.h / 2;
  5144. };
  5145. /**
  5146. * Set style options for each bubbleLegend range.
  5147. *
  5148. * @private
  5149. * @function Highcharts.BubbleLegend#setOptions
  5150. * @return {void}
  5151. */
  5152. BubbleLegend.prototype.setOptions = function () {
  5153. var ranges = this.ranges, options = this.options, series = this.chart.series[options.seriesIndex], baseline = this.legend.baseline, bubbleStyle = {
  5154. 'z-index': options.zIndex,
  5155. 'stroke-width': options.borderWidth
  5156. }, connectorStyle = {
  5157. 'z-index': options.zIndex,
  5158. 'stroke-width': options.connectorWidth
  5159. }, labelStyle = this.getLabelStyles(), fillOpacity = series.options.marker.fillOpacity, styledMode = this.chart.styledMode;
  5160. // Allow to parts of styles be used individually for range
  5161. ranges.forEach(function (range, i) {
  5162. if (!styledMode) {
  5163. bubbleStyle.stroke = pick(range.borderColor, options.borderColor, series.color);
  5164. bubbleStyle.fill = pick(range.color, options.color, fillOpacity !== 1 ?
  5165. color(series.color).setOpacity(fillOpacity)
  5166. .get('rgba') :
  5167. series.color);
  5168. connectorStyle.stroke = pick(range.connectorColor, options.connectorColor, series.color);
  5169. }
  5170. // Set options needed for rendering each range
  5171. ranges[i].radius = this.getRangeRadius(range.value);
  5172. ranges[i] = merge(ranges[i], {
  5173. center: (ranges[0].radius - ranges[i].radius +
  5174. baseline)
  5175. });
  5176. if (!styledMode) {
  5177. merge(true, ranges[i], {
  5178. bubbleStyle: merge(false, bubbleStyle),
  5179. connectorStyle: merge(false, connectorStyle),
  5180. labelStyle: labelStyle
  5181. });
  5182. }
  5183. }, this);
  5184. };
  5185. /**
  5186. * Merge options for bubbleLegend labels.
  5187. *
  5188. * @private
  5189. * @function Highcharts.BubbleLegend#getLabelStyles
  5190. * @return {Highcharts.CSSObject}
  5191. */
  5192. BubbleLegend.prototype.getLabelStyles = function () {
  5193. var options = this.options, additionalLabelsStyle = {}, labelsOnLeft = options.labels.align === 'left', rtl = this.legend.options.rtl;
  5194. // To separate additional style options
  5195. objectEach(options.labels.style, function (value, key) {
  5196. if (key !== 'color' &&
  5197. key !== 'fontSize' &&
  5198. key !== 'z-index') {
  5199. additionalLabelsStyle[key] = value;
  5200. }
  5201. });
  5202. return merge(false, additionalLabelsStyle, {
  5203. 'font-size': options.labels.style.fontSize,
  5204. fill: pick(options.labels.style.color, '#000000'),
  5205. 'z-index': options.zIndex,
  5206. align: rtl || labelsOnLeft ? 'right' : 'left'
  5207. });
  5208. };
  5209. /**
  5210. * Calculate radius for each bubble range,
  5211. * used code from BubbleSeries.js 'getRadius' method.
  5212. *
  5213. * @private
  5214. * @function Highcharts.BubbleLegend#getRangeRadius
  5215. * @param {number} value
  5216. * Range value
  5217. * @return {number|null}
  5218. * Radius for one range
  5219. */
  5220. BubbleLegend.prototype.getRangeRadius = function (value) {
  5221. var options = this.options, seriesIndex = this.options.seriesIndex, bubbleSeries = this.chart.series[seriesIndex], zMax = options.ranges[0].value, zMin = options.ranges[options.ranges.length - 1].value, minSize = options.minSize, maxSize = options.maxSize;
  5222. return bubbleSeries.getRadius.call(this, zMin, zMax, minSize, maxSize, value);
  5223. };
  5224. /**
  5225. * Render the legendSymbol group.
  5226. *
  5227. * @private
  5228. * @function Highcharts.BubbleLegend#render
  5229. * @return {void}
  5230. */
  5231. BubbleLegend.prototype.render = function () {
  5232. var renderer = this.chart.renderer, zThreshold = this.options.zThreshold;
  5233. if (!this.symbols) {
  5234. this.symbols = {
  5235. connectors: [],
  5236. bubbleItems: [],
  5237. labels: []
  5238. };
  5239. }
  5240. // Nesting SVG groups to enable handleOverflow
  5241. this.legendSymbol = renderer.g('bubble-legend');
  5242. this.legendItem = renderer.g('bubble-legend-item');
  5243. // To enable default 'hideOverlappingLabels' method
  5244. this.legendSymbol.translateX = 0;
  5245. this.legendSymbol.translateY = 0;
  5246. this.ranges.forEach(function (range) {
  5247. if (range.value >= zThreshold) {
  5248. this.renderRange(range);
  5249. }
  5250. }, this);
  5251. // To use handleOverflow method
  5252. this.legendSymbol.add(this.legendItem);
  5253. this.legendItem.add(this.legendGroup);
  5254. this.hideOverlappingLabels();
  5255. };
  5256. /**
  5257. * Render one range, consisting of bubble symbol, connector and label.
  5258. *
  5259. * @private
  5260. * @function Highcharts.BubbleLegend#renderRange
  5261. * @param {Highcharts.LegendBubbleLegendRangesOptions} range
  5262. * Range options
  5263. * @return {void}
  5264. */
  5265. BubbleLegend.prototype.renderRange = function (range) {
  5266. var mainRange = this.ranges[0], legend = this.legend, options = this.options, labelsOptions = options.labels, chart = this.chart, renderer = chart.renderer, symbols = this.symbols, labels = symbols.labels, label, elementCenter = range.center, absoluteRadius = Math.abs(range.radius), connectorDistance = options.connectorDistance || 0, labelsAlign = labelsOptions.align, rtl = legend.options.rtl, fontSize = labelsOptions.style.fontSize, connectorLength = rtl || labelsAlign === 'left' ?
  5267. -connectorDistance : connectorDistance, borderWidth = options.borderWidth, connectorWidth = options.connectorWidth, posX = mainRange.radius || 0, posY = elementCenter - absoluteRadius -
  5268. borderWidth / 2 + connectorWidth / 2, labelY, labelX, fontMetrics = this.fontMetrics, labelMovement = fontSize / 2 - (fontMetrics.h - fontSize) / 2, crispMovement = (posY % 1 ? 1 : 0.5) -
  5269. (connectorWidth % 2 ? 0 : 0.5), styledMode = renderer.styledMode;
  5270. // Set options for centered labels
  5271. if (labelsAlign === 'center') {
  5272. connectorLength = 0; // do not use connector
  5273. options.connectorDistance = 0;
  5274. range.labelStyle.align = 'center';
  5275. }
  5276. labelY = posY + options.labels.y;
  5277. labelX = posX + connectorLength + options.labels.x;
  5278. // Render bubble symbol
  5279. symbols.bubbleItems.push(renderer
  5280. .circle(posX, elementCenter + crispMovement, absoluteRadius)
  5281. .attr(styledMode ? {} : range.bubbleStyle)
  5282. .addClass((styledMode ?
  5283. 'highcharts-color-' +
  5284. this.options.seriesIndex + ' ' :
  5285. '') +
  5286. 'highcharts-bubble-legend-symbol ' +
  5287. (options.className || '')).add(this.legendSymbol));
  5288. // Render connector
  5289. symbols.connectors.push(renderer
  5290. .path(renderer.crispLine([
  5291. ['M', posX, posY],
  5292. ['L', posX + connectorLength, posY]
  5293. ], options.connectorWidth))
  5294. .attr(styledMode ? {} : range.connectorStyle)
  5295. .addClass((styledMode ?
  5296. 'highcharts-color-' +
  5297. this.options.seriesIndex + ' ' : '') +
  5298. 'highcharts-bubble-legend-connectors ' +
  5299. (options.connectorClassName || '')).add(this.legendSymbol));
  5300. // Render label
  5301. label = renderer
  5302. .text(this.formatLabel(range), labelX, labelY + labelMovement)
  5303. .attr(styledMode ? {} : range.labelStyle)
  5304. .addClass('highcharts-bubble-legend-labels ' +
  5305. (options.labels.className || '')).add(this.legendSymbol);
  5306. labels.push(label);
  5307. // To enable default 'hideOverlappingLabels' method
  5308. label.placed = true;
  5309. label.alignAttr = {
  5310. x: labelX,
  5311. y: labelY + labelMovement
  5312. };
  5313. };
  5314. /**
  5315. * Get the label which takes up the most space.
  5316. *
  5317. * @private
  5318. * @function Highcharts.BubbleLegend#getMaxLabelSize
  5319. * @return {Highcharts.BBoxObject}
  5320. */
  5321. BubbleLegend.prototype.getMaxLabelSize = function () {
  5322. var labels = this.symbols.labels, maxLabel, labelSize;
  5323. labels.forEach(function (label) {
  5324. labelSize = label.getBBox(true);
  5325. if (maxLabel) {
  5326. maxLabel = labelSize.width > maxLabel.width ?
  5327. labelSize : maxLabel;
  5328. }
  5329. else {
  5330. maxLabel = labelSize;
  5331. }
  5332. });
  5333. return maxLabel || {};
  5334. };
  5335. /**
  5336. * Get formatted label for range.
  5337. *
  5338. * @private
  5339. * @function Highcharts.BubbleLegend#formatLabel
  5340. * @param {Highcharts.LegendBubbleLegendRangesOptions} range
  5341. * Range options
  5342. * @return {string}
  5343. * Range label text
  5344. */
  5345. BubbleLegend.prototype.formatLabel = function (range) {
  5346. var options = this.options, formatter = options.labels.formatter, format = options.labels.format;
  5347. var numberFormatter = this.chart.numberFormatter;
  5348. return format ? U.format(format, range) :
  5349. formatter ? formatter.call(range) :
  5350. numberFormatter(range.value, 1);
  5351. };
  5352. /**
  5353. * By using default chart 'hideOverlappingLabels' method, hide or show
  5354. * labels and connectors.
  5355. *
  5356. * @private
  5357. * @function Highcharts.BubbleLegend#hideOverlappingLabels
  5358. * @return {void}
  5359. */
  5360. BubbleLegend.prototype.hideOverlappingLabels = function () {
  5361. var chart = this.chart, allowOverlap = this.options.labels.allowOverlap, symbols = this.symbols;
  5362. if (!allowOverlap && symbols) {
  5363. chart.hideOverlappingLabels(symbols.labels);
  5364. // Hide or show connectors
  5365. symbols.labels.forEach(function (label, index) {
  5366. if (!label.newOpacity) {
  5367. symbols.connectors[index].hide();
  5368. }
  5369. else if (label.newOpacity !== label.oldOpacity) {
  5370. symbols.connectors[index].show();
  5371. }
  5372. });
  5373. }
  5374. };
  5375. /**
  5376. * Calculate ranges from created series.
  5377. *
  5378. * @private
  5379. * @function Highcharts.BubbleLegend#getRanges
  5380. * @return {Array<Highcharts.LegendBubbleLegendRangesOptions>}
  5381. * Array of range objects
  5382. */
  5383. BubbleLegend.prototype.getRanges = function () {
  5384. var bubbleLegend = this.legend.bubbleLegend, series = bubbleLegend.chart.series, ranges, rangesOptions = bubbleLegend.options.ranges, zData, minZ = Number.MAX_VALUE, maxZ = -Number.MAX_VALUE;
  5385. series.forEach(function (s) {
  5386. // Find the min and max Z, like in bubble series
  5387. if (s.isBubble && !s.ignoreSeries) {
  5388. zData = s.zData.filter(isNumber);
  5389. if (zData.length) {
  5390. minZ = pick(s.options.zMin, Math.min(minZ, Math.max(arrayMin(zData), s.options.displayNegative === false ?
  5391. s.options.zThreshold :
  5392. -Number.MAX_VALUE)));
  5393. maxZ = pick(s.options.zMax, Math.max(maxZ, arrayMax(zData)));
  5394. }
  5395. }
  5396. });
  5397. // Set values for ranges
  5398. if (minZ === maxZ) {
  5399. // Only one range if min and max values are the same.
  5400. ranges = [{ value: maxZ }];
  5401. }
  5402. else {
  5403. ranges = [
  5404. { value: minZ },
  5405. { value: (minZ + maxZ) / 2 },
  5406. { value: maxZ, autoRanges: true }
  5407. ];
  5408. }
  5409. // Prevent reverse order of ranges after redraw
  5410. if (rangesOptions.length && rangesOptions[0].radius) {
  5411. ranges.reverse();
  5412. }
  5413. // Merge ranges values with user options
  5414. ranges.forEach(function (range, i) {
  5415. if (rangesOptions && rangesOptions[i]) {
  5416. ranges[i] = merge(false, rangesOptions[i], range);
  5417. }
  5418. });
  5419. return ranges;
  5420. };
  5421. /**
  5422. * Calculate bubble legend sizes from rendered series.
  5423. *
  5424. * @private
  5425. * @function Highcharts.BubbleLegend#predictBubbleSizes
  5426. * @return {Array<number,number>}
  5427. * Calculated min and max bubble sizes
  5428. */
  5429. BubbleLegend.prototype.predictBubbleSizes = function () {
  5430. var chart = this.chart, fontMetrics = this.fontMetrics, legendOptions = chart.legend.options, floating = legendOptions.floating, horizontal = legendOptions.layout === 'horizontal', lastLineHeight = horizontal ? chart.legend.lastLineHeight : 0, plotSizeX = chart.plotSizeX, plotSizeY = chart.plotSizeY, bubbleSeries = chart.series[this.options.seriesIndex], minSize = Math.ceil(bubbleSeries.minPxSize), maxPxSize = Math.ceil(bubbleSeries.maxPxSize), maxSize = bubbleSeries.options.maxSize, plotSize = Math.min(plotSizeY, plotSizeX), calculatedSize;
  5431. // Calculate prediceted max size of bubble
  5432. if (floating || !(/%$/.test(maxSize))) {
  5433. calculatedSize = maxPxSize;
  5434. }
  5435. else {
  5436. maxSize = parseFloat(maxSize);
  5437. calculatedSize = ((plotSize + lastLineHeight -
  5438. fontMetrics.h / 2) * maxSize / 100) / (maxSize / 100 + 1);
  5439. // Get maxPxSize from bubble series if calculated bubble legend
  5440. // size will not affect to bubbles series.
  5441. if ((horizontal && plotSizeY - calculatedSize >=
  5442. plotSizeX) || (!horizontal && plotSizeX -
  5443. calculatedSize >= plotSizeY)) {
  5444. calculatedSize = maxPxSize;
  5445. }
  5446. }
  5447. return [minSize, Math.ceil(calculatedSize)];
  5448. };
  5449. /**
  5450. * Correct ranges with calculated sizes.
  5451. *
  5452. * @private
  5453. * @function Highcharts.BubbleLegend#updateRanges
  5454. * @param {number} min
  5455. * @param {number} max
  5456. * @return {void}
  5457. */
  5458. BubbleLegend.prototype.updateRanges = function (min, max) {
  5459. var bubbleLegendOptions = this.legend.options.bubbleLegend;
  5460. bubbleLegendOptions.minSize = min;
  5461. bubbleLegendOptions.maxSize = max;
  5462. bubbleLegendOptions.ranges = this.getRanges();
  5463. };
  5464. /**
  5465. * Because of the possibility of creating another legend line, predicted
  5466. * bubble legend sizes may differ by a few pixels, so it is necessary to
  5467. * correct them.
  5468. *
  5469. * @private
  5470. * @function Highcharts.BubbleLegend#correctSizes
  5471. * @return {void}
  5472. */
  5473. BubbleLegend.prototype.correctSizes = function () {
  5474. var legend = this.legend, chart = this.chart, bubbleSeries = chart.series[this.options.seriesIndex], bubbleSeriesSize = bubbleSeries.maxPxSize, bubbleLegendSize = this.options.maxSize;
  5475. if (Math.abs(Math.ceil(bubbleSeriesSize) - bubbleLegendSize) >
  5476. 1) {
  5477. this.updateRanges(this.options.minSize, bubbleSeries.maxPxSize);
  5478. legend.render();
  5479. }
  5480. };
  5481. return BubbleLegend;
  5482. }());
  5483. // Start the bubble legend creation process.
  5484. addEvent(Legend, 'afterGetAllItems', function (e) {
  5485. var legend = this, bubbleLegend = legend.bubbleLegend, legendOptions = legend.options, options = legendOptions.bubbleLegend, bubbleSeriesIndex = legend.chart.getVisibleBubbleSeriesIndex();
  5486. // Remove unnecessary element
  5487. if (bubbleLegend && bubbleLegend.ranges && bubbleLegend.ranges.length) {
  5488. // Allow change the way of calculating ranges in update
  5489. if (options.ranges.length) {
  5490. options.autoRanges =
  5491. !!options.ranges[0].autoRanges;
  5492. }
  5493. // Update bubbleLegend dimensions in each redraw
  5494. legend.destroyItem(bubbleLegend);
  5495. }
  5496. // Create bubble legend
  5497. if (bubbleSeriesIndex >= 0 &&
  5498. legendOptions.enabled &&
  5499. options.enabled) {
  5500. options.seriesIndex = bubbleSeriesIndex;
  5501. legend.bubbleLegend = new H.BubbleLegend(options, legend);
  5502. legend.bubbleLegend.addToLegend(e.allItems);
  5503. }
  5504. });
  5505. /**
  5506. * Check if there is at least one visible bubble series.
  5507. *
  5508. * @private
  5509. * @function Highcharts.Chart#getVisibleBubbleSeriesIndex
  5510. * @return {number}
  5511. * First visible bubble series index
  5512. */
  5513. Chart.prototype.getVisibleBubbleSeriesIndex = function () {
  5514. var series = this.series, i = 0;
  5515. while (i < series.length) {
  5516. if (series[i] &&
  5517. series[i].isBubble &&
  5518. series[i].visible &&
  5519. series[i].zData.length) {
  5520. return i;
  5521. }
  5522. i++;
  5523. }
  5524. return -1;
  5525. };
  5526. /**
  5527. * Calculate height for each row in legend.
  5528. *
  5529. * @private
  5530. * @function Highcharts.Legend#getLinesHeights
  5531. * @return {Array<Highcharts.Dictionary<number>>}
  5532. * Informations about line height and items amount
  5533. */
  5534. Legend.prototype.getLinesHeights = function () {
  5535. var items = this.allItems, lines = [], lastLine, length = items.length, i = 0, j = 0;
  5536. for (i = 0; i < length; i++) {
  5537. if (items[i].legendItemHeight) {
  5538. // for bubbleLegend
  5539. items[i].itemHeight = items[i].legendItemHeight;
  5540. }
  5541. if ( // Line break
  5542. items[i] === items[length - 1] ||
  5543. items[i + 1] &&
  5544. items[i]._legendItemPos[1] !==
  5545. items[i + 1]._legendItemPos[1]) {
  5546. lines.push({ height: 0 });
  5547. lastLine = lines[lines.length - 1];
  5548. // Find the highest item in line
  5549. for (j; j <= i; j++) {
  5550. if (items[j].itemHeight > lastLine.height) {
  5551. lastLine.height = items[j].itemHeight;
  5552. }
  5553. }
  5554. lastLine.step = i;
  5555. }
  5556. }
  5557. return lines;
  5558. };
  5559. /**
  5560. * Correct legend items translation in case of different elements heights.
  5561. *
  5562. * @private
  5563. * @function Highcharts.Legend#retranslateItems
  5564. * @param {Array<Highcharts.Dictionary<number>>} lines
  5565. * Informations about line height and items amount
  5566. * @return {void}
  5567. */
  5568. Legend.prototype.retranslateItems = function (lines) {
  5569. var items = this.allItems, orgTranslateX, orgTranslateY, movementX, rtl = this.options.rtl, actualLine = 0;
  5570. items.forEach(function (item, index) {
  5571. orgTranslateX = item.legendGroup.translateX;
  5572. orgTranslateY = item._legendItemPos[1];
  5573. movementX = item.movementX;
  5574. if (movementX || (rtl && item.ranges)) {
  5575. movementX = rtl ?
  5576. orgTranslateX - item.options.maxSize / 2 :
  5577. orgTranslateX + movementX;
  5578. item.legendGroup.attr({ translateX: movementX });
  5579. }
  5580. if (index > lines[actualLine].step) {
  5581. actualLine++;
  5582. }
  5583. item.legendGroup.attr({
  5584. translateY: Math.round(orgTranslateY + lines[actualLine].height / 2)
  5585. });
  5586. item._legendItemPos[1] = orgTranslateY +
  5587. lines[actualLine].height / 2;
  5588. });
  5589. };
  5590. // Toggle bubble legend depending on the visible status of bubble series.
  5591. addEvent(Series, 'legendItemClick', function () {
  5592. var series = this, chart = series.chart, visible = series.visible, legend = series.chart.legend, status;
  5593. if (legend && legend.bubbleLegend) {
  5594. // Temporary correct 'visible' property
  5595. series.visible = !visible;
  5596. // Save future status for getRanges method
  5597. series.ignoreSeries = visible;
  5598. // Check if at lest one bubble series is visible
  5599. status = chart.getVisibleBubbleSeriesIndex() >= 0;
  5600. // Hide bubble legend if all bubble series are disabled
  5601. if (legend.bubbleLegend.visible !== status) {
  5602. // Show or hide bubble legend
  5603. legend.update({
  5604. bubbleLegend: { enabled: status }
  5605. });
  5606. legend.bubbleLegend.visible = status; // Restore default status
  5607. }
  5608. series.visible = visible;
  5609. }
  5610. });
  5611. // If ranges are not specified, determine ranges from rendered bubble series
  5612. // and render legend again.
  5613. wrap(Chart.prototype, 'drawChartBox', function (proceed, options, callback) {
  5614. var chart = this, legend = chart.legend, bubbleSeries = chart.getVisibleBubbleSeriesIndex() >= 0, bubbleLegendOptions, bubbleSizes;
  5615. if (legend && legend.options.enabled && legend.bubbleLegend &&
  5616. legend.options.bubbleLegend.autoRanges && bubbleSeries) {
  5617. bubbleLegendOptions = legend.bubbleLegend.options;
  5618. bubbleSizes = legend.bubbleLegend.predictBubbleSizes();
  5619. legend.bubbleLegend.updateRanges(bubbleSizes[0], bubbleSizes[1]);
  5620. // Disable animation on init
  5621. if (!bubbleLegendOptions.placed) {
  5622. legend.group.placed = false;
  5623. legend.allItems.forEach(function (item) {
  5624. item.legendGroup.translateY = null;
  5625. });
  5626. }
  5627. // Create legend with bubbleLegend
  5628. legend.render();
  5629. chart.getMargins();
  5630. chart.axes.forEach(function (axis) {
  5631. if (axis.visible) { // #11448
  5632. axis.render();
  5633. }
  5634. if (!bubbleLegendOptions.placed) {
  5635. axis.setScale();
  5636. axis.updateNames();
  5637. // Disable axis animation on init
  5638. objectEach(axis.ticks, function (tick) {
  5639. tick.isNew = true;
  5640. tick.isNewLabel = true;
  5641. });
  5642. }
  5643. });
  5644. bubbleLegendOptions.placed = true;
  5645. // After recalculate axes, calculate margins again.
  5646. chart.getMargins();
  5647. // Call default 'drawChartBox' method.
  5648. proceed.call(chart, options, callback);
  5649. // Check bubble legend sizes and correct them if necessary.
  5650. legend.bubbleLegend.correctSizes();
  5651. // Correct items positions with different dimensions in legend.
  5652. legend.retranslateItems(legend.getLinesHeights());
  5653. }
  5654. else {
  5655. proceed.call(chart, options, callback);
  5656. // Allow color change on static bubble legend after click on legend
  5657. if (legend && legend.options.enabled && legend.bubbleLegend) {
  5658. legend.render();
  5659. legend.retranslateItems(legend.getLinesHeights());
  5660. }
  5661. }
  5662. });
  5663. H.BubbleLegend = BubbleLegend;
  5664. return H.BubbleLegend;
  5665. });
  5666. _registerModule(_modules, 'parts-more/BubbleSeries.js', [_modules['parts/Globals.js'], _modules['parts/Color.js'], _modules['parts/Point.js'], _modules['parts/Utilities.js']], function (H, Color, Point, U) {
  5667. /* *
  5668. *
  5669. * (c) 2010-2020 Torstein Honsi
  5670. *
  5671. * License: www.highcharts.com/license
  5672. *
  5673. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  5674. *
  5675. * */
  5676. /**
  5677. * @typedef {"area"|"width"} Highcharts.BubbleSizeByValue
  5678. */
  5679. var color = Color.parse;
  5680. var arrayMax = U.arrayMax, arrayMin = U.arrayMin, clamp = U.clamp, extend = U.extend, isNumber = U.isNumber, pick = U.pick, pInt = U.pInt, seriesType = U.seriesType;
  5681. var Axis = H.Axis, noop = H.noop, Series = H.Series, seriesTypes = H.seriesTypes;
  5682. /**
  5683. * A bubble series is a three dimensional series type where each point renders
  5684. * an X, Y and Z value. Each points is drawn as a bubble where the position
  5685. * along the X and Y axes mark the X and Y values, and the size of the bubble
  5686. * relates to the Z value.
  5687. *
  5688. * @sample {highcharts} highcharts/demo/bubble/
  5689. * Bubble chart
  5690. *
  5691. * @extends plotOptions.scatter
  5692. * @excluding cluster
  5693. * @product highcharts highstock
  5694. * @requires highcharts-more
  5695. * @optionparent plotOptions.bubble
  5696. */
  5697. seriesType('bubble', 'scatter', {
  5698. dataLabels: {
  5699. formatter: function () {
  5700. return this.point.z;
  5701. },
  5702. inside: true,
  5703. verticalAlign: 'middle'
  5704. },
  5705. /**
  5706. * If there are more points in the series than the `animationLimit`, the
  5707. * animation won't run. Animation affects overall performance and doesn't
  5708. * work well with heavy data series.
  5709. *
  5710. * @since 6.1.0
  5711. */
  5712. animationLimit: 250,
  5713. /**
  5714. * Whether to display negative sized bubbles. The threshold is given
  5715. * by the [zThreshold](#plotOptions.bubble.zThreshold) option, and negative
  5716. * bubbles can be visualized by setting
  5717. * [negativeColor](#plotOptions.bubble.negativeColor).
  5718. *
  5719. * @sample {highcharts} highcharts/plotoptions/bubble-negative/
  5720. * Negative bubbles
  5721. *
  5722. * @type {boolean}
  5723. * @default true
  5724. * @since 3.0
  5725. * @apioption plotOptions.bubble.displayNegative
  5726. */
  5727. /**
  5728. * @extends plotOptions.series.marker
  5729. * @excluding enabled, enabledThreshold, height, radius, width
  5730. */
  5731. marker: {
  5732. lineColor: null,
  5733. lineWidth: 1,
  5734. /**
  5735. * The fill opacity of the bubble markers.
  5736. */
  5737. fillOpacity: 0.5,
  5738. /**
  5739. * In bubble charts, the radius is overridden and determined based on
  5740. * the point's data value.
  5741. *
  5742. * @ignore-option
  5743. */
  5744. radius: null,
  5745. states: {
  5746. hover: {
  5747. radiusPlus: 0
  5748. }
  5749. },
  5750. /**
  5751. * A predefined shape or symbol for the marker. Possible values are
  5752. * "circle", "square", "diamond", "triangle" and "triangle-down".
  5753. *
  5754. * Additionally, the URL to a graphic can be given on the form
  5755. * `url(graphic.png)`. Note that for the image to be applied to exported
  5756. * charts, its URL needs to be accessible by the export server.
  5757. *
  5758. * Custom callbacks for symbol path generation can also be added to
  5759. * `Highcharts.SVGRenderer.prototype.symbols`. The callback is then
  5760. * used by its method name, as shown in the demo.
  5761. *
  5762. * @sample {highcharts} highcharts/plotoptions/bubble-symbol/
  5763. * Bubble chart with various symbols
  5764. * @sample {highcharts} highcharts/plotoptions/series-marker-symbol/
  5765. * General chart with predefined, graphic and custom markers
  5766. *
  5767. * @type {Highcharts.SymbolKeyValue|string}
  5768. * @since 5.0.11
  5769. */
  5770. symbol: 'circle'
  5771. },
  5772. /**
  5773. * Minimum bubble size. Bubbles will automatically size between the
  5774. * `minSize` and `maxSize` to reflect the `z` value of each bubble.
  5775. * Can be either pixels (when no unit is given), or a percentage of
  5776. * the smallest one of the plot width and height.
  5777. *
  5778. * @sample {highcharts} highcharts/plotoptions/bubble-size/
  5779. * Bubble size
  5780. *
  5781. * @type {number|string}
  5782. * @since 3.0
  5783. * @product highcharts highstock
  5784. */
  5785. minSize: 8,
  5786. /**
  5787. * Maximum bubble size. Bubbles will automatically size between the
  5788. * `minSize` and `maxSize` to reflect the `z` value of each bubble.
  5789. * Can be either pixels (when no unit is given), or a percentage of
  5790. * the smallest one of the plot width and height.
  5791. *
  5792. * @sample {highcharts} highcharts/plotoptions/bubble-size/
  5793. * Bubble size
  5794. *
  5795. * @type {number|string}
  5796. * @since 3.0
  5797. * @product highcharts highstock
  5798. */
  5799. maxSize: '20%',
  5800. /**
  5801. * When a point's Z value is below the
  5802. * [zThreshold](#plotOptions.bubble.zThreshold) setting, this color is used.
  5803. *
  5804. * @sample {highcharts} highcharts/plotoptions/bubble-negative/
  5805. * Negative bubbles
  5806. *
  5807. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  5808. * @since 3.0
  5809. * @product highcharts
  5810. * @apioption plotOptions.bubble.negativeColor
  5811. */
  5812. /**
  5813. * Whether the bubble's value should be represented by the area or the
  5814. * width of the bubble. The default, `area`, corresponds best to the
  5815. * human perception of the size of each bubble.
  5816. *
  5817. * @sample {highcharts} highcharts/plotoptions/bubble-sizeby/
  5818. * Comparison of area and size
  5819. *
  5820. * @type {Highcharts.BubbleSizeByValue}
  5821. * @default area
  5822. * @since 3.0.7
  5823. * @apioption plotOptions.bubble.sizeBy
  5824. */
  5825. /**
  5826. * When this is true, the absolute value of z determines the size of
  5827. * the bubble. This means that with the default `zThreshold` of 0, a
  5828. * bubble of value -1 will have the same size as a bubble of value 1,
  5829. * while a bubble of value 0 will have a smaller size according to
  5830. * `minSize`.
  5831. *
  5832. * @sample {highcharts} highcharts/plotoptions/bubble-sizebyabsolutevalue/
  5833. * Size by absolute value, various thresholds
  5834. *
  5835. * @type {boolean}
  5836. * @default false
  5837. * @since 4.1.9
  5838. * @product highcharts
  5839. * @apioption plotOptions.bubble.sizeByAbsoluteValue
  5840. */
  5841. /**
  5842. * When this is true, the series will not cause the Y axis to cross
  5843. * the zero plane (or [threshold](#plotOptions.series.threshold) option)
  5844. * unless the data actually crosses the plane.
  5845. *
  5846. * For example, if `softThreshold` is `false`, a series of 0, 1, 2,
  5847. * 3 will make the Y axis show negative values according to the `minPadding`
  5848. * option. If `softThreshold` is `true`, the Y axis starts at 0.
  5849. *
  5850. * @since 4.1.9
  5851. * @product highcharts
  5852. */
  5853. softThreshold: false,
  5854. states: {
  5855. hover: {
  5856. halo: {
  5857. size: 5
  5858. }
  5859. }
  5860. },
  5861. tooltip: {
  5862. pointFormat: '({point.x}, {point.y}), Size: {point.z}'
  5863. },
  5864. turboThreshold: 0,
  5865. /**
  5866. * The minimum for the Z value range. Defaults to the highest Z value
  5867. * in the data.
  5868. *
  5869. * @see [zMin](#plotOptions.bubble.zMin)
  5870. *
  5871. * @sample {highcharts} highcharts/plotoptions/bubble-zmin-zmax/
  5872. * Z has a possible range of 0-100
  5873. *
  5874. * @type {number}
  5875. * @since 4.0.3
  5876. * @product highcharts
  5877. * @apioption plotOptions.bubble.zMax
  5878. */
  5879. /**
  5880. * @default z
  5881. * @apioption plotOptions.bubble.colorKey
  5882. */
  5883. /**
  5884. * The minimum for the Z value range. Defaults to the lowest Z value
  5885. * in the data.
  5886. *
  5887. * @see [zMax](#plotOptions.bubble.zMax)
  5888. *
  5889. * @sample {highcharts} highcharts/plotoptions/bubble-zmin-zmax/
  5890. * Z has a possible range of 0-100
  5891. *
  5892. * @type {number}
  5893. * @since 4.0.3
  5894. * @product highcharts
  5895. * @apioption plotOptions.bubble.zMin
  5896. */
  5897. /**
  5898. * When [displayNegative](#plotOptions.bubble.displayNegative) is `false`,
  5899. * bubbles with lower Z values are skipped. When `displayNegative`
  5900. * is `true` and a [negativeColor](#plotOptions.bubble.negativeColor)
  5901. * is given, points with lower Z is colored.
  5902. *
  5903. * @sample {highcharts} highcharts/plotoptions/bubble-negative/
  5904. * Negative bubbles
  5905. *
  5906. * @since 3.0
  5907. * @product highcharts
  5908. */
  5909. zThreshold: 0,
  5910. zoneAxis: 'z'
  5911. // Prototype members
  5912. }, {
  5913. pointArrayMap: ['y', 'z'],
  5914. parallelArrays: ['x', 'y', 'z'],
  5915. trackerGroups: ['group', 'dataLabelsGroup'],
  5916. specialGroup: 'group',
  5917. bubblePadding: true,
  5918. zoneAxis: 'z',
  5919. directTouch: true,
  5920. isBubble: true,
  5921. /* eslint-disable valid-jsdoc */
  5922. /**
  5923. * @private
  5924. */
  5925. pointAttribs: function (point, state) {
  5926. var markerOptions = this.options.marker, fillOpacity = markerOptions.fillOpacity, attr = Series.prototype.pointAttribs.call(this, point, state);
  5927. if (fillOpacity !== 1) {
  5928. attr.fill = color(attr.fill)
  5929. .setOpacity(fillOpacity)
  5930. .get('rgba');
  5931. }
  5932. return attr;
  5933. },
  5934. /**
  5935. * Get the radius for each point based on the minSize, maxSize and each
  5936. * point's Z value. This must be done prior to Series.translate because
  5937. * the axis needs to add padding in accordance with the point sizes.
  5938. * @private
  5939. */
  5940. getRadii: function (zMin, zMax, series) {
  5941. var len, i, zData = this.zData, yData = this.yData, minSize = series.minPxSize, maxSize = series.maxPxSize, radii = [], value;
  5942. // Set the shape type and arguments to be picked up in drawPoints
  5943. for (i = 0, len = zData.length; i < len; i++) {
  5944. value = zData[i];
  5945. // Separate method to get individual radius for bubbleLegend
  5946. radii.push(this.getRadius(zMin, zMax, minSize, maxSize, value, yData[i]));
  5947. }
  5948. this.radii = radii;
  5949. },
  5950. /**
  5951. * Get the individual radius for one point.
  5952. * @private
  5953. */
  5954. getRadius: function (zMin, zMax, minSize, maxSize, value, yValue) {
  5955. var options = this.options, sizeByArea = options.sizeBy !== 'width', zThreshold = options.zThreshold, zRange = zMax - zMin, pos = 0.5;
  5956. // #8608 - bubble should be visible when z is undefined
  5957. if (yValue === null || value === null) {
  5958. return null;
  5959. }
  5960. if (isNumber(value)) {
  5961. // When sizing by threshold, the absolute value of z determines
  5962. // the size of the bubble.
  5963. if (options.sizeByAbsoluteValue) {
  5964. value = Math.abs(value - zThreshold);
  5965. zMax = zRange = Math.max(zMax - zThreshold, Math.abs(zMin - zThreshold));
  5966. zMin = 0;
  5967. }
  5968. // Issue #4419 - if value is less than zMin, push a radius that's
  5969. // always smaller than the minimum size
  5970. if (value < zMin) {
  5971. return minSize / 2 - 1;
  5972. }
  5973. // Relative size, a number between 0 and 1
  5974. if (zRange > 0) {
  5975. pos = (value - zMin) / zRange;
  5976. }
  5977. }
  5978. if (sizeByArea && pos >= 0) {
  5979. pos = Math.sqrt(pos);
  5980. }
  5981. return Math.ceil(minSize + pos * (maxSize - minSize)) / 2;
  5982. },
  5983. /**
  5984. * Perform animation on the bubbles
  5985. * @private
  5986. */
  5987. animate: function (init) {
  5988. if (!init &&
  5989. this.points.length < this.options.animationLimit // #8099
  5990. ) {
  5991. this.points.forEach(function (point) {
  5992. var graphic = point.graphic;
  5993. if (graphic && graphic.width) { // URL symbols don't have width
  5994. // Start values
  5995. if (!this.hasRendered) {
  5996. graphic.attr({
  5997. x: point.plotX,
  5998. y: point.plotY,
  5999. width: 1,
  6000. height: 1
  6001. });
  6002. }
  6003. // Run animation
  6004. graphic.animate(this.markerAttribs(point), this.options.animation);
  6005. }
  6006. }, this);
  6007. }
  6008. },
  6009. /**
  6010. * Define hasData function for non-cartesian series.
  6011. * Returns true if the series has points at all.
  6012. * @private
  6013. */
  6014. hasData: function () {
  6015. return !!this.processedXData.length; // != 0
  6016. },
  6017. /**
  6018. * Extend the base translate method to handle bubble size
  6019. * @private
  6020. */
  6021. translate: function () {
  6022. var i, data = this.data, point, radius, radii = this.radii;
  6023. // Run the parent method
  6024. seriesTypes.scatter.prototype.translate.call(this);
  6025. // Set the shape type and arguments to be picked up in drawPoints
  6026. i = data.length;
  6027. while (i--) {
  6028. point = data[i];
  6029. radius = radii ? radii[i] : 0; // #1737
  6030. if (isNumber(radius) && radius >= this.minPxSize / 2) {
  6031. // Shape arguments
  6032. point.marker = extend(point.marker, {
  6033. radius: radius,
  6034. width: 2 * radius,
  6035. height: 2 * radius
  6036. });
  6037. // Alignment box for the data label
  6038. point.dlBox = {
  6039. x: point.plotX - radius,
  6040. y: point.plotY - radius,
  6041. width: 2 * radius,
  6042. height: 2 * radius
  6043. };
  6044. }
  6045. else { // below zThreshold
  6046. // #1691
  6047. point.shapeArgs = point.plotY = point.dlBox = void 0;
  6048. }
  6049. }
  6050. },
  6051. alignDataLabel: seriesTypes.column.prototype.alignDataLabel,
  6052. buildKDTree: noop,
  6053. applyZones: noop
  6054. // Point class
  6055. }, {
  6056. /**
  6057. * @private
  6058. */
  6059. haloPath: function (size) {
  6060. return Point.prototype.haloPath.call(this,
  6061. // #6067
  6062. size === 0 ? 0 : (this.marker ? this.marker.radius || 0 : 0) + size);
  6063. },
  6064. ttBelow: false
  6065. });
  6066. // Add logic to pad each axis with the amount of pixels necessary to avoid the
  6067. // bubbles to overflow.
  6068. Axis.prototype.beforePadding = function () {
  6069. var axis = this, axisLength = this.len, chart = this.chart, pxMin = 0, pxMax = axisLength, isXAxis = this.isXAxis, dataKey = isXAxis ? 'xData' : 'yData', min = this.min, extremes = {}, smallestSize = Math.min(chart.plotWidth, chart.plotHeight), zMin = Number.MAX_VALUE, zMax = -Number.MAX_VALUE, range = this.max - min, transA = axisLength / range, activeSeries = [];
  6070. // Handle padding on the second pass, or on redraw
  6071. this.series.forEach(function (series) {
  6072. var seriesOptions = series.options, zData;
  6073. if (series.bubblePadding &&
  6074. (series.visible || !chart.options.chart.ignoreHiddenSeries)) {
  6075. // Correction for #1673
  6076. axis.allowZoomOutside = true;
  6077. // Cache it
  6078. activeSeries.push(series);
  6079. if (isXAxis) { // because X axis is evaluated first
  6080. // For each series, translate the size extremes to pixel values
  6081. ['minSize', 'maxSize'].forEach(function (prop) {
  6082. var length = seriesOptions[prop], isPercent = /%$/.test(length);
  6083. length = pInt(length);
  6084. extremes[prop] = isPercent ?
  6085. smallestSize * length / 100 :
  6086. length;
  6087. });
  6088. series.minPxSize = extremes.minSize;
  6089. // Prioritize min size if conflict to make sure bubbles are
  6090. // always visible. #5873
  6091. series.maxPxSize = Math.max(extremes.maxSize, extremes.minSize);
  6092. // Find the min and max Z
  6093. zData = series.zData.filter(isNumber);
  6094. if (zData.length) { // #1735
  6095. zMin = pick(seriesOptions.zMin, clamp(arrayMin(zData), seriesOptions.displayNegative === false ?
  6096. seriesOptions.zThreshold :
  6097. -Number.MAX_VALUE, zMin));
  6098. zMax = pick(seriesOptions.zMax, Math.max(zMax, arrayMax(zData)));
  6099. }
  6100. }
  6101. }
  6102. });
  6103. activeSeries.forEach(function (series) {
  6104. var data = series[dataKey], i = data.length, radius;
  6105. if (isXAxis) {
  6106. series.getRadii(zMin, zMax, series);
  6107. }
  6108. if (range > 0) {
  6109. while (i--) {
  6110. if (isNumber(data[i]) &&
  6111. axis.dataMin <= data[i] &&
  6112. data[i] <= axis.max) {
  6113. radius = series.radii ? series.radii[i] : 0;
  6114. pxMin = Math.min(((data[i] - min) * transA) - radius, pxMin);
  6115. pxMax = Math.max(((data[i] - min) * transA) + radius, pxMax);
  6116. }
  6117. }
  6118. }
  6119. });
  6120. // Apply the padding to the min and max properties
  6121. if (activeSeries.length && range > 0 && !this.logarithmic) {
  6122. pxMax -= axisLength;
  6123. transA *= (axisLength +
  6124. Math.max(0, pxMin) - // #8901
  6125. Math.min(pxMax, axisLength)) / axisLength;
  6126. [
  6127. ['min', 'userMin', pxMin],
  6128. ['max', 'userMax', pxMax]
  6129. ].forEach(function (keys) {
  6130. if (typeof pick(axis.options[keys[0]], axis[keys[1]]) === 'undefined') {
  6131. axis[keys[0]] += keys[2] / transA;
  6132. }
  6133. });
  6134. }
  6135. /* eslint-enable valid-jsdoc */
  6136. };
  6137. /**
  6138. * A `bubble` series. If the [type](#series.bubble.type) option is
  6139. * not specified, it is inherited from [chart.type](#chart.type).
  6140. *
  6141. * @extends series,plotOptions.bubble
  6142. * @excluding dataParser, dataURL, stack
  6143. * @product highcharts highstock
  6144. * @requires highcharts-more
  6145. * @apioption series.bubble
  6146. */
  6147. /**
  6148. * An array of data points for the series. For the `bubble` series type,
  6149. * points can be given in the following ways:
  6150. *
  6151. * 1. An array of arrays with 3 or 2 values. In this case, the values correspond
  6152. * to `x,y,z`. If the first value is a string, it is applied as the name of
  6153. * the point, and the `x` value is inferred. The `x` value can also be
  6154. * omitted, in which case the inner arrays should be of length 2\. Then the
  6155. * `x` value is automatically calculated, either starting at 0 and
  6156. * incremented by 1, or from `pointStart` and `pointInterval` given in the
  6157. * series options.
  6158. * ```js
  6159. * data: [
  6160. * [0, 1, 2],
  6161. * [1, 5, 5],
  6162. * [2, 0, 2]
  6163. * ]
  6164. * ```
  6165. *
  6166. * 2. An array of objects with named values. The following snippet shows only a
  6167. * few settings, see the complete options set below. If the total number of
  6168. * data points exceeds the series'
  6169. * [turboThreshold](#series.bubble.turboThreshold), this option is not
  6170. * available.
  6171. * ```js
  6172. * data: [{
  6173. * x: 1,
  6174. * y: 1,
  6175. * z: 1,
  6176. * name: "Point2",
  6177. * color: "#00FF00"
  6178. * }, {
  6179. * x: 1,
  6180. * y: 5,
  6181. * z: 4,
  6182. * name: "Point1",
  6183. * color: "#FF00FF"
  6184. * }]
  6185. * ```
  6186. *
  6187. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  6188. * Arrays of numeric x and y
  6189. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  6190. * Arrays of datetime x and y
  6191. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  6192. * Arrays of point.name and y
  6193. * @sample {highcharts} highcharts/series/data-array-of-objects/
  6194. * Config objects
  6195. *
  6196. * @type {Array<Array<(number|string),number>|Array<(number|string),number,number>|*>}
  6197. * @extends series.line.data
  6198. * @product highcharts
  6199. * @apioption series.bubble.data
  6200. */
  6201. /**
  6202. * @extends series.line.data.marker
  6203. * @excluding enabledThreshold, height, radius, width
  6204. * @product highcharts
  6205. * @apioption series.bubble.data.marker
  6206. */
  6207. /**
  6208. * The size value for each bubble. The bubbles' diameters are computed
  6209. * based on the `z`, and controlled by series options like `minSize`,
  6210. * `maxSize`, `sizeBy`, `zMin` and `zMax`.
  6211. *
  6212. * @type {number|null}
  6213. * @product highcharts
  6214. * @apioption series.bubble.data.z
  6215. */
  6216. /**
  6217. * @excluding enabled, enabledThreshold, height, radius, width
  6218. * @apioption series.bubble.marker
  6219. */
  6220. ''; // adds doclets above to transpiled file
  6221. });
  6222. _registerModule(_modules, 'modules/networkgraph/integrations.js', [_modules['parts/Globals.js']], function (H) {
  6223. /* *
  6224. *
  6225. * Networkgraph series
  6226. *
  6227. * (c) 2010-2020 Paweł Fus
  6228. *
  6229. * License: www.highcharts.com/license
  6230. *
  6231. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  6232. *
  6233. * */
  6234. /* eslint-disable no-invalid-this, valid-jsdoc */
  6235. H.networkgraphIntegrations = {
  6236. verlet: {
  6237. /**
  6238. * Attractive force funtion. Can be replaced by API's
  6239. * `layoutAlgorithm.attractiveForce`
  6240. *
  6241. * @private
  6242. * @param {number} d current distance between two nodes
  6243. * @param {number} k expected distance between two nodes
  6244. * @return {number} force
  6245. */
  6246. attractiveForceFunction: function (d, k) {
  6247. // Used in API:
  6248. return (k - d) / d;
  6249. },
  6250. /**
  6251. * Repulsive force funtion. Can be replaced by API's
  6252. * `layoutAlgorithm.repulsiveForce`
  6253. *
  6254. * @private
  6255. * @param {number} d current distance between two nodes
  6256. * @param {number} k expected distance between two nodes
  6257. * @return {number} force
  6258. */
  6259. repulsiveForceFunction: function (d, k) {
  6260. // Used in API:
  6261. return (k - d) / d * (k > d ? 1 : 0); // Force only for close nodes
  6262. },
  6263. /**
  6264. * Barycenter force. Calculate and applys barycenter forces on the
  6265. * nodes. Making them closer to the center of their barycenter point.
  6266. *
  6267. * In Verlet integration, force is applied on a node immidatelly to it's
  6268. * `plotX` and `plotY` position.
  6269. *
  6270. * @private
  6271. * @return {void}
  6272. */
  6273. barycenter: function () {
  6274. var gravitationalConstant = this.options.gravitationalConstant, xFactor = this.barycenter.xFactor, yFactor = this.barycenter.yFactor;
  6275. // To consider:
  6276. xFactor = (xFactor - (this.box.left + this.box.width) / 2) *
  6277. gravitationalConstant;
  6278. yFactor = (yFactor - (this.box.top + this.box.height) / 2) *
  6279. gravitationalConstant;
  6280. this.nodes.forEach(function (node) {
  6281. if (!node.fixedPosition) {
  6282. node.plotX -=
  6283. xFactor / node.mass / node.degree;
  6284. node.plotY -=
  6285. yFactor / node.mass / node.degree;
  6286. }
  6287. });
  6288. },
  6289. /**
  6290. * Repulsive force.
  6291. *
  6292. * In Verlet integration, force is applied on a node immidatelly to it's
  6293. * `plotX` and `plotY` position.
  6294. *
  6295. * @private
  6296. * @param {Highcharts.Point} node
  6297. * Node that should be translated by force.
  6298. * @param {number} force
  6299. * Force calcualated in `repulsiveForceFunction`
  6300. * @param {Highcharts.PositionObject} distance
  6301. * Distance between two nodes e.g. `{x, y}`
  6302. * @return {void}
  6303. */
  6304. repulsive: function (node, force, distanceXY) {
  6305. var factor = force * this.diffTemperature / node.mass / node.degree;
  6306. if (!node.fixedPosition) {
  6307. node.plotX += distanceXY.x * factor;
  6308. node.plotY += distanceXY.y * factor;
  6309. }
  6310. },
  6311. /**
  6312. * Attractive force.
  6313. *
  6314. * In Verlet integration, force is applied on a node immidatelly to it's
  6315. * `plotX` and `plotY` position.
  6316. *
  6317. * @private
  6318. * @param {Highcharts.Point} link
  6319. * Link that connects two nodes
  6320. * @param {number} force
  6321. * Force calcualated in `repulsiveForceFunction`
  6322. * @param {Highcharts.PositionObject} distance
  6323. * Distance between two nodes e.g. `{x, y}`
  6324. * @return {void}
  6325. */
  6326. attractive: function (link, force, distanceXY) {
  6327. var massFactor = link.getMass(), translatedX = -distanceXY.x * force * this.diffTemperature, translatedY = -distanceXY.y * force * this.diffTemperature;
  6328. if (!link.fromNode.fixedPosition) {
  6329. link.fromNode.plotX -=
  6330. translatedX * massFactor.fromNode / link.fromNode.degree;
  6331. link.fromNode.plotY -=
  6332. translatedY * massFactor.fromNode / link.fromNode.degree;
  6333. }
  6334. if (!link.toNode.fixedPosition) {
  6335. link.toNode.plotX +=
  6336. translatedX * massFactor.toNode / link.toNode.degree;
  6337. link.toNode.plotY +=
  6338. translatedY * massFactor.toNode / link.toNode.degree;
  6339. }
  6340. },
  6341. /**
  6342. * Integration method.
  6343. *
  6344. * In Verlet integration, forces are applied on node immidatelly to it's
  6345. * `plotX` and `plotY` position.
  6346. *
  6347. * Verlet without velocity:
  6348. *
  6349. * x(n+1) = 2 * x(n) - x(n-1) + A(T) * deltaT ^ 2
  6350. *
  6351. * where:
  6352. * - x(n+1) - new position
  6353. * - x(n) - current position
  6354. * - x(n-1) - previous position
  6355. *
  6356. * Assuming A(t) = 0 (no acceleration) and (deltaT = 1) we get:
  6357. *
  6358. * x(n+1) = x(n) + (x(n) - x(n-1))
  6359. *
  6360. * where:
  6361. * - (x(n) - x(n-1)) - position change
  6362. *
  6363. * TO DO:
  6364. * Consider Verlet with velocity to support additional
  6365. * forces. Or even Time-Corrected Verlet by Jonathan
  6366. * "lonesock" Dummer
  6367. *
  6368. * @private
  6369. * @param {Highcharts.NetworkgraphLayout} layout layout object
  6370. * @param {Highcharts.Point} node node that should be translated
  6371. * @return {void}
  6372. */
  6373. integrate: function (layout, node) {
  6374. var friction = -layout.options.friction, maxSpeed = layout.options.maxSpeed, prevX = node.prevX, prevY = node.prevY,
  6375. // Apply friciton:
  6376. diffX = ((node.plotX + node.dispX -
  6377. prevX) * friction), diffY = ((node.plotY + node.dispY -
  6378. prevY) * friction), abs = Math.abs, signX = abs(diffX) / (diffX || 1), // need to deal with 0
  6379. signY = abs(diffY) / (diffY || 1);
  6380. // Apply max speed:
  6381. diffX = signX * Math.min(maxSpeed, Math.abs(diffX));
  6382. diffY = signY * Math.min(maxSpeed, Math.abs(diffY));
  6383. // Store for the next iteration:
  6384. node.prevX = node.plotX + node.dispX;
  6385. node.prevY = node.plotY + node.dispY;
  6386. // Update positions:
  6387. node.plotX += diffX;
  6388. node.plotY += diffY;
  6389. node.temperature = layout.vectorLength({
  6390. x: diffX,
  6391. y: diffY
  6392. });
  6393. },
  6394. /**
  6395. * Estiamte the best possible distance between two nodes, making graph
  6396. * readable.
  6397. *
  6398. * @private
  6399. * @param {Highcharts.NetworkgraphLayout} layout layout object
  6400. * @return {number}
  6401. */
  6402. getK: function (layout) {
  6403. return Math.pow(layout.box.width * layout.box.height / layout.nodes.length, 0.5);
  6404. }
  6405. },
  6406. euler: {
  6407. /**
  6408. * Attractive force funtion. Can be replaced by API's
  6409. * `layoutAlgorithm.attractiveForce`
  6410. *
  6411. * Other forces that can be used:
  6412. *
  6413. * basic, not recommended:
  6414. * `function (d, k) { return d / k }`
  6415. *
  6416. * @private
  6417. * @param {number} d current distance between two nodes
  6418. * @param {number} k expected distance between two nodes
  6419. * @return {number} force
  6420. */
  6421. attractiveForceFunction: function (d, k) {
  6422. return d * d / k;
  6423. },
  6424. /**
  6425. * Repulsive force funtion. Can be replaced by API's
  6426. * `layoutAlgorithm.repulsiveForce`.
  6427. *
  6428. * Other forces that can be used:
  6429. *
  6430. * basic, not recommended:
  6431. * `function (d, k) { return k / d }`
  6432. *
  6433. * standard:
  6434. * `function (d, k) { return k * k / d }`
  6435. *
  6436. * grid-variant:
  6437. * `function (d, k) { return k * k / d * (2 * k - d > 0 ? 1 : 0) }`
  6438. *
  6439. * @private
  6440. * @param {number} d current distance between two nodes
  6441. * @param {number} k expected distance between two nodes
  6442. * @return {number} force
  6443. */
  6444. repulsiveForceFunction: function (d, k) {
  6445. return k * k / d;
  6446. },
  6447. /**
  6448. * Barycenter force. Calculate and applys barycenter forces on the
  6449. * nodes. Making them closer to the center of their barycenter point.
  6450. *
  6451. * In Euler integration, force is stored in a node, not changing it's
  6452. * position. Later, in `integrate()` forces are applied on nodes.
  6453. *
  6454. * @private
  6455. * @return {void}
  6456. */
  6457. barycenter: function () {
  6458. var gravitationalConstant = this.options.gravitationalConstant, xFactor = this.barycenter.xFactor, yFactor = this.barycenter.yFactor;
  6459. this.nodes.forEach(function (node) {
  6460. if (!node.fixedPosition) {
  6461. var degree = node.getDegree(), phi = degree * (1 + degree / 2);
  6462. node.dispX += ((xFactor - node.plotX) *
  6463. gravitationalConstant *
  6464. phi / node.degree);
  6465. node.dispY += ((yFactor - node.plotY) *
  6466. gravitationalConstant *
  6467. phi / node.degree);
  6468. }
  6469. });
  6470. },
  6471. /**
  6472. * Repulsive force.
  6473. *
  6474. * @private
  6475. * @param {Highcharts.Point} node
  6476. * Node that should be translated by force.
  6477. * @param {number} force
  6478. * Force calcualated in `repulsiveForceFunction`
  6479. * @param {Highcharts.PositionObject} distanceXY
  6480. * Distance between two nodes e.g. `{x, y}`
  6481. * @return {void}
  6482. */
  6483. repulsive: function (node, force, distanceXY, distanceR) {
  6484. node.dispX +=
  6485. (distanceXY.x / distanceR) * force / node.degree;
  6486. node.dispY +=
  6487. (distanceXY.y / distanceR) * force / node.degree;
  6488. },
  6489. /**
  6490. * Attractive force.
  6491. *
  6492. * In Euler integration, force is stored in a node, not changing it's
  6493. * position. Later, in `integrate()` forces are applied on nodes.
  6494. *
  6495. * @private
  6496. * @param {Highcharts.Point} link
  6497. * Link that connects two nodes
  6498. * @param {number} force
  6499. * Force calcualated in `repulsiveForceFunction`
  6500. * @param {Highcharts.PositionObject} distanceXY
  6501. * Distance between two nodes e.g. `{x, y}`
  6502. * @param {number} distanceR
  6503. * @return {void}
  6504. */
  6505. attractive: function (link, force, distanceXY, distanceR) {
  6506. var massFactor = link.getMass(), translatedX = (distanceXY.x / distanceR) * force, translatedY = (distanceXY.y / distanceR) * force;
  6507. if (!link.fromNode.fixedPosition) {
  6508. link.fromNode.dispX -=
  6509. translatedX * massFactor.fromNode / link.fromNode.degree;
  6510. link.fromNode.dispY -=
  6511. translatedY * massFactor.fromNode / link.fromNode.degree;
  6512. }
  6513. if (!link.toNode.fixedPosition) {
  6514. link.toNode.dispX +=
  6515. translatedX * massFactor.toNode / link.toNode.degree;
  6516. link.toNode.dispY +=
  6517. translatedY * massFactor.toNode / link.toNode.degree;
  6518. }
  6519. },
  6520. /**
  6521. * Integration method.
  6522. *
  6523. * In Euler integration, force were stored in a node, not changing it's
  6524. * position. Now, in the integrator method, we apply changes.
  6525. *
  6526. * Euler:
  6527. *
  6528. * Basic form: `x(n+1) = x(n) + v(n)`
  6529. *
  6530. * With Rengoild-Fruchterman we get:
  6531. * `x(n+1) = x(n) + v(n) / length(v(n)) * min(v(n), temperature(n))`
  6532. * where:
  6533. * - `x(n+1)`: next position
  6534. * - `x(n)`: current position
  6535. * - `v(n)`: velocity (comes from net force)
  6536. * - `temperature(n)`: current temperature
  6537. *
  6538. * Known issues:
  6539. * Oscillations when force vector has the same magnitude but opposite
  6540. * direction in the next step. Potentially solved by decreasing force by
  6541. * `v * (1 / node.degree)`
  6542. *
  6543. * Note:
  6544. * Actually `min(v(n), temperature(n))` replaces simulated annealing.
  6545. *
  6546. * @private
  6547. * @param {Highcharts.NetworkgraphLayout} layout
  6548. * Layout object
  6549. * @param {Highcharts.Point} node
  6550. * Node that should be translated
  6551. * @return {void}
  6552. */
  6553. integrate: function (layout, node) {
  6554. var distanceR;
  6555. node.dispX +=
  6556. node.dispX * layout.options.friction;
  6557. node.dispY +=
  6558. node.dispY * layout.options.friction;
  6559. distanceR = node.temperature = layout.vectorLength({
  6560. x: node.dispX,
  6561. y: node.dispY
  6562. });
  6563. if (distanceR !== 0) {
  6564. node.plotX += (node.dispX / distanceR *
  6565. Math.min(Math.abs(node.dispX), layout.temperature));
  6566. node.plotY += (node.dispY / distanceR *
  6567. Math.min(Math.abs(node.dispY), layout.temperature));
  6568. }
  6569. },
  6570. /**
  6571. * Estiamte the best possible distance between two nodes, making graph
  6572. * readable.
  6573. *
  6574. * @private
  6575. * @param {object} layout layout object
  6576. * @return {number}
  6577. */
  6578. getK: function (layout) {
  6579. return Math.pow(layout.box.width * layout.box.height / layout.nodes.length, 0.3);
  6580. }
  6581. }
  6582. };
  6583. });
  6584. _registerModule(_modules, 'modules/networkgraph/QuadTree.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
  6585. /* *
  6586. *
  6587. * Networkgraph series
  6588. *
  6589. * (c) 2010-2020 Paweł Fus
  6590. *
  6591. * License: www.highcharts.com/license
  6592. *
  6593. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  6594. *
  6595. * */
  6596. var extend = U.extend;
  6597. /* eslint-disable no-invalid-this, valid-jsdoc */
  6598. /**
  6599. * The QuadTree node class. Used in Networkgraph chart as a base for Barnes-Hut
  6600. * approximation.
  6601. *
  6602. * @private
  6603. * @class
  6604. * @name Highcharts.QuadTreeNode
  6605. *
  6606. * @param {Highcharts.Dictionary<number>} box Available space for the node
  6607. */
  6608. var QuadTreeNode = H.QuadTreeNode = function (box) {
  6609. /**
  6610. * Read only. The available space for node.
  6611. *
  6612. * @name Highcharts.QuadTreeNode#box
  6613. * @type {Highcharts.Dictionary<number>}
  6614. */
  6615. this.box = box;
  6616. /**
  6617. * Read only. The minium of width and height values.
  6618. *
  6619. * @name Highcharts.QuadTreeNode#boxSize
  6620. * @type {number}
  6621. */
  6622. this.boxSize = Math.min(box.width, box.height);
  6623. /**
  6624. * Read only. Array of subnodes. Empty if QuadTreeNode has just one Point.
  6625. * When added another Point to this QuadTreeNode, array is filled with four
  6626. * subnodes.
  6627. *
  6628. * @name Highcharts.QuadTreeNode#nodes
  6629. * @type {Array<Highcharts.QuadTreeNode>}
  6630. */
  6631. this.nodes = [];
  6632. /**
  6633. * Read only. Flag to determine if QuadTreeNode is internal (and has
  6634. * subnodes with mass and central position) or external (bound to Point).
  6635. *
  6636. * @name Highcharts.QuadTreeNode#isInternal
  6637. * @type {boolean}
  6638. */
  6639. this.isInternal = false;
  6640. /**
  6641. * Read only. If QuadTreeNode is an external node, Point is stored in
  6642. * `this.body`.
  6643. *
  6644. * @name Highcharts.QuadTreeNode#body
  6645. * @type {boolean|Highcharts.Point}
  6646. */
  6647. this.body = false;
  6648. /**
  6649. * Read only. Internal nodes when created are empty to reserve the space. If
  6650. * Point is added to this QuadTreeNode, QuadTreeNode is no longer empty.
  6651. *
  6652. * @name Highcharts.QuadTreeNode#isEmpty
  6653. * @type {boolean}
  6654. */
  6655. this.isEmpty = true;
  6656. };
  6657. extend(QuadTreeNode.prototype,
  6658. /** @lends Highcharts.QuadTreeNode.prototype */
  6659. {
  6660. /**
  6661. * Insert recursively point(node) into the QuadTree. If the given
  6662. * quadrant is already occupied, divide it into smaller quadrants.
  6663. *
  6664. * @param {Highcharts.Point} point
  6665. * Point/node to be inserted
  6666. * @param {number} depth
  6667. * Max depth of the QuadTree
  6668. */
  6669. insert: function (point, depth) {
  6670. var newQuadTreeNode;
  6671. if (this.isInternal) {
  6672. // Internal node:
  6673. this.nodes[this.getBoxPosition(point)].insert(point, depth - 1);
  6674. }
  6675. else {
  6676. this.isEmpty = false;
  6677. if (!this.body) {
  6678. // First body in a quadrant:
  6679. this.isInternal = false;
  6680. this.body = point;
  6681. }
  6682. else {
  6683. if (depth) {
  6684. // Every other body in a quadrant:
  6685. this.isInternal = true;
  6686. this.divideBox();
  6687. // Reinsert main body only once:
  6688. if (this.body !== true) {
  6689. this.nodes[this.getBoxPosition(this.body)]
  6690. .insert(this.body, depth - 1);
  6691. this.body = true;
  6692. }
  6693. // Add second body:
  6694. this.nodes[this.getBoxPosition(point)]
  6695. .insert(point, depth - 1);
  6696. }
  6697. else {
  6698. // We are below max allowed depth. That means either:
  6699. // - really huge number of points
  6700. // - falling two points into exactly the same position
  6701. // In this case, create another node in the QuadTree.
  6702. //
  6703. // Alternatively we could add some noise to the
  6704. // position, but that could result in different
  6705. // rendered chart in exporting.
  6706. newQuadTreeNode = new QuadTreeNode({
  6707. top: point.plotX,
  6708. left: point.plotY,
  6709. // Width/height below 1px
  6710. width: 0.1,
  6711. height: 0.1
  6712. });
  6713. newQuadTreeNode.body = point;
  6714. newQuadTreeNode.isInternal = false;
  6715. this.nodes.push(newQuadTreeNode);
  6716. }
  6717. }
  6718. }
  6719. },
  6720. /**
  6721. * Each quad node requires it's mass and center position. That mass and
  6722. * position is used to imitate real node in the layout by approximation.
  6723. */
  6724. updateMassAndCenter: function () {
  6725. var mass = 0, plotX = 0, plotY = 0;
  6726. if (this.isInternal) {
  6727. // Calcualte weightened mass of the quad node:
  6728. this.nodes.forEach(function (pointMass) {
  6729. if (!pointMass.isEmpty) {
  6730. mass += pointMass.mass;
  6731. plotX +=
  6732. pointMass.plotX * pointMass.mass;
  6733. plotY +=
  6734. pointMass.plotY * pointMass.mass;
  6735. }
  6736. });
  6737. plotX /= mass;
  6738. plotY /= mass;
  6739. }
  6740. else if (this.body) {
  6741. // Just one node, use coordinates directly:
  6742. mass = this.body.mass;
  6743. plotX = this.body.plotX;
  6744. plotY = this.body.plotY;
  6745. }
  6746. // Store details:
  6747. this.mass = mass;
  6748. this.plotX = plotX;
  6749. this.plotY = plotY;
  6750. },
  6751. /**
  6752. * When inserting another node into the box, that already hove one node,
  6753. * divide the available space into another four quadrants.
  6754. *
  6755. * Indexes of quadrants are:
  6756. * ```
  6757. * ------------- -------------
  6758. * | | | | |
  6759. * | | | 0 | 1 |
  6760. * | | divide() | | |
  6761. * | 1 | -----------> -------------
  6762. * | | | | |
  6763. * | | | 3 | 2 |
  6764. * | | | | |
  6765. * ------------- -------------
  6766. * ```
  6767. */
  6768. divideBox: function () {
  6769. var halfWidth = this.box.width / 2, halfHeight = this.box.height / 2;
  6770. // Top left
  6771. this.nodes[0] = new QuadTreeNode({
  6772. left: this.box.left,
  6773. top: this.box.top,
  6774. width: halfWidth,
  6775. height: halfHeight
  6776. });
  6777. // Top right
  6778. this.nodes[1] = new QuadTreeNode({
  6779. left: this.box.left + halfWidth,
  6780. top: this.box.top,
  6781. width: halfWidth,
  6782. height: halfHeight
  6783. });
  6784. // Bottom right
  6785. this.nodes[2] = new QuadTreeNode({
  6786. left: this.box.left + halfWidth,
  6787. top: this.box.top + halfHeight,
  6788. width: halfWidth,
  6789. height: halfHeight
  6790. });
  6791. // Bottom left
  6792. this.nodes[3] = new QuadTreeNode({
  6793. left: this.box.left,
  6794. top: this.box.top + halfHeight,
  6795. width: halfWidth,
  6796. height: halfHeight
  6797. });
  6798. },
  6799. /**
  6800. * Determine which of the quadrants should be used when placing node in
  6801. * the QuadTree. Returned index is always in range `< 0 , 3 >`.
  6802. *
  6803. * @param {Highcharts.Point} point
  6804. * @return {number}
  6805. */
  6806. getBoxPosition: function (point) {
  6807. var left = point.plotX < this.box.left + this.box.width / 2, top = point.plotY < this.box.top + this.box.height / 2, index;
  6808. if (left) {
  6809. if (top) {
  6810. // Top left
  6811. index = 0;
  6812. }
  6813. else {
  6814. // Bottom left
  6815. index = 3;
  6816. }
  6817. }
  6818. else {
  6819. if (top) {
  6820. // Top right
  6821. index = 1;
  6822. }
  6823. else {
  6824. // Bottom right
  6825. index = 2;
  6826. }
  6827. }
  6828. return index;
  6829. }
  6830. });
  6831. /**
  6832. * The QuadTree class. Used in Networkgraph chart as a base for Barnes-Hut
  6833. * approximation.
  6834. *
  6835. * @private
  6836. * @class
  6837. * @name Highcharts.QuadTree
  6838. *
  6839. * @param {number} x left position of the plotting area
  6840. * @param {number} y top position of the plotting area
  6841. * @param {number} width width of the plotting area
  6842. * @param {number} height height of the plotting area
  6843. */
  6844. var QuadTree = H.QuadTree = function (x, y, width, height) {
  6845. // Boundary rectangle:
  6846. this.box = {
  6847. left: x,
  6848. top: y,
  6849. width: width,
  6850. height: height
  6851. };
  6852. this.maxDepth = 25;
  6853. this.root = new QuadTreeNode(this.box, '0');
  6854. this.root.isInternal = true;
  6855. this.root.isRoot = true;
  6856. this.root.divideBox();
  6857. };
  6858. extend(QuadTree.prototype,
  6859. /** @lends Highcharts.QuadTree.prototype */
  6860. {
  6861. /**
  6862. * Insert nodes into the QuadTree
  6863. *
  6864. * @param {Array<Highcharts.Point>} points
  6865. */
  6866. insertNodes: function (points) {
  6867. points.forEach(function (point) {
  6868. this.root.insert(point, this.maxDepth);
  6869. }, this);
  6870. },
  6871. /**
  6872. * Depfth first treversal (DFS). Using `before` and `after` callbacks,
  6873. * we can get two results: preorder and postorder traversals, reminder:
  6874. *
  6875. * ```
  6876. * (a)
  6877. * / \
  6878. * (b) (c)
  6879. * / \
  6880. * (d) (e)
  6881. * ```
  6882. *
  6883. * DFS (preorder): `a -> b -> d -> e -> c`
  6884. *
  6885. * DFS (postorder): `d -> e -> b -> c -> a`
  6886. *
  6887. * @param {Highcharts.QuadTreeNode|null} node
  6888. * @param {Function} [beforeCallback] function to be called before
  6889. * visiting children nodes
  6890. * @param {Function} [afterCallback] function to be called after
  6891. * visiting children nodes
  6892. */
  6893. visitNodeRecursive: function (node, beforeCallback, afterCallback) {
  6894. var goFurther;
  6895. if (!node) {
  6896. node = this.root;
  6897. }
  6898. if (node === this.root && beforeCallback) {
  6899. goFurther = beforeCallback(node);
  6900. }
  6901. if (goFurther === false) {
  6902. return;
  6903. }
  6904. node.nodes.forEach(function (qtNode) {
  6905. if (qtNode.isInternal) {
  6906. if (beforeCallback) {
  6907. goFurther = beforeCallback(qtNode);
  6908. }
  6909. if (goFurther === false) {
  6910. return;
  6911. }
  6912. this.visitNodeRecursive(qtNode, beforeCallback, afterCallback);
  6913. }
  6914. else if (qtNode.body) {
  6915. if (beforeCallback) {
  6916. beforeCallback(qtNode.body);
  6917. }
  6918. }
  6919. if (afterCallback) {
  6920. afterCallback(qtNode);
  6921. }
  6922. }, this);
  6923. if (node === this.root && afterCallback) {
  6924. afterCallback(node);
  6925. }
  6926. },
  6927. /**
  6928. * Calculate mass of the each QuadNode in the tree.
  6929. */
  6930. calculateMassAndCenter: function () {
  6931. this.visitNodeRecursive(null, null, function (node) {
  6932. node.updateMassAndCenter();
  6933. });
  6934. }
  6935. });
  6936. });
  6937. _registerModule(_modules, 'modules/networkgraph/layouts.js', [_modules['parts/Chart.js'], _modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (Chart, H, U) {
  6938. /* *
  6939. *
  6940. * Networkgraph series
  6941. *
  6942. * (c) 2010-2020 Paweł Fus
  6943. *
  6944. * License: www.highcharts.com/license
  6945. *
  6946. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  6947. *
  6948. * */
  6949. var addEvent = U.addEvent, clamp = U.clamp, defined = U.defined, extend = U.extend, isFunction = U.isFunction, pick = U.pick, setAnimation = U.setAnimation;
  6950. /* eslint-disable no-invalid-this, valid-jsdoc */
  6951. H.layouts = {
  6952. 'reingold-fruchterman': function () {
  6953. }
  6954. };
  6955. extend(
  6956. /**
  6957. * Reingold-Fruchterman algorithm from
  6958. * "Graph Drawing by Force-directed Placement" paper.
  6959. * @private
  6960. */
  6961. H.layouts['reingold-fruchterman'].prototype, {
  6962. init: function (options) {
  6963. this.options = options;
  6964. this.nodes = [];
  6965. this.links = [];
  6966. this.series = [];
  6967. this.box = {
  6968. x: 0,
  6969. y: 0,
  6970. width: 0,
  6971. height: 0
  6972. };
  6973. this.setInitialRendering(true);
  6974. this.integration =
  6975. H.networkgraphIntegrations[options.integration];
  6976. this.enableSimulation = options.enableSimulation;
  6977. this.attractiveForce = pick(options.attractiveForce, this.integration.attractiveForceFunction);
  6978. this.repulsiveForce = pick(options.repulsiveForce, this.integration.repulsiveForceFunction);
  6979. this.approximation = options.approximation;
  6980. },
  6981. updateSimulation: function (enable) {
  6982. this.enableSimulation = pick(enable, this.options.enableSimulation);
  6983. },
  6984. start: function () {
  6985. var layout = this, series = this.series, options = this.options;
  6986. layout.currentStep = 0;
  6987. layout.forces = series[0] && series[0].forces || [];
  6988. layout.chart = series[0] && series[0].chart;
  6989. if (layout.initialRendering) {
  6990. layout.initPositions();
  6991. // Render elements in initial positions:
  6992. series.forEach(function (s) {
  6993. s.finishedAnimating = true; // #13169
  6994. s.render();
  6995. });
  6996. }
  6997. layout.setK();
  6998. layout.resetSimulation(options);
  6999. if (layout.enableSimulation) {
  7000. layout.step();
  7001. }
  7002. },
  7003. step: function () {
  7004. var layout = this, series = this.series, options = this.options;
  7005. // Algorithm:
  7006. layout.currentStep++;
  7007. if (layout.approximation === 'barnes-hut') {
  7008. layout.createQuadTree();
  7009. layout.quadTree.calculateMassAndCenter();
  7010. }
  7011. layout.forces.forEach(function (forceName) {
  7012. layout[forceName + 'Forces'](layout.temperature);
  7013. });
  7014. // Limit to the plotting area and cool down:
  7015. layout.applyLimits(layout.temperature);
  7016. // Cool down the system:
  7017. layout.temperature = layout.coolDown(layout.startTemperature, layout.diffTemperature, layout.currentStep);
  7018. layout.prevSystemTemperature = layout.systemTemperature;
  7019. layout.systemTemperature = layout.getSystemTemperature();
  7020. if (layout.enableSimulation) {
  7021. series.forEach(function (s) {
  7022. // Chart could be destroyed during the simulation
  7023. if (s.chart) {
  7024. s.render();
  7025. }
  7026. });
  7027. if (layout.maxIterations-- &&
  7028. isFinite(layout.temperature) &&
  7029. !layout.isStable()) {
  7030. if (layout.simulation) {
  7031. H.win.cancelAnimationFrame(layout.simulation);
  7032. }
  7033. layout.simulation = H.win.requestAnimationFrame(function () {
  7034. layout.step();
  7035. });
  7036. }
  7037. else {
  7038. layout.simulation = false;
  7039. }
  7040. }
  7041. },
  7042. stop: function () {
  7043. if (this.simulation) {
  7044. H.win.cancelAnimationFrame(this.simulation);
  7045. }
  7046. },
  7047. setArea: function (x, y, w, h) {
  7048. this.box = {
  7049. left: x,
  7050. top: y,
  7051. width: w,
  7052. height: h
  7053. };
  7054. },
  7055. setK: function () {
  7056. // Optimal distance between nodes,
  7057. // available space around the node:
  7058. this.k = this.options.linkLength || this.integration.getK(this);
  7059. },
  7060. addElementsToCollection: function (elements, collection) {
  7061. elements.forEach(function (elem) {
  7062. if (collection.indexOf(elem) === -1) {
  7063. collection.push(elem);
  7064. }
  7065. });
  7066. },
  7067. removeElementFromCollection: function (element, collection) {
  7068. var index = collection.indexOf(element);
  7069. if (index !== -1) {
  7070. collection.splice(index, 1);
  7071. }
  7072. },
  7073. clear: function () {
  7074. this.nodes.length = 0;
  7075. this.links.length = 0;
  7076. this.series.length = 0;
  7077. this.resetSimulation();
  7078. },
  7079. resetSimulation: function () {
  7080. this.forcedStop = false;
  7081. this.systemTemperature = 0;
  7082. this.setMaxIterations();
  7083. this.setTemperature();
  7084. this.setDiffTemperature();
  7085. },
  7086. restartSimulation: function () {
  7087. if (!this.simulation) {
  7088. // When dragging nodes, we don't need to calculate
  7089. // initial positions and rendering nodes:
  7090. this.setInitialRendering(false);
  7091. // Start new simulation:
  7092. if (!this.enableSimulation) {
  7093. // Run only one iteration to speed things up:
  7094. this.setMaxIterations(1);
  7095. }
  7096. else {
  7097. this.start();
  7098. }
  7099. if (this.chart) {
  7100. this.chart.redraw();
  7101. }
  7102. // Restore defaults:
  7103. this.setInitialRendering(true);
  7104. }
  7105. else {
  7106. // Extend current simulation:
  7107. this.resetSimulation();
  7108. }
  7109. },
  7110. setMaxIterations: function (maxIterations) {
  7111. this.maxIterations = pick(maxIterations, this.options.maxIterations);
  7112. },
  7113. setTemperature: function () {
  7114. this.temperature = this.startTemperature =
  7115. Math.sqrt(this.nodes.length);
  7116. },
  7117. setDiffTemperature: function () {
  7118. this.diffTemperature = this.startTemperature /
  7119. (this.options.maxIterations + 1);
  7120. },
  7121. setInitialRendering: function (enable) {
  7122. this.initialRendering = enable;
  7123. },
  7124. createQuadTree: function () {
  7125. this.quadTree = new H.QuadTree(this.box.left, this.box.top, this.box.width, this.box.height);
  7126. this.quadTree.insertNodes(this.nodes);
  7127. },
  7128. initPositions: function () {
  7129. var initialPositions = this.options.initialPositions;
  7130. if (isFunction(initialPositions)) {
  7131. initialPositions.call(this);
  7132. this.nodes.forEach(function (node) {
  7133. if (!defined(node.prevX)) {
  7134. node.prevX = node.plotX;
  7135. }
  7136. if (!defined(node.prevY)) {
  7137. node.prevY = node.plotY;
  7138. }
  7139. node.dispX = 0;
  7140. node.dispY = 0;
  7141. });
  7142. }
  7143. else if (initialPositions === 'circle') {
  7144. this.setCircularPositions();
  7145. }
  7146. else {
  7147. this.setRandomPositions();
  7148. }
  7149. },
  7150. setCircularPositions: function () {
  7151. var box = this.box, nodes = this.nodes, nodesLength = nodes.length + 1, angle = 2 * Math.PI / nodesLength, rootNodes = nodes.filter(function (node) {
  7152. return node.linksTo.length === 0;
  7153. }), sortedNodes = [], visitedNodes = {}, radius = this.options.initialPositionRadius;
  7154. /**
  7155. * @private
  7156. */
  7157. function addToNodes(node) {
  7158. node.linksFrom.forEach(function (link) {
  7159. if (!visitedNodes[link.toNode.id]) {
  7160. visitedNodes[link.toNode.id] = true;
  7161. sortedNodes.push(link.toNode);
  7162. addToNodes(link.toNode);
  7163. }
  7164. });
  7165. }
  7166. // Start with identified root nodes an sort the nodes by their
  7167. // hierarchy. In trees, this ensures that branches don't cross
  7168. // eachother.
  7169. rootNodes.forEach(function (rootNode) {
  7170. sortedNodes.push(rootNode);
  7171. addToNodes(rootNode);
  7172. });
  7173. // Cyclic tree, no root node found
  7174. if (!sortedNodes.length) {
  7175. sortedNodes = nodes;
  7176. // Dangling, cyclic trees
  7177. }
  7178. else {
  7179. nodes.forEach(function (node) {
  7180. if (sortedNodes.indexOf(node) === -1) {
  7181. sortedNodes.push(node);
  7182. }
  7183. });
  7184. }
  7185. // Initial positions are laid out along a small circle, appearing
  7186. // as a cluster in the middle
  7187. sortedNodes.forEach(function (node, index) {
  7188. node.plotX = node.prevX = pick(node.plotX, box.width / 2 + radius * Math.cos(index * angle));
  7189. node.plotY = node.prevY = pick(node.plotY, box.height / 2 + radius * Math.sin(index * angle));
  7190. node.dispX = 0;
  7191. node.dispY = 0;
  7192. });
  7193. },
  7194. setRandomPositions: function () {
  7195. var box = this.box, nodes = this.nodes, nodesLength = nodes.length + 1;
  7196. /**
  7197. * Return a repeatable, quasi-random number based on an integer
  7198. * input. For the initial positions
  7199. * @private
  7200. */
  7201. function unrandom(n) {
  7202. var rand = n * n / Math.PI;
  7203. rand = rand - Math.floor(rand);
  7204. return rand;
  7205. }
  7206. // Initial positions:
  7207. nodes.forEach(function (node, index) {
  7208. node.plotX = node.prevX = pick(node.plotX, box.width * unrandom(index));
  7209. node.plotY = node.prevY = pick(node.plotY, box.height * unrandom(nodesLength + index));
  7210. node.dispX = 0;
  7211. node.dispY = 0;
  7212. });
  7213. },
  7214. force: function (name) {
  7215. this.integration[name].apply(this, Array.prototype.slice.call(arguments, 1));
  7216. },
  7217. barycenterForces: function () {
  7218. this.getBarycenter();
  7219. this.force('barycenter');
  7220. },
  7221. getBarycenter: function () {
  7222. var systemMass = 0, cx = 0, cy = 0;
  7223. this.nodes.forEach(function (node) {
  7224. cx += node.plotX * node.mass;
  7225. cy += node.plotY * node.mass;
  7226. systemMass += node.mass;
  7227. });
  7228. this.barycenter = {
  7229. x: cx,
  7230. y: cy,
  7231. xFactor: cx / systemMass,
  7232. yFactor: cy / systemMass
  7233. };
  7234. return this.barycenter;
  7235. },
  7236. barnesHutApproximation: function (node, quadNode) {
  7237. var layout = this, distanceXY = layout.getDistXY(node, quadNode), distanceR = layout.vectorLength(distanceXY), goDeeper, force;
  7238. if (node !== quadNode && distanceR !== 0) {
  7239. if (quadNode.isInternal) {
  7240. // Internal node:
  7241. if (quadNode.boxSize / distanceR <
  7242. layout.options.theta &&
  7243. distanceR !== 0) {
  7244. // Treat as an external node:
  7245. force = layout.repulsiveForce(distanceR, layout.k);
  7246. layout.force('repulsive', node, force * quadNode.mass, distanceXY, distanceR);
  7247. goDeeper = false;
  7248. }
  7249. else {
  7250. // Go deeper:
  7251. goDeeper = true;
  7252. }
  7253. }
  7254. else {
  7255. // External node, direct force:
  7256. force = layout.repulsiveForce(distanceR, layout.k);
  7257. layout.force('repulsive', node, force * quadNode.mass, distanceXY, distanceR);
  7258. }
  7259. }
  7260. return goDeeper;
  7261. },
  7262. repulsiveForces: function () {
  7263. var layout = this;
  7264. if (layout.approximation === 'barnes-hut') {
  7265. layout.nodes.forEach(function (node) {
  7266. layout.quadTree.visitNodeRecursive(null, function (quadNode) {
  7267. return layout.barnesHutApproximation(node, quadNode);
  7268. });
  7269. });
  7270. }
  7271. else {
  7272. layout.nodes.forEach(function (node) {
  7273. layout.nodes.forEach(function (repNode) {
  7274. var force, distanceR, distanceXY;
  7275. if (
  7276. // Node can not repulse itself:
  7277. node !== repNode &&
  7278. // Only close nodes affect each other:
  7279. // layout.getDistR(node, repNode) < 2 * k &&
  7280. // Not dragged:
  7281. !node.fixedPosition) {
  7282. distanceXY = layout.getDistXY(node, repNode);
  7283. distanceR = layout.vectorLength(distanceXY);
  7284. if (distanceR !== 0) {
  7285. force = layout.repulsiveForce(distanceR, layout.k);
  7286. layout.force('repulsive', node, force * repNode.mass, distanceXY, distanceR);
  7287. }
  7288. }
  7289. });
  7290. });
  7291. }
  7292. },
  7293. attractiveForces: function () {
  7294. var layout = this, distanceXY, distanceR, force;
  7295. layout.links.forEach(function (link) {
  7296. if (link.fromNode && link.toNode) {
  7297. distanceXY = layout.getDistXY(link.fromNode, link.toNode);
  7298. distanceR = layout.vectorLength(distanceXY);
  7299. if (distanceR !== 0) {
  7300. force = layout.attractiveForce(distanceR, layout.k);
  7301. layout.force('attractive', link, force, distanceXY, distanceR);
  7302. }
  7303. }
  7304. });
  7305. },
  7306. applyLimits: function () {
  7307. var layout = this, nodes = layout.nodes;
  7308. nodes.forEach(function (node) {
  7309. if (node.fixedPosition) {
  7310. return;
  7311. }
  7312. layout.integration.integrate(layout, node);
  7313. layout.applyLimitBox(node, layout.box);
  7314. // Reset displacement:
  7315. node.dispX = 0;
  7316. node.dispY = 0;
  7317. });
  7318. },
  7319. /**
  7320. * External box that nodes should fall. When hitting an edge, node
  7321. * should stop or bounce.
  7322. * @private
  7323. */
  7324. applyLimitBox: function (node, box) {
  7325. var radius = node.radius;
  7326. /*
  7327. TO DO: Consider elastic collision instead of stopping.
  7328. o' means end position when hitting plotting area edge:
  7329. - "inelastic":
  7330. o
  7331. \
  7332. ______
  7333. | o'
  7334. | \
  7335. | \
  7336. - "elastic"/"bounced":
  7337. o
  7338. \
  7339. ______
  7340. | ^
  7341. | / \
  7342. |o' \
  7343. Euler sample:
  7344. if (plotX < 0) {
  7345. plotX = 0;
  7346. dispX *= -1;
  7347. }
  7348. if (plotX > box.width) {
  7349. plotX = box.width;
  7350. dispX *= -1;
  7351. }
  7352. */
  7353. // Limit X-coordinates:
  7354. node.plotX = clamp(node.plotX, box.left + radius, box.width - radius);
  7355. // Limit Y-coordinates:
  7356. node.plotY = clamp(node.plotY, box.top + radius, box.height - radius);
  7357. },
  7358. /**
  7359. * From "A comparison of simulated annealing cooling strategies" by
  7360. * Nourani and Andresen work.
  7361. * @private
  7362. */
  7363. coolDown: function (temperature, temperatureStep, currentStep) {
  7364. // Logarithmic:
  7365. /*
  7366. return Math.sqrt(this.nodes.length) -
  7367. Math.log(
  7368. currentStep * layout.diffTemperature
  7369. );
  7370. */
  7371. // Exponential:
  7372. /*
  7373. var alpha = 0.1;
  7374. layout.temperature = Math.sqrt(layout.nodes.length) *
  7375. Math.pow(alpha, layout.diffTemperature);
  7376. */
  7377. // Linear:
  7378. return temperature - temperatureStep * currentStep;
  7379. },
  7380. isStable: function () {
  7381. return Math.abs(this.systemTemperature -
  7382. this.prevSystemTemperature) < 0.00001 || this.temperature <= 0;
  7383. },
  7384. getSystemTemperature: function () {
  7385. return this.nodes.reduce(function (value, node) {
  7386. return value + node.temperature;
  7387. }, 0);
  7388. },
  7389. vectorLength: function (vector) {
  7390. return Math.sqrt(vector.x * vector.x + vector.y * vector.y);
  7391. },
  7392. getDistR: function (nodeA, nodeB) {
  7393. var distance = this.getDistXY(nodeA, nodeB);
  7394. return this.vectorLength(distance);
  7395. },
  7396. getDistXY: function (nodeA, nodeB) {
  7397. var xDist = nodeA.plotX - nodeB.plotX, yDist = nodeA.plotY - nodeB.plotY;
  7398. return {
  7399. x: xDist,
  7400. y: yDist,
  7401. absX: Math.abs(xDist),
  7402. absY: Math.abs(yDist)
  7403. };
  7404. }
  7405. });
  7406. /* ************************************************************************** *
  7407. * Multiple series support:
  7408. * ************************************************************************** */
  7409. // Clear previous layouts
  7410. addEvent(Chart, 'predraw', function () {
  7411. if (this.graphLayoutsLookup) {
  7412. this.graphLayoutsLookup.forEach(function (layout) {
  7413. layout.stop();
  7414. });
  7415. }
  7416. });
  7417. addEvent(Chart, 'render', function () {
  7418. var systemsStable, afterRender = false;
  7419. /**
  7420. * @private
  7421. */
  7422. function layoutStep(layout) {
  7423. if (layout.maxIterations-- &&
  7424. isFinite(layout.temperature) &&
  7425. !layout.isStable() &&
  7426. !layout.enableSimulation) {
  7427. // Hook similar to build-in addEvent, but instead of
  7428. // creating whole events logic, use just a function.
  7429. // It's faster which is important for rAF code.
  7430. // Used e.g. in packed-bubble series for bubble radius
  7431. // calculations
  7432. if (layout.beforeStep) {
  7433. layout.beforeStep();
  7434. }
  7435. layout.step();
  7436. systemsStable = false;
  7437. afterRender = true;
  7438. }
  7439. }
  7440. if (this.graphLayoutsLookup) {
  7441. setAnimation(false, this);
  7442. // Start simulation
  7443. this.graphLayoutsLookup.forEach(function (layout) {
  7444. layout.start();
  7445. });
  7446. // Just one sync step, to run different layouts similar to
  7447. // async mode.
  7448. while (!systemsStable) {
  7449. systemsStable = true;
  7450. this.graphLayoutsLookup.forEach(layoutStep);
  7451. }
  7452. if (afterRender) {
  7453. this.series.forEach(function (s) {
  7454. if (s && s.layout) {
  7455. s.render();
  7456. }
  7457. });
  7458. }
  7459. }
  7460. });
  7461. // disable simulation before print if enabled
  7462. addEvent(Chart, 'beforePrint', function () {
  7463. if (this.graphLayoutsLookup) {
  7464. this.graphLayoutsLookup.forEach(function (layout) {
  7465. layout.updateSimulation(false);
  7466. });
  7467. this.redraw();
  7468. }
  7469. });
  7470. // re-enable simulation after print
  7471. addEvent(Chart, 'afterPrint', function () {
  7472. if (this.graphLayoutsLookup) {
  7473. this.graphLayoutsLookup.forEach(function (layout) {
  7474. // return to default simulation
  7475. layout.updateSimulation();
  7476. });
  7477. }
  7478. this.redraw();
  7479. });
  7480. });
  7481. _registerModule(_modules, 'modules/networkgraph/draggable-nodes.js', [_modules['parts/Chart.js'], _modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (Chart, H, U) {
  7482. /* *
  7483. *
  7484. * Networkgraph series
  7485. *
  7486. * (c) 2010-2020 Paweł Fus
  7487. *
  7488. * License: www.highcharts.com/license
  7489. *
  7490. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  7491. *
  7492. * */
  7493. var addEvent = U.addEvent;
  7494. /* eslint-disable no-invalid-this, valid-jsdoc */
  7495. H.dragNodesMixin = {
  7496. /**
  7497. * Mouse down action, initializing drag&drop mode.
  7498. *
  7499. * @private
  7500. * @param {Highcharts.Point} point The point that event occured.
  7501. * @param {Highcharts.PointerEventObject} event Browser event, before normalization.
  7502. * @return {void}
  7503. */
  7504. onMouseDown: function (point, event) {
  7505. var normalizedEvent = this.chart.pointer.normalize(event);
  7506. point.fixedPosition = {
  7507. chartX: normalizedEvent.chartX,
  7508. chartY: normalizedEvent.chartY,
  7509. plotX: point.plotX,
  7510. plotY: point.plotY
  7511. };
  7512. point.inDragMode = true;
  7513. },
  7514. /**
  7515. * Mouse move action during drag&drop.
  7516. *
  7517. * @private
  7518. *
  7519. * @param {global.Event} event Browser event, before normalization.
  7520. * @param {Highcharts.Point} point The point that event occured.
  7521. *
  7522. * @return {void}
  7523. */
  7524. onMouseMove: function (point, event) {
  7525. if (point.fixedPosition && point.inDragMode) {
  7526. var series = this, chart = series.chart, normalizedEvent = chart.pointer.normalize(event), diffX = point.fixedPosition.chartX - normalizedEvent.chartX, diffY = point.fixedPosition.chartY - normalizedEvent.chartY, newPlotX, newPlotY, graphLayoutsLookup = chart.graphLayoutsLookup;
  7527. // At least 5px to apply change (avoids simple click):
  7528. if (Math.abs(diffX) > 5 || Math.abs(diffY) > 5) {
  7529. newPlotX = point.fixedPosition.plotX - diffX;
  7530. newPlotY = point.fixedPosition.plotY - diffY;
  7531. if (chart.isInsidePlot(newPlotX, newPlotY)) {
  7532. point.plotX = newPlotX;
  7533. point.plotY = newPlotY;
  7534. point.hasDragged = true;
  7535. this.redrawHalo(point);
  7536. graphLayoutsLookup.forEach(function (layout) {
  7537. layout.restartSimulation();
  7538. });
  7539. }
  7540. }
  7541. }
  7542. },
  7543. /**
  7544. * Mouse up action, finalizing drag&drop.
  7545. *
  7546. * @private
  7547. * @param {Highcharts.Point} point The point that event occured.
  7548. * @return {void}
  7549. */
  7550. onMouseUp: function (point, event) {
  7551. if (point.fixedPosition && point.hasDragged) {
  7552. if (this.layout.enableSimulation) {
  7553. this.layout.start();
  7554. }
  7555. else {
  7556. this.chart.redraw();
  7557. }
  7558. point.inDragMode = point.hasDragged = false;
  7559. if (!this.options.fixedDraggable) {
  7560. delete point.fixedPosition;
  7561. }
  7562. }
  7563. },
  7564. // Draggable mode:
  7565. /**
  7566. * Redraw halo on mousemove during the drag&drop action.
  7567. *
  7568. * @private
  7569. * @param {Highcharts.Point} point The point that should show halo.
  7570. * @return {void}
  7571. */
  7572. redrawHalo: function (point) {
  7573. if (point && this.halo) {
  7574. this.halo.attr({
  7575. d: point.haloPath(this.options.states.hover.halo.size)
  7576. });
  7577. }
  7578. }
  7579. };
  7580. /*
  7581. * Draggable mode:
  7582. */
  7583. addEvent(Chart, 'load', function () {
  7584. var chart = this, mousedownUnbinder, mousemoveUnbinder, mouseupUnbinder;
  7585. if (chart.container) {
  7586. mousedownUnbinder = addEvent(chart.container, 'mousedown', function (event) {
  7587. var point = chart.hoverPoint;
  7588. if (point &&
  7589. point.series &&
  7590. point.series.hasDraggableNodes &&
  7591. point.series.options.draggable) {
  7592. point.series.onMouseDown(point, event);
  7593. mousemoveUnbinder = addEvent(chart.container, 'mousemove', function (e) {
  7594. return point &&
  7595. point.series &&
  7596. point.series.onMouseMove(point, e);
  7597. });
  7598. mouseupUnbinder = addEvent(chart.container.ownerDocument, 'mouseup', function (e) {
  7599. mousemoveUnbinder();
  7600. mouseupUnbinder();
  7601. return point &&
  7602. point.series &&
  7603. point.series.onMouseUp(point, e);
  7604. });
  7605. }
  7606. });
  7607. }
  7608. addEvent(chart, 'destroy', function () {
  7609. mousedownUnbinder();
  7610. });
  7611. });
  7612. });
  7613. _registerModule(_modules, 'parts-more/PackedBubbleSeries.js', [_modules['parts/Chart.js'], _modules['parts/Color.js'], _modules['parts/Globals.js'], _modules['parts/Point.js'], _modules['parts/Utilities.js']], function (Chart, Color, H, Point, U) {
  7614. /* *
  7615. *
  7616. * (c) 2010-2018 Grzegorz Blachlinski, Sebastian Bochan
  7617. *
  7618. * License: www.highcharts.com/license
  7619. *
  7620. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  7621. *
  7622. * */
  7623. var color = Color.parse;
  7624. var addEvent = U.addEvent, clamp = U.clamp, defined = U.defined, extend = U.extend, extendClass = U.extendClass, fireEvent = U.fireEvent, isArray = U.isArray, isNumber = U.isNumber, merge = U.merge, pick = U.pick, seriesType = U.seriesType;
  7625. /**
  7626. * Formatter callback function.
  7627. *
  7628. * @callback Highcharts.SeriesPackedBubbleDataLabelsFormatterCallbackFunction
  7629. *
  7630. * @param {Highcharts.SeriesPackedBubbleDataLabelsFormatterContextObject} this
  7631. * Data label context to format
  7632. *
  7633. * @return {string}
  7634. * Formatted data label text
  7635. */
  7636. /**
  7637. * Context for the formatter function.
  7638. *
  7639. * @interface Highcharts.SeriesPackedBubbleDataLabelsFormatterContextObject
  7640. * @extends Highcharts.PointLabelObject
  7641. * @since 7.0.0
  7642. */ /**
  7643. * The color of the node.
  7644. * @name Highcharts.SeriesPackedBubbleDataLabelsFormatterContextObject#color
  7645. * @type {Highcharts.ColorString}
  7646. * @since 7.0.0
  7647. */ /**
  7648. * The point (node) object. The node name, if defined, is available through
  7649. * `this.point.name`. Arrays: `this.point.linksFrom` and `this.point.linksTo`
  7650. * contains all nodes connected to this point.
  7651. * @name Highcharts.SeriesPackedBubbleDataLabelsFormatterContextObject#point
  7652. * @type {Highcharts.Point}
  7653. * @since 7.0.0
  7654. */ /**
  7655. * The ID of the node.
  7656. * @name Highcharts.SeriesPackedBubbleDataLabelsFormatterContextObject#key
  7657. * @type {string}
  7658. * @since 7.0.0
  7659. */
  7660. var Series = H.Series, Reingold = H.layouts['reingold-fruchterman'], NetworkPoint = H.seriesTypes.bubble.prototype.pointClass, dragNodesMixin = H.dragNodesMixin;
  7661. Chart.prototype.getSelectedParentNodes = function () {
  7662. var chart = this, series = chart.series, selectedParentsNodes = [];
  7663. series.forEach(function (series) {
  7664. if (series.parentNode && series.parentNode.selected) {
  7665. selectedParentsNodes.push(series.parentNode);
  7666. }
  7667. });
  7668. return selectedParentsNodes;
  7669. };
  7670. H.networkgraphIntegrations.packedbubble = {
  7671. repulsiveForceFunction: function (d, k, node, repNode) {
  7672. return Math.min(d, (node.marker.radius + repNode.marker.radius) / 2);
  7673. },
  7674. barycenter: function () {
  7675. var layout = this, gravitationalConstant = layout.options.gravitationalConstant, box = layout.box, nodes = layout.nodes, centerX, centerY;
  7676. nodes.forEach(function (node) {
  7677. if (layout.options.splitSeries && !node.isParentNode) {
  7678. centerX = node.series.parentNode.plotX;
  7679. centerY = node.series.parentNode.plotY;
  7680. }
  7681. else {
  7682. centerX = box.width / 2;
  7683. centerY = box.height / 2;
  7684. }
  7685. if (!node.fixedPosition) {
  7686. node.plotX -=
  7687. (node.plotX - centerX) *
  7688. gravitationalConstant /
  7689. (node.mass * Math.sqrt(nodes.length));
  7690. node.plotY -=
  7691. (node.plotY - centerY) *
  7692. gravitationalConstant /
  7693. (node.mass * Math.sqrt(nodes.length));
  7694. }
  7695. });
  7696. },
  7697. repulsive: function (node, force, distanceXY, repNode) {
  7698. var factor = (force * this.diffTemperature / node.mass /
  7699. node.degree), x = distanceXY.x * factor, y = distanceXY.y * factor;
  7700. if (!node.fixedPosition) {
  7701. node.plotX += x;
  7702. node.plotY += y;
  7703. }
  7704. if (!repNode.fixedPosition) {
  7705. repNode.plotX -= x;
  7706. repNode.plotY -= y;
  7707. }
  7708. },
  7709. integrate: H.networkgraphIntegrations.verlet.integrate,
  7710. getK: H.noop
  7711. };
  7712. H.layouts.packedbubble = extendClass(Reingold, {
  7713. beforeStep: function () {
  7714. if (this.options.marker) {
  7715. this.series.forEach(function (series) {
  7716. if (series) {
  7717. series.calculateParentRadius();
  7718. }
  7719. });
  7720. }
  7721. },
  7722. setCircularPositions: function () {
  7723. var layout = this, box = layout.box, nodes = layout.nodes, nodesLength = nodes.length + 1, angle = 2 * Math.PI / nodesLength, centerX, centerY, radius = layout.options.initialPositionRadius;
  7724. nodes.forEach(function (node, index) {
  7725. if (layout.options.splitSeries &&
  7726. !node.isParentNode) {
  7727. centerX = node.series.parentNode.plotX;
  7728. centerY = node.series.parentNode.plotY;
  7729. }
  7730. else {
  7731. centerX = box.width / 2;
  7732. centerY = box.height / 2;
  7733. }
  7734. node.plotX = node.prevX = pick(node.plotX, centerX +
  7735. radius * Math.cos(node.index || index * angle));
  7736. node.plotY = node.prevY = pick(node.plotY, centerY +
  7737. radius * Math.sin(node.index || index * angle));
  7738. node.dispX = 0;
  7739. node.dispY = 0;
  7740. });
  7741. },
  7742. repulsiveForces: function () {
  7743. var layout = this, force, distanceR, distanceXY, bubblePadding = layout.options.bubblePadding;
  7744. layout.nodes.forEach(function (node) {
  7745. node.degree = node.mass;
  7746. node.neighbours = 0;
  7747. layout.nodes.forEach(function (repNode) {
  7748. force = 0;
  7749. if (
  7750. // Node can not repulse itself:
  7751. node !== repNode &&
  7752. // Only close nodes affect each other:
  7753. // Not dragged:
  7754. !node.fixedPosition &&
  7755. (layout.options.seriesInteraction ||
  7756. node.series === repNode.series)) {
  7757. distanceXY = layout.getDistXY(node, repNode);
  7758. distanceR = (layout.vectorLength(distanceXY) -
  7759. (node.marker.radius +
  7760. repNode.marker.radius +
  7761. bubblePadding));
  7762. // TODO padding configurable
  7763. if (distanceR < 0) {
  7764. node.degree += 0.01;
  7765. node.neighbours++;
  7766. force = layout.repulsiveForce(-distanceR / Math.sqrt(node.neighbours), layout.k, node, repNode);
  7767. }
  7768. layout.force('repulsive', node, force * repNode.mass, distanceXY, repNode, distanceR);
  7769. }
  7770. });
  7771. });
  7772. },
  7773. applyLimitBox: function (node) {
  7774. var layout = this, distanceXY, distanceR, factor = 0.01;
  7775. // parentNodeLimit should be used together
  7776. // with seriesInteraction: false
  7777. if (layout.options.splitSeries &&
  7778. !node.isParentNode &&
  7779. layout.options.parentNodeLimit) {
  7780. distanceXY = layout.getDistXY(node, node.series.parentNode);
  7781. distanceR = (node.series.parentNodeRadius -
  7782. node.marker.radius -
  7783. layout.vectorLength(distanceXY));
  7784. if (distanceR < 0 &&
  7785. distanceR > -2 * node.marker.radius) {
  7786. node.plotX -= distanceXY.x * factor;
  7787. node.plotY -= distanceXY.y * factor;
  7788. }
  7789. }
  7790. Reingold.prototype.applyLimitBox.apply(this, arguments);
  7791. }
  7792. });
  7793. /**
  7794. * @private
  7795. * @class
  7796. * @name Highcharts.seriesTypes.packedbubble
  7797. *
  7798. * @extends Highcharts.Series
  7799. */
  7800. seriesType('packedbubble', 'bubble',
  7801. /**
  7802. * A packed bubble series is a two dimensional series type, where each point
  7803. * renders a value in X, Y position. Each point is drawn as a bubble
  7804. * where the bubbles don't overlap with each other and the radius
  7805. * of the bubble relates to the value.
  7806. *
  7807. * @sample highcharts/demo/packed-bubble/
  7808. * Packed bubble chart
  7809. * @sample highcharts/demo/packed-bubble-split/
  7810. * Split packed bubble chart
  7811. * @extends plotOptions.bubble
  7812. * @excluding connectEnds, connectNulls, dragDrop, jitter, keys,
  7813. * pointPlacement, sizeByAbsoluteValue, step, xAxis, yAxis,
  7814. * zMax, zMin, dataSorting
  7815. * @product highcharts
  7816. * @since 7.0.0
  7817. * @requires highcharts-more
  7818. * @optionparent plotOptions.packedbubble
  7819. */
  7820. {
  7821. /**
  7822. * Minimum bubble size. Bubbles will automatically size between the
  7823. * `minSize` and `maxSize` to reflect the value of each bubble.
  7824. * Can be either pixels (when no unit is given), or a percentage of
  7825. * the smallest one of the plot width and height, divided by the square
  7826. * root of total number of points.
  7827. *
  7828. * @sample highcharts/plotoptions/bubble-size/
  7829. * Bubble size
  7830. *
  7831. * @type {number|string}
  7832. *
  7833. * @private
  7834. */
  7835. minSize: '10%',
  7836. /**
  7837. * Maximum bubble size. Bubbles will automatically size between the
  7838. * `minSize` and `maxSize` to reflect the value of each bubble.
  7839. * Can be either pixels (when no unit is given), or a percentage of
  7840. * the smallest one of the plot width and height, divided by the square
  7841. * root of total number of points.
  7842. *
  7843. * @sample highcharts/plotoptions/bubble-size/
  7844. * Bubble size
  7845. *
  7846. * @type {number|string}
  7847. *
  7848. * @private
  7849. */
  7850. maxSize: '50%',
  7851. sizeBy: 'area',
  7852. zoneAxis: 'y',
  7853. crisp: false,
  7854. tooltip: {
  7855. pointFormat: 'Value: {point.value}'
  7856. },
  7857. /**
  7858. * Flag to determine if nodes are draggable or not. Available for
  7859. * graph with useSimulation set to true only.
  7860. *
  7861. * @since 7.1.0
  7862. *
  7863. * @private
  7864. */
  7865. draggable: true,
  7866. /**
  7867. * An option is giving a possibility to choose between using simulation
  7868. * for calculating bubble positions. These reflects in both animation
  7869. * and final position of bubbles. Simulation is also adding options to
  7870. * the series graph based on used layout. In case of big data sets, with
  7871. * any performance issues, it is possible to disable animation and pack
  7872. * bubble in a simple circular way.
  7873. *
  7874. * @sample highcharts/series-packedbubble/spiral/
  7875. * useSimulation set to false
  7876. *
  7877. * @since 7.1.0
  7878. *
  7879. * @private
  7880. */
  7881. useSimulation: true,
  7882. /**
  7883. * Series options for parent nodes.
  7884. *
  7885. * @since 8.1.1
  7886. *
  7887. * @private
  7888. */
  7889. parentNode: {
  7890. /**
  7891. * Allow this series' parent nodes to be selected
  7892. * by clicking on the graph.
  7893. *
  7894. * @since 8.1.1
  7895. */
  7896. allowPointSelect: false
  7897. },
  7898. /**
  7899. /**
  7900. *
  7901. * @declare Highcharts.SeriesPackedBubbleDataLabelsOptionsObject
  7902. *
  7903. * @private
  7904. */
  7905. dataLabels: {
  7906. /**
  7907. * The
  7908. * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
  7909. * specifying what to show for _node_ in the networkgraph. In v7.0
  7910. * defaults to `{key}`, since v7.1 defaults to `undefined` and
  7911. * `formatter` is used instead.
  7912. *
  7913. * @type {string}
  7914. * @since 7.0.0
  7915. * @apioption plotOptions.packedbubble.dataLabels.format
  7916. */
  7917. // eslint-disable-next-line valid-jsdoc
  7918. /**
  7919. * Callback JavaScript function to format the data label for a node.
  7920. * Note that if a `format` is defined, the format takes precedence
  7921. * and the formatter is ignored.
  7922. *
  7923. * @type {Highcharts.SeriesPackedBubbleDataLabelsFormatterCallbackFunction}
  7924. * @since 7.0.0
  7925. */
  7926. formatter: function () {
  7927. return this.point.value;
  7928. },
  7929. /**
  7930. * @type {string}
  7931. * @since 7.1.0
  7932. * @apioption plotOptions.packedbubble.dataLabels.parentNodeFormat
  7933. */
  7934. // eslint-disable-next-line valid-jsdoc
  7935. /**
  7936. * @type {Highcharts.SeriesPackedBubbleDataLabelsFormatterCallbackFunction}
  7937. * @since 7.1.0
  7938. */
  7939. parentNodeFormatter: function () {
  7940. return this.name;
  7941. },
  7942. /**
  7943. * @sample {highcharts} highcharts/series-packedbubble/packed-dashboard
  7944. * Dashboard with dataLabels on parentNodes
  7945. *
  7946. * @declare Highcharts.SeriesPackedBubbleDataLabelsTextPathOptionsObject
  7947. * @since 7.1.0
  7948. */
  7949. parentNodeTextPath: {
  7950. /**
  7951. * Presentation attributes for the text path.
  7952. *
  7953. * @type {Highcharts.SVGAttributes}
  7954. * @since 7.1.0
  7955. * @apioption plotOptions.packedbubble.dataLabels.attributes
  7956. */
  7957. /**
  7958. * Enable or disable `textPath` option for link's or marker's
  7959. * data labels.
  7960. *
  7961. * @since 7.1.0
  7962. */
  7963. enabled: true
  7964. },
  7965. /**
  7966. * Options for a _node_ label text which should follow marker's
  7967. * shape.
  7968. *
  7969. * **Note:** Only SVG-based renderer supports this option.
  7970. *
  7971. * @extends plotOptions.series.dataLabels.textPath
  7972. * @apioption plotOptions.packedbubble.dataLabels.textPath
  7973. */
  7974. padding: 0,
  7975. style: {
  7976. transition: 'opacity 2000ms'
  7977. }
  7978. },
  7979. /**
  7980. * Options for layout algorithm when simulation is enabled. Inside there
  7981. * are options to change the speed, padding, initial bubbles positions
  7982. * and more.
  7983. *
  7984. * @extends plotOptions.networkgraph.layoutAlgorithm
  7985. * @excluding approximation, attractiveForce, repulsiveForce, theta
  7986. * @since 7.1.0
  7987. *
  7988. * @private
  7989. */
  7990. layoutAlgorithm: {
  7991. /**
  7992. * Initial layout algorithm for positioning nodes. Can be one of
  7993. * the built-in options ("circle", "random") or a function where
  7994. * positions should be set on each node (`this.nodes`) as
  7995. * `node.plotX` and `node.plotY`.
  7996. *
  7997. * @sample highcharts/series-networkgraph/initial-positions/
  7998. * Initial positions with callback
  7999. *
  8000. * @type {"circle"|"random"|Function}
  8001. */
  8002. initialPositions: 'circle',
  8003. /**
  8004. * @sample highcharts/series-packedbubble/initial-radius/
  8005. * Initial radius set to 200
  8006. *
  8007. * @extends plotOptions.networkgraph.layoutAlgorithm.initialPositionRadius
  8008. * @excluding states
  8009. */
  8010. initialPositionRadius: 20,
  8011. /**
  8012. * The distance between two bubbles, when the algorithm starts to
  8013. * treat two bubbles as overlapping. The `bubblePadding` is also the
  8014. * expected distance between all the bubbles on simulation end.
  8015. */
  8016. bubblePadding: 5,
  8017. /**
  8018. * Whether bubbles should interact with their parentNode to keep
  8019. * them inside.
  8020. */
  8021. parentNodeLimit: false,
  8022. /**
  8023. * Whether series should interact with each other or not. When
  8024. * `parentNodeLimit` is set to true, thi option should be set to
  8025. * false to avoid sticking points in wrong series parentNode.
  8026. */
  8027. seriesInteraction: true,
  8028. /**
  8029. * In case of split series, this option allows user to drag and
  8030. * drop points between series, for changing point related series.
  8031. *
  8032. * @sample highcharts/series-packedbubble/packed-dashboard/
  8033. * Example of drag'n drop bubbles for bubble kanban
  8034. */
  8035. dragBetweenSeries: false,
  8036. /**
  8037. * Layout algorithm options for parent nodes.
  8038. *
  8039. * @extends plotOptions.networkgraph.layoutAlgorithm
  8040. * @excluding approximation, attractiveForce, enableSimulation,
  8041. * repulsiveForce, theta
  8042. */
  8043. parentNodeOptions: {
  8044. maxIterations: 400,
  8045. gravitationalConstant: 0.03,
  8046. maxSpeed: 50,
  8047. initialPositionRadius: 100,
  8048. seriesInteraction: true,
  8049. /**
  8050. * Styling options for parentNodes markers. Similar to
  8051. * line.marker options.
  8052. *
  8053. * @sample highcharts/series-packedbubble/parentnode-style/
  8054. * Bubble size
  8055. *
  8056. * @extends plotOptions.series.marker
  8057. * @excluding states
  8058. */
  8059. marker: {
  8060. fillColor: null,
  8061. fillOpacity: 1,
  8062. lineWidth: 1,
  8063. lineColor: null,
  8064. symbol: 'circle'
  8065. }
  8066. },
  8067. enableSimulation: true,
  8068. /**
  8069. * Type of the algorithm used when positioning bubbles.
  8070. * @ignore-option
  8071. */
  8072. type: 'packedbubble',
  8073. /**
  8074. * Integration type. Integration determines how forces are applied
  8075. * on particles. The `packedbubble` integration is based on
  8076. * the networkgraph `verlet` integration, where the new position
  8077. * is based on a previous position without velocity:
  8078. * `newPosition += previousPosition - newPosition`.
  8079. *
  8080. * @sample highcharts/series-networkgraph/forces/
  8081. *
  8082. * @ignore-option
  8083. */
  8084. integration: 'packedbubble',
  8085. maxIterations: 1000,
  8086. /**
  8087. * Whether to split series into individual groups or to mix all
  8088. * series together.
  8089. *
  8090. * @since 7.1.0
  8091. * @default false
  8092. */
  8093. splitSeries: false,
  8094. /**
  8095. * Max speed that node can get in one iteration. In terms of
  8096. * simulation, it's a maximum translation (in pixels) that a node
  8097. * can move (in both, x and y, dimensions). While `friction` is
  8098. * applied on all nodes, max speed is applied only for nodes that
  8099. * move very fast, for example small or disconnected ones.
  8100. *
  8101. * @see [layoutAlgorithm.integration](#series.networkgraph.layoutAlgorithm.integration)
  8102. *
  8103. * @see [layoutAlgorithm.friction](#series.networkgraph.layoutAlgorithm.friction)
  8104. */
  8105. maxSpeed: 5,
  8106. gravitationalConstant: 0.01,
  8107. friction: -0.981
  8108. }
  8109. }, {
  8110. /**
  8111. * An internal option used for allowing nodes dragging.
  8112. * @private
  8113. */
  8114. hasDraggableNodes: true,
  8115. /**
  8116. * Array of internal forces. Each force should be later defined in
  8117. * integrations.js.
  8118. * @private
  8119. */
  8120. forces: ['barycenter', 'repulsive'],
  8121. pointArrayMap: ['value'],
  8122. trackerGroups: ['group', 'dataLabelsGroup', 'parentNodesGroup'],
  8123. pointValKey: 'value',
  8124. isCartesian: false,
  8125. requireSorting: false,
  8126. directTouch: true,
  8127. axisTypes: [],
  8128. noSharedTooltip: true,
  8129. // solving #12287
  8130. searchPoint: H.noop,
  8131. /* eslint-disable no-invalid-this, valid-jsdoc */
  8132. /**
  8133. * Create a single array of all points from all series
  8134. * @private
  8135. * @param {Highcharts.Series} series Array of all series objects
  8136. * @return {Array<Highcharts.PackedBubbleData>} Returns the array of all points.
  8137. */
  8138. accumulateAllPoints: function (series) {
  8139. var chart = series.chart, allDataPoints = [], i, j;
  8140. for (i = 0; i < chart.series.length; i++) {
  8141. series = chart.series[i];
  8142. if (series.is('packedbubble') && // #13574
  8143. series.visible ||
  8144. !chart.options.chart.ignoreHiddenSeries) {
  8145. // add data to array only if series is visible
  8146. for (j = 0; j < series.yData.length; j++) {
  8147. allDataPoints.push([
  8148. null, null,
  8149. series.yData[j],
  8150. series.index,
  8151. j,
  8152. {
  8153. id: j,
  8154. marker: {
  8155. radius: 0
  8156. }
  8157. }
  8158. ]);
  8159. }
  8160. }
  8161. }
  8162. return allDataPoints;
  8163. },
  8164. init: function () {
  8165. Series.prototype.init.apply(this, arguments);
  8166. // When one series is modified, the others need to be recomputed
  8167. addEvent(this, 'updatedData', function () {
  8168. this.chart.series.forEach(function (s) {
  8169. if (s.type === this.type) {
  8170. s.isDirty = true;
  8171. }
  8172. }, this);
  8173. });
  8174. return this;
  8175. },
  8176. render: function () {
  8177. var series = this, dataLabels = [];
  8178. Series.prototype.render.apply(this, arguments);
  8179. // #10823 - dataLabels should stay visible
  8180. // when enabled allowOverlap.
  8181. if (!series.options.dataLabels.allowOverlap) {
  8182. series.data.forEach(function (point) {
  8183. if (isArray(point.dataLabels)) {
  8184. point.dataLabels.forEach(function (dataLabel) {
  8185. dataLabels.push(dataLabel);
  8186. });
  8187. }
  8188. });
  8189. // Only hide overlapping dataLabels for layouts that
  8190. // use simulation. Spiral packedbubble don't need
  8191. // additional dataLabel hiding on every simulation step
  8192. if (series.options.useSimulation) {
  8193. series.chart.hideOverlappingLabels(dataLabels);
  8194. }
  8195. }
  8196. },
  8197. // Needed because of z-indexing issue if point is added in series.group
  8198. setVisible: function () {
  8199. var series = this;
  8200. Series.prototype.setVisible.apply(series, arguments);
  8201. if (series.parentNodeLayout && series.graph) {
  8202. if (series.visible) {
  8203. series.graph.show();
  8204. if (series.parentNode.dataLabel) {
  8205. series.parentNode.dataLabel.show();
  8206. }
  8207. }
  8208. else {
  8209. series.graph.hide();
  8210. series.parentNodeLayout
  8211. .removeElementFromCollection(series.parentNode, series.parentNodeLayout.nodes);
  8212. if (series.parentNode.dataLabel) {
  8213. series.parentNode.dataLabel.hide();
  8214. }
  8215. }
  8216. }
  8217. else if (series.layout) {
  8218. if (series.visible) {
  8219. series.layout.addElementsToCollection(series.points, series.layout.nodes);
  8220. }
  8221. else {
  8222. series.points.forEach(function (node) {
  8223. series.layout.removeElementFromCollection(node, series.layout.nodes);
  8224. });
  8225. }
  8226. }
  8227. },
  8228. // Packedbubble has two separate collecions of nodes if split, render
  8229. // dataLabels for both sets:
  8230. drawDataLabels: function () {
  8231. var textPath = this.options.dataLabels.textPath, points = this.points;
  8232. // Render node labels:
  8233. Series.prototype.drawDataLabels.apply(this, arguments);
  8234. // Render parentNode labels:
  8235. if (this.parentNode) {
  8236. this.parentNode.formatPrefix = 'parentNode';
  8237. this.points = [this.parentNode];
  8238. this.options.dataLabels.textPath =
  8239. this.options.dataLabels.parentNodeTextPath;
  8240. Series.prototype.drawDataLabels.apply(this, arguments);
  8241. // Restore nodes
  8242. this.points = points;
  8243. this.options.dataLabels.textPath = textPath;
  8244. }
  8245. },
  8246. /**
  8247. * The function responsible for calculating series bubble' s bBox.
  8248. * Needed because of exporting failure when useSimulation
  8249. * is set to false
  8250. * @private
  8251. */
  8252. seriesBox: function () {
  8253. var series = this, chart = series.chart, data = series.data, max = Math.max, min = Math.min, radius,
  8254. // bBox = [xMin, xMax, yMin, yMax]
  8255. bBox = [
  8256. chart.plotLeft,
  8257. chart.plotLeft + chart.plotWidth,
  8258. chart.plotTop,
  8259. chart.plotTop + chart.plotHeight
  8260. ];
  8261. data.forEach(function (p) {
  8262. if (defined(p.plotX) &&
  8263. defined(p.plotY) &&
  8264. p.marker.radius) {
  8265. radius = p.marker.radius;
  8266. bBox[0] = min(bBox[0], p.plotX - radius);
  8267. bBox[1] = max(bBox[1], p.plotX + radius);
  8268. bBox[2] = min(bBox[2], p.plotY - radius);
  8269. bBox[3] = max(bBox[3], p.plotY + radius);
  8270. }
  8271. });
  8272. return isNumber(bBox.width / bBox.height) ?
  8273. bBox :
  8274. null;
  8275. },
  8276. /**
  8277. * The function responsible for calculating the parent node radius
  8278. * based on the total surface of iniside-bubbles and the group BBox
  8279. * @private
  8280. */
  8281. calculateParentRadius: function () {
  8282. var series = this, bBox, parentPadding = 20, minParentRadius = 20;
  8283. bBox = series.seriesBox();
  8284. series.parentNodeRadius = clamp(Math.sqrt(2 * series.parentNodeMass / Math.PI) + parentPadding, minParentRadius, bBox ?
  8285. Math.max(Math.sqrt(Math.pow(bBox.width, 2) +
  8286. Math.pow(bBox.height, 2)) / 2 + parentPadding, minParentRadius) :
  8287. Math.sqrt(2 * series.parentNodeMass / Math.PI) + parentPadding);
  8288. if (series.parentNode) {
  8289. series.parentNode.marker.radius =
  8290. series.parentNode.radius = series.parentNodeRadius;
  8291. }
  8292. },
  8293. // Create Background/Parent Nodes for split series.
  8294. drawGraph: function () {
  8295. // if the series is not using layout, don't add parent nodes
  8296. if (!this.layout || !this.layout.options.splitSeries) {
  8297. return;
  8298. }
  8299. var series = this, chart = series.chart, parentAttribs = {}, nodeMarker = this.layout.options.parentNodeOptions.marker, parentOptions = {
  8300. fill: nodeMarker.fillColor || color(series.color).brighten(0.4).get(),
  8301. opacity: nodeMarker.fillOpacity,
  8302. stroke: nodeMarker.lineColor || series.color,
  8303. 'stroke-width': nodeMarker.lineWidth
  8304. }, visibility = series.visible ? 'inherit' : 'hidden';
  8305. // create the group for parent Nodes if doesn't exist
  8306. if (!this.parentNodesGroup) {
  8307. series.parentNodesGroup = series.plotGroup('parentNodesGroup', 'parentNode', visibility, 0.1, chart.seriesGroup);
  8308. series.group.attr({
  8309. zIndex: 2
  8310. });
  8311. }
  8312. this.calculateParentRadius();
  8313. parentAttribs = merge({
  8314. x: series.parentNode.plotX -
  8315. series.parentNodeRadius,
  8316. y: series.parentNode.plotY -
  8317. series.parentNodeRadius,
  8318. width: series.parentNodeRadius * 2,
  8319. height: series.parentNodeRadius * 2
  8320. }, parentOptions);
  8321. if (!series.parentNode.graphic) {
  8322. series.graph = series.parentNode.graphic =
  8323. chart.renderer.symbol(parentOptions.symbol)
  8324. .add(series.parentNodesGroup);
  8325. }
  8326. series.parentNode.graphic.attr(parentAttribs);
  8327. },
  8328. /**
  8329. * Creating parent nodes for split series, in which all the bubbles
  8330. * are rendered.
  8331. * @private
  8332. */
  8333. createParentNodes: function () {
  8334. var series = this, chart = series.chart, parentNodeLayout = series.parentNodeLayout, nodeAdded, parentNode = series.parentNode, PackedBubblePoint = series.pointClass;
  8335. series.parentNodeMass = 0;
  8336. series.points.forEach(function (p) {
  8337. series.parentNodeMass +=
  8338. Math.PI * Math.pow(p.marker.radius, 2);
  8339. });
  8340. series.calculateParentRadius();
  8341. parentNodeLayout.nodes.forEach(function (node) {
  8342. if (node.seriesIndex === series.index) {
  8343. nodeAdded = true;
  8344. }
  8345. });
  8346. parentNodeLayout.setArea(0, 0, chart.plotWidth, chart.plotHeight);
  8347. if (!nodeAdded) {
  8348. if (!parentNode) {
  8349. parentNode = (new PackedBubblePoint()).init(this, {
  8350. mass: series.parentNodeRadius / 2,
  8351. marker: {
  8352. radius: series.parentNodeRadius
  8353. },
  8354. dataLabels: {
  8355. inside: false
  8356. },
  8357. dataLabelOnNull: true,
  8358. degree: series.parentNodeRadius,
  8359. isParentNode: true,
  8360. seriesIndex: series.index
  8361. });
  8362. }
  8363. if (series.parentNode) {
  8364. parentNode.plotX = series.parentNode.plotX;
  8365. parentNode.plotY = series.parentNode.plotY;
  8366. }
  8367. series.parentNode = parentNode;
  8368. parentNodeLayout.addElementsToCollection([series], parentNodeLayout.series);
  8369. parentNodeLayout.addElementsToCollection([parentNode], parentNodeLayout.nodes);
  8370. }
  8371. },
  8372. drawTracker: function () {
  8373. var series = this, chart = series.chart, pointer = chart.pointer, onMouseOver = function (e) {
  8374. var point = pointer.getPointFromEvent(e);
  8375. // undefined on graph in scatterchart
  8376. if (typeof point !== 'undefined') {
  8377. pointer.isDirectTouch = true;
  8378. point.onMouseOver(e);
  8379. }
  8380. }, parentNode = series.parentNode;
  8381. var dataLabels;
  8382. H.TrackerMixin.drawTrackerPoint.call(this);
  8383. // Add reference to the point
  8384. if (parentNode) {
  8385. dataLabels = (isArray(parentNode.dataLabels) ?
  8386. parentNode.dataLabels :
  8387. (parentNode.dataLabel ? [parentNode.dataLabel] : []));
  8388. if (parentNode.graphic) {
  8389. parentNode.graphic.element.point = parentNode;
  8390. }
  8391. dataLabels.forEach(function (dataLabel) {
  8392. if (dataLabel.div) {
  8393. dataLabel.div.point = parentNode;
  8394. }
  8395. else {
  8396. dataLabel.element.point = parentNode;
  8397. }
  8398. });
  8399. }
  8400. },
  8401. /**
  8402. * Function responsible for adding series layout, used for parent nodes.
  8403. * @private
  8404. */
  8405. addSeriesLayout: function () {
  8406. var series = this, layoutOptions = series.options.layoutAlgorithm, graphLayoutsStorage = series.chart.graphLayoutsStorage, graphLayoutsLookup = series.chart.graphLayoutsLookup, parentNodeOptions = merge(layoutOptions, layoutOptions.parentNodeOptions, {
  8407. enableSimulation: series.layout.options.enableSimulation
  8408. }), parentNodeLayout;
  8409. parentNodeLayout = graphLayoutsStorage[layoutOptions.type + '-series'];
  8410. if (!parentNodeLayout) {
  8411. graphLayoutsStorage[layoutOptions.type + '-series'] =
  8412. parentNodeLayout =
  8413. new H.layouts[layoutOptions.type]();
  8414. parentNodeLayout.init(parentNodeOptions);
  8415. graphLayoutsLookup.splice(parentNodeLayout.index, 0, parentNodeLayout);
  8416. }
  8417. series.parentNodeLayout = parentNodeLayout;
  8418. this.createParentNodes();
  8419. },
  8420. /**
  8421. * Adding the basic layout to series points.
  8422. * @private
  8423. */
  8424. addLayout: function () {
  8425. var series = this, layoutOptions = series.options.layoutAlgorithm, graphLayoutsStorage = series.chart.graphLayoutsStorage, graphLayoutsLookup = series.chart.graphLayoutsLookup, chartOptions = series.chart.options.chart, layout;
  8426. if (!graphLayoutsStorage) {
  8427. series.chart.graphLayoutsStorage = graphLayoutsStorage = {};
  8428. series.chart.graphLayoutsLookup = graphLayoutsLookup = [];
  8429. }
  8430. layout = graphLayoutsStorage[layoutOptions.type];
  8431. if (!layout) {
  8432. layoutOptions.enableSimulation =
  8433. !defined(chartOptions.forExport) ?
  8434. layoutOptions.enableSimulation :
  8435. !chartOptions.forExport;
  8436. graphLayoutsStorage[layoutOptions.type] = layout =
  8437. new H.layouts[layoutOptions.type]();
  8438. layout.init(layoutOptions);
  8439. graphLayoutsLookup.splice(layout.index, 0, layout);
  8440. }
  8441. series.layout = layout;
  8442. series.points.forEach(function (node) {
  8443. node.mass = 2;
  8444. node.degree = 1;
  8445. node.collisionNmb = 1;
  8446. });
  8447. layout.setArea(0, 0, series.chart.plotWidth, series.chart.plotHeight);
  8448. layout.addElementsToCollection([series], layout.series);
  8449. layout.addElementsToCollection(series.points, layout.nodes);
  8450. },
  8451. /**
  8452. * Function responsible for adding all the layouts to the chart.
  8453. * @private
  8454. */
  8455. deferLayout: function () {
  8456. // TODO split layouts to independent methods
  8457. var series = this, layoutOptions = series.options.layoutAlgorithm;
  8458. if (!series.visible) {
  8459. return;
  8460. }
  8461. // layout is using nodes for position calculation
  8462. series.addLayout();
  8463. if (layoutOptions.splitSeries) {
  8464. series.addSeriesLayout();
  8465. }
  8466. },
  8467. /**
  8468. * Extend the base translate method to handle bubble size,
  8469. * and correct positioning them.
  8470. * @private
  8471. */
  8472. translate: function () {
  8473. var series = this, chart = series.chart, data = series.data, index = series.index, point, radius, positions, i, useSimulation = series.options.useSimulation;
  8474. series.processedXData = series.xData;
  8475. series.generatePoints();
  8476. // merged data is an array with all of the data from all series
  8477. if (!defined(chart.allDataPoints)) {
  8478. chart.allDataPoints = series.accumulateAllPoints(series);
  8479. // calculate radius for all added data
  8480. series.getPointRadius();
  8481. }
  8482. // after getting initial radius, calculate bubble positions
  8483. if (useSimulation) {
  8484. positions = chart.allDataPoints;
  8485. }
  8486. else {
  8487. positions = series.placeBubbles(chart.allDataPoints);
  8488. series.options.draggable = false;
  8489. }
  8490. // Set the shape and arguments to be picked up in drawPoints
  8491. for (i = 0; i < positions.length; i++) {
  8492. if (positions[i][3] === index) {
  8493. // update the series points with the val from positions
  8494. // array
  8495. point = data[positions[i][4]];
  8496. radius = positions[i][2];
  8497. if (!useSimulation) {
  8498. point.plotX = (positions[i][0] - chart.plotLeft +
  8499. chart.diffX);
  8500. point.plotY = (positions[i][1] - chart.plotTop +
  8501. chart.diffY);
  8502. }
  8503. point.marker = extend(point.marker, {
  8504. radius: radius,
  8505. width: 2 * radius,
  8506. height: 2 * radius
  8507. });
  8508. point.radius = radius;
  8509. }
  8510. }
  8511. if (useSimulation) {
  8512. series.deferLayout();
  8513. }
  8514. fireEvent(series, 'afterTranslate');
  8515. },
  8516. /**
  8517. * Check if two bubbles overlaps.
  8518. * @private
  8519. * @param {Array} first bubble
  8520. * @param {Array} second bubble
  8521. * @return {Boolean} overlap or not
  8522. */
  8523. checkOverlap: function (bubble1, bubble2) {
  8524. var diffX = bubble1[0] - bubble2[0], // diff of X center values
  8525. diffY = bubble1[1] - bubble2[1], // diff of Y center values
  8526. sumRad = bubble1[2] + bubble2[2]; // sum of bubble radius
  8527. return (Math.sqrt(diffX * diffX + diffY * diffY) -
  8528. Math.abs(sumRad)) < -0.001;
  8529. },
  8530. /**
  8531. * Function that is adding one bubble based on positions and sizes of
  8532. * two other bubbles, lastBubble is the last added bubble, newOrigin is
  8533. * the bubble for positioning new bubbles. nextBubble is the curently
  8534. * added bubble for which we are calculating positions
  8535. * @private
  8536. * @param {Array<number>} lastBubble The closest last bubble
  8537. * @param {Array<number>} newOrigin New bubble
  8538. * @param {Array<number>} nextBubble The closest next bubble
  8539. * @return {Array<number>} Bubble with correct positions
  8540. */
  8541. positionBubble: function (lastBubble, newOrigin, nextBubble) {
  8542. var sqrt = Math.sqrt, asin = Math.asin, acos = Math.acos, pow = Math.pow, abs = Math.abs, distance = sqrt(// dist between lastBubble and newOrigin
  8543. pow((lastBubble[0] - newOrigin[0]), 2) +
  8544. pow((lastBubble[1] - newOrigin[1]), 2)), alfa = acos(
  8545. // from cosinus theorem: alfa is an angle used for
  8546. // calculating correct position
  8547. (pow(distance, 2) +
  8548. pow(nextBubble[2] + newOrigin[2], 2) -
  8549. pow(nextBubble[2] + lastBubble[2], 2)) / (2 * (nextBubble[2] + newOrigin[2]) * distance)), beta = asin(// from sinus theorem.
  8550. abs(lastBubble[0] - newOrigin[0]) /
  8551. distance),
  8552. // providing helping variables, related to angle between
  8553. // lastBubble and newOrigin
  8554. gamma = (lastBubble[1] - newOrigin[1]) < 0 ? 0 : Math.PI,
  8555. // if new origin y is smaller than last bubble y value
  8556. // (2 and 3 quarter),
  8557. // add Math.PI to final angle
  8558. delta = (lastBubble[0] - newOrigin[0]) *
  8559. (lastBubble[1] - newOrigin[1]) < 0 ?
  8560. 1 : -1, // (1st and 3rd quarter)
  8561. finalAngle = gamma + alfa + beta * delta, cosA = Math.cos(finalAngle), sinA = Math.sin(finalAngle), posX = newOrigin[0] + (newOrigin[2] + nextBubble[2]) * sinA,
  8562. // center of new origin + (radius1 + radius2) * sinus A
  8563. posY = newOrigin[1] - (newOrigin[2] + nextBubble[2]) * cosA;
  8564. return [
  8565. posX,
  8566. posY,
  8567. nextBubble[2],
  8568. nextBubble[3],
  8569. nextBubble[4]
  8570. ]; // the same as described before
  8571. },
  8572. /**
  8573. * This is the main function responsible
  8574. * for positioning all of the bubbles
  8575. * allDataPoints - bubble array, in format [pixel x value,
  8576. * pixel y value, radius,
  8577. * related series index, related point index]
  8578. * @private
  8579. * @param {Array<Highcharts.PackedBubbleData>} allDataPoints All points from all series
  8580. * @return {Array<Highcharts.PackedBubbleData>} Positions of all bubbles
  8581. */
  8582. placeBubbles: function (allDataPoints) {
  8583. var series = this, checkOverlap = series.checkOverlap, positionBubble = series.positionBubble, bubblePos = [], stage = 1, j = 0, k = 0, calculatedBubble, sortedArr, arr = [], i;
  8584. // sort all points
  8585. sortedArr = allDataPoints.sort(function (a, b) {
  8586. return b[2] - a[2];
  8587. });
  8588. if (sortedArr.length) {
  8589. // create first bubble in the middle of the chart
  8590. bubblePos.push([
  8591. [
  8592. 0,
  8593. 0,
  8594. sortedArr[0][2],
  8595. sortedArr[0][3],
  8596. sortedArr[0][4]
  8597. ] // point index
  8598. ]); // 0 level bubble
  8599. if (sortedArr.length > 1) {
  8600. bubblePos.push([
  8601. [
  8602. 0,
  8603. (0 - sortedArr[1][2] -
  8604. sortedArr[0][2]),
  8605. // move bubble above first one
  8606. sortedArr[1][2],
  8607. sortedArr[1][3],
  8608. sortedArr[1][4]
  8609. ]
  8610. ]); // 1 level 1st bubble
  8611. // first two already positioned so starting from 2
  8612. for (i = 2; i < sortedArr.length; i++) {
  8613. sortedArr[i][2] = sortedArr[i][2] || 1;
  8614. // in case if radius is calculated as 0.
  8615. calculatedBubble = positionBubble(bubblePos[stage][j], bubblePos[stage - 1][k], sortedArr[i]); // calculate initial bubble position
  8616. if (checkOverlap(calculatedBubble, bubblePos[stage][0])) {
  8617. /* if new bubble is overlapping with first bubble
  8618. * in current level (stage)
  8619. */
  8620. bubblePos.push([]);
  8621. k = 0;
  8622. /* reset index of bubble, used for
  8623. * positioning the bubbles around it,
  8624. * we are starting from first bubble in next
  8625. * stage because we are changing level to higher
  8626. */
  8627. bubblePos[stage + 1].push(positionBubble(bubblePos[stage][j], bubblePos[stage][0], sortedArr[i]));
  8628. // (last bubble, 1. from curr stage, new bubble)
  8629. stage++; // the new level is created, above current
  8630. j = 0; // set the index of bubble in curr level to 0
  8631. }
  8632. else if (stage > 1 &&
  8633. bubblePos[stage - 1][k + 1] &&
  8634. checkOverlap(calculatedBubble, bubblePos[stage - 1][k + 1])) {
  8635. /* if new bubble is overlapping with one of the prev
  8636. * stage bubbles, it means that - bubble, used for
  8637. * positioning the bubbles around it has changed
  8638. * so we need to recalculate it
  8639. */
  8640. k++;
  8641. bubblePos[stage].push(positionBubble(bubblePos[stage][j], bubblePos[stage - 1][k], sortedArr[i]));
  8642. // (last bubble, prev stage bubble, new bubble)
  8643. j++;
  8644. }
  8645. else { // simply add calculated bubble
  8646. j++;
  8647. bubblePos[stage].push(calculatedBubble);
  8648. }
  8649. }
  8650. }
  8651. series.chart.stages = bubblePos;
  8652. // it may not be necessary but adding it just in case -
  8653. // it is containing all of the bubble levels
  8654. series.chart.rawPositions =
  8655. []
  8656. .concat.apply([], bubblePos);
  8657. // bubble positions merged into one array
  8658. series.resizeRadius();
  8659. arr = series.chart.rawPositions;
  8660. }
  8661. return arr;
  8662. },
  8663. /**
  8664. * The function responsible for resizing the bubble radius.
  8665. * In shortcut: it is taking the initially
  8666. * calculated positions of bubbles. Then it is calculating the min max
  8667. * of both dimensions, creating something in shape of bBox.
  8668. * The comparison of bBox and the size of plotArea
  8669. * (later it may be also the size set by customer) is giving the
  8670. * value how to recalculate the radius so it will match the size
  8671. * @private
  8672. */
  8673. resizeRadius: function () {
  8674. var chart = this.chart, positions = chart.rawPositions, min = Math.min, max = Math.max, plotLeft = chart.plotLeft, plotTop = chart.plotTop, chartHeight = chart.plotHeight, chartWidth = chart.plotWidth, minX, maxX, minY, maxY, radius, bBox, spaceRatio, smallerDimension, i;
  8675. minX = minY = Number.POSITIVE_INFINITY; // set initial values
  8676. maxX = maxY = Number.NEGATIVE_INFINITY;
  8677. for (i = 0; i < positions.length; i++) {
  8678. radius = positions[i][2];
  8679. minX = min(minX, positions[i][0] - radius);
  8680. // (x center-radius) is the min x value used by specific bubble
  8681. maxX = max(maxX, positions[i][0] + radius);
  8682. minY = min(minY, positions[i][1] - radius);
  8683. maxY = max(maxY, positions[i][1] + radius);
  8684. }
  8685. bBox = [maxX - minX, maxY - minY];
  8686. spaceRatio = [
  8687. (chartWidth - plotLeft) / bBox[0],
  8688. (chartHeight - plotTop) / bBox[1]
  8689. ];
  8690. smallerDimension = min.apply([], spaceRatio);
  8691. if (Math.abs(smallerDimension - 1) > 1e-10) {
  8692. // if bBox is considered not the same width as possible size
  8693. for (i = 0; i < positions.length; i++) {
  8694. positions[i][2] *= smallerDimension;
  8695. }
  8696. this.placeBubbles(positions);
  8697. }
  8698. else {
  8699. /** if no radius recalculation is needed, we need to position
  8700. * the whole bubbles in center of chart plotarea
  8701. * for this, we are adding two parameters,
  8702. * diffY and diffX, that are related to differences
  8703. * between the initial center and the bounding box
  8704. */
  8705. chart.diffY = chartHeight / 2 +
  8706. plotTop - minY - (maxY - minY) / 2;
  8707. chart.diffX = chartWidth / 2 +
  8708. plotLeft - minX - (maxX - minX) / 2;
  8709. }
  8710. },
  8711. /**
  8712. * Calculate min and max bubble value for radius calculation.
  8713. * @private
  8714. */
  8715. calculateZExtremes: function () {
  8716. var chart = this.chart, zMin = this.options.zMin, zMax = this.options.zMax, valMin = Infinity, valMax = -Infinity;
  8717. if (zMin && zMax) {
  8718. return [zMin, zMax];
  8719. }
  8720. // it is needed to deal with null
  8721. // and undefined values
  8722. chart.series.forEach(function (s) {
  8723. s.yData.forEach(function (p) {
  8724. if (defined(p)) {
  8725. if (p > valMax) {
  8726. valMax = p;
  8727. }
  8728. if (p < valMin) {
  8729. valMin = p;
  8730. }
  8731. }
  8732. });
  8733. });
  8734. zMin = pick(zMin, valMin);
  8735. zMax = pick(zMax, valMax);
  8736. return [zMin, zMax];
  8737. },
  8738. /**
  8739. * Calculate radius of bubbles in series.
  8740. * @private
  8741. */
  8742. getPointRadius: function () {
  8743. var series = this, chart = series.chart, plotWidth = chart.plotWidth, plotHeight = chart.plotHeight, seriesOptions = series.options, useSimulation = seriesOptions.useSimulation, smallestSize = Math.min(plotWidth, plotHeight), extremes = {}, radii = [], allDataPoints = chart.allDataPoints, minSize, maxSize, value, radius, zExtremes;
  8744. ['minSize', 'maxSize'].forEach(function (prop) {
  8745. var length = parseInt(seriesOptions[prop], 10), isPercent = /%$/.test(seriesOptions[prop]);
  8746. extremes[prop] = isPercent ?
  8747. smallestSize * length / 100 :
  8748. length * Math.sqrt(allDataPoints.length);
  8749. });
  8750. chart.minRadius = minSize = extremes.minSize /
  8751. Math.sqrt(allDataPoints.length);
  8752. chart.maxRadius = maxSize = extremes.maxSize /
  8753. Math.sqrt(allDataPoints.length);
  8754. zExtremes = useSimulation ?
  8755. series.calculateZExtremes() :
  8756. [minSize, maxSize];
  8757. (allDataPoints || []).forEach(function (point, i) {
  8758. value = useSimulation ?
  8759. clamp(point[2], zExtremes[0], zExtremes[1]) :
  8760. point[2];
  8761. radius = series.getRadius(zExtremes[0], zExtremes[1], minSize, maxSize, value);
  8762. if (radius === 0) {
  8763. radius = null;
  8764. }
  8765. allDataPoints[i][2] = radius;
  8766. radii.push(radius);
  8767. });
  8768. series.radii = radii;
  8769. },
  8770. // Draggable mode:
  8771. /**
  8772. * Redraw halo on mousemove during the drag&drop action.
  8773. * @private
  8774. * @param {Highcharts.Point} point The point that should show halo.
  8775. */
  8776. redrawHalo: dragNodesMixin.redrawHalo,
  8777. /**
  8778. * Mouse down action, initializing drag&drop mode.
  8779. * @private
  8780. * @param {global.Event} event Browser event, before normalization.
  8781. * @param {Highcharts.Point} point The point that event occured.
  8782. */
  8783. onMouseDown: dragNodesMixin.onMouseDown,
  8784. /**
  8785. * Mouse move action during drag&drop.
  8786. * @private
  8787. * @param {global.Event} event Browser event, before normalization.
  8788. * @param {Highcharts.Point} point The point that event occured.
  8789. */
  8790. onMouseMove: dragNodesMixin.onMouseMove,
  8791. /**
  8792. * Mouse up action, finalizing drag&drop.
  8793. * @private
  8794. * @param {Highcharts.Point} point The point that event occured.
  8795. */
  8796. onMouseUp: function (point) {
  8797. if (point.fixedPosition && !point.removed) {
  8798. var distanceXY, distanceR, layout = this.layout, parentNodeLayout = this.parentNodeLayout;
  8799. if (parentNodeLayout && layout.options.dragBetweenSeries) {
  8800. parentNodeLayout.nodes.forEach(function (node) {
  8801. if (point && point.marker &&
  8802. node !== point.series.parentNode) {
  8803. distanceXY = layout.getDistXY(point, node);
  8804. distanceR = (layout.vectorLength(distanceXY) -
  8805. node.marker.radius -
  8806. point.marker.radius);
  8807. if (distanceR < 0) {
  8808. node.series.addPoint(merge(point.options, {
  8809. plotX: point.plotX,
  8810. plotY: point.plotY
  8811. }), false);
  8812. layout.removeElementFromCollection(point, layout.nodes);
  8813. point.remove();
  8814. }
  8815. }
  8816. });
  8817. }
  8818. dragNodesMixin.onMouseUp.apply(this, arguments);
  8819. }
  8820. },
  8821. destroy: function () {
  8822. // Remove the series from all layouts series collections #11469
  8823. if (this.chart.graphLayoutsLookup) {
  8824. this.chart.graphLayoutsLookup.forEach(function (layout) {
  8825. layout.removeElementFromCollection(this, layout.series);
  8826. }, this);
  8827. }
  8828. if (this.parentNode) {
  8829. this.parentNodeLayout.removeElementFromCollection(this.parentNode, this.parentNodeLayout.nodes);
  8830. if (this.parentNode.dataLabel) {
  8831. this.parentNode.dataLabel =
  8832. this.parentNode.dataLabel.destroy();
  8833. }
  8834. }
  8835. H.Series.prototype.destroy.apply(this, arguments);
  8836. },
  8837. alignDataLabel: H.Series.prototype.alignDataLabel
  8838. }, {
  8839. /**
  8840. * Destroy point.
  8841. * Then remove point from the layout.
  8842. * @private
  8843. * @return {undefined}
  8844. */
  8845. destroy: function () {
  8846. if (this.series.layout) {
  8847. this.series.layout.removeElementFromCollection(this, this.series.layout.nodes);
  8848. }
  8849. return Point.prototype.destroy.apply(this, arguments);
  8850. },
  8851. firePointEvent: function (eventType, eventArgs, defaultFunction) {
  8852. var point = this, series = this.series, seriesOptions = series.options;
  8853. if (this.isParentNode && seriesOptions.parentNode) {
  8854. var temp = seriesOptions.allowPointSelect;
  8855. seriesOptions.allowPointSelect = seriesOptions.parentNode.allowPointSelect;
  8856. Point.prototype.firePointEvent.apply(this, arguments);
  8857. seriesOptions.allowPointSelect = temp;
  8858. }
  8859. else {
  8860. Point.prototype.firePointEvent.apply(this, arguments);
  8861. }
  8862. },
  8863. select: function (selected, accumulate) {
  8864. var point = this, series = this.series, chart = series.chart;
  8865. if (point.isParentNode) {
  8866. chart.getSelectedPoints = chart.getSelectedParentNodes;
  8867. Point.prototype.select.apply(this, arguments);
  8868. chart.getSelectedPoints = H.Chart.prototype.getSelectedPoints;
  8869. }
  8870. else {
  8871. Point.prototype.select.apply(this, arguments);
  8872. }
  8873. }
  8874. });
  8875. // Remove accumulated data points to redistribute all of them again
  8876. // (i.e after hiding series by legend)
  8877. addEvent(Chart, 'beforeRedraw', function () {
  8878. if (this.allDataPoints) {
  8879. delete this.allDataPoints;
  8880. }
  8881. });
  8882. /* eslint-enable no-invalid-this, valid-jsdoc */
  8883. /**
  8884. * A `packedbubble` series. If the [type](#series.packedbubble.type) option is
  8885. * not specified, it is inherited from [chart.type](#chart.type).
  8886. *
  8887. * @type {Object}
  8888. * @extends series,plotOptions.packedbubble
  8889. * @excluding dataParser, dataSorting, dataURL, dragDrop, stack
  8890. * @product highcharts
  8891. * @requires highcharts-more
  8892. * @apioption series.packedbubble
  8893. */
  8894. /**
  8895. * An array of data points for the series. For the `packedbubble` series type,
  8896. * points can be given in the following ways:
  8897. *
  8898. * 1. An array of `values`.
  8899. *
  8900. * ```js
  8901. * data: [5, 1, 20]
  8902. * ```
  8903. *
  8904. * 2. An array of objects with named values. The objects are point
  8905. * configuration objects as seen below. If the total number of data points
  8906. * exceeds the series' [turboThreshold](#series.packedbubble.turboThreshold),
  8907. * this option is not available.
  8908. *
  8909. * ```js
  8910. * data: [{
  8911. * value: 1,
  8912. * name: "Point2",
  8913. * color: "#00FF00"
  8914. * }, {
  8915. * value: 5,
  8916. * name: "Point1",
  8917. * color: "#FF00FF"
  8918. * }]
  8919. * ```
  8920. *
  8921. * @type {Array<Object|Array>}
  8922. * @extends series.line.data
  8923. * @excluding marker, x, y
  8924. * @sample {highcharts} highcharts/series/data-array-of-objects/
  8925. * Config objects
  8926. * @product highcharts
  8927. * @apioption series.packedbubble.data
  8928. */
  8929. /**
  8930. * @type {Highcharts.SeriesPackedBubbleDataLabelsOptionsObject|Array<Highcharts.SeriesPackedBubbleDataLabelsOptionsObject>}
  8931. * @product highcharts
  8932. * @apioption series.packedbubble.data.dataLabels
  8933. */
  8934. /**
  8935. * @excluding enabled,enabledThreshold,height,radius,width
  8936. * @product highcharts
  8937. * @apioption series.packedbubble.marker
  8938. */
  8939. ''; // adds doclets above to transpiled file
  8940. });
  8941. _registerModule(_modules, 'parts-more/Polar.js', [_modules['parts/Chart.js'], _modules['parts/Globals.js'], _modules['parts-more/Pane.js'], _modules['parts/Pointer.js'], _modules['parts/SVGRenderer.js'], _modules['parts/Utilities.js']], function (Chart, H, Pane, Pointer, SVGRenderer, U) {
  8942. /* *
  8943. *
  8944. * (c) 2010-2020 Torstein Honsi
  8945. *
  8946. * License: www.highcharts.com/license
  8947. *
  8948. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  8949. *
  8950. * */
  8951. var addEvent = U.addEvent, animObject = U.animObject, defined = U.defined, find = U.find, isNumber = U.isNumber, pick = U.pick, splat = U.splat, uniqueKey = U.uniqueKey, wrap = U.wrap;
  8952. // Extensions for polar charts. Additionally, much of the geometry required for
  8953. // polar charts is gathered in RadialAxes.js.
  8954. var Series = H.Series, seriesTypes = H.seriesTypes, seriesProto = Series.prototype, pointerProto = Pointer.prototype, colProto, arearangeProto;
  8955. /* eslint-disable no-invalid-this, valid-jsdoc */
  8956. /**
  8957. * Search a k-d tree by the point angle, used for shared tooltips in polar
  8958. * charts
  8959. * @private
  8960. */
  8961. seriesProto.searchPointByAngle = function (e) {
  8962. var series = this, chart = series.chart, xAxis = series.xAxis, center = xAxis.pane.center, plotX = e.chartX - center[0] - chart.plotLeft, plotY = e.chartY - center[1] - chart.plotTop;
  8963. return this.searchKDTree({
  8964. clientX: 180 + (Math.atan2(plotX, plotY) * (-180 / Math.PI))
  8965. });
  8966. };
  8967. /**
  8968. * #6212 Calculate connectors for spline series in polar chart.
  8969. * @private
  8970. * @param {boolean} calculateNeighbours
  8971. * Check if connectors should be calculated for neighbour points as
  8972. * well allows short recurence
  8973. */
  8974. seriesProto.getConnectors = function (segment, index, calculateNeighbours, connectEnds) {
  8975. var i, prevPointInd, nextPointInd, previousPoint, nextPoint, previousX, previousY, nextX, nextY, plotX, plotY, ret,
  8976. // 1 means control points midway between points, 2 means 1/3 from
  8977. // the point, 3 is 1/4 etc;
  8978. smoothing = 1.5, denom = smoothing + 1, leftContX, leftContY, rightContX, rightContY, dLControlPoint, // distance left control point
  8979. dRControlPoint, leftContAngle, rightContAngle, jointAngle, addedNumber = connectEnds ? 1 : 0;
  8980. // Calculate final index of points depending on the initial index value.
  8981. // Because of calculating neighbours, index may be outisde segment
  8982. // array.
  8983. if (index >= 0 && index <= segment.length - 1) {
  8984. i = index;
  8985. }
  8986. else if (index < 0) {
  8987. i = segment.length - 1 + index;
  8988. }
  8989. else {
  8990. i = 0;
  8991. }
  8992. prevPointInd = (i - 1 < 0) ? segment.length - (1 + addedNumber) : i - 1;
  8993. nextPointInd = (i + 1 > segment.length - 1) ? addedNumber : i + 1;
  8994. previousPoint = segment[prevPointInd];
  8995. nextPoint = segment[nextPointInd];
  8996. previousX = previousPoint.plotX;
  8997. previousY = previousPoint.plotY;
  8998. nextX = nextPoint.plotX;
  8999. nextY = nextPoint.plotY;
  9000. plotX = segment[i].plotX; // actual point
  9001. plotY = segment[i].plotY;
  9002. leftContX = (smoothing * plotX + previousX) / denom;
  9003. leftContY = (smoothing * plotY + previousY) / denom;
  9004. rightContX = (smoothing * plotX + nextX) / denom;
  9005. rightContY = (smoothing * plotY + nextY) / denom;
  9006. dLControlPoint = Math.sqrt(Math.pow(leftContX - plotX, 2) + Math.pow(leftContY - plotY, 2));
  9007. dRControlPoint = Math.sqrt(Math.pow(rightContX - plotX, 2) + Math.pow(rightContY - plotY, 2));
  9008. leftContAngle = Math.atan2(leftContY - plotY, leftContX - plotX);
  9009. rightContAngle = Math.atan2(rightContY - plotY, rightContX - plotX);
  9010. jointAngle = (Math.PI / 2) + ((leftContAngle + rightContAngle) / 2);
  9011. // Ensure the right direction, jointAngle should be in the same quadrant
  9012. // as leftContAngle
  9013. if (Math.abs(leftContAngle - jointAngle) > Math.PI / 2) {
  9014. jointAngle -= Math.PI;
  9015. }
  9016. // Find the corrected control points for a spline straight through the
  9017. // point
  9018. leftContX = plotX + Math.cos(jointAngle) * dLControlPoint;
  9019. leftContY = plotY + Math.sin(jointAngle) * dLControlPoint;
  9020. rightContX = plotX + Math.cos(Math.PI + jointAngle) * dRControlPoint;
  9021. rightContY = plotY + Math.sin(Math.PI + jointAngle) * dRControlPoint;
  9022. // push current point's connectors into returned object
  9023. ret = {
  9024. rightContX: rightContX,
  9025. rightContY: rightContY,
  9026. leftContX: leftContX,
  9027. leftContY: leftContY,
  9028. plotX: plotX,
  9029. plotY: plotY
  9030. };
  9031. // calculate connectors for previous and next point and push them inside
  9032. // returned object
  9033. if (calculateNeighbours) {
  9034. ret.prevPointCont = this.getConnectors(segment, prevPointInd, false, connectEnds);
  9035. }
  9036. return ret;
  9037. };
  9038. /**
  9039. * Translate a point's plotX and plotY from the internal angle and radius
  9040. * measures to true plotX, plotY coordinates
  9041. * @private
  9042. */
  9043. seriesProto.toXY = function (point) {
  9044. var xy, chart = this.chart, xAxis = this.xAxis, yAxis = this.yAxis, plotX = point.plotX, plotY = point.plotY, series = point.series, inverted = chart.inverted, pointY = point.y, radius = inverted ? plotX : yAxis.len - plotY, clientX;
  9045. // Corrected y position of inverted series other than column
  9046. if (inverted && series && !series.isRadialBar) {
  9047. point.plotY = plotY =
  9048. typeof pointY === 'number' ? (yAxis.translate(pointY) || 0) : 0;
  9049. }
  9050. // Save rectangular plotX, plotY for later computation
  9051. point.rectPlotX = plotX;
  9052. point.rectPlotY = plotY;
  9053. if (yAxis.center) {
  9054. radius += yAxis.center[3] / 2;
  9055. }
  9056. // Find the polar plotX and plotY
  9057. xy = inverted ? yAxis.postTranslate(plotY, radius) :
  9058. xAxis.postTranslate(plotX, radius);
  9059. point.plotX = point.polarPlotX = xy.x - chart.plotLeft;
  9060. point.plotY = point.polarPlotY = xy.y - chart.plotTop;
  9061. // If shared tooltip, record the angle in degrees in order to align X
  9062. // points. Otherwise, use a standard k-d tree to get the nearest point
  9063. // in two dimensions.
  9064. if (this.kdByAngle) {
  9065. clientX = ((plotX / Math.PI * 180) +
  9066. xAxis.pane.options.startAngle) % 360;
  9067. if (clientX < 0) { // #2665
  9068. clientX += 360;
  9069. }
  9070. point.clientX = clientX;
  9071. }
  9072. else {
  9073. point.clientX = point.plotX;
  9074. }
  9075. };
  9076. if (seriesTypes.spline) {
  9077. /**
  9078. * Overridden method for calculating a spline from one point to the next
  9079. * @private
  9080. */
  9081. wrap(seriesTypes.spline.prototype, 'getPointSpline', function (proceed, segment, point, i) {
  9082. var ret, connectors;
  9083. if (this.chart.polar) {
  9084. // moveTo or lineTo
  9085. if (!i) {
  9086. ret = ['M', point.plotX, point.plotY];
  9087. }
  9088. else { // curve from last point to this
  9089. connectors = this.getConnectors(segment, i, true, this.connectEnds);
  9090. ret = [
  9091. 'C',
  9092. connectors.prevPointCont.rightContX,
  9093. connectors.prevPointCont.rightContY,
  9094. connectors.leftContX,
  9095. connectors.leftContY,
  9096. connectors.plotX,
  9097. connectors.plotY
  9098. ];
  9099. }
  9100. }
  9101. else {
  9102. ret = proceed.call(this, segment, point, i);
  9103. }
  9104. return ret;
  9105. });
  9106. // #6430 Areasplinerange series use unwrapped getPointSpline method, so
  9107. // we need to set this method again.
  9108. if (seriesTypes.areasplinerange) {
  9109. seriesTypes.areasplinerange.prototype.getPointSpline =
  9110. seriesTypes.spline.prototype.getPointSpline;
  9111. }
  9112. }
  9113. /**
  9114. * Extend translate. The plotX and plotY values are computed as if the polar
  9115. * chart were a cartesian plane, where plotX denotes the angle in radians
  9116. * and (yAxis.len - plotY) is the pixel distance from center.
  9117. * @private
  9118. */
  9119. addEvent(Series, 'afterTranslate', function () {
  9120. var series = this;
  9121. var chart = series.chart;
  9122. if (chart.polar && series.xAxis) {
  9123. // Prepare k-d-tree handling. It searches by angle (clientX) in
  9124. // case of shared tooltip, and by two dimensional distance in case
  9125. // of non-shared.
  9126. series.kdByAngle = chart.tooltip && chart.tooltip.shared;
  9127. if (series.kdByAngle) {
  9128. series.searchPoint = series.searchPointByAngle;
  9129. }
  9130. else {
  9131. series.options.findNearestPointBy = 'xy';
  9132. }
  9133. // Postprocess plot coordinates
  9134. if (!series.preventPostTranslate) {
  9135. var points = series.points;
  9136. var i = points.length;
  9137. while (i--) {
  9138. // Translate plotX, plotY from angle and radius to true plot
  9139. // coordinates
  9140. series.toXY(points[i]);
  9141. // Treat points below Y axis min as null (#10082)
  9142. if (!chart.hasParallelCoordinates &&
  9143. !series.yAxis.reversed &&
  9144. points[i].y < series.yAxis.min) {
  9145. points[i].isNull = true;
  9146. }
  9147. }
  9148. }
  9149. // Perform clip after render
  9150. if (!this.hasClipCircleSetter) {
  9151. this.hasClipCircleSetter = !!series.eventsToUnbind.push(addEvent(series, 'afterRender', function () {
  9152. var circ;
  9153. if (chart.polar) {
  9154. // For clipping purposes there is a need for
  9155. // coordinates from the absolute center
  9156. circ = this.yAxis.pane.center;
  9157. if (!this.clipCircle) {
  9158. this.clipCircle = chart.renderer.clipCircle(circ[0], circ[1], circ[2] / 2, circ[3] / 2);
  9159. }
  9160. else {
  9161. this.clipCircle.animate({
  9162. x: circ[0],
  9163. y: circ[1],
  9164. r: circ[2] / 2,
  9165. innerR: circ[3] / 2
  9166. });
  9167. }
  9168. this.group.clip(this.clipCircle);
  9169. this.setClip = H.noop;
  9170. }
  9171. }));
  9172. }
  9173. }
  9174. }, { order: 2 }); // Run after translation of ||-coords
  9175. /**
  9176. * Extend getSegmentPath to allow connecting ends across 0 to provide a
  9177. * closed circle in line-like series.
  9178. * @private
  9179. */
  9180. wrap(seriesProto, 'getGraphPath', function (proceed, points) {
  9181. var series = this, i, firstValid, popLastPoint;
  9182. // Connect the path
  9183. if (this.chart.polar) {
  9184. points = points || this.points;
  9185. // Append first valid point in order to connect the ends
  9186. for (i = 0; i < points.length; i++) {
  9187. if (!points[i].isNull) {
  9188. firstValid = i;
  9189. break;
  9190. }
  9191. }
  9192. /**
  9193. * Polar charts only. Whether to connect the ends of a line series
  9194. * plot across the extremes.
  9195. *
  9196. * @sample {highcharts} highcharts/plotoptions/line-connectends-false/
  9197. * Do not connect
  9198. *
  9199. * @type {boolean}
  9200. * @since 2.3.0
  9201. * @product highcharts
  9202. * @apioption plotOptions.series.connectEnds
  9203. */
  9204. if (this.options.connectEnds !== false &&
  9205. typeof firstValid !== 'undefined') {
  9206. this.connectEnds = true; // re-used in splines
  9207. points.splice(points.length, 0, points[firstValid]);
  9208. popLastPoint = true;
  9209. }
  9210. // For area charts, pseudo points are added to the graph, now we
  9211. // need to translate these
  9212. points.forEach(function (point) {
  9213. if (typeof point.polarPlotY === 'undefined') {
  9214. series.toXY(point);
  9215. }
  9216. });
  9217. }
  9218. // Run uber method
  9219. var ret = proceed.apply(this, [].slice.call(arguments, 1));
  9220. // #6212 points.splice method is adding points to an array. In case of
  9221. // areaspline getGraphPath method is used two times and in both times
  9222. // points are added to an array. That is why points.pop is used, to get
  9223. // unmodified points.
  9224. if (popLastPoint) {
  9225. points.pop();
  9226. }
  9227. return ret;
  9228. });
  9229. var polarAnimate = function (proceed, init) {
  9230. var series = this, chart = this.chart, animation = this.options.animation, group = this.group, markerGroup = this.markerGroup, center = this.xAxis.center, plotLeft = chart.plotLeft, plotTop = chart.plotTop, attribs, paneInnerR, graphic, shapeArgs, r, innerR;
  9231. // Specific animation for polar charts
  9232. if (chart.polar) {
  9233. if (series.isRadialBar) {
  9234. if (!init) {
  9235. // Run the pie animation for radial bars
  9236. series.startAngleRad = pick(series.translatedThreshold, series.xAxis.startAngleRad);
  9237. H.seriesTypes.pie.prototype.animate.call(series, init);
  9238. }
  9239. }
  9240. else {
  9241. // Enable animation on polar charts only in SVG. In VML, the scaling
  9242. // is different, plus animation would be so slow it would't matter.
  9243. if (chart.renderer.isSVG) {
  9244. animation = animObject(animation);
  9245. // A different animation needed for column like series
  9246. if (series.is('column')) {
  9247. if (!init) {
  9248. paneInnerR = center[3] / 2;
  9249. series.points.forEach(function (point) {
  9250. graphic = point.graphic;
  9251. shapeArgs = point.shapeArgs;
  9252. r = shapeArgs && shapeArgs.r;
  9253. innerR = shapeArgs && shapeArgs.innerR;
  9254. if (graphic && shapeArgs) {
  9255. // start values
  9256. graphic.attr({
  9257. r: paneInnerR,
  9258. innerR: paneInnerR
  9259. });
  9260. // animate
  9261. graphic.animate({
  9262. r: r,
  9263. innerR: innerR
  9264. }, series.options.animation);
  9265. }
  9266. });
  9267. }
  9268. }
  9269. else {
  9270. // Initialize the animation
  9271. if (init) {
  9272. // Scale down the group and place it in the center
  9273. attribs = {
  9274. translateX: center[0] + plotLeft,
  9275. translateY: center[1] + plotTop,
  9276. scaleX: 0.001,
  9277. scaleY: 0.001
  9278. };
  9279. group.attr(attribs);
  9280. if (markerGroup) {
  9281. markerGroup.attr(attribs);
  9282. }
  9283. // Run the animation
  9284. }
  9285. else {
  9286. attribs = {
  9287. translateX: plotLeft,
  9288. translateY: plotTop,
  9289. scaleX: 1,
  9290. scaleY: 1
  9291. };
  9292. group.animate(attribs, animation);
  9293. if (markerGroup) {
  9294. markerGroup.animate(attribs, animation);
  9295. }
  9296. }
  9297. }
  9298. }
  9299. }
  9300. // For non-polar charts, revert to the basic animation
  9301. }
  9302. else {
  9303. proceed.call(this, init);
  9304. }
  9305. };
  9306. // Define the animate method for regular series
  9307. wrap(seriesProto, 'animate', polarAnimate);
  9308. if (seriesTypes.column) {
  9309. arearangeProto = seriesTypes.arearange.prototype;
  9310. colProto = seriesTypes.column.prototype;
  9311. colProto.polarArc = function (low, high, start, end) {
  9312. var center = this.xAxis.center, len = this.yAxis.len, paneInnerR = center[3] / 2, r = len - high + paneInnerR, innerR = len - pick(low, len) + paneInnerR;
  9313. // Prevent columns from shooting through the pane's center
  9314. if (this.yAxis.reversed) {
  9315. if (r < 0) {
  9316. r = paneInnerR;
  9317. }
  9318. if (innerR < 0) {
  9319. innerR = paneInnerR;
  9320. }
  9321. }
  9322. // Return a new shapeArgs
  9323. return {
  9324. x: center[0],
  9325. y: center[1],
  9326. r: r,
  9327. innerR: innerR,
  9328. start: start,
  9329. end: end
  9330. };
  9331. };
  9332. /**
  9333. * Define the animate method for columnseries
  9334. * @private
  9335. */
  9336. wrap(colProto, 'animate', polarAnimate);
  9337. /**
  9338. * Extend the column prototype's translate method
  9339. * @private
  9340. */
  9341. wrap(colProto, 'translate', function (proceed) {
  9342. var series = this, options = series.options, threshold = options.threshold, stacking = options.stacking, chart = series.chart, xAxis = series.xAxis, yAxis = series.yAxis, reversed = yAxis.reversed, center = yAxis.center, startAngleRad = xAxis.startAngleRad, endAngleRad = xAxis.endAngleRad, visibleRange = endAngleRad - startAngleRad, thresholdAngleRad, points, point, i, yMin, yMax, start, end, tooltipPos, pointX, pointY, stackValues, stack, barX, innerR, r;
  9343. series.preventPostTranslate = true;
  9344. // Run uber method
  9345. proceed.call(series);
  9346. // Postprocess plot coordinates
  9347. if (xAxis.isRadial) {
  9348. points = series.points;
  9349. i = points.length;
  9350. yMin = yAxis.translate(yAxis.min);
  9351. yMax = yAxis.translate(yAxis.max);
  9352. threshold = options.threshold || 0;
  9353. if (chart.inverted) {
  9354. // Finding a correct threshold
  9355. if (isNumber(threshold)) {
  9356. thresholdAngleRad = yAxis.translate(threshold);
  9357. // Checks if threshold is outside the visible range
  9358. if (defined(thresholdAngleRad)) {
  9359. if (thresholdAngleRad < 0) {
  9360. thresholdAngleRad = 0;
  9361. }
  9362. else if (thresholdAngleRad > visibleRange) {
  9363. thresholdAngleRad = visibleRange;
  9364. }
  9365. // Adding start angle offset
  9366. series.translatedThreshold =
  9367. thresholdAngleRad + startAngleRad;
  9368. }
  9369. }
  9370. }
  9371. while (i--) {
  9372. point = points[i];
  9373. barX = point.barX;
  9374. pointX = point.x;
  9375. pointY = point.y;
  9376. point.shapeType = 'arc';
  9377. if (chart.inverted) {
  9378. point.plotY = yAxis.translate(pointY);
  9379. if (stacking && yAxis.stacking) {
  9380. stack = yAxis.stacking.stacks[(pointY < 0 ? '-' : '') +
  9381. series.stackKey];
  9382. if (series.visible && stack && stack[pointX]) {
  9383. if (!point.isNull) {
  9384. stackValues = stack[pointX].points[series.getStackIndicator(void 0, pointX, series.index).key];
  9385. // Translating to radial values
  9386. start = yAxis.translate(stackValues[0]);
  9387. end = yAxis.translate(stackValues[1]);
  9388. // If starting point is beyond the
  9389. // range, set it to 0
  9390. if (defined(start)) {
  9391. start = U.clamp(start, 0, visibleRange);
  9392. }
  9393. }
  9394. }
  9395. }
  9396. else {
  9397. // Initial start and end angles for radial bar
  9398. start = thresholdAngleRad;
  9399. end = point.plotY;
  9400. }
  9401. if (start > end) {
  9402. // Swapping start and end
  9403. end = [start, start = end][0];
  9404. }
  9405. // Prevent from rendering point outside the
  9406. // acceptable circular range
  9407. if (!reversed) {
  9408. if (start < yMin) {
  9409. start = yMin;
  9410. }
  9411. else if (end > yMax) {
  9412. end = yMax;
  9413. }
  9414. else if (end < yMin || start > yMax) {
  9415. start = end = 0;
  9416. }
  9417. }
  9418. else {
  9419. if (end > yMin) {
  9420. end = yMin;
  9421. }
  9422. else if (start < yMax) {
  9423. start = yMax;
  9424. }
  9425. else if (start > yMin || end < yMax) {
  9426. start = end = visibleRange;
  9427. }
  9428. }
  9429. if (yAxis.min > yAxis.max) {
  9430. start = end = reversed ? visibleRange : 0;
  9431. }
  9432. start += startAngleRad;
  9433. end += startAngleRad;
  9434. if (center) {
  9435. point.barX = barX += center[3] / 2;
  9436. }
  9437. // In case when radius, inner radius or both are
  9438. // negative, a point is rendered but partially or as
  9439. // a center point
  9440. innerR = Math.max(barX, 0);
  9441. r = Math.max(barX + point.pointWidth, 0);
  9442. point.shapeArgs = {
  9443. x: center && center[0],
  9444. y: center && center[1],
  9445. r: r,
  9446. innerR: innerR,
  9447. start: start,
  9448. end: end
  9449. };
  9450. // Fade out the points if not inside the polar "plot area"
  9451. point.opacity = start === end ? 0 : void 0;
  9452. // A correct value for stacked or not fully visible
  9453. // point
  9454. point.plotY = (defined(series.translatedThreshold) &&
  9455. (start < series.translatedThreshold ? start : end)) -
  9456. startAngleRad;
  9457. }
  9458. else {
  9459. start = barX + startAngleRad;
  9460. // Changed the way polar columns are drawn in order to make
  9461. // it more consistent with the drawing of inverted columns
  9462. // (they are using the same function now). Also, it was
  9463. // essential to make the animation work correctly (the
  9464. // scaling of the group) is replaced by animating each
  9465. // element separately.
  9466. point.shapeArgs = series.polarArc(point.yBottom, point.plotY, start, start + point.pointWidth);
  9467. }
  9468. // Provided a correct coordinates for the tooltip
  9469. series.toXY(point);
  9470. if (chart.inverted) {
  9471. tooltipPos = yAxis.postTranslate(point.rectPlotY, barX + point.pointWidth / 2);
  9472. point.tooltipPos = [
  9473. tooltipPos.x - chart.plotLeft,
  9474. tooltipPos.y - chart.plotTop
  9475. ];
  9476. }
  9477. else {
  9478. point.tooltipPos = [point.plotX, point.plotY];
  9479. }
  9480. if (center) {
  9481. point.ttBelow = point.plotY > center[1];
  9482. }
  9483. }
  9484. }
  9485. });
  9486. /**
  9487. * Find correct align and vertical align based on an angle in polar chart
  9488. * @private
  9489. */
  9490. colProto.findAlignments = function (angle, options) {
  9491. var align, verticalAlign;
  9492. if (options.align === null) {
  9493. if (angle > 20 && angle < 160) {
  9494. align = 'left'; // right hemisphere
  9495. }
  9496. else if (angle > 200 && angle < 340) {
  9497. align = 'right'; // left hemisphere
  9498. }
  9499. else {
  9500. align = 'center'; // top or bottom
  9501. }
  9502. options.align = align;
  9503. }
  9504. if (options.verticalAlign === null) {
  9505. if (angle < 45 || angle > 315) {
  9506. verticalAlign = 'bottom'; // top part
  9507. }
  9508. else if (angle > 135 && angle < 225) {
  9509. verticalAlign = 'top'; // bottom part
  9510. }
  9511. else {
  9512. verticalAlign = 'middle'; // left or right
  9513. }
  9514. options.verticalAlign = verticalAlign;
  9515. }
  9516. return options;
  9517. };
  9518. if (arearangeProto) {
  9519. arearangeProto.findAlignments = colProto.findAlignments;
  9520. }
  9521. /**
  9522. * Align column data labels outside the columns. #1199.
  9523. * @private
  9524. */
  9525. wrap(colProto, 'alignDataLabel', function (proceed, point, dataLabel, options, alignTo, isNew) {
  9526. var chart = this.chart, inside = pick(options.inside, !!this.options.stacking), angle, shapeArgs, labelPos;
  9527. if (chart.polar) {
  9528. angle = point.rectPlotX / Math.PI * 180;
  9529. if (!chart.inverted) {
  9530. // Align nicely outside the perimeter of the columns
  9531. if (this.findAlignments) {
  9532. options = this.findAlignments(angle, options);
  9533. }
  9534. }
  9535. else { // Required corrections for data labels of inverted bars
  9536. // The plotX and plotY are correctly set therefore they
  9537. // don't need to be swapped (inverted argument is false)
  9538. this.forceDL = chart.isInsidePlot(point.plotX, Math.round(point.plotY), false);
  9539. // Checks if labels should be positioned inside
  9540. if (inside && point.shapeArgs) {
  9541. shapeArgs = point.shapeArgs;
  9542. // Calculates pixel positions for a data label to be
  9543. // inside
  9544. labelPos =
  9545. this.yAxis.postTranslate(
  9546. // angle
  9547. (shapeArgs.start + shapeArgs.end) / 2 -
  9548. this
  9549. .xAxis.startAngleRad,
  9550. // radius
  9551. point.barX +
  9552. point.pointWidth / 2);
  9553. alignTo = {
  9554. x: labelPos.x - chart.plotLeft,
  9555. y: labelPos.y - chart.plotTop
  9556. };
  9557. }
  9558. else if (point.tooltipPos) {
  9559. alignTo = {
  9560. x: point.tooltipPos[0],
  9561. y: point.tooltipPos[1]
  9562. };
  9563. }
  9564. options.align = pick(options.align, 'center');
  9565. options.verticalAlign =
  9566. pick(options.verticalAlign, 'middle');
  9567. }
  9568. seriesProto.alignDataLabel.call(this, point, dataLabel, options, alignTo, isNew);
  9569. // Hide label of a point (only inverted) that is outside the
  9570. // visible y range
  9571. if (this.isRadialBar && point.shapeArgs &&
  9572. point.shapeArgs.start === point.shapeArgs.end) {
  9573. dataLabel.hide(true);
  9574. }
  9575. }
  9576. else {
  9577. proceed.call(this, point, dataLabel, options, alignTo, isNew);
  9578. }
  9579. });
  9580. }
  9581. /**
  9582. * Extend getCoordinates to prepare for polar axis values
  9583. * @private
  9584. */
  9585. wrap(pointerProto, 'getCoordinates', function (proceed, e) {
  9586. var chart = this.chart, ret = {
  9587. xAxis: [],
  9588. yAxis: []
  9589. };
  9590. if (chart.polar) {
  9591. chart.axes.forEach(function (axis) {
  9592. var isXAxis = axis.isXAxis, center = axis.center, x, y;
  9593. // Skip colorAxis
  9594. if (axis.coll === 'colorAxis') {
  9595. return;
  9596. }
  9597. x = e.chartX - center[0] - chart.plotLeft;
  9598. y = e.chartY - center[1] - chart.plotTop;
  9599. ret[isXAxis ? 'xAxis' : 'yAxis'].push({
  9600. axis: axis,
  9601. value: axis.translate(isXAxis ?
  9602. Math.PI - Math.atan2(x, y) : // angle
  9603. // distance from center
  9604. Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)), true)
  9605. });
  9606. });
  9607. }
  9608. else {
  9609. ret = proceed.call(this, e);
  9610. }
  9611. return ret;
  9612. });
  9613. SVGRenderer.prototype.clipCircle = function (x, y, r, innerR) {
  9614. var wrapper, id = uniqueKey(), clipPath = this.createElement('clipPath').attr({
  9615. id: id
  9616. }).add(this.defs);
  9617. wrapper = innerR ?
  9618. this.arc(x, y, r, innerR, 0, 2 * Math.PI).add(clipPath) :
  9619. this.circle(x, y, r).add(clipPath);
  9620. wrapper.id = id;
  9621. wrapper.clipPath = clipPath;
  9622. return wrapper;
  9623. };
  9624. addEvent(Chart, 'getAxes', function () {
  9625. if (!this.pane) {
  9626. this.pane = [];
  9627. }
  9628. splat(this.options.pane).forEach(function (paneOptions) {
  9629. new Pane(// eslint-disable-line no-new
  9630. paneOptions, this);
  9631. }, this);
  9632. });
  9633. addEvent(Chart, 'afterDrawChartBox', function () {
  9634. this.pane.forEach(function (pane) {
  9635. pane.render();
  9636. });
  9637. });
  9638. addEvent(H.Series, 'afterInit', function () {
  9639. var chart = this.chart;
  9640. // Add flags that identifies radial inverted series
  9641. if (chart.inverted && chart.polar) {
  9642. this.isRadialSeries = true;
  9643. if (this.is('column')) {
  9644. this.isRadialBar = true;
  9645. }
  9646. }
  9647. });
  9648. /**
  9649. * Extend chart.get to also search in panes. Used internally in
  9650. * responsiveness and chart.update.
  9651. * @private
  9652. */
  9653. wrap(Chart.prototype, 'get', function (proceed, id) {
  9654. return find(this.pane, function (pane) {
  9655. return pane.options.id === id;
  9656. }) || proceed.call(this, id);
  9657. });
  9658. });
  9659. _registerModule(_modules, 'masters/highcharts-more.src.js', [], function () {
  9660. });
  9661. }));