highcharts-more.src.js 406 KB

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