highcharts-gantt.src.js 2.6 MB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725257262572725728257292573025731257322573325734257352573625737257382573925740257412574225743257442574525746257472574825749257502575125752257532575425755257562575725758257592576025761257622576325764257652576625767257682576925770257712577225773257742577525776257772577825779257802578125782257832578425785257862578725788257892579025791257922579325794257952579625797257982579925800258012580225803258042580525806258072580825809258102581125812258132581425815258162581725818258192582025821258222582325824258252582625827258282582925830258312583225833258342583525836258372583825839258402584125842258432584425845258462584725848258492585025851258522585325854258552585625857258582585925860258612586225863258642586525866258672586825869258702587125872258732587425875258762587725878258792588025881258822588325884258852588625887258882588925890258912589225893258942589525896258972589825899259002590125902259032590425905259062590725908259092591025911259122591325914259152591625917259182591925920259212592225923259242592525926259272592825929259302593125932259332593425935259362593725938259392594025941259422594325944259452594625947259482594925950259512595225953259542595525956259572595825959259602596125962259632596425965259662596725968259692597025971259722597325974259752597625977259782597925980259812598225983259842598525986259872598825989259902599125992259932599425995259962599725998259992600026001260022600326004260052600626007260082600926010260112601226013260142601526016260172601826019260202602126022260232602426025260262602726028260292603026031260322603326034260352603626037260382603926040260412604226043260442604526046260472604826049260502605126052260532605426055260562605726058260592606026061260622606326064260652606626067260682606926070260712607226073260742607526076260772607826079260802608126082260832608426085260862608726088260892609026091260922609326094260952609626097260982609926100261012610226103261042610526106261072610826109261102611126112261132611426115261162611726118261192612026121261222612326124261252612626127261282612926130261312613226133261342613526136261372613826139261402614126142261432614426145261462614726148261492615026151261522615326154261552615626157261582615926160261612616226163261642616526166261672616826169261702617126172261732617426175261762617726178261792618026181261822618326184261852618626187261882618926190261912619226193261942619526196261972619826199262002620126202262032620426205262062620726208262092621026211262122621326214262152621626217262182621926220262212622226223262242622526226262272622826229262302623126232262332623426235262362623726238262392624026241262422624326244262452624626247262482624926250262512625226253262542625526256262572625826259262602626126262262632626426265262662626726268262692627026271262722627326274262752627626277262782627926280262812628226283262842628526286262872628826289262902629126292262932629426295262962629726298262992630026301263022630326304263052630626307263082630926310263112631226313263142631526316263172631826319263202632126322263232632426325263262632726328263292633026331263322633326334263352633626337263382633926340263412634226343263442634526346263472634826349263502635126352263532635426355263562635726358263592636026361263622636326364263652636626367263682636926370263712637226373263742637526376263772637826379263802638126382263832638426385263862638726388263892639026391263922639326394263952639626397263982639926400264012640226403264042640526406264072640826409264102641126412264132641426415264162641726418264192642026421264222642326424264252642626427264282642926430264312643226433264342643526436264372643826439264402644126442264432644426445264462644726448264492645026451264522645326454264552645626457264582645926460264612646226463264642646526466264672646826469264702647126472264732647426475264762647726478264792648026481264822648326484264852648626487264882648926490264912649226493264942649526496264972649826499265002650126502265032650426505265062650726508265092651026511265122651326514265152651626517265182651926520265212652226523265242652526526265272652826529265302653126532265332653426535265362653726538265392654026541265422654326544265452654626547265482654926550265512655226553265542655526556265572655826559265602656126562265632656426565265662656726568265692657026571265722657326574265752657626577265782657926580265812658226583265842658526586265872658826589265902659126592265932659426595265962659726598265992660026601266022660326604266052660626607266082660926610266112661226613266142661526616266172661826619266202662126622266232662426625266262662726628266292663026631266322663326634266352663626637266382663926640266412664226643266442664526646266472664826649266502665126652266532665426655266562665726658266592666026661266622666326664266652666626667266682666926670266712667226673266742667526676266772667826679266802668126682266832668426685266862668726688266892669026691266922669326694266952669626697266982669926700267012670226703267042670526706267072670826709267102671126712267132671426715267162671726718267192672026721267222672326724267252672626727267282672926730267312673226733267342673526736267372673826739267402674126742267432674426745267462674726748267492675026751267522675326754267552675626757267582675926760267612676226763267642676526766267672676826769267702677126772267732677426775267762677726778267792678026781267822678326784267852678626787267882678926790267912679226793267942679526796267972679826799268002680126802268032680426805268062680726808268092681026811268122681326814268152681626817268182681926820268212682226823268242682526826268272682826829268302683126832268332683426835268362683726838268392684026841268422684326844268452684626847268482684926850268512685226853268542685526856268572685826859268602686126862268632686426865268662686726868268692687026871268722687326874268752687626877268782687926880268812688226883268842688526886268872688826889268902689126892268932689426895268962689726898268992690026901269022690326904269052690626907269082690926910269112691226913269142691526916269172691826919269202692126922269232692426925269262692726928269292693026931269322693326934269352693626937269382693926940269412694226943269442694526946269472694826949269502695126952269532695426955269562695726958269592696026961269622696326964269652696626967269682696926970269712697226973269742697526976269772697826979269802698126982269832698426985269862698726988269892699026991269922699326994269952699626997269982699927000270012700227003270042700527006270072700827009270102701127012270132701427015270162701727018270192702027021270222702327024270252702627027270282702927030270312703227033270342703527036270372703827039270402704127042270432704427045270462704727048270492705027051270522705327054270552705627057270582705927060270612706227063270642706527066270672706827069270702707127072270732707427075270762707727078270792708027081270822708327084270852708627087270882708927090270912709227093270942709527096270972709827099271002710127102271032710427105271062710727108271092711027111271122711327114271152711627117271182711927120271212712227123271242712527126271272712827129271302713127132271332713427135271362713727138271392714027141271422714327144271452714627147271482714927150271512715227153271542715527156271572715827159271602716127162271632716427165271662716727168271692717027171271722717327174271752717627177271782717927180271812718227183271842718527186271872718827189271902719127192271932719427195271962719727198271992720027201272022720327204272052720627207272082720927210272112721227213272142721527216272172721827219272202722127222272232722427225272262722727228272292723027231272322723327234272352723627237272382723927240272412724227243272442724527246272472724827249272502725127252272532725427255272562725727258272592726027261272622726327264272652726627267272682726927270272712727227273272742727527276272772727827279272802728127282272832728427285272862728727288272892729027291272922729327294272952729627297272982729927300273012730227303273042730527306273072730827309273102731127312273132731427315273162731727318273192732027321273222732327324273252732627327273282732927330273312733227333273342733527336273372733827339273402734127342273432734427345273462734727348273492735027351273522735327354273552735627357273582735927360273612736227363273642736527366273672736827369273702737127372273732737427375273762737727378273792738027381273822738327384273852738627387273882738927390273912739227393273942739527396273972739827399274002740127402274032740427405274062740727408274092741027411274122741327414274152741627417274182741927420274212742227423274242742527426274272742827429274302743127432274332743427435274362743727438274392744027441274422744327444274452744627447274482744927450274512745227453274542745527456274572745827459274602746127462274632746427465274662746727468274692747027471274722747327474274752747627477274782747927480274812748227483274842748527486274872748827489274902749127492274932749427495274962749727498274992750027501275022750327504275052750627507275082750927510275112751227513275142751527516275172751827519275202752127522275232752427525275262752727528275292753027531275322753327534275352753627537275382753927540275412754227543275442754527546275472754827549275502755127552275532755427555275562755727558275592756027561275622756327564275652756627567275682756927570275712757227573275742757527576275772757827579275802758127582275832758427585275862758727588275892759027591275922759327594275952759627597275982759927600276012760227603276042760527606276072760827609276102761127612276132761427615276162761727618276192762027621276222762327624276252762627627276282762927630276312763227633276342763527636276372763827639276402764127642276432764427645276462764727648276492765027651276522765327654276552765627657276582765927660276612766227663276642766527666276672766827669276702767127672276732767427675276762767727678276792768027681276822768327684276852768627687276882768927690276912769227693276942769527696276972769827699277002770127702277032770427705277062770727708277092771027711277122771327714277152771627717277182771927720277212772227723277242772527726277272772827729277302773127732277332773427735277362773727738277392774027741277422774327744277452774627747277482774927750277512775227753277542775527756277572775827759277602776127762277632776427765277662776727768277692777027771277722777327774277752777627777277782777927780277812778227783277842778527786277872778827789277902779127792277932779427795277962779727798277992780027801278022780327804278052780627807278082780927810278112781227813278142781527816278172781827819278202782127822278232782427825278262782727828278292783027831278322783327834278352783627837278382783927840278412784227843278442784527846278472784827849278502785127852278532785427855278562785727858278592786027861278622786327864278652786627867278682786927870278712787227873278742787527876278772787827879278802788127882278832788427885278862788727888278892789027891278922789327894278952789627897278982789927900279012790227903279042790527906279072790827909279102791127912279132791427915279162791727918279192792027921279222792327924279252792627927279282792927930279312793227933279342793527936279372793827939279402794127942279432794427945279462794727948279492795027951279522795327954279552795627957279582795927960279612796227963279642796527966279672796827969279702797127972279732797427975279762797727978279792798027981279822798327984279852798627987279882798927990279912799227993279942799527996279972799827999280002800128002280032800428005280062800728008280092801028011280122801328014280152801628017280182801928020280212802228023280242802528026280272802828029280302803128032280332803428035280362803728038280392804028041280422804328044280452804628047280482804928050280512805228053280542805528056280572805828059280602806128062280632806428065280662806728068280692807028071280722807328074280752807628077280782807928080280812808228083280842808528086280872808828089280902809128092280932809428095280962809728098280992810028101281022810328104281052810628107281082810928110281112811228113281142811528116281172811828119281202812128122281232812428125281262812728128281292813028131281322813328134281352813628137281382813928140281412814228143281442814528146281472814828149281502815128152281532815428155281562815728158281592816028161281622816328164281652816628167281682816928170281712817228173281742817528176281772817828179281802818128182281832818428185281862818728188281892819028191281922819328194281952819628197281982819928200282012820228203282042820528206282072820828209282102821128212282132821428215282162821728218282192822028221282222822328224282252822628227282282822928230282312823228233282342823528236282372823828239282402824128242282432824428245282462824728248282492825028251282522825328254282552825628257282582825928260282612826228263282642826528266282672826828269282702827128272282732827428275282762827728278282792828028281282822828328284282852828628287282882828928290282912829228293282942829528296282972829828299283002830128302283032830428305283062830728308283092831028311283122831328314283152831628317283182831928320283212832228323283242832528326283272832828329283302833128332283332833428335283362833728338283392834028341283422834328344283452834628347283482834928350283512835228353283542835528356283572835828359283602836128362283632836428365283662836728368283692837028371283722837328374283752837628377283782837928380283812838228383283842838528386283872838828389283902839128392283932839428395283962839728398283992840028401284022840328404284052840628407284082840928410284112841228413284142841528416284172841828419284202842128422284232842428425284262842728428284292843028431284322843328434284352843628437284382843928440284412844228443284442844528446284472844828449284502845128452284532845428455284562845728458284592846028461284622846328464284652846628467284682846928470284712847228473284742847528476284772847828479284802848128482284832848428485284862848728488284892849028491284922849328494284952849628497284982849928500285012850228503285042850528506285072850828509285102851128512285132851428515285162851728518285192852028521285222852328524285252852628527285282852928530285312853228533285342853528536285372853828539285402854128542285432854428545285462854728548285492855028551285522855328554285552855628557285582855928560285612856228563285642856528566285672856828569285702857128572285732857428575285762857728578285792858028581285822858328584285852858628587285882858928590285912859228593285942859528596285972859828599286002860128602286032860428605286062860728608286092861028611286122861328614286152861628617286182861928620286212862228623286242862528626286272862828629286302863128632286332863428635286362863728638286392864028641286422864328644286452864628647286482864928650286512865228653286542865528656286572865828659286602866128662286632866428665286662866728668286692867028671286722867328674286752867628677286782867928680286812868228683286842868528686286872868828689286902869128692286932869428695286962869728698286992870028701287022870328704287052870628707287082870928710287112871228713287142871528716287172871828719287202872128722287232872428725287262872728728287292873028731287322873328734287352873628737287382873928740287412874228743287442874528746287472874828749287502875128752287532875428755287562875728758287592876028761287622876328764287652876628767287682876928770287712877228773287742877528776287772877828779287802878128782287832878428785287862878728788287892879028791287922879328794287952879628797287982879928800288012880228803288042880528806288072880828809288102881128812288132881428815288162881728818288192882028821288222882328824288252882628827288282882928830288312883228833288342883528836288372883828839288402884128842288432884428845288462884728848288492885028851288522885328854288552885628857288582885928860288612886228863288642886528866288672886828869288702887128872288732887428875288762887728878288792888028881288822888328884288852888628887288882888928890288912889228893288942889528896288972889828899289002890128902289032890428905289062890728908289092891028911289122891328914289152891628917289182891928920289212892228923289242892528926289272892828929289302893128932289332893428935289362893728938289392894028941289422894328944289452894628947289482894928950289512895228953289542895528956289572895828959289602896128962289632896428965289662896728968289692897028971289722897328974289752897628977289782897928980289812898228983289842898528986289872898828989289902899128992289932899428995289962899728998289992900029001290022900329004290052900629007290082900929010290112901229013290142901529016290172901829019290202902129022290232902429025290262902729028290292903029031290322903329034290352903629037290382903929040290412904229043290442904529046290472904829049290502905129052290532905429055290562905729058290592906029061290622906329064290652906629067290682906929070290712907229073290742907529076290772907829079290802908129082290832908429085290862908729088290892909029091290922909329094290952909629097290982909929100291012910229103291042910529106291072910829109291102911129112291132911429115291162911729118291192912029121291222912329124291252912629127291282912929130291312913229133291342913529136291372913829139291402914129142291432914429145291462914729148291492915029151291522915329154291552915629157291582915929160291612916229163291642916529166291672916829169291702917129172291732917429175291762917729178291792918029181291822918329184291852918629187291882918929190291912919229193291942919529196291972919829199292002920129202292032920429205292062920729208292092921029211292122921329214292152921629217292182921929220292212922229223292242922529226292272922829229292302923129232292332923429235292362923729238292392924029241292422924329244292452924629247292482924929250292512925229253292542925529256292572925829259292602926129262292632926429265292662926729268292692927029271292722927329274292752927629277292782927929280292812928229283292842928529286292872928829289292902929129292292932929429295292962929729298292992930029301293022930329304293052930629307293082930929310293112931229313293142931529316293172931829319293202932129322293232932429325293262932729328293292933029331293322933329334293352933629337293382933929340293412934229343293442934529346293472934829349293502935129352293532935429355293562935729358293592936029361293622936329364293652936629367293682936929370293712937229373293742937529376293772937829379293802938129382293832938429385293862938729388293892939029391293922939329394293952939629397293982939929400294012940229403294042940529406294072940829409294102941129412294132941429415294162941729418294192942029421294222942329424294252942629427294282942929430294312943229433294342943529436294372943829439294402944129442294432944429445294462944729448294492945029451294522945329454294552945629457294582945929460294612946229463294642946529466294672946829469294702947129472294732947429475294762947729478294792948029481294822948329484294852948629487294882948929490294912949229493294942949529496294972949829499295002950129502295032950429505295062950729508295092951029511295122951329514295152951629517295182951929520295212952229523295242952529526295272952829529295302953129532295332953429535295362953729538295392954029541295422954329544295452954629547295482954929550295512955229553295542955529556295572955829559295602956129562295632956429565295662956729568295692957029571295722957329574295752957629577295782957929580295812958229583295842958529586295872958829589295902959129592295932959429595295962959729598295992960029601296022960329604296052960629607296082960929610296112961229613296142961529616296172961829619296202962129622296232962429625296262962729628296292963029631296322963329634296352963629637296382963929640296412964229643296442964529646296472964829649296502965129652296532965429655296562965729658296592966029661296622966329664296652966629667296682966929670296712967229673296742967529676296772967829679296802968129682296832968429685296862968729688296892969029691296922969329694296952969629697296982969929700297012970229703297042970529706297072970829709297102971129712297132971429715297162971729718297192972029721297222972329724297252972629727297282972929730297312973229733297342973529736297372973829739297402974129742297432974429745297462974729748297492975029751297522975329754297552975629757297582975929760297612976229763297642976529766297672976829769297702977129772297732977429775297762977729778297792978029781297822978329784297852978629787297882978929790297912979229793297942979529796297972979829799298002980129802298032980429805298062980729808298092981029811298122981329814298152981629817298182981929820298212982229823298242982529826298272982829829298302983129832298332983429835298362983729838298392984029841298422984329844298452984629847298482984929850298512985229853298542985529856298572985829859298602986129862298632986429865298662986729868298692987029871298722987329874298752987629877298782987929880298812988229883298842988529886298872988829889298902989129892298932989429895298962989729898298992990029901299022990329904299052990629907299082990929910299112991229913299142991529916299172991829919299202992129922299232992429925299262992729928299292993029931299322993329934299352993629937299382993929940299412994229943299442994529946299472994829949299502995129952299532995429955299562995729958299592996029961299622996329964299652996629967299682996929970299712997229973299742997529976299772997829979299802998129982299832998429985299862998729988299892999029991299922999329994299952999629997299982999930000300013000230003300043000530006300073000830009300103001130012300133001430015300163001730018300193002030021300223002330024300253002630027300283002930030300313003230033300343003530036300373003830039300403004130042300433004430045300463004730048300493005030051300523005330054300553005630057300583005930060300613006230063300643006530066300673006830069300703007130072300733007430075300763007730078300793008030081300823008330084300853008630087300883008930090300913009230093300943009530096300973009830099301003010130102301033010430105301063010730108301093011030111301123011330114301153011630117301183011930120301213012230123301243012530126301273012830129301303013130132301333013430135301363013730138301393014030141301423014330144301453014630147301483014930150301513015230153301543015530156301573015830159301603016130162301633016430165301663016730168301693017030171301723017330174301753017630177301783017930180301813018230183301843018530186301873018830189301903019130192301933019430195301963019730198301993020030201302023020330204302053020630207302083020930210302113021230213302143021530216302173021830219302203022130222302233022430225302263022730228302293023030231302323023330234302353023630237302383023930240302413024230243302443024530246302473024830249302503025130252302533025430255302563025730258302593026030261302623026330264302653026630267302683026930270302713027230273302743027530276302773027830279302803028130282302833028430285302863028730288302893029030291302923029330294302953029630297302983029930300303013030230303303043030530306303073030830309303103031130312303133031430315303163031730318303193032030321303223032330324303253032630327303283032930330303313033230333303343033530336303373033830339303403034130342303433034430345303463034730348303493035030351303523035330354303553035630357303583035930360303613036230363303643036530366303673036830369303703037130372303733037430375303763037730378303793038030381303823038330384303853038630387303883038930390303913039230393303943039530396303973039830399304003040130402304033040430405304063040730408304093041030411304123041330414304153041630417304183041930420304213042230423304243042530426304273042830429304303043130432304333043430435304363043730438304393044030441304423044330444304453044630447304483044930450304513045230453304543045530456304573045830459304603046130462304633046430465304663046730468304693047030471304723047330474304753047630477304783047930480304813048230483304843048530486304873048830489304903049130492304933049430495304963049730498304993050030501305023050330504305053050630507305083050930510305113051230513305143051530516305173051830519305203052130522305233052430525305263052730528305293053030531305323053330534305353053630537305383053930540305413054230543305443054530546305473054830549305503055130552305533055430555305563055730558305593056030561305623056330564305653056630567305683056930570305713057230573305743057530576305773057830579305803058130582305833058430585305863058730588305893059030591305923059330594305953059630597305983059930600306013060230603306043060530606306073060830609306103061130612306133061430615306163061730618306193062030621306223062330624306253062630627306283062930630306313063230633306343063530636306373063830639306403064130642306433064430645306463064730648306493065030651306523065330654306553065630657306583065930660306613066230663306643066530666306673066830669306703067130672306733067430675306763067730678306793068030681306823068330684306853068630687306883068930690306913069230693306943069530696306973069830699307003070130702307033070430705307063070730708307093071030711307123071330714307153071630717307183071930720307213072230723307243072530726307273072830729307303073130732307333073430735307363073730738307393074030741307423074330744307453074630747307483074930750307513075230753307543075530756307573075830759307603076130762307633076430765307663076730768307693077030771307723077330774307753077630777307783077930780307813078230783307843078530786307873078830789307903079130792307933079430795307963079730798307993080030801308023080330804308053080630807308083080930810308113081230813308143081530816308173081830819308203082130822308233082430825308263082730828308293083030831308323083330834308353083630837308383083930840308413084230843308443084530846308473084830849308503085130852308533085430855308563085730858308593086030861308623086330864308653086630867308683086930870308713087230873308743087530876308773087830879308803088130882308833088430885308863088730888308893089030891308923089330894308953089630897308983089930900309013090230903309043090530906309073090830909309103091130912309133091430915309163091730918309193092030921309223092330924309253092630927309283092930930309313093230933309343093530936309373093830939309403094130942309433094430945309463094730948309493095030951309523095330954309553095630957309583095930960309613096230963309643096530966309673096830969309703097130972309733097430975309763097730978309793098030981309823098330984309853098630987309883098930990309913099230993309943099530996309973099830999310003100131002310033100431005310063100731008310093101031011310123101331014310153101631017310183101931020310213102231023310243102531026310273102831029310303103131032310333103431035310363103731038310393104031041310423104331044310453104631047310483104931050310513105231053310543105531056310573105831059310603106131062310633106431065310663106731068310693107031071310723107331074310753107631077310783107931080310813108231083310843108531086310873108831089310903109131092310933109431095310963109731098310993110031101311023110331104311053110631107311083110931110311113111231113311143111531116311173111831119311203112131122311233112431125311263112731128311293113031131311323113331134311353113631137311383113931140311413114231143311443114531146311473114831149311503115131152311533115431155311563115731158311593116031161311623116331164311653116631167311683116931170311713117231173311743117531176311773117831179311803118131182311833118431185311863118731188311893119031191311923119331194311953119631197311983119931200312013120231203312043120531206312073120831209312103121131212312133121431215312163121731218312193122031221312223122331224312253122631227312283122931230312313123231233312343123531236312373123831239312403124131242312433124431245312463124731248312493125031251312523125331254312553125631257312583125931260312613126231263312643126531266312673126831269312703127131272312733127431275312763127731278312793128031281312823128331284312853128631287312883128931290312913129231293312943129531296312973129831299313003130131302313033130431305313063130731308313093131031311313123131331314313153131631317313183131931320313213132231323313243132531326313273132831329313303133131332313333133431335313363133731338313393134031341313423134331344313453134631347313483134931350313513135231353313543135531356313573135831359313603136131362313633136431365313663136731368313693137031371313723137331374313753137631377313783137931380313813138231383313843138531386313873138831389313903139131392313933139431395313963139731398313993140031401314023140331404314053140631407314083140931410314113141231413314143141531416314173141831419314203142131422314233142431425314263142731428314293143031431314323143331434314353143631437314383143931440314413144231443314443144531446314473144831449314503145131452314533145431455314563145731458314593146031461314623146331464314653146631467314683146931470314713147231473314743147531476314773147831479314803148131482314833148431485314863148731488314893149031491314923149331494314953149631497314983149931500315013150231503315043150531506315073150831509315103151131512315133151431515315163151731518315193152031521315223152331524315253152631527315283152931530315313153231533315343153531536315373153831539315403154131542315433154431545315463154731548315493155031551315523155331554315553155631557315583155931560315613156231563315643156531566315673156831569315703157131572315733157431575315763157731578315793158031581315823158331584315853158631587315883158931590315913159231593315943159531596315973159831599316003160131602316033160431605316063160731608316093161031611316123161331614316153161631617316183161931620316213162231623316243162531626316273162831629316303163131632316333163431635316363163731638316393164031641316423164331644316453164631647316483164931650316513165231653316543165531656316573165831659316603166131662316633166431665316663166731668316693167031671316723167331674316753167631677316783167931680316813168231683316843168531686316873168831689316903169131692316933169431695316963169731698316993170031701317023170331704317053170631707317083170931710317113171231713317143171531716317173171831719317203172131722317233172431725317263172731728317293173031731317323173331734317353173631737317383173931740317413174231743317443174531746317473174831749317503175131752317533175431755317563175731758317593176031761317623176331764317653176631767317683176931770317713177231773317743177531776317773177831779317803178131782317833178431785317863178731788317893179031791317923179331794317953179631797317983179931800318013180231803318043180531806318073180831809318103181131812318133181431815318163181731818318193182031821318223182331824318253182631827318283182931830318313183231833318343183531836318373183831839318403184131842318433184431845318463184731848318493185031851318523185331854318553185631857318583185931860318613186231863318643186531866318673186831869318703187131872318733187431875318763187731878318793188031881318823188331884318853188631887318883188931890318913189231893318943189531896318973189831899319003190131902319033190431905319063190731908319093191031911319123191331914319153191631917319183191931920319213192231923319243192531926319273192831929319303193131932319333193431935319363193731938319393194031941319423194331944319453194631947319483194931950319513195231953319543195531956319573195831959319603196131962319633196431965319663196731968319693197031971319723197331974319753197631977319783197931980319813198231983319843198531986319873198831989319903199131992319933199431995319963199731998319993200032001320023200332004320053200632007320083200932010320113201232013320143201532016320173201832019320203202132022320233202432025320263202732028320293203032031320323203332034320353203632037320383203932040320413204232043320443204532046320473204832049320503205132052320533205432055320563205732058320593206032061320623206332064320653206632067320683206932070320713207232073320743207532076320773207832079320803208132082320833208432085320863208732088320893209032091320923209332094320953209632097320983209932100321013210232103321043210532106321073210832109321103211132112321133211432115321163211732118321193212032121321223212332124321253212632127321283212932130321313213232133321343213532136321373213832139321403214132142321433214432145321463214732148321493215032151321523215332154321553215632157321583215932160321613216232163321643216532166321673216832169321703217132172321733217432175321763217732178321793218032181321823218332184321853218632187321883218932190321913219232193321943219532196321973219832199322003220132202322033220432205322063220732208322093221032211322123221332214322153221632217322183221932220322213222232223322243222532226322273222832229322303223132232322333223432235322363223732238322393224032241322423224332244322453224632247322483224932250322513225232253322543225532256322573225832259322603226132262322633226432265322663226732268322693227032271322723227332274322753227632277322783227932280322813228232283322843228532286322873228832289322903229132292322933229432295322963229732298322993230032301323023230332304323053230632307323083230932310323113231232313323143231532316323173231832319323203232132322323233232432325323263232732328323293233032331323323233332334323353233632337323383233932340323413234232343323443234532346323473234832349323503235132352323533235432355323563235732358323593236032361323623236332364323653236632367323683236932370323713237232373323743237532376323773237832379323803238132382323833238432385323863238732388323893239032391323923239332394323953239632397323983239932400324013240232403324043240532406324073240832409324103241132412324133241432415324163241732418324193242032421324223242332424324253242632427324283242932430324313243232433324343243532436324373243832439324403244132442324433244432445324463244732448324493245032451324523245332454324553245632457324583245932460324613246232463324643246532466324673246832469324703247132472324733247432475324763247732478324793248032481324823248332484324853248632487324883248932490324913249232493324943249532496324973249832499325003250132502325033250432505325063250732508325093251032511325123251332514325153251632517325183251932520325213252232523325243252532526325273252832529325303253132532325333253432535325363253732538325393254032541325423254332544325453254632547325483254932550325513255232553325543255532556325573255832559325603256132562325633256432565325663256732568325693257032571325723257332574325753257632577325783257932580325813258232583325843258532586325873258832589325903259132592325933259432595325963259732598325993260032601326023260332604326053260632607326083260932610326113261232613326143261532616326173261832619326203262132622326233262432625326263262732628326293263032631326323263332634326353263632637326383263932640326413264232643326443264532646326473264832649326503265132652326533265432655326563265732658326593266032661326623266332664326653266632667326683266932670326713267232673326743267532676326773267832679326803268132682326833268432685326863268732688326893269032691326923269332694326953269632697326983269932700327013270232703327043270532706327073270832709327103271132712327133271432715327163271732718327193272032721327223272332724327253272632727327283272932730327313273232733327343273532736327373273832739327403274132742327433274432745327463274732748327493275032751327523275332754327553275632757327583275932760327613276232763327643276532766327673276832769327703277132772327733277432775327763277732778327793278032781327823278332784327853278632787327883278932790327913279232793327943279532796327973279832799328003280132802328033280432805328063280732808328093281032811328123281332814328153281632817328183281932820328213282232823328243282532826328273282832829328303283132832328333283432835328363283732838328393284032841328423284332844328453284632847328483284932850328513285232853328543285532856328573285832859328603286132862328633286432865328663286732868328693287032871328723287332874328753287632877328783287932880328813288232883328843288532886328873288832889328903289132892328933289432895328963289732898328993290032901329023290332904329053290632907329083290932910329113291232913329143291532916329173291832919329203292132922329233292432925329263292732928329293293032931329323293332934329353293632937329383293932940329413294232943329443294532946329473294832949329503295132952329533295432955329563295732958329593296032961329623296332964329653296632967329683296932970329713297232973329743297532976329773297832979329803298132982329833298432985329863298732988329893299032991329923299332994329953299632997329983299933000330013300233003330043300533006330073300833009330103301133012330133301433015330163301733018330193302033021330223302333024330253302633027330283302933030330313303233033330343303533036330373303833039330403304133042330433304433045330463304733048330493305033051330523305333054330553305633057330583305933060330613306233063330643306533066330673306833069330703307133072330733307433075330763307733078330793308033081330823308333084330853308633087330883308933090330913309233093330943309533096330973309833099331003310133102331033310433105331063310733108331093311033111331123311333114331153311633117331183311933120331213312233123331243312533126331273312833129331303313133132331333313433135331363313733138331393314033141331423314333144331453314633147331483314933150331513315233153331543315533156331573315833159331603316133162331633316433165331663316733168331693317033171331723317333174331753317633177331783317933180331813318233183331843318533186331873318833189331903319133192331933319433195331963319733198331993320033201332023320333204332053320633207332083320933210332113321233213332143321533216332173321833219332203322133222332233322433225332263322733228332293323033231332323323333234332353323633237332383323933240332413324233243332443324533246332473324833249332503325133252332533325433255332563325733258332593326033261332623326333264332653326633267332683326933270332713327233273332743327533276332773327833279332803328133282332833328433285332863328733288332893329033291332923329333294332953329633297332983329933300333013330233303333043330533306333073330833309333103331133312333133331433315333163331733318333193332033321333223332333324333253332633327333283332933330333313333233333333343333533336333373333833339333403334133342333433334433345333463334733348333493335033351333523335333354333553335633357333583335933360333613336233363333643336533366333673336833369333703337133372333733337433375333763337733378333793338033381333823338333384333853338633387333883338933390333913339233393333943339533396333973339833399334003340133402334033340433405334063340733408334093341033411334123341333414334153341633417334183341933420334213342233423334243342533426334273342833429334303343133432334333343433435334363343733438334393344033441334423344333444334453344633447334483344933450334513345233453334543345533456334573345833459334603346133462334633346433465334663346733468334693347033471334723347333474334753347633477334783347933480334813348233483334843348533486334873348833489334903349133492334933349433495334963349733498334993350033501335023350333504335053350633507335083350933510335113351233513335143351533516335173351833519335203352133522335233352433525335263352733528335293353033531335323353333534335353353633537335383353933540335413354233543335443354533546335473354833549335503355133552335533355433555335563355733558335593356033561335623356333564335653356633567335683356933570335713357233573335743357533576335773357833579335803358133582335833358433585335863358733588335893359033591335923359333594335953359633597335983359933600336013360233603336043360533606336073360833609336103361133612336133361433615336163361733618336193362033621336223362333624336253362633627336283362933630336313363233633336343363533636336373363833639336403364133642336433364433645336463364733648336493365033651336523365333654336553365633657336583365933660336613366233663336643366533666336673366833669336703367133672336733367433675336763367733678336793368033681336823368333684336853368633687336883368933690336913369233693336943369533696336973369833699337003370133702337033370433705337063370733708337093371033711337123371333714337153371633717337183371933720337213372233723337243372533726337273372833729337303373133732337333373433735337363373733738337393374033741337423374333744337453374633747337483374933750337513375233753337543375533756337573375833759337603376133762337633376433765337663376733768337693377033771337723377333774337753377633777337783377933780337813378233783337843378533786337873378833789337903379133792337933379433795337963379733798337993380033801338023380333804338053380633807338083380933810338113381233813338143381533816338173381833819338203382133822338233382433825338263382733828338293383033831338323383333834338353383633837338383383933840338413384233843338443384533846338473384833849338503385133852338533385433855338563385733858338593386033861338623386333864338653386633867338683386933870338713387233873338743387533876338773387833879338803388133882338833388433885338863388733888338893389033891338923389333894338953389633897338983389933900339013390233903339043390533906339073390833909339103391133912339133391433915339163391733918339193392033921339223392333924339253392633927339283392933930339313393233933339343393533936339373393833939339403394133942339433394433945339463394733948339493395033951339523395333954339553395633957339583395933960339613396233963339643396533966339673396833969339703397133972339733397433975339763397733978339793398033981339823398333984339853398633987339883398933990339913399233993339943399533996339973399833999340003400134002340033400434005340063400734008340093401034011340123401334014340153401634017340183401934020340213402234023340243402534026340273402834029340303403134032340333403434035340363403734038340393404034041340423404334044340453404634047340483404934050340513405234053340543405534056340573405834059340603406134062340633406434065340663406734068340693407034071340723407334074340753407634077340783407934080340813408234083340843408534086340873408834089340903409134092340933409434095340963409734098340993410034101341023410334104341053410634107341083410934110341113411234113341143411534116341173411834119341203412134122341233412434125341263412734128341293413034131341323413334134341353413634137341383413934140341413414234143341443414534146341473414834149341503415134152341533415434155341563415734158341593416034161341623416334164341653416634167341683416934170341713417234173341743417534176341773417834179341803418134182341833418434185341863418734188341893419034191341923419334194341953419634197341983419934200342013420234203342043420534206342073420834209342103421134212342133421434215342163421734218342193422034221342223422334224342253422634227342283422934230342313423234233342343423534236342373423834239342403424134242342433424434245342463424734248342493425034251342523425334254342553425634257342583425934260342613426234263342643426534266342673426834269342703427134272342733427434275342763427734278342793428034281342823428334284342853428634287342883428934290342913429234293342943429534296342973429834299343003430134302343033430434305343063430734308343093431034311343123431334314343153431634317343183431934320343213432234323343243432534326343273432834329343303433134332343333433434335343363433734338343393434034341343423434334344343453434634347343483434934350343513435234353343543435534356343573435834359343603436134362343633436434365343663436734368343693437034371343723437334374343753437634377343783437934380343813438234383343843438534386343873438834389343903439134392343933439434395343963439734398343993440034401344023440334404344053440634407344083440934410344113441234413344143441534416344173441834419344203442134422344233442434425344263442734428344293443034431344323443334434344353443634437344383443934440344413444234443344443444534446344473444834449344503445134452344533445434455344563445734458344593446034461344623446334464344653446634467344683446934470344713447234473344743447534476344773447834479344803448134482344833448434485344863448734488344893449034491344923449334494344953449634497344983449934500345013450234503345043450534506345073450834509345103451134512345133451434515345163451734518345193452034521345223452334524345253452634527345283452934530345313453234533345343453534536345373453834539345403454134542345433454434545345463454734548345493455034551345523455334554345553455634557345583455934560345613456234563345643456534566345673456834569345703457134572345733457434575345763457734578345793458034581345823458334584345853458634587345883458934590345913459234593345943459534596345973459834599346003460134602346033460434605346063460734608346093461034611346123461334614346153461634617346183461934620346213462234623346243462534626346273462834629346303463134632346333463434635346363463734638346393464034641346423464334644346453464634647346483464934650346513465234653346543465534656346573465834659346603466134662346633466434665346663466734668346693467034671346723467334674346753467634677346783467934680346813468234683346843468534686346873468834689346903469134692346933469434695346963469734698346993470034701347023470334704347053470634707347083470934710347113471234713347143471534716347173471834719347203472134722347233472434725347263472734728347293473034731347323473334734347353473634737347383473934740347413474234743347443474534746347473474834749347503475134752347533475434755347563475734758347593476034761347623476334764347653476634767347683476934770347713477234773347743477534776347773477834779347803478134782347833478434785347863478734788347893479034791347923479334794347953479634797347983479934800348013480234803348043480534806348073480834809348103481134812348133481434815348163481734818348193482034821348223482334824348253482634827348283482934830348313483234833348343483534836348373483834839348403484134842348433484434845348463484734848348493485034851348523485334854348553485634857348583485934860348613486234863348643486534866348673486834869348703487134872348733487434875348763487734878348793488034881348823488334884348853488634887348883488934890348913489234893348943489534896348973489834899349003490134902349033490434905349063490734908349093491034911349123491334914349153491634917349183491934920349213492234923349243492534926349273492834929349303493134932349333493434935349363493734938349393494034941349423494334944349453494634947349483494934950349513495234953349543495534956349573495834959349603496134962349633496434965349663496734968349693497034971349723497334974349753497634977349783497934980349813498234983349843498534986349873498834989349903499134992349933499434995349963499734998349993500035001350023500335004350053500635007350083500935010350113501235013350143501535016350173501835019350203502135022350233502435025350263502735028350293503035031350323503335034350353503635037350383503935040350413504235043350443504535046350473504835049350503505135052350533505435055350563505735058350593506035061350623506335064350653506635067350683506935070350713507235073350743507535076350773507835079350803508135082350833508435085350863508735088350893509035091350923509335094350953509635097350983509935100351013510235103351043510535106351073510835109351103511135112351133511435115351163511735118351193512035121351223512335124351253512635127351283512935130351313513235133351343513535136351373513835139351403514135142351433514435145351463514735148351493515035151351523515335154351553515635157351583515935160351613516235163351643516535166351673516835169351703517135172351733517435175351763517735178351793518035181351823518335184351853518635187351883518935190351913519235193351943519535196351973519835199352003520135202352033520435205352063520735208352093521035211352123521335214352153521635217352183521935220352213522235223352243522535226352273522835229352303523135232352333523435235352363523735238352393524035241352423524335244352453524635247352483524935250352513525235253352543525535256352573525835259352603526135262352633526435265352663526735268352693527035271352723527335274352753527635277352783527935280352813528235283352843528535286352873528835289352903529135292352933529435295352963529735298352993530035301353023530335304353053530635307353083530935310353113531235313353143531535316353173531835319353203532135322353233532435325353263532735328353293533035331353323533335334353353533635337353383533935340353413534235343353443534535346353473534835349353503535135352353533535435355353563535735358353593536035361353623536335364353653536635367353683536935370353713537235373353743537535376353773537835379353803538135382353833538435385353863538735388353893539035391353923539335394353953539635397353983539935400354013540235403354043540535406354073540835409354103541135412354133541435415354163541735418354193542035421354223542335424354253542635427354283542935430354313543235433354343543535436354373543835439354403544135442354433544435445354463544735448354493545035451354523545335454354553545635457354583545935460354613546235463354643546535466354673546835469354703547135472354733547435475354763547735478354793548035481354823548335484354853548635487354883548935490354913549235493354943549535496354973549835499355003550135502355033550435505355063550735508355093551035511355123551335514355153551635517355183551935520355213552235523355243552535526355273552835529355303553135532355333553435535355363553735538355393554035541355423554335544355453554635547355483554935550355513555235553355543555535556355573555835559355603556135562355633556435565355663556735568355693557035571355723557335574355753557635577355783557935580355813558235583355843558535586355873558835589355903559135592355933559435595355963559735598355993560035601356023560335604356053560635607356083560935610356113561235613356143561535616356173561835619356203562135622356233562435625356263562735628356293563035631356323563335634356353563635637356383563935640356413564235643356443564535646356473564835649356503565135652356533565435655356563565735658356593566035661356623566335664356653566635667356683566935670356713567235673356743567535676356773567835679356803568135682356833568435685356863568735688356893569035691356923569335694356953569635697356983569935700357013570235703357043570535706357073570835709357103571135712357133571435715357163571735718357193572035721357223572335724357253572635727357283572935730357313573235733357343573535736357373573835739357403574135742357433574435745357463574735748357493575035751357523575335754357553575635757357583575935760357613576235763357643576535766357673576835769357703577135772357733577435775357763577735778357793578035781357823578335784357853578635787357883578935790357913579235793357943579535796357973579835799358003580135802358033580435805358063580735808358093581035811358123581335814358153581635817358183581935820358213582235823358243582535826358273582835829358303583135832358333583435835358363583735838358393584035841358423584335844358453584635847358483584935850358513585235853358543585535856358573585835859358603586135862358633586435865358663586735868358693587035871358723587335874358753587635877358783587935880358813588235883358843588535886358873588835889358903589135892358933589435895358963589735898358993590035901359023590335904359053590635907359083590935910359113591235913359143591535916359173591835919359203592135922359233592435925359263592735928359293593035931359323593335934359353593635937359383593935940359413594235943359443594535946359473594835949359503595135952359533595435955359563595735958359593596035961359623596335964359653596635967359683596935970359713597235973359743597535976359773597835979359803598135982359833598435985359863598735988359893599035991359923599335994359953599635997359983599936000360013600236003360043600536006360073600836009360103601136012360133601436015360163601736018360193602036021360223602336024360253602636027360283602936030360313603236033360343603536036360373603836039360403604136042360433604436045360463604736048360493605036051360523605336054360553605636057360583605936060360613606236063360643606536066360673606836069360703607136072360733607436075360763607736078360793608036081360823608336084360853608636087360883608936090360913609236093360943609536096360973609836099361003610136102361033610436105361063610736108361093611036111361123611336114361153611636117361183611936120361213612236123361243612536126361273612836129361303613136132361333613436135361363613736138361393614036141361423614336144361453614636147361483614936150361513615236153361543615536156361573615836159361603616136162361633616436165361663616736168361693617036171361723617336174361753617636177361783617936180361813618236183361843618536186361873618836189361903619136192361933619436195361963619736198361993620036201362023620336204362053620636207362083620936210362113621236213362143621536216362173621836219362203622136222362233622436225362263622736228362293623036231362323623336234362353623636237362383623936240362413624236243362443624536246362473624836249362503625136252362533625436255362563625736258362593626036261362623626336264362653626636267362683626936270362713627236273362743627536276362773627836279362803628136282362833628436285362863628736288362893629036291362923629336294362953629636297362983629936300363013630236303363043630536306363073630836309363103631136312363133631436315363163631736318363193632036321363223632336324363253632636327363283632936330363313633236333363343633536336363373633836339363403634136342363433634436345363463634736348363493635036351363523635336354363553635636357363583635936360363613636236363363643636536366363673636836369363703637136372363733637436375363763637736378363793638036381363823638336384363853638636387363883638936390363913639236393363943639536396363973639836399364003640136402364033640436405364063640736408364093641036411364123641336414364153641636417364183641936420364213642236423364243642536426364273642836429364303643136432364333643436435364363643736438364393644036441364423644336444364453644636447364483644936450364513645236453364543645536456364573645836459364603646136462364633646436465364663646736468364693647036471364723647336474364753647636477364783647936480364813648236483364843648536486364873648836489364903649136492364933649436495364963649736498364993650036501365023650336504365053650636507365083650936510365113651236513365143651536516365173651836519365203652136522365233652436525365263652736528365293653036531365323653336534365353653636537365383653936540365413654236543365443654536546365473654836549365503655136552365533655436555365563655736558365593656036561365623656336564365653656636567365683656936570365713657236573365743657536576365773657836579365803658136582365833658436585365863658736588365893659036591365923659336594365953659636597365983659936600366013660236603366043660536606366073660836609366103661136612366133661436615366163661736618366193662036621366223662336624366253662636627366283662936630366313663236633366343663536636366373663836639366403664136642366433664436645366463664736648366493665036651366523665336654366553665636657366583665936660366613666236663366643666536666366673666836669366703667136672366733667436675366763667736678366793668036681366823668336684366853668636687366883668936690366913669236693366943669536696366973669836699367003670136702367033670436705367063670736708367093671036711367123671336714367153671636717367183671936720367213672236723367243672536726367273672836729367303673136732367333673436735367363673736738367393674036741367423674336744367453674636747367483674936750367513675236753367543675536756367573675836759367603676136762367633676436765367663676736768367693677036771367723677336774367753677636777367783677936780367813678236783367843678536786367873678836789367903679136792367933679436795367963679736798367993680036801368023680336804368053680636807368083680936810368113681236813368143681536816368173681836819368203682136822368233682436825368263682736828368293683036831368323683336834368353683636837368383683936840368413684236843368443684536846368473684836849368503685136852368533685436855368563685736858368593686036861368623686336864368653686636867368683686936870368713687236873368743687536876368773687836879368803688136882368833688436885368863688736888368893689036891368923689336894368953689636897368983689936900369013690236903369043690536906369073690836909369103691136912369133691436915369163691736918369193692036921369223692336924369253692636927369283692936930369313693236933369343693536936369373693836939369403694136942369433694436945369463694736948369493695036951369523695336954369553695636957369583695936960369613696236963369643696536966369673696836969369703697136972369733697436975369763697736978369793698036981369823698336984369853698636987369883698936990369913699236993369943699536996369973699836999370003700137002370033700437005370063700737008370093701037011370123701337014370153701637017370183701937020370213702237023370243702537026370273702837029370303703137032370333703437035370363703737038370393704037041370423704337044370453704637047370483704937050370513705237053370543705537056370573705837059370603706137062370633706437065370663706737068370693707037071370723707337074370753707637077370783707937080370813708237083370843708537086370873708837089370903709137092370933709437095370963709737098370993710037101371023710337104371053710637107371083710937110371113711237113371143711537116371173711837119371203712137122371233712437125371263712737128371293713037131371323713337134371353713637137371383713937140371413714237143371443714537146371473714837149371503715137152371533715437155371563715737158371593716037161371623716337164371653716637167371683716937170371713717237173371743717537176371773717837179371803718137182371833718437185371863718737188371893719037191371923719337194371953719637197371983719937200372013720237203372043720537206372073720837209372103721137212372133721437215372163721737218372193722037221372223722337224372253722637227372283722937230372313723237233372343723537236372373723837239372403724137242372433724437245372463724737248372493725037251372523725337254372553725637257372583725937260372613726237263372643726537266372673726837269372703727137272372733727437275372763727737278372793728037281372823728337284372853728637287372883728937290372913729237293372943729537296372973729837299373003730137302373033730437305373063730737308373093731037311373123731337314373153731637317373183731937320373213732237323373243732537326373273732837329373303733137332373333733437335373363733737338373393734037341373423734337344373453734637347373483734937350373513735237353373543735537356373573735837359373603736137362373633736437365373663736737368373693737037371373723737337374373753737637377373783737937380373813738237383373843738537386373873738837389373903739137392373933739437395373963739737398373993740037401374023740337404374053740637407374083740937410374113741237413374143741537416374173741837419374203742137422374233742437425374263742737428374293743037431374323743337434374353743637437374383743937440374413744237443374443744537446374473744837449374503745137452374533745437455374563745737458374593746037461374623746337464374653746637467374683746937470374713747237473374743747537476374773747837479374803748137482374833748437485374863748737488374893749037491374923749337494374953749637497374983749937500375013750237503375043750537506375073750837509375103751137512375133751437515375163751737518375193752037521375223752337524375253752637527375283752937530375313753237533375343753537536375373753837539375403754137542375433754437545375463754737548375493755037551375523755337554375553755637557375583755937560375613756237563375643756537566375673756837569375703757137572375733757437575375763757737578375793758037581375823758337584375853758637587375883758937590375913759237593375943759537596375973759837599376003760137602376033760437605376063760737608376093761037611376123761337614376153761637617376183761937620376213762237623376243762537626376273762837629376303763137632376333763437635376363763737638376393764037641376423764337644376453764637647376483764937650376513765237653376543765537656376573765837659376603766137662376633766437665376663766737668376693767037671376723767337674376753767637677376783767937680376813768237683376843768537686376873768837689376903769137692376933769437695376963769737698376993770037701377023770337704377053770637707377083770937710377113771237713377143771537716377173771837719377203772137722377233772437725377263772737728377293773037731377323773337734377353773637737377383773937740377413774237743377443774537746377473774837749377503775137752377533775437755377563775737758377593776037761377623776337764377653776637767377683776937770377713777237773377743777537776377773777837779377803778137782377833778437785377863778737788377893779037791377923779337794377953779637797377983779937800378013780237803378043780537806378073780837809378103781137812378133781437815378163781737818378193782037821378223782337824378253782637827378283782937830378313783237833378343783537836378373783837839378403784137842378433784437845378463784737848378493785037851378523785337854378553785637857378583785937860378613786237863378643786537866378673786837869378703787137872378733787437875378763787737878378793788037881378823788337884378853788637887378883788937890378913789237893378943789537896378973789837899379003790137902379033790437905379063790737908379093791037911379123791337914379153791637917379183791937920379213792237923379243792537926379273792837929379303793137932379333793437935379363793737938379393794037941379423794337944379453794637947379483794937950379513795237953379543795537956379573795837959379603796137962379633796437965379663796737968379693797037971379723797337974379753797637977379783797937980379813798237983379843798537986379873798837989379903799137992379933799437995379963799737998379993800038001380023800338004380053800638007380083800938010380113801238013380143801538016380173801838019380203802138022380233802438025380263802738028380293803038031380323803338034380353803638037380383803938040380413804238043380443804538046380473804838049380503805138052380533805438055380563805738058380593806038061380623806338064380653806638067380683806938070380713807238073380743807538076380773807838079380803808138082380833808438085380863808738088380893809038091380923809338094380953809638097380983809938100381013810238103381043810538106381073810838109381103811138112381133811438115381163811738118381193812038121381223812338124381253812638127381283812938130381313813238133381343813538136381373813838139381403814138142381433814438145381463814738148381493815038151381523815338154381553815638157381583815938160381613816238163381643816538166381673816838169381703817138172381733817438175381763817738178381793818038181381823818338184381853818638187381883818938190381913819238193381943819538196381973819838199382003820138202382033820438205382063820738208382093821038211382123821338214382153821638217382183821938220382213822238223382243822538226382273822838229382303823138232382333823438235382363823738238382393824038241382423824338244382453824638247382483824938250382513825238253382543825538256382573825838259382603826138262382633826438265382663826738268382693827038271382723827338274382753827638277382783827938280382813828238283382843828538286382873828838289382903829138292382933829438295382963829738298382993830038301383023830338304383053830638307383083830938310383113831238313383143831538316383173831838319383203832138322383233832438325383263832738328383293833038331383323833338334383353833638337383383833938340383413834238343383443834538346383473834838349383503835138352383533835438355383563835738358383593836038361383623836338364383653836638367383683836938370383713837238373383743837538376383773837838379383803838138382383833838438385383863838738388383893839038391383923839338394383953839638397383983839938400384013840238403384043840538406384073840838409384103841138412384133841438415384163841738418384193842038421384223842338424384253842638427384283842938430384313843238433384343843538436384373843838439384403844138442384433844438445384463844738448384493845038451384523845338454384553845638457384583845938460384613846238463384643846538466384673846838469384703847138472384733847438475384763847738478384793848038481384823848338484384853848638487384883848938490384913849238493384943849538496384973849838499385003850138502385033850438505385063850738508385093851038511385123851338514385153851638517385183851938520385213852238523385243852538526385273852838529385303853138532385333853438535385363853738538385393854038541385423854338544385453854638547385483854938550385513855238553385543855538556385573855838559385603856138562385633856438565385663856738568385693857038571385723857338574385753857638577385783857938580385813858238583385843858538586385873858838589385903859138592385933859438595385963859738598385993860038601386023860338604386053860638607386083860938610386113861238613386143861538616386173861838619386203862138622386233862438625386263862738628386293863038631386323863338634386353863638637386383863938640386413864238643386443864538646386473864838649386503865138652386533865438655386563865738658386593866038661386623866338664386653866638667386683866938670386713867238673386743867538676386773867838679386803868138682386833868438685386863868738688386893869038691386923869338694386953869638697386983869938700387013870238703387043870538706387073870838709387103871138712387133871438715387163871738718387193872038721387223872338724387253872638727387283872938730387313873238733387343873538736387373873838739387403874138742387433874438745387463874738748387493875038751387523875338754387553875638757387583875938760387613876238763387643876538766387673876838769387703877138772387733877438775387763877738778387793878038781387823878338784387853878638787387883878938790387913879238793387943879538796387973879838799388003880138802388033880438805388063880738808388093881038811388123881338814388153881638817388183881938820388213882238823388243882538826388273882838829388303883138832388333883438835388363883738838388393884038841388423884338844388453884638847388483884938850388513885238853388543885538856388573885838859388603886138862388633886438865388663886738868388693887038871388723887338874388753887638877388783887938880388813888238883388843888538886388873888838889388903889138892388933889438895388963889738898388993890038901389023890338904389053890638907389083890938910389113891238913389143891538916389173891838919389203892138922389233892438925389263892738928389293893038931389323893338934389353893638937389383893938940389413894238943389443894538946389473894838949389503895138952389533895438955389563895738958389593896038961389623896338964389653896638967389683896938970389713897238973389743897538976389773897838979389803898138982389833898438985389863898738988389893899038991389923899338994389953899638997389983899939000390013900239003390043900539006390073900839009390103901139012390133901439015390163901739018390193902039021390223902339024390253902639027390283902939030390313903239033390343903539036390373903839039390403904139042390433904439045390463904739048390493905039051390523905339054390553905639057390583905939060390613906239063390643906539066390673906839069390703907139072390733907439075390763907739078390793908039081390823908339084390853908639087390883908939090390913909239093390943909539096390973909839099391003910139102391033910439105391063910739108391093911039111391123911339114391153911639117391183911939120391213912239123391243912539126391273912839129391303913139132391333913439135391363913739138391393914039141391423914339144391453914639147391483914939150391513915239153391543915539156391573915839159391603916139162391633916439165391663916739168391693917039171391723917339174391753917639177391783917939180391813918239183391843918539186391873918839189391903919139192391933919439195391963919739198391993920039201392023920339204392053920639207392083920939210392113921239213392143921539216392173921839219392203922139222392233922439225392263922739228392293923039231392323923339234392353923639237392383923939240392413924239243392443924539246392473924839249392503925139252392533925439255392563925739258392593926039261392623926339264392653926639267392683926939270392713927239273392743927539276392773927839279392803928139282392833928439285392863928739288392893929039291392923929339294392953929639297392983929939300393013930239303393043930539306393073930839309393103931139312393133931439315393163931739318393193932039321393223932339324393253932639327393283932939330393313933239333393343933539336393373933839339393403934139342393433934439345393463934739348393493935039351393523935339354393553935639357393583935939360393613936239363393643936539366393673936839369393703937139372393733937439375393763937739378393793938039381393823938339384393853938639387393883938939390393913939239393393943939539396393973939839399394003940139402394033940439405394063940739408394093941039411394123941339414394153941639417394183941939420394213942239423394243942539426394273942839429394303943139432394333943439435394363943739438394393944039441394423944339444394453944639447394483944939450394513945239453394543945539456394573945839459394603946139462394633946439465394663946739468394693947039471394723947339474394753947639477394783947939480394813948239483394843948539486394873948839489394903949139492394933949439495394963949739498394993950039501395023950339504395053950639507395083950939510395113951239513395143951539516395173951839519395203952139522395233952439525395263952739528395293953039531395323953339534395353953639537395383953939540395413954239543395443954539546395473954839549395503955139552395533955439555395563955739558395593956039561395623956339564395653956639567395683956939570395713957239573395743957539576395773957839579395803958139582395833958439585395863958739588395893959039591395923959339594395953959639597395983959939600396013960239603396043960539606396073960839609396103961139612396133961439615396163961739618396193962039621396223962339624396253962639627396283962939630396313963239633396343963539636396373963839639396403964139642396433964439645396463964739648396493965039651396523965339654396553965639657396583965939660396613966239663396643966539666396673966839669396703967139672396733967439675396763967739678396793968039681396823968339684396853968639687396883968939690396913969239693396943969539696396973969839699397003970139702397033970439705397063970739708397093971039711397123971339714397153971639717397183971939720397213972239723397243972539726397273972839729397303973139732397333973439735397363973739738397393974039741397423974339744397453974639747397483974939750397513975239753397543975539756397573975839759397603976139762397633976439765397663976739768397693977039771397723977339774397753977639777397783977939780397813978239783397843978539786397873978839789397903979139792397933979439795397963979739798397993980039801398023980339804398053980639807398083980939810398113981239813398143981539816398173981839819398203982139822398233982439825398263982739828398293983039831398323983339834398353983639837398383983939840398413984239843398443984539846398473984839849398503985139852398533985439855398563985739858398593986039861398623986339864398653986639867398683986939870398713987239873398743987539876398773987839879398803988139882398833988439885398863988739888398893989039891398923989339894398953989639897398983989939900399013990239903399043990539906399073990839909399103991139912399133991439915399163991739918399193992039921399223992339924399253992639927399283992939930399313993239933399343993539936399373993839939399403994139942399433994439945399463994739948399493995039951399523995339954399553995639957399583995939960399613996239963399643996539966399673996839969399703997139972399733997439975399763997739978399793998039981399823998339984399853998639987399883998939990399913999239993399943999539996399973999839999400004000140002400034000440005400064000740008400094001040011400124001340014400154001640017400184001940020400214002240023400244002540026400274002840029400304003140032400334003440035400364003740038400394004040041400424004340044400454004640047400484004940050400514005240053400544005540056400574005840059400604006140062400634006440065400664006740068400694007040071400724007340074400754007640077400784007940080400814008240083400844008540086400874008840089400904009140092400934009440095400964009740098400994010040101401024010340104401054010640107401084010940110401114011240113401144011540116401174011840119401204012140122401234012440125401264012740128401294013040131401324013340134401354013640137401384013940140401414014240143401444014540146401474014840149401504015140152401534015440155401564015740158401594016040161401624016340164401654016640167401684016940170401714017240173401744017540176401774017840179401804018140182401834018440185401864018740188401894019040191401924019340194401954019640197401984019940200402014020240203402044020540206402074020840209402104021140212402134021440215402164021740218402194022040221402224022340224402254022640227402284022940230402314023240233402344023540236402374023840239402404024140242402434024440245402464024740248402494025040251402524025340254402554025640257402584025940260402614026240263402644026540266402674026840269402704027140272402734027440275402764027740278402794028040281402824028340284402854028640287402884028940290402914029240293402944029540296402974029840299403004030140302403034030440305403064030740308403094031040311403124031340314403154031640317403184031940320403214032240323403244032540326403274032840329403304033140332403334033440335403364033740338403394034040341403424034340344403454034640347403484034940350403514035240353403544035540356403574035840359403604036140362403634036440365403664036740368403694037040371403724037340374403754037640377403784037940380403814038240383403844038540386403874038840389403904039140392403934039440395403964039740398403994040040401404024040340404404054040640407404084040940410404114041240413404144041540416404174041840419404204042140422404234042440425404264042740428404294043040431404324043340434404354043640437404384043940440404414044240443404444044540446404474044840449404504045140452404534045440455404564045740458404594046040461404624046340464404654046640467404684046940470404714047240473404744047540476404774047840479404804048140482404834048440485404864048740488404894049040491404924049340494404954049640497404984049940500405014050240503405044050540506405074050840509405104051140512405134051440515405164051740518405194052040521405224052340524405254052640527405284052940530405314053240533405344053540536405374053840539405404054140542405434054440545405464054740548405494055040551405524055340554405554055640557405584055940560405614056240563405644056540566405674056840569405704057140572405734057440575405764057740578405794058040581405824058340584405854058640587405884058940590405914059240593405944059540596405974059840599406004060140602406034060440605406064060740608406094061040611406124061340614406154061640617406184061940620406214062240623406244062540626406274062840629406304063140632406334063440635406364063740638406394064040641406424064340644406454064640647406484064940650406514065240653406544065540656406574065840659406604066140662406634066440665406664066740668406694067040671406724067340674406754067640677406784067940680406814068240683406844068540686406874068840689406904069140692406934069440695406964069740698406994070040701407024070340704407054070640707407084070940710407114071240713407144071540716407174071840719407204072140722407234072440725407264072740728407294073040731407324073340734407354073640737407384073940740407414074240743407444074540746407474074840749407504075140752407534075440755407564075740758407594076040761407624076340764407654076640767407684076940770407714077240773407744077540776407774077840779407804078140782407834078440785407864078740788407894079040791407924079340794407954079640797407984079940800408014080240803408044080540806408074080840809408104081140812408134081440815408164081740818408194082040821408224082340824408254082640827408284082940830408314083240833408344083540836408374083840839408404084140842408434084440845408464084740848408494085040851408524085340854408554085640857408584085940860408614086240863408644086540866408674086840869408704087140872408734087440875408764087740878408794088040881408824088340884408854088640887408884088940890408914089240893408944089540896408974089840899409004090140902409034090440905409064090740908409094091040911409124091340914409154091640917409184091940920409214092240923409244092540926409274092840929409304093140932409334093440935409364093740938409394094040941409424094340944409454094640947409484094940950409514095240953409544095540956409574095840959409604096140962409634096440965409664096740968409694097040971409724097340974409754097640977409784097940980409814098240983409844098540986409874098840989409904099140992409934099440995409964099740998409994100041001410024100341004410054100641007410084100941010410114101241013410144101541016410174101841019410204102141022410234102441025410264102741028410294103041031410324103341034410354103641037410384103941040410414104241043410444104541046410474104841049410504105141052410534105441055410564105741058410594106041061410624106341064410654106641067410684106941070410714107241073410744107541076410774107841079410804108141082410834108441085410864108741088410894109041091410924109341094410954109641097410984109941100411014110241103411044110541106411074110841109411104111141112411134111441115411164111741118411194112041121411224112341124411254112641127411284112941130411314113241133411344113541136411374113841139411404114141142411434114441145411464114741148411494115041151411524115341154411554115641157411584115941160411614116241163411644116541166411674116841169411704117141172411734117441175411764117741178411794118041181411824118341184411854118641187411884118941190411914119241193411944119541196411974119841199412004120141202412034120441205412064120741208412094121041211412124121341214412154121641217412184121941220412214122241223412244122541226412274122841229412304123141232412334123441235412364123741238412394124041241412424124341244412454124641247412484124941250412514125241253412544125541256412574125841259412604126141262412634126441265412664126741268412694127041271412724127341274412754127641277412784127941280412814128241283412844128541286412874128841289412904129141292412934129441295412964129741298412994130041301413024130341304413054130641307413084130941310413114131241313413144131541316413174131841319413204132141322413234132441325413264132741328413294133041331413324133341334413354133641337413384133941340413414134241343413444134541346413474134841349413504135141352413534135441355413564135741358413594136041361413624136341364413654136641367413684136941370413714137241373413744137541376413774137841379413804138141382413834138441385413864138741388413894139041391413924139341394413954139641397413984139941400414014140241403414044140541406414074140841409414104141141412414134141441415414164141741418414194142041421414224142341424414254142641427414284142941430414314143241433414344143541436414374143841439414404144141442414434144441445414464144741448414494145041451414524145341454414554145641457414584145941460414614146241463414644146541466414674146841469414704147141472414734147441475414764147741478414794148041481414824148341484414854148641487414884148941490414914149241493414944149541496414974149841499415004150141502415034150441505415064150741508415094151041511415124151341514415154151641517415184151941520415214152241523415244152541526415274152841529415304153141532415334153441535415364153741538415394154041541415424154341544415454154641547415484154941550415514155241553415544155541556415574155841559415604156141562415634156441565415664156741568415694157041571415724157341574415754157641577415784157941580415814158241583415844158541586415874158841589415904159141592415934159441595415964159741598415994160041601416024160341604416054160641607416084160941610416114161241613416144161541616416174161841619416204162141622416234162441625416264162741628416294163041631416324163341634416354163641637416384163941640416414164241643416444164541646416474164841649416504165141652416534165441655416564165741658416594166041661416624166341664416654166641667416684166941670416714167241673416744167541676416774167841679416804168141682416834168441685416864168741688416894169041691416924169341694416954169641697416984169941700417014170241703417044170541706417074170841709417104171141712417134171441715417164171741718417194172041721417224172341724417254172641727417284172941730417314173241733417344173541736417374173841739417404174141742417434174441745417464174741748417494175041751417524175341754417554175641757417584175941760417614176241763417644176541766417674176841769417704177141772417734177441775417764177741778417794178041781417824178341784417854178641787417884178941790417914179241793417944179541796417974179841799418004180141802418034180441805418064180741808418094181041811418124181341814418154181641817418184181941820418214182241823418244182541826418274182841829418304183141832418334183441835418364183741838418394184041841418424184341844418454184641847418484184941850418514185241853418544185541856418574185841859418604186141862418634186441865418664186741868418694187041871418724187341874418754187641877418784187941880418814188241883418844188541886418874188841889418904189141892418934189441895418964189741898418994190041901419024190341904419054190641907419084190941910419114191241913419144191541916419174191841919419204192141922419234192441925419264192741928419294193041931419324193341934419354193641937419384193941940419414194241943419444194541946419474194841949419504195141952419534195441955419564195741958419594196041961419624196341964419654196641967419684196941970419714197241973419744197541976419774197841979419804198141982419834198441985419864198741988419894199041991419924199341994419954199641997419984199942000420014200242003420044200542006420074200842009420104201142012420134201442015420164201742018420194202042021420224202342024420254202642027420284202942030420314203242033420344203542036420374203842039420404204142042420434204442045420464204742048420494205042051420524205342054420554205642057420584205942060420614206242063420644206542066420674206842069420704207142072420734207442075420764207742078420794208042081420824208342084420854208642087420884208942090420914209242093420944209542096420974209842099421004210142102421034210442105421064210742108421094211042111421124211342114421154211642117421184211942120421214212242123421244212542126421274212842129421304213142132421334213442135421364213742138421394214042141421424214342144421454214642147421484214942150421514215242153421544215542156421574215842159421604216142162421634216442165421664216742168421694217042171421724217342174421754217642177421784217942180421814218242183421844218542186421874218842189421904219142192421934219442195421964219742198421994220042201422024220342204422054220642207422084220942210422114221242213422144221542216422174221842219422204222142222422234222442225422264222742228422294223042231422324223342234422354223642237422384223942240422414224242243422444224542246422474224842249422504225142252422534225442255422564225742258422594226042261422624226342264422654226642267422684226942270422714227242273422744227542276422774227842279422804228142282422834228442285422864228742288422894229042291422924229342294422954229642297422984229942300423014230242303423044230542306423074230842309423104231142312423134231442315423164231742318423194232042321423224232342324423254232642327423284232942330423314233242333423344233542336423374233842339423404234142342423434234442345423464234742348423494235042351423524235342354423554235642357423584235942360423614236242363423644236542366423674236842369423704237142372423734237442375423764237742378423794238042381423824238342384423854238642387423884238942390423914239242393423944239542396423974239842399424004240142402424034240442405424064240742408424094241042411424124241342414424154241642417424184241942420424214242242423424244242542426424274242842429424304243142432424334243442435424364243742438424394244042441424424244342444424454244642447424484244942450424514245242453424544245542456424574245842459424604246142462424634246442465424664246742468424694247042471424724247342474424754247642477424784247942480424814248242483424844248542486424874248842489424904249142492424934249442495424964249742498424994250042501425024250342504425054250642507425084250942510425114251242513425144251542516425174251842519425204252142522425234252442525425264252742528425294253042531425324253342534425354253642537425384253942540425414254242543425444254542546425474254842549425504255142552425534255442555425564255742558425594256042561425624256342564425654256642567425684256942570425714257242573425744257542576425774257842579425804258142582425834258442585425864258742588425894259042591425924259342594425954259642597425984259942600426014260242603426044260542606426074260842609426104261142612426134261442615426164261742618426194262042621426224262342624426254262642627426284262942630426314263242633426344263542636426374263842639426404264142642426434264442645426464264742648426494265042651426524265342654426554265642657426584265942660426614266242663426644266542666426674266842669426704267142672426734267442675426764267742678426794268042681426824268342684426854268642687426884268942690426914269242693426944269542696426974269842699427004270142702427034270442705427064270742708427094271042711427124271342714427154271642717427184271942720427214272242723427244272542726427274272842729427304273142732427334273442735427364273742738427394274042741427424274342744427454274642747427484274942750427514275242753427544275542756427574275842759427604276142762427634276442765427664276742768427694277042771427724277342774427754277642777427784277942780427814278242783427844278542786427874278842789427904279142792427934279442795427964279742798427994280042801428024280342804428054280642807428084280942810428114281242813428144281542816428174281842819428204282142822428234282442825428264282742828428294283042831428324283342834428354283642837428384283942840428414284242843428444284542846428474284842849428504285142852428534285442855428564285742858428594286042861428624286342864428654286642867428684286942870428714287242873428744287542876428774287842879428804288142882428834288442885428864288742888428894289042891428924289342894428954289642897428984289942900429014290242903429044290542906429074290842909429104291142912429134291442915429164291742918429194292042921429224292342924429254292642927429284292942930429314293242933429344293542936429374293842939429404294142942429434294442945429464294742948429494295042951429524295342954429554295642957429584295942960429614296242963429644296542966429674296842969429704297142972429734297442975429764297742978429794298042981429824298342984429854298642987429884298942990429914299242993429944299542996429974299842999430004300143002430034300443005430064300743008430094301043011430124301343014430154301643017430184301943020430214302243023430244302543026430274302843029430304303143032430334303443035430364303743038430394304043041430424304343044430454304643047430484304943050430514305243053430544305543056430574305843059430604306143062430634306443065430664306743068430694307043071430724307343074430754307643077430784307943080430814308243083430844308543086430874308843089430904309143092430934309443095430964309743098430994310043101431024310343104431054310643107431084310943110431114311243113431144311543116431174311843119431204312143122431234312443125431264312743128431294313043131431324313343134431354313643137431384313943140431414314243143431444314543146431474314843149431504315143152431534315443155431564315743158431594316043161431624316343164431654316643167431684316943170431714317243173431744317543176431774317843179431804318143182431834318443185431864318743188431894319043191431924319343194431954319643197431984319943200432014320243203432044320543206432074320843209432104321143212432134321443215432164321743218432194322043221432224322343224432254322643227432284322943230432314323243233432344323543236432374323843239432404324143242432434324443245432464324743248432494325043251432524325343254432554325643257432584325943260432614326243263432644326543266432674326843269432704327143272432734327443275432764327743278432794328043281432824328343284432854328643287432884328943290432914329243293432944329543296432974329843299433004330143302433034330443305433064330743308433094331043311433124331343314433154331643317433184331943320433214332243323433244332543326433274332843329433304333143332433334333443335433364333743338433394334043341433424334343344433454334643347433484334943350433514335243353433544335543356433574335843359433604336143362433634336443365433664336743368433694337043371433724337343374433754337643377433784337943380433814338243383433844338543386433874338843389433904339143392433934339443395433964339743398433994340043401434024340343404434054340643407434084340943410434114341243413434144341543416434174341843419434204342143422434234342443425434264342743428434294343043431434324343343434434354343643437434384343943440434414344243443434444344543446434474344843449434504345143452434534345443455434564345743458434594346043461434624346343464434654346643467434684346943470434714347243473434744347543476434774347843479434804348143482434834348443485434864348743488434894349043491434924349343494434954349643497434984349943500435014350243503435044350543506435074350843509435104351143512435134351443515435164351743518435194352043521435224352343524435254352643527435284352943530435314353243533435344353543536435374353843539435404354143542435434354443545435464354743548435494355043551435524355343554435554355643557435584355943560435614356243563435644356543566435674356843569435704357143572435734357443575435764357743578435794358043581435824358343584435854358643587435884358943590435914359243593435944359543596435974359843599436004360143602436034360443605436064360743608436094361043611436124361343614436154361643617436184361943620436214362243623436244362543626436274362843629436304363143632436334363443635436364363743638436394364043641436424364343644436454364643647436484364943650436514365243653436544365543656436574365843659436604366143662436634366443665436664366743668436694367043671436724367343674436754367643677436784367943680436814368243683436844368543686436874368843689436904369143692436934369443695436964369743698436994370043701437024370343704437054370643707437084370943710437114371243713437144371543716437174371843719437204372143722437234372443725437264372743728437294373043731437324373343734437354373643737437384373943740437414374243743437444374543746437474374843749437504375143752437534375443755437564375743758437594376043761437624376343764437654376643767437684376943770437714377243773437744377543776437774377843779437804378143782437834378443785437864378743788437894379043791437924379343794437954379643797437984379943800438014380243803438044380543806438074380843809438104381143812438134381443815438164381743818438194382043821438224382343824438254382643827438284382943830438314383243833438344383543836438374383843839438404384143842438434384443845438464384743848438494385043851438524385343854438554385643857438584385943860438614386243863438644386543866438674386843869438704387143872438734387443875438764387743878438794388043881438824388343884438854388643887438884388943890438914389243893438944389543896438974389843899439004390143902439034390443905439064390743908439094391043911439124391343914439154391643917439184391943920439214392243923439244392543926439274392843929439304393143932439334393443935439364393743938439394394043941439424394343944439454394643947439484394943950439514395243953439544395543956439574395843959439604396143962439634396443965439664396743968439694397043971439724397343974439754397643977439784397943980439814398243983439844398543986439874398843989439904399143992439934399443995439964399743998439994400044001440024400344004440054400644007440084400944010440114401244013440144401544016440174401844019440204402144022440234402444025440264402744028440294403044031440324403344034440354403644037440384403944040440414404244043440444404544046440474404844049440504405144052440534405444055440564405744058440594406044061440624406344064440654406644067440684406944070440714407244073440744407544076440774407844079440804408144082440834408444085440864408744088440894409044091440924409344094440954409644097440984409944100441014410244103441044410544106441074410844109441104411144112441134411444115441164411744118441194412044121441224412344124441254412644127441284412944130441314413244133441344413544136441374413844139441404414144142441434414444145441464414744148441494415044151441524415344154441554415644157441584415944160441614416244163441644416544166441674416844169441704417144172441734417444175441764417744178441794418044181441824418344184441854418644187441884418944190441914419244193441944419544196441974419844199442004420144202442034420444205442064420744208442094421044211442124421344214442154421644217442184421944220442214422244223442244422544226442274422844229442304423144232442334423444235442364423744238442394424044241442424424344244442454424644247442484424944250442514425244253442544425544256442574425844259442604426144262442634426444265442664426744268442694427044271442724427344274442754427644277442784427944280442814428244283442844428544286442874428844289442904429144292442934429444295442964429744298442994430044301443024430344304443054430644307443084430944310443114431244313443144431544316443174431844319443204432144322443234432444325443264432744328443294433044331443324433344334443354433644337443384433944340443414434244343443444434544346443474434844349443504435144352443534435444355443564435744358443594436044361443624436344364443654436644367443684436944370443714437244373443744437544376443774437844379443804438144382443834438444385443864438744388443894439044391443924439344394443954439644397443984439944400444014440244403444044440544406444074440844409444104441144412444134441444415444164441744418444194442044421444224442344424444254442644427444284442944430444314443244433444344443544436444374443844439444404444144442444434444444445444464444744448444494445044451444524445344454444554445644457444584445944460444614446244463444644446544466444674446844469444704447144472444734447444475444764447744478444794448044481444824448344484444854448644487444884448944490444914449244493444944449544496444974449844499445004450144502445034450444505445064450744508445094451044511445124451344514445154451644517445184451944520445214452244523445244452544526445274452844529445304453144532445334453444535445364453744538445394454044541445424454344544445454454644547445484454944550445514455244553445544455544556445574455844559445604456144562445634456444565445664456744568445694457044571445724457344574445754457644577445784457944580445814458244583445844458544586445874458844589445904459144592445934459444595445964459744598445994460044601446024460344604446054460644607446084460944610446114461244613446144461544616446174461844619446204462144622446234462444625446264462744628446294463044631446324463344634446354463644637446384463944640446414464244643446444464544646446474464844649446504465144652446534465444655446564465744658446594466044661446624466344664446654466644667446684466944670446714467244673446744467544676446774467844679446804468144682446834468444685446864468744688446894469044691446924469344694446954469644697446984469944700447014470244703447044470544706447074470844709447104471144712447134471444715447164471744718447194472044721447224472344724447254472644727447284472944730447314473244733447344473544736447374473844739447404474144742447434474444745447464474744748447494475044751447524475344754447554475644757447584475944760447614476244763447644476544766447674476844769447704477144772447734477444775447764477744778447794478044781447824478344784447854478644787447884478944790447914479244793447944479544796447974479844799448004480144802448034480444805448064480744808448094481044811448124481344814448154481644817448184481944820448214482244823448244482544826448274482844829448304483144832448334483444835448364483744838448394484044841448424484344844448454484644847448484484944850448514485244853448544485544856448574485844859448604486144862448634486444865448664486744868448694487044871448724487344874448754487644877448784487944880448814488244883448844488544886448874488844889448904489144892448934489444895448964489744898448994490044901449024490344904449054490644907449084490944910449114491244913449144491544916449174491844919449204492144922449234492444925449264492744928449294493044931449324493344934449354493644937449384493944940449414494244943449444494544946449474494844949449504495144952449534495444955449564495744958449594496044961449624496344964449654496644967449684496944970449714497244973449744497544976449774497844979449804498144982449834498444985449864498744988449894499044991449924499344994449954499644997449984499945000450014500245003450044500545006450074500845009450104501145012450134501445015450164501745018450194502045021450224502345024450254502645027450284502945030450314503245033450344503545036450374503845039450404504145042450434504445045450464504745048450494505045051450524505345054450554505645057450584505945060450614506245063450644506545066450674506845069450704507145072450734507445075450764507745078450794508045081450824508345084450854508645087450884508945090450914509245093450944509545096450974509845099451004510145102451034510445105451064510745108451094511045111451124511345114451154511645117451184511945120451214512245123451244512545126451274512845129451304513145132451334513445135451364513745138451394514045141451424514345144451454514645147451484514945150451514515245153451544515545156451574515845159451604516145162451634516445165451664516745168451694517045171451724517345174451754517645177451784517945180451814518245183451844518545186451874518845189451904519145192451934519445195451964519745198451994520045201452024520345204452054520645207452084520945210452114521245213452144521545216452174521845219452204522145222452234522445225452264522745228452294523045231452324523345234452354523645237452384523945240452414524245243452444524545246452474524845249452504525145252452534525445255452564525745258452594526045261452624526345264452654526645267452684526945270452714527245273452744527545276452774527845279452804528145282452834528445285452864528745288452894529045291452924529345294452954529645297452984529945300453014530245303453044530545306453074530845309453104531145312453134531445315453164531745318453194532045321453224532345324453254532645327453284532945330453314533245333453344533545336453374533845339453404534145342453434534445345453464534745348453494535045351453524535345354453554535645357453584535945360453614536245363453644536545366453674536845369453704537145372453734537445375453764537745378453794538045381453824538345384453854538645387453884538945390453914539245393453944539545396453974539845399454004540145402454034540445405454064540745408454094541045411454124541345414454154541645417454184541945420454214542245423454244542545426454274542845429454304543145432454334543445435454364543745438454394544045441454424544345444454454544645447454484544945450454514545245453454544545545456454574545845459454604546145462454634546445465454664546745468454694547045471454724547345474454754547645477454784547945480454814548245483454844548545486454874548845489454904549145492454934549445495454964549745498454994550045501455024550345504455054550645507455084550945510455114551245513455144551545516455174551845519455204552145522455234552445525455264552745528455294553045531455324553345534455354553645537455384553945540455414554245543455444554545546455474554845549455504555145552455534555445555455564555745558455594556045561455624556345564455654556645567455684556945570455714557245573455744557545576455774557845579455804558145582455834558445585455864558745588455894559045591455924559345594455954559645597455984559945600456014560245603456044560545606456074560845609456104561145612456134561445615456164561745618456194562045621456224562345624456254562645627456284562945630456314563245633456344563545636456374563845639456404564145642456434564445645456464564745648456494565045651456524565345654456554565645657456584565945660456614566245663456644566545666456674566845669456704567145672456734567445675456764567745678456794568045681456824568345684456854568645687456884568945690456914569245693456944569545696456974569845699457004570145702457034570445705457064570745708457094571045711457124571345714457154571645717457184571945720457214572245723457244572545726457274572845729457304573145732457334573445735457364573745738457394574045741457424574345744457454574645747457484574945750457514575245753457544575545756457574575845759457604576145762457634576445765457664576745768457694577045771457724577345774457754577645777457784577945780457814578245783457844578545786457874578845789457904579145792457934579445795457964579745798457994580045801458024580345804458054580645807458084580945810458114581245813458144581545816458174581845819458204582145822458234582445825458264582745828458294583045831458324583345834458354583645837458384583945840458414584245843458444584545846458474584845849458504585145852458534585445855458564585745858458594586045861458624586345864458654586645867458684586945870458714587245873458744587545876458774587845879458804588145882458834588445885458864588745888458894589045891458924589345894458954589645897458984589945900459014590245903459044590545906459074590845909459104591145912459134591445915459164591745918459194592045921459224592345924459254592645927459284592945930459314593245933459344593545936459374593845939459404594145942459434594445945459464594745948459494595045951459524595345954459554595645957459584595945960459614596245963459644596545966459674596845969459704597145972459734597445975459764597745978459794598045981459824598345984459854598645987459884598945990459914599245993459944599545996459974599845999460004600146002460034600446005460064600746008460094601046011460124601346014460154601646017460184601946020460214602246023460244602546026460274602846029460304603146032460334603446035460364603746038460394604046041460424604346044460454604646047460484604946050460514605246053460544605546056460574605846059460604606146062460634606446065460664606746068460694607046071460724607346074460754607646077460784607946080460814608246083460844608546086460874608846089460904609146092460934609446095460964609746098460994610046101461024610346104461054610646107461084610946110461114611246113461144611546116461174611846119461204612146122461234612446125461264612746128461294613046131461324613346134461354613646137461384613946140461414614246143461444614546146461474614846149461504615146152461534615446155461564615746158461594616046161461624616346164461654616646167461684616946170461714617246173461744617546176461774617846179461804618146182461834618446185461864618746188461894619046191461924619346194461954619646197461984619946200462014620246203462044620546206462074620846209462104621146212462134621446215462164621746218462194622046221462224622346224462254622646227462284622946230462314623246233462344623546236462374623846239462404624146242462434624446245462464624746248462494625046251462524625346254462554625646257462584625946260462614626246263462644626546266462674626846269462704627146272462734627446275462764627746278462794628046281462824628346284462854628646287462884628946290462914629246293462944629546296462974629846299463004630146302463034630446305463064630746308463094631046311463124631346314463154631646317463184631946320463214632246323463244632546326463274632846329463304633146332463334633446335463364633746338463394634046341463424634346344463454634646347463484634946350463514635246353463544635546356463574635846359463604636146362463634636446365463664636746368463694637046371463724637346374463754637646377463784637946380463814638246383463844638546386463874638846389463904639146392463934639446395463964639746398463994640046401464024640346404464054640646407464084640946410464114641246413464144641546416464174641846419464204642146422464234642446425464264642746428464294643046431464324643346434464354643646437464384643946440464414644246443464444644546446464474644846449464504645146452464534645446455464564645746458464594646046461464624646346464464654646646467464684646946470464714647246473464744647546476464774647846479464804648146482464834648446485464864648746488464894649046491464924649346494464954649646497464984649946500465014650246503465044650546506465074650846509465104651146512465134651446515465164651746518465194652046521465224652346524465254652646527465284652946530465314653246533465344653546536465374653846539465404654146542465434654446545465464654746548465494655046551465524655346554465554655646557465584655946560465614656246563465644656546566465674656846569465704657146572465734657446575465764657746578465794658046581465824658346584465854658646587465884658946590465914659246593465944659546596465974659846599466004660146602466034660446605466064660746608466094661046611466124661346614466154661646617466184661946620466214662246623466244662546626466274662846629466304663146632466334663446635466364663746638466394664046641466424664346644466454664646647466484664946650466514665246653466544665546656466574665846659466604666146662466634666446665466664666746668466694667046671466724667346674466754667646677466784667946680466814668246683466844668546686466874668846689466904669146692466934669446695466964669746698466994670046701467024670346704467054670646707467084670946710467114671246713467144671546716467174671846719467204672146722467234672446725467264672746728467294673046731467324673346734467354673646737467384673946740467414674246743467444674546746467474674846749467504675146752467534675446755467564675746758467594676046761467624676346764467654676646767467684676946770467714677246773467744677546776467774677846779467804678146782467834678446785467864678746788467894679046791467924679346794467954679646797467984679946800468014680246803468044680546806468074680846809468104681146812468134681446815468164681746818468194682046821468224682346824468254682646827468284682946830468314683246833468344683546836468374683846839468404684146842468434684446845468464684746848468494685046851468524685346854468554685646857468584685946860468614686246863468644686546866468674686846869468704687146872468734687446875468764687746878468794688046881468824688346884468854688646887468884688946890468914689246893468944689546896468974689846899469004690146902469034690446905469064690746908469094691046911469124691346914469154691646917469184691946920469214692246923469244692546926469274692846929469304693146932469334693446935469364693746938469394694046941469424694346944469454694646947469484694946950469514695246953469544695546956469574695846959469604696146962469634696446965469664696746968469694697046971469724697346974469754697646977469784697946980469814698246983469844698546986469874698846989469904699146992469934699446995469964699746998469994700047001470024700347004470054700647007470084700947010470114701247013470144701547016470174701847019470204702147022470234702447025470264702747028470294703047031470324703347034470354703647037470384703947040470414704247043470444704547046470474704847049470504705147052470534705447055470564705747058470594706047061470624706347064470654706647067470684706947070470714707247073470744707547076470774707847079470804708147082470834708447085470864708747088470894709047091470924709347094470954709647097470984709947100471014710247103471044710547106471074710847109471104711147112471134711447115471164711747118471194712047121471224712347124471254712647127471284712947130471314713247133471344713547136471374713847139471404714147142471434714447145471464714747148471494715047151471524715347154471554715647157471584715947160471614716247163471644716547166471674716847169471704717147172471734717447175471764717747178471794718047181471824718347184471854718647187471884718947190471914719247193471944719547196471974719847199472004720147202472034720447205472064720747208472094721047211472124721347214472154721647217472184721947220472214722247223472244722547226472274722847229472304723147232472334723447235472364723747238472394724047241472424724347244472454724647247472484724947250472514725247253472544725547256472574725847259472604726147262472634726447265472664726747268472694727047271472724727347274472754727647277472784727947280472814728247283472844728547286472874728847289472904729147292472934729447295472964729747298472994730047301473024730347304473054730647307473084730947310473114731247313473144731547316473174731847319473204732147322473234732447325473264732747328473294733047331473324733347334473354733647337473384733947340473414734247343473444734547346473474734847349473504735147352473534735447355473564735747358473594736047361473624736347364473654736647367473684736947370473714737247373473744737547376473774737847379473804738147382473834738447385473864738747388473894739047391473924739347394473954739647397473984739947400474014740247403474044740547406474074740847409474104741147412474134741447415474164741747418474194742047421474224742347424474254742647427474284742947430474314743247433474344743547436474374743847439474404744147442474434744447445474464744747448474494745047451474524745347454474554745647457474584745947460474614746247463474644746547466474674746847469474704747147472474734747447475474764747747478474794748047481474824748347484474854748647487474884748947490474914749247493474944749547496474974749847499475004750147502475034750447505475064750747508475094751047511475124751347514475154751647517475184751947520475214752247523475244752547526475274752847529475304753147532475334753447535475364753747538475394754047541475424754347544475454754647547475484754947550475514755247553475544755547556475574755847559475604756147562475634756447565475664756747568475694757047571475724757347574475754757647577475784757947580475814758247583475844758547586475874758847589475904759147592475934759447595475964759747598475994760047601476024760347604476054760647607476084760947610476114761247613476144761547616476174761847619476204762147622476234762447625476264762747628476294763047631476324763347634476354763647637476384763947640476414764247643476444764547646476474764847649476504765147652476534765447655476564765747658476594766047661476624766347664476654766647667476684766947670476714767247673476744767547676476774767847679476804768147682476834768447685476864768747688476894769047691476924769347694476954769647697476984769947700477014770247703477044770547706477074770847709477104771147712477134771447715477164771747718477194772047721477224772347724477254772647727477284772947730477314773247733477344773547736477374773847739477404774147742477434774447745477464774747748477494775047751477524775347754477554775647757477584775947760477614776247763477644776547766477674776847769477704777147772477734777447775477764777747778477794778047781477824778347784477854778647787477884778947790477914779247793477944779547796477974779847799478004780147802478034780447805478064780747808478094781047811478124781347814478154781647817478184781947820478214782247823478244782547826478274782847829478304783147832478334783447835478364783747838478394784047841478424784347844478454784647847478484784947850478514785247853478544785547856478574785847859478604786147862478634786447865478664786747868478694787047871478724787347874478754787647877478784787947880478814788247883478844788547886478874788847889478904789147892478934789447895478964789747898478994790047901479024790347904479054790647907479084790947910479114791247913479144791547916479174791847919479204792147922479234792447925479264792747928479294793047931479324793347934479354793647937479384793947940479414794247943479444794547946479474794847949479504795147952479534795447955479564795747958479594796047961479624796347964479654796647967479684796947970479714797247973479744797547976479774797847979479804798147982479834798447985479864798747988479894799047991479924799347994479954799647997479984799948000480014800248003480044800548006480074800848009480104801148012480134801448015480164801748018480194802048021480224802348024480254802648027480284802948030480314803248033480344803548036480374803848039480404804148042480434804448045480464804748048480494805048051480524805348054480554805648057480584805948060480614806248063480644806548066480674806848069480704807148072480734807448075480764807748078480794808048081480824808348084480854808648087480884808948090480914809248093480944809548096480974809848099481004810148102481034810448105481064810748108481094811048111481124811348114481154811648117481184811948120481214812248123481244812548126481274812848129481304813148132481334813448135481364813748138481394814048141481424814348144481454814648147481484814948150481514815248153481544815548156481574815848159481604816148162481634816448165481664816748168481694817048171481724817348174481754817648177481784817948180481814818248183481844818548186481874818848189481904819148192481934819448195481964819748198481994820048201482024820348204482054820648207482084820948210482114821248213482144821548216482174821848219482204822148222482234822448225482264822748228482294823048231482324823348234482354823648237482384823948240482414824248243482444824548246482474824848249482504825148252482534825448255482564825748258482594826048261482624826348264482654826648267482684826948270482714827248273482744827548276482774827848279482804828148282482834828448285482864828748288482894829048291482924829348294482954829648297482984829948300483014830248303483044830548306483074830848309483104831148312483134831448315483164831748318483194832048321483224832348324483254832648327483284832948330483314833248333483344833548336483374833848339483404834148342483434834448345483464834748348483494835048351483524835348354483554835648357483584835948360483614836248363483644836548366483674836848369483704837148372483734837448375483764837748378483794838048381483824838348384483854838648387483884838948390483914839248393483944839548396483974839848399484004840148402484034840448405484064840748408484094841048411484124841348414484154841648417484184841948420484214842248423484244842548426484274842848429484304843148432484334843448435484364843748438484394844048441484424844348444484454844648447484484844948450484514845248453484544845548456484574845848459484604846148462484634846448465484664846748468484694847048471484724847348474484754847648477484784847948480484814848248483484844848548486484874848848489484904849148492484934849448495484964849748498484994850048501485024850348504485054850648507485084850948510485114851248513485144851548516485174851848519485204852148522485234852448525485264852748528485294853048531485324853348534485354853648537485384853948540485414854248543485444854548546485474854848549485504855148552485534855448555485564855748558485594856048561485624856348564485654856648567485684856948570485714857248573485744857548576485774857848579485804858148582485834858448585485864858748588485894859048591485924859348594485954859648597485984859948600486014860248603486044860548606486074860848609486104861148612486134861448615486164861748618486194862048621486224862348624486254862648627486284862948630486314863248633486344863548636486374863848639486404864148642486434864448645486464864748648486494865048651486524865348654486554865648657486584865948660486614866248663486644866548666486674866848669486704867148672486734867448675486764867748678486794868048681486824868348684486854868648687486884868948690486914869248693486944869548696486974869848699487004870148702487034870448705487064870748708487094871048711487124871348714487154871648717487184871948720487214872248723487244872548726487274872848729487304873148732487334873448735487364873748738487394874048741487424874348744487454874648747487484874948750487514875248753487544875548756487574875848759487604876148762487634876448765487664876748768487694877048771487724877348774487754877648777487784877948780487814878248783487844878548786487874878848789487904879148792487934879448795487964879748798487994880048801488024880348804488054880648807488084880948810488114881248813488144881548816488174881848819488204882148822488234882448825488264882748828488294883048831488324883348834488354883648837488384883948840488414884248843488444884548846488474884848849488504885148852488534885448855488564885748858488594886048861488624886348864488654886648867488684886948870488714887248873488744887548876488774887848879488804888148882488834888448885488864888748888488894889048891488924889348894488954889648897488984889948900489014890248903489044890548906489074890848909489104891148912489134891448915489164891748918489194892048921489224892348924489254892648927489284892948930489314893248933489344893548936489374893848939489404894148942489434894448945489464894748948489494895048951489524895348954489554895648957489584895948960489614896248963489644896548966489674896848969489704897148972489734897448975489764897748978489794898048981489824898348984489854898648987489884898948990489914899248993489944899548996489974899848999490004900149002490034900449005490064900749008490094901049011490124901349014490154901649017490184901949020490214902249023490244902549026490274902849029490304903149032490334903449035490364903749038490394904049041490424904349044490454904649047490484904949050490514905249053490544905549056490574905849059490604906149062490634906449065490664906749068490694907049071490724907349074490754907649077490784907949080490814908249083490844908549086490874908849089490904909149092490934909449095490964909749098490994910049101491024910349104491054910649107491084910949110491114911249113491144911549116491174911849119491204912149122491234912449125491264912749128491294913049131491324913349134491354913649137491384913949140491414914249143491444914549146491474914849149491504915149152491534915449155491564915749158491594916049161491624916349164491654916649167491684916949170491714917249173491744917549176491774917849179491804918149182491834918449185491864918749188491894919049191491924919349194491954919649197491984919949200492014920249203492044920549206492074920849209492104921149212492134921449215492164921749218492194922049221492224922349224492254922649227492284922949230492314923249233492344923549236492374923849239492404924149242492434924449245492464924749248492494925049251492524925349254492554925649257492584925949260492614926249263492644926549266492674926849269492704927149272492734927449275492764927749278492794928049281492824928349284492854928649287492884928949290492914929249293492944929549296492974929849299493004930149302493034930449305493064930749308493094931049311493124931349314493154931649317493184931949320493214932249323493244932549326493274932849329493304933149332493334933449335493364933749338493394934049341493424934349344493454934649347493484934949350493514935249353493544935549356493574935849359493604936149362493634936449365493664936749368493694937049371493724937349374493754937649377493784937949380493814938249383493844938549386493874938849389493904939149392493934939449395493964939749398493994940049401494024940349404494054940649407494084940949410494114941249413494144941549416494174941849419494204942149422494234942449425494264942749428494294943049431494324943349434494354943649437494384943949440494414944249443494444944549446494474944849449494504945149452494534945449455494564945749458494594946049461494624946349464494654946649467494684946949470494714947249473494744947549476494774947849479494804948149482494834948449485494864948749488494894949049491494924949349494494954949649497494984949949500495014950249503495044950549506495074950849509495104951149512495134951449515495164951749518495194952049521495224952349524495254952649527495284952949530495314953249533495344953549536495374953849539495404954149542495434954449545495464954749548495494955049551495524955349554495554955649557495584955949560495614956249563495644956549566495674956849569495704957149572495734957449575495764957749578495794958049581495824958349584495854958649587495884958949590495914959249593495944959549596495974959849599496004960149602496034960449605496064960749608496094961049611496124961349614496154961649617496184961949620496214962249623496244962549626496274962849629496304963149632496334963449635496364963749638496394964049641496424964349644496454964649647496484964949650496514965249653496544965549656496574965849659496604966149662496634966449665496664966749668496694967049671496724967349674496754967649677496784967949680496814968249683496844968549686496874968849689496904969149692496934969449695496964969749698496994970049701497024970349704497054970649707497084970949710497114971249713497144971549716497174971849719497204972149722497234972449725497264972749728497294973049731497324973349734497354973649737497384973949740497414974249743497444974549746497474974849749497504975149752497534975449755497564975749758497594976049761497624976349764497654976649767497684976949770497714977249773497744977549776497774977849779497804978149782497834978449785497864978749788497894979049791497924979349794497954979649797497984979949800498014980249803498044980549806498074980849809498104981149812498134981449815498164981749818498194982049821498224982349824498254982649827498284982949830498314983249833498344983549836498374983849839498404984149842498434984449845498464984749848498494985049851498524985349854498554985649857498584985949860498614986249863498644986549866498674986849869498704987149872498734987449875498764987749878498794988049881498824988349884498854988649887498884988949890498914989249893498944989549896498974989849899499004990149902499034990449905499064990749908499094991049911499124991349914499154991649917499184991949920499214992249923499244992549926499274992849929499304993149932499334993449935499364993749938499394994049941499424994349944499454994649947499484994949950499514995249953499544995549956499574995849959499604996149962499634996449965499664996749968499694997049971499724997349974499754997649977499784997949980499814998249983499844998549986499874998849989499904999149992499934999449995499964999749998499995000050001500025000350004500055000650007500085000950010500115001250013500145001550016500175001850019500205002150022500235002450025500265002750028500295003050031500325003350034500355003650037500385003950040500415004250043500445004550046500475004850049500505005150052500535005450055500565005750058500595006050061500625006350064500655006650067500685006950070500715007250073500745007550076500775007850079500805008150082500835008450085500865008750088500895009050091500925009350094500955009650097500985009950100501015010250103501045010550106501075010850109501105011150112501135011450115501165011750118501195012050121501225012350124501255012650127501285012950130501315013250133501345013550136501375013850139501405014150142501435014450145501465014750148501495015050151501525015350154501555015650157501585015950160501615016250163501645016550166501675016850169501705017150172501735017450175501765017750178501795018050181501825018350184501855018650187501885018950190501915019250193501945019550196501975019850199502005020150202502035020450205502065020750208502095021050211502125021350214502155021650217502185021950220502215022250223502245022550226502275022850229502305023150232502335023450235502365023750238502395024050241502425024350244502455024650247502485024950250502515025250253502545025550256502575025850259502605026150262502635026450265502665026750268502695027050271502725027350274502755027650277502785027950280502815028250283502845028550286502875028850289502905029150292502935029450295502965029750298502995030050301503025030350304503055030650307503085030950310503115031250313503145031550316503175031850319503205032150322503235032450325503265032750328503295033050331503325033350334503355033650337503385033950340503415034250343503445034550346503475034850349503505035150352503535035450355503565035750358503595036050361503625036350364503655036650367503685036950370503715037250373503745037550376503775037850379503805038150382503835038450385503865038750388503895039050391503925039350394503955039650397503985039950400504015040250403504045040550406504075040850409504105041150412504135041450415504165041750418504195042050421504225042350424504255042650427504285042950430504315043250433504345043550436504375043850439504405044150442504435044450445504465044750448504495045050451504525045350454504555045650457504585045950460504615046250463504645046550466504675046850469504705047150472504735047450475504765047750478504795048050481504825048350484504855048650487504885048950490504915049250493504945049550496504975049850499505005050150502505035050450505505065050750508505095051050511505125051350514505155051650517505185051950520505215052250523505245052550526505275052850529505305053150532505335053450535505365053750538505395054050541505425054350544505455054650547505485054950550505515055250553505545055550556505575055850559505605056150562505635056450565505665056750568505695057050571505725057350574505755057650577505785057950580505815058250583505845058550586505875058850589505905059150592505935059450595505965059750598505995060050601506025060350604506055060650607506085060950610506115061250613506145061550616506175061850619506205062150622506235062450625506265062750628506295063050631506325063350634506355063650637506385063950640506415064250643506445064550646506475064850649506505065150652506535065450655506565065750658506595066050661506625066350664506655066650667506685066950670506715067250673506745067550676506775067850679506805068150682506835068450685506865068750688506895069050691506925069350694506955069650697506985069950700507015070250703507045070550706507075070850709507105071150712507135071450715507165071750718507195072050721507225072350724507255072650727507285072950730507315073250733507345073550736507375073850739507405074150742507435074450745507465074750748507495075050751507525075350754507555075650757507585075950760507615076250763507645076550766507675076850769507705077150772507735077450775507765077750778507795078050781507825078350784507855078650787507885078950790507915079250793507945079550796507975079850799508005080150802508035080450805508065080750808508095081050811508125081350814508155081650817508185081950820508215082250823508245082550826508275082850829508305083150832508335083450835508365083750838508395084050841508425084350844508455084650847508485084950850508515085250853508545085550856508575085850859508605086150862508635086450865508665086750868508695087050871508725087350874508755087650877508785087950880508815088250883508845088550886508875088850889508905089150892508935089450895508965089750898508995090050901509025090350904509055090650907509085090950910509115091250913509145091550916509175091850919509205092150922509235092450925509265092750928509295093050931509325093350934509355093650937509385093950940509415094250943509445094550946509475094850949509505095150952509535095450955509565095750958509595096050961509625096350964509655096650967509685096950970509715097250973509745097550976509775097850979509805098150982509835098450985509865098750988509895099050991509925099350994509955099650997509985099951000510015100251003510045100551006510075100851009510105101151012510135101451015510165101751018510195102051021510225102351024510255102651027510285102951030510315103251033510345103551036510375103851039510405104151042510435104451045510465104751048510495105051051510525105351054510555105651057510585105951060510615106251063510645106551066510675106851069510705107151072510735107451075510765107751078510795108051081510825108351084510855108651087510885108951090510915109251093510945109551096510975109851099511005110151102511035110451105511065110751108511095111051111511125111351114511155111651117511185111951120511215112251123511245112551126511275112851129511305113151132511335113451135511365113751138511395114051141511425114351144511455114651147511485114951150511515115251153511545115551156511575115851159511605116151162511635116451165511665116751168511695117051171511725117351174511755117651177511785117951180511815118251183511845118551186511875118851189511905119151192511935119451195511965119751198511995120051201512025120351204512055120651207512085120951210512115121251213512145121551216512175121851219512205122151222512235122451225512265122751228512295123051231512325123351234512355123651237512385123951240512415124251243512445124551246512475124851249512505125151252512535125451255512565125751258512595126051261512625126351264512655126651267512685126951270512715127251273512745127551276512775127851279512805128151282512835128451285512865128751288512895129051291512925129351294512955129651297512985129951300513015130251303513045130551306513075130851309513105131151312513135131451315513165131751318513195132051321513225132351324513255132651327513285132951330513315133251333513345133551336513375133851339513405134151342513435134451345513465134751348513495135051351513525135351354513555135651357513585135951360513615136251363513645136551366513675136851369513705137151372513735137451375513765137751378513795138051381513825138351384513855138651387513885138951390513915139251393513945139551396513975139851399514005140151402514035140451405514065140751408514095141051411514125141351414514155141651417514185141951420514215142251423514245142551426514275142851429514305143151432514335143451435514365143751438514395144051441514425144351444514455144651447514485144951450514515145251453514545145551456514575145851459514605146151462514635146451465514665146751468514695147051471514725147351474514755147651477514785147951480514815148251483514845148551486514875148851489514905149151492514935149451495514965149751498514995150051501515025150351504515055150651507515085150951510515115151251513515145151551516515175151851519515205152151522515235152451525515265152751528515295153051531515325153351534515355153651537515385153951540515415154251543515445154551546515475154851549515505155151552515535155451555515565155751558515595156051561515625156351564515655156651567515685156951570515715157251573515745157551576515775157851579515805158151582515835158451585515865158751588515895159051591515925159351594515955159651597515985159951600516015160251603516045160551606516075160851609516105161151612516135161451615516165161751618516195162051621516225162351624516255162651627516285162951630516315163251633516345163551636516375163851639516405164151642516435164451645516465164751648516495165051651516525165351654516555165651657516585165951660516615166251663516645166551666516675166851669516705167151672516735167451675516765167751678516795168051681516825168351684516855168651687516885168951690516915169251693516945169551696516975169851699517005170151702517035170451705517065170751708517095171051711517125171351714517155171651717517185171951720517215172251723517245172551726517275172851729517305173151732517335173451735517365173751738517395174051741517425174351744517455174651747517485174951750517515175251753517545175551756517575175851759517605176151762517635176451765517665176751768517695177051771517725177351774517755177651777517785177951780517815178251783517845178551786517875178851789517905179151792517935179451795517965179751798517995180051801518025180351804518055180651807518085180951810518115181251813518145181551816518175181851819518205182151822518235182451825518265182751828518295183051831518325183351834518355183651837518385183951840518415184251843518445184551846518475184851849518505185151852518535185451855518565185751858518595186051861518625186351864518655186651867518685186951870518715187251873518745187551876518775187851879518805188151882518835188451885518865188751888518895189051891518925189351894518955189651897518985189951900519015190251903519045190551906519075190851909519105191151912519135191451915519165191751918519195192051921519225192351924519255192651927519285192951930519315193251933519345193551936519375193851939519405194151942519435194451945519465194751948519495195051951519525195351954519555195651957519585195951960519615196251963519645196551966519675196851969519705197151972519735197451975519765197751978519795198051981519825198351984519855198651987519885198951990519915199251993519945199551996519975199851999520005200152002520035200452005520065200752008520095201052011520125201352014520155201652017520185201952020520215202252023520245202552026520275202852029520305203152032520335203452035520365203752038520395204052041520425204352044520455204652047520485204952050520515205252053520545205552056520575205852059520605206152062520635206452065520665206752068520695207052071520725207352074520755207652077520785207952080520815208252083520845208552086520875208852089520905209152092520935209452095520965209752098520995210052101521025210352104521055210652107521085210952110521115211252113521145211552116521175211852119521205212152122521235212452125521265212752128521295213052131521325213352134521355213652137521385213952140521415214252143521445214552146521475214852149521505215152152521535215452155521565215752158521595216052161521625216352164521655216652167521685216952170521715217252173521745217552176521775217852179521805218152182521835218452185521865218752188521895219052191521925219352194521955219652197521985219952200522015220252203522045220552206522075220852209522105221152212522135221452215522165221752218522195222052221522225222352224522255222652227522285222952230522315223252233522345223552236522375223852239522405224152242522435224452245522465224752248522495225052251522525225352254522555225652257522585225952260522615226252263522645226552266522675226852269522705227152272522735227452275522765227752278522795228052281522825228352284522855228652287522885228952290522915229252293522945229552296522975229852299523005230152302523035230452305523065230752308523095231052311523125231352314523155231652317523185231952320523215232252323523245232552326523275232852329523305233152332523335233452335523365233752338523395234052341523425234352344523455234652347523485234952350523515235252353523545235552356523575235852359523605236152362523635236452365523665236752368523695237052371523725237352374523755237652377523785237952380523815238252383523845238552386523875238852389523905239152392523935239452395523965239752398523995240052401524025240352404524055240652407524085240952410524115241252413524145241552416524175241852419524205242152422524235242452425524265242752428524295243052431524325243352434524355243652437524385243952440524415244252443524445244552446524475244852449524505245152452524535245452455524565245752458524595246052461524625246352464524655246652467524685246952470524715247252473524745247552476524775247852479524805248152482524835248452485524865248752488524895249052491524925249352494524955249652497524985249952500525015250252503525045250552506525075250852509525105251152512525135251452515525165251752518525195252052521525225252352524525255252652527525285252952530525315253252533525345253552536525375253852539525405254152542525435254452545525465254752548525495255052551525525255352554525555255652557525585255952560525615256252563525645256552566525675256852569525705257152572525735257452575525765257752578525795258052581525825258352584525855258652587525885258952590525915259252593525945259552596525975259852599526005260152602526035260452605526065260752608526095261052611526125261352614526155261652617526185261952620526215262252623526245262552626526275262852629526305263152632526335263452635526365263752638526395264052641526425264352644526455264652647526485264952650526515265252653526545265552656526575265852659526605266152662526635266452665526665266752668526695267052671526725267352674526755267652677526785267952680526815268252683526845268552686526875268852689526905269152692526935269452695526965269752698526995270052701527025270352704527055270652707527085270952710527115271252713527145271552716527175271852719527205272152722527235272452725527265272752728527295273052731527325273352734527355273652737527385273952740527415274252743527445274552746527475274852749527505275152752527535275452755527565275752758527595276052761527625276352764527655276652767527685276952770527715277252773527745277552776527775277852779527805278152782527835278452785527865278752788527895279052791527925279352794527955279652797527985279952800528015280252803528045280552806528075280852809528105281152812528135281452815528165281752818528195282052821528225282352824528255282652827528285282952830528315283252833528345283552836528375283852839528405284152842528435284452845528465284752848528495285052851528525285352854528555285652857528585285952860528615286252863528645286552866528675286852869528705287152872528735287452875528765287752878528795288052881528825288352884528855288652887528885288952890528915289252893528945289552896528975289852899529005290152902529035290452905529065290752908529095291052911529125291352914529155291652917529185291952920529215292252923529245292552926529275292852929529305293152932529335293452935529365293752938529395294052941529425294352944529455294652947529485294952950529515295252953529545295552956529575295852959529605296152962529635296452965529665296752968529695297052971529725297352974529755297652977529785297952980529815298252983529845298552986529875298852989529905299152992529935299452995529965299752998529995300053001530025300353004530055300653007530085300953010530115301253013530145301553016530175301853019530205302153022530235302453025530265302753028530295303053031530325303353034530355303653037530385303953040530415304253043530445304553046530475304853049530505305153052530535305453055530565305753058530595306053061530625306353064530655306653067530685306953070530715307253073530745307553076530775307853079530805308153082530835308453085530865308753088530895309053091530925309353094530955309653097530985309953100531015310253103531045310553106531075310853109531105311153112531135311453115531165311753118531195312053121531225312353124531255312653127531285312953130531315313253133531345313553136531375313853139531405314153142531435314453145531465314753148531495315053151531525315353154531555315653157531585315953160531615316253163531645316553166531675316853169531705317153172531735317453175531765317753178531795318053181531825318353184531855318653187531885318953190531915319253193531945319553196531975319853199532005320153202532035320453205532065320753208532095321053211532125321353214532155321653217532185321953220532215322253223532245322553226532275322853229532305323153232532335323453235532365323753238532395324053241532425324353244532455324653247532485324953250532515325253253532545325553256532575325853259532605326153262532635326453265532665326753268532695327053271532725327353274532755327653277532785327953280532815328253283532845328553286532875328853289532905329153292532935329453295532965329753298532995330053301533025330353304533055330653307533085330953310533115331253313533145331553316533175331853319533205332153322533235332453325533265332753328533295333053331533325333353334533355333653337533385333953340533415334253343533445334553346533475334853349533505335153352533535335453355533565335753358533595336053361533625336353364533655336653367533685336953370533715337253373533745337553376533775337853379533805338153382533835338453385533865338753388533895339053391533925339353394533955339653397533985339953400534015340253403534045340553406534075340853409534105341153412534135341453415534165341753418534195342053421534225342353424534255342653427534285342953430534315343253433534345343553436534375343853439534405344153442534435344453445534465344753448534495345053451534525345353454534555345653457534585345953460534615346253463534645346553466534675346853469534705347153472534735347453475534765347753478534795348053481534825348353484534855348653487534885348953490534915349253493534945349553496534975349853499535005350153502535035350453505535065350753508535095351053511535125351353514535155351653517535185351953520535215352253523535245352553526535275352853529535305353153532535335353453535535365353753538535395354053541535425354353544535455354653547535485354953550535515355253553535545355553556535575355853559535605356153562535635356453565535665356753568535695357053571535725357353574535755357653577535785357953580535815358253583535845358553586535875358853589535905359153592535935359453595535965359753598535995360053601536025360353604536055360653607536085360953610536115361253613536145361553616536175361853619536205362153622536235362453625536265362753628536295363053631536325363353634536355363653637536385363953640536415364253643536445364553646536475364853649536505365153652536535365453655536565365753658536595366053661536625366353664536655366653667536685366953670536715367253673536745367553676536775367853679536805368153682536835368453685536865368753688536895369053691536925369353694536955369653697536985369953700537015370253703537045370553706537075370853709537105371153712537135371453715537165371753718537195372053721537225372353724537255372653727537285372953730537315373253733537345373553736537375373853739537405374153742537435374453745537465374753748537495375053751537525375353754537555375653757537585375953760537615376253763537645376553766537675376853769537705377153772537735377453775537765377753778537795378053781537825378353784537855378653787537885378953790537915379253793537945379553796537975379853799538005380153802538035380453805538065380753808538095381053811538125381353814538155381653817538185381953820538215382253823538245382553826538275382853829538305383153832538335383453835538365383753838538395384053841538425384353844538455384653847538485384953850538515385253853538545385553856538575385853859538605386153862538635386453865538665386753868538695387053871538725387353874538755387653877538785387953880538815388253883538845388553886538875388853889538905389153892538935389453895538965389753898538995390053901539025390353904539055390653907539085390953910539115391253913539145391553916539175391853919539205392153922539235392453925539265392753928539295393053931539325393353934539355393653937539385393953940539415394253943539445394553946539475394853949539505395153952539535395453955539565395753958539595396053961539625396353964539655396653967539685396953970539715397253973539745397553976539775397853979539805398153982539835398453985539865398753988539895399053991539925399353994539955399653997539985399954000540015400254003540045400554006540075400854009540105401154012540135401454015540165401754018540195402054021540225402354024540255402654027540285402954030540315403254033540345403554036540375403854039540405404154042540435404454045540465404754048540495405054051540525405354054540555405654057540585405954060540615406254063540645406554066540675406854069540705407154072540735407454075540765407754078540795408054081540825408354084540855408654087540885408954090540915409254093540945409554096540975409854099541005410154102541035410454105541065410754108541095411054111541125411354114541155411654117541185411954120541215412254123541245412554126541275412854129541305413154132541335413454135541365413754138541395414054141541425414354144541455414654147541485414954150541515415254153541545415554156541575415854159541605416154162541635416454165541665416754168541695417054171541725417354174541755417654177541785417954180541815418254183541845418554186541875418854189541905419154192541935419454195541965419754198541995420054201542025420354204542055420654207542085420954210542115421254213542145421554216542175421854219542205422154222542235422454225542265422754228542295423054231542325423354234542355423654237542385423954240542415424254243542445424554246542475424854249542505425154252542535425454255542565425754258542595426054261542625426354264542655426654267542685426954270542715427254273542745427554276542775427854279542805428154282542835428454285542865428754288542895429054291542925429354294542955429654297542985429954300543015430254303543045430554306543075430854309543105431154312543135431454315543165431754318543195432054321543225432354324543255432654327543285432954330543315433254333543345433554336543375433854339543405434154342543435434454345543465434754348543495435054351543525435354354543555435654357543585435954360543615436254363543645436554366543675436854369543705437154372543735437454375543765437754378543795438054381543825438354384543855438654387543885438954390543915439254393543945439554396543975439854399544005440154402544035440454405544065440754408544095441054411544125441354414544155441654417544185441954420544215442254423544245442554426544275442854429544305443154432544335443454435544365443754438544395444054441544425444354444544455444654447544485444954450544515445254453544545445554456544575445854459544605446154462544635446454465544665446754468544695447054471544725447354474544755447654477544785447954480544815448254483544845448554486544875448854489544905449154492544935449454495544965449754498544995450054501545025450354504545055450654507545085450954510545115451254513545145451554516545175451854519545205452154522545235452454525545265452754528545295453054531545325453354534545355453654537545385453954540545415454254543545445454554546545475454854549545505455154552545535455454555545565455754558545595456054561545625456354564545655456654567545685456954570545715457254573545745457554576545775457854579545805458154582545835458454585545865458754588545895459054591545925459354594545955459654597545985459954600546015460254603546045460554606546075460854609546105461154612546135461454615546165461754618546195462054621546225462354624546255462654627546285462954630546315463254633546345463554636546375463854639546405464154642546435464454645546465464754648546495465054651546525465354654546555465654657546585465954660546615466254663546645466554666546675466854669546705467154672546735467454675546765467754678546795468054681546825468354684546855468654687546885468954690546915469254693546945469554696546975469854699547005470154702547035470454705547065470754708547095471054711547125471354714547155471654717547185471954720547215472254723547245472554726547275472854729547305473154732547335473454735547365473754738547395474054741547425474354744547455474654747547485474954750547515475254753547545475554756547575475854759547605476154762547635476454765547665476754768547695477054771547725477354774547755477654777547785477954780547815478254783547845478554786547875478854789547905479154792547935479454795547965479754798547995480054801548025480354804548055480654807548085480954810548115481254813548145481554816548175481854819548205482154822548235482454825548265482754828548295483054831548325483354834548355483654837548385483954840548415484254843548445484554846548475484854849548505485154852548535485454855548565485754858548595486054861548625486354864548655486654867548685486954870548715487254873548745487554876548775487854879548805488154882548835488454885548865488754888548895489054891548925489354894548955489654897548985489954900549015490254903549045490554906549075490854909549105491154912549135491454915549165491754918549195492054921549225492354924549255492654927549285492954930549315493254933549345493554936549375493854939549405494154942549435494454945549465494754948549495495054951549525495354954549555495654957549585495954960549615496254963549645496554966549675496854969549705497154972549735497454975549765497754978549795498054981549825498354984549855498654987549885498954990549915499254993549945499554996549975499854999550005500155002550035500455005550065500755008550095501055011550125501355014550155501655017550185501955020550215502255023550245502555026550275502855029550305503155032550335503455035550365503755038550395504055041550425504355044550455504655047550485504955050550515505255053550545505555056550575505855059550605506155062550635506455065550665506755068550695507055071550725507355074550755507655077550785507955080550815508255083550845508555086550875508855089550905509155092550935509455095550965509755098550995510055101551025510355104551055510655107551085510955110551115511255113551145511555116551175511855119551205512155122551235512455125551265512755128551295513055131551325513355134551355513655137551385513955140551415514255143551445514555146551475514855149551505515155152551535515455155551565515755158551595516055161551625516355164551655516655167551685516955170551715517255173551745517555176551775517855179551805518155182551835518455185551865518755188551895519055191551925519355194551955519655197551985519955200552015520255203552045520555206552075520855209552105521155212552135521455215552165521755218552195522055221552225522355224552255522655227552285522955230552315523255233552345523555236552375523855239552405524155242552435524455245552465524755248552495525055251552525525355254552555525655257552585525955260552615526255263552645526555266552675526855269552705527155272552735527455275552765527755278552795528055281552825528355284552855528655287552885528955290552915529255293552945529555296552975529855299553005530155302553035530455305553065530755308553095531055311553125531355314553155531655317553185531955320553215532255323553245532555326553275532855329553305533155332553335533455335553365533755338553395534055341553425534355344553455534655347553485534955350553515535255353553545535555356553575535855359553605536155362553635536455365553665536755368553695537055371553725537355374553755537655377553785537955380553815538255383553845538555386553875538855389553905539155392553935539455395553965539755398553995540055401554025540355404554055540655407554085540955410554115541255413554145541555416554175541855419554205542155422554235542455425554265542755428554295543055431554325543355434554355543655437554385543955440554415544255443554445544555446554475544855449554505545155452554535545455455554565545755458554595546055461554625546355464554655546655467554685546955470554715547255473554745547555476554775547855479554805548155482554835548455485554865548755488554895549055491554925549355494554955549655497554985549955500555015550255503555045550555506555075550855509555105551155512555135551455515555165551755518555195552055521555225552355524555255552655527555285552955530555315553255533555345553555536555375553855539555405554155542555435554455545555465554755548555495555055551555525555355554555555555655557555585555955560555615556255563555645556555566555675556855569555705557155572555735557455575555765557755578555795558055581555825558355584555855558655587555885558955590555915559255593555945559555596555975559855599556005560155602556035560455605556065560755608556095561055611556125561355614556155561655617556185561955620556215562255623556245562555626556275562855629556305563155632556335563455635556365563755638556395564055641556425564355644556455564655647556485564955650556515565255653556545565555656556575565855659556605566155662556635566455665556665566755668556695567055671556725567355674556755567655677556785567955680556815568255683556845568555686556875568855689556905569155692556935569455695556965569755698556995570055701557025570355704557055570655707557085570955710557115571255713557145571555716557175571855719557205572155722557235572455725557265572755728557295573055731557325573355734557355573655737557385573955740557415574255743557445574555746557475574855749557505575155752557535575455755557565575755758557595576055761557625576355764557655576655767557685576955770557715577255773557745577555776557775577855779557805578155782557835578455785557865578755788557895579055791557925579355794557955579655797557985579955800558015580255803558045580555806558075580855809558105581155812558135581455815558165581755818558195582055821558225582355824558255582655827558285582955830558315583255833558345583555836558375583855839558405584155842558435584455845558465584755848558495585055851558525585355854558555585655857558585585955860558615586255863558645586555866558675586855869558705587155872558735587455875558765587755878558795588055881558825588355884558855588655887558885588955890558915589255893558945589555896558975589855899559005590155902559035590455905559065590755908559095591055911559125591355914559155591655917559185591955920559215592255923559245592555926559275592855929559305593155932559335593455935559365593755938559395594055941559425594355944559455594655947559485594955950559515595255953559545595555956559575595855959559605596155962559635596455965559665596755968559695597055971559725597355974559755597655977559785597955980559815598255983559845598555986559875598855989559905599155992559935599455995559965599755998559995600056001560025600356004560055600656007560085600956010560115601256013560145601556016560175601856019560205602156022560235602456025560265602756028560295603056031560325603356034560355603656037560385603956040560415604256043560445604556046560475604856049560505605156052560535605456055560565605756058560595606056061560625606356064560655606656067560685606956070560715607256073560745607556076560775607856079560805608156082560835608456085560865608756088560895609056091560925609356094560955609656097560985609956100561015610256103561045610556106561075610856109561105611156112561135611456115561165611756118561195612056121561225612356124561255612656127561285612956130561315613256133561345613556136561375613856139561405614156142561435614456145561465614756148561495615056151561525615356154561555615656157561585615956160561615616256163561645616556166561675616856169561705617156172561735617456175561765617756178561795618056181561825618356184561855618656187561885618956190561915619256193561945619556196561975619856199562005620156202562035620456205562065620756208562095621056211562125621356214562155621656217562185621956220562215622256223562245622556226562275622856229562305623156232562335623456235562365623756238562395624056241562425624356244562455624656247562485624956250562515625256253562545625556256562575625856259562605626156262562635626456265562665626756268562695627056271562725627356274562755627656277562785627956280562815628256283562845628556286562875628856289562905629156292562935629456295562965629756298562995630056301563025630356304563055630656307563085630956310563115631256313563145631556316563175631856319563205632156322563235632456325563265632756328563295633056331563325633356334563355633656337563385633956340563415634256343563445634556346563475634856349563505635156352563535635456355563565635756358563595636056361563625636356364563655636656367563685636956370563715637256373563745637556376563775637856379563805638156382563835638456385563865638756388563895639056391563925639356394563955639656397563985639956400564015640256403564045640556406564075640856409564105641156412564135641456415564165641756418564195642056421564225642356424564255642656427564285642956430564315643256433564345643556436564375643856439564405644156442564435644456445564465644756448564495645056451564525645356454564555645656457564585645956460564615646256463564645646556466564675646856469564705647156472564735647456475564765647756478564795648056481564825648356484564855648656487564885648956490564915649256493564945649556496564975649856499565005650156502565035650456505565065650756508565095651056511565125651356514565155651656517565185651956520565215652256523565245652556526565275652856529565305653156532565335653456535565365653756538565395654056541565425654356544565455654656547565485654956550565515655256553565545655556556565575655856559565605656156562565635656456565565665656756568565695657056571565725657356574565755657656577565785657956580565815658256583565845658556586565875658856589565905659156592565935659456595565965659756598565995660056601566025660356604566055660656607566085660956610566115661256613566145661556616566175661856619566205662156622566235662456625566265662756628566295663056631566325663356634566355663656637566385663956640566415664256643566445664556646566475664856649566505665156652566535665456655566565665756658566595666056661566625666356664566655666656667566685666956670566715667256673566745667556676566775667856679566805668156682566835668456685566865668756688566895669056691566925669356694566955669656697566985669956700567015670256703567045670556706567075670856709567105671156712567135671456715567165671756718567195672056721567225672356724567255672656727567285672956730567315673256733567345673556736567375673856739567405674156742567435674456745567465674756748567495675056751567525675356754567555675656757567585675956760567615676256763567645676556766567675676856769567705677156772567735677456775567765677756778567795678056781567825678356784567855678656787567885678956790567915679256793567945679556796567975679856799568005680156802568035680456805568065680756808568095681056811568125681356814568155681656817568185681956820568215682256823568245682556826568275682856829568305683156832568335683456835568365683756838568395684056841568425684356844568455684656847568485684956850568515685256853568545685556856568575685856859568605686156862568635686456865568665686756868568695687056871568725687356874568755687656877568785687956880568815688256883568845688556886568875688856889568905689156892568935689456895568965689756898568995690056901569025690356904569055690656907569085690956910569115691256913569145691556916569175691856919569205692156922569235692456925569265692756928569295693056931569325693356934569355693656937569385693956940569415694256943569445694556946569475694856949569505695156952569535695456955569565695756958569595696056961569625696356964569655696656967569685696956970569715697256973569745697556976569775697856979569805698156982569835698456985569865698756988569895699056991569925699356994569955699656997569985699957000570015700257003570045700557006570075700857009570105701157012570135701457015570165701757018570195702057021570225702357024570255702657027570285702957030570315703257033570345703557036570375703857039570405704157042570435704457045570465704757048570495705057051570525705357054570555705657057570585705957060570615706257063570645706557066570675706857069570705707157072570735707457075570765707757078570795708057081570825708357084570855708657087570885708957090570915709257093570945709557096570975709857099571005710157102571035710457105571065710757108571095711057111571125711357114571155711657117571185711957120571215712257123571245712557126571275712857129571305713157132571335713457135571365713757138571395714057141571425714357144571455714657147571485714957150571515715257153571545715557156571575715857159571605716157162571635716457165571665716757168571695717057171571725717357174571755717657177571785717957180571815718257183571845718557186571875718857189571905719157192571935719457195571965719757198571995720057201572025720357204572055720657207572085720957210572115721257213572145721557216572175721857219572205722157222572235722457225572265722757228572295723057231572325723357234572355723657237572385723957240572415724257243572445724557246572475724857249572505725157252572535725457255572565725757258572595726057261572625726357264572655726657267572685726957270572715727257273572745727557276572775727857279572805728157282572835728457285572865728757288572895729057291572925729357294572955729657297572985729957300573015730257303573045730557306573075730857309573105731157312573135731457315573165731757318573195732057321573225732357324573255732657327573285732957330573315733257333573345733557336573375733857339573405734157342573435734457345573465734757348573495735057351573525735357354573555735657357573585735957360573615736257363573645736557366573675736857369573705737157372573735737457375573765737757378573795738057381573825738357384573855738657387573885738957390573915739257393573945739557396573975739857399574005740157402574035740457405574065740757408574095741057411574125741357414574155741657417574185741957420574215742257423574245742557426574275742857429574305743157432574335743457435574365743757438574395744057441574425744357444574455744657447574485744957450574515745257453574545745557456574575745857459574605746157462574635746457465574665746757468574695747057471574725747357474574755747657477574785747957480574815748257483574845748557486574875748857489574905749157492574935749457495574965749757498574995750057501575025750357504575055750657507575085750957510575115751257513575145751557516575175751857519575205752157522575235752457525575265752757528575295753057531575325753357534575355753657537575385753957540575415754257543575445754557546575475754857549575505755157552575535755457555575565755757558575595756057561575625756357564575655756657567575685756957570575715757257573575745757557576575775757857579575805758157582575835758457585575865758757588575895759057591575925759357594575955759657597575985759957600576015760257603576045760557606576075760857609576105761157612576135761457615576165761757618576195762057621576225762357624576255762657627576285762957630576315763257633576345763557636576375763857639576405764157642576435764457645576465764757648576495765057651576525765357654576555765657657576585765957660576615766257663576645766557666576675766857669576705767157672576735767457675576765767757678576795768057681576825768357684576855768657687576885768957690576915769257693576945769557696576975769857699577005770157702577035770457705577065770757708577095771057711577125771357714577155771657717577185771957720577215772257723577245772557726577275772857729577305773157732577335773457735577365773757738577395774057741577425774357744577455774657747577485774957750577515775257753577545775557756577575775857759577605776157762577635776457765577665776757768577695777057771577725777357774577755777657777577785777957780577815778257783577845778557786577875778857789577905779157792577935779457795577965779757798577995780057801578025780357804578055780657807578085780957810578115781257813578145781557816578175781857819578205782157822578235782457825578265782757828578295783057831578325783357834578355783657837578385783957840578415784257843578445784557846578475784857849578505785157852578535785457855578565785757858578595786057861578625786357864578655786657867578685786957870578715787257873578745787557876578775787857879578805788157882578835788457885578865788757888578895789057891578925789357894578955789657897578985789957900579015790257903579045790557906579075790857909579105791157912579135791457915579165791757918579195792057921579225792357924579255792657927579285792957930579315793257933579345793557936579375793857939579405794157942579435794457945579465794757948579495795057951579525795357954579555795657957579585795957960579615796257963579645796557966579675796857969579705797157972579735797457975579765797757978579795798057981579825798357984579855798657987579885798957990579915799257993579945799557996579975799857999580005800158002580035800458005580065800758008580095801058011580125801358014580155801658017580185801958020580215802258023580245802558026580275802858029580305803158032580335803458035580365803758038580395804058041580425804358044580455804658047580485804958050580515805258053580545805558056580575805858059580605806158062580635806458065580665806758068580695807058071580725807358074580755807658077580785807958080580815808258083580845808558086580875808858089580905809158092580935809458095580965809758098580995810058101581025810358104581055810658107581085810958110581115811258113581145811558116581175811858119581205812158122581235812458125581265812758128581295813058131581325813358134581355813658137581385813958140581415814258143581445814558146581475814858149581505815158152581535815458155581565815758158581595816058161581625816358164581655816658167581685816958170581715817258173581745817558176581775817858179581805818158182581835818458185581865818758188581895819058191581925819358194581955819658197581985819958200582015820258203582045820558206582075820858209582105821158212582135821458215582165821758218582195822058221582225822358224582255822658227582285822958230582315823258233582345823558236582375823858239582405824158242582435824458245582465824758248582495825058251582525825358254582555825658257582585825958260582615826258263582645826558266582675826858269582705827158272582735827458275582765827758278582795828058281582825828358284582855828658287582885828958290582915829258293582945829558296582975829858299583005830158302583035830458305583065830758308583095831058311583125831358314583155831658317583185831958320583215832258323583245832558326583275832858329583305833158332583335833458335583365833758338583395834058341583425834358344583455834658347583485834958350583515835258353583545835558356583575835858359583605836158362583635836458365583665836758368583695837058371583725837358374583755837658377583785837958380583815838258383583845838558386583875838858389583905839158392583935839458395583965839758398583995840058401584025840358404584055840658407584085840958410584115841258413584145841558416584175841858419584205842158422584235842458425584265842758428584295843058431584325843358434584355843658437584385843958440584415844258443584445844558446584475844858449584505845158452584535845458455584565845758458584595846058461584625846358464584655846658467584685846958470584715847258473584745847558476584775847858479584805848158482584835848458485584865848758488584895849058491584925849358494584955849658497584985849958500585015850258503585045850558506585075850858509585105851158512585135851458515585165851758518585195852058521585225852358524585255852658527585285852958530585315853258533585345853558536585375853858539585405854158542585435854458545585465854758548585495855058551585525855358554585555855658557585585855958560585615856258563585645856558566585675856858569585705857158572585735857458575585765857758578585795858058581585825858358584585855858658587585885858958590585915859258593585945859558596585975859858599586005860158602586035860458605586065860758608586095861058611586125861358614586155861658617586185861958620586215862258623586245862558626586275862858629586305863158632586335863458635586365863758638586395864058641586425864358644586455864658647586485864958650586515865258653586545865558656586575865858659586605866158662586635866458665586665866758668586695867058671586725867358674586755867658677586785867958680586815868258683586845868558686586875868858689586905869158692586935869458695586965869758698586995870058701587025870358704587055870658707587085870958710587115871258713587145871558716587175871858719587205872158722587235872458725587265872758728587295873058731587325873358734587355873658737587385873958740587415874258743587445874558746587475874858749587505875158752587535875458755587565875758758587595876058761587625876358764587655876658767587685876958770587715877258773587745877558776587775877858779587805878158782587835878458785587865878758788587895879058791587925879358794587955879658797587985879958800588015880258803588045880558806588075880858809588105881158812588135881458815588165881758818588195882058821588225882358824588255882658827588285882958830588315883258833588345883558836588375883858839588405884158842588435884458845588465884758848588495885058851588525885358854588555885658857588585885958860588615886258863588645886558866588675886858869588705887158872588735887458875588765887758878588795888058881588825888358884588855888658887588885888958890588915889258893588945889558896588975889858899589005890158902589035890458905589065890758908589095891058911589125891358914589155891658917589185891958920589215892258923589245892558926589275892858929589305893158932589335893458935589365893758938589395894058941589425894358944589455894658947589485894958950589515895258953589545895558956589575895858959589605896158962589635896458965589665896758968589695897058971589725897358974589755897658977589785897958980589815898258983589845898558986589875898858989589905899158992589935899458995589965899758998589995900059001590025900359004590055900659007590085900959010590115901259013590145901559016590175901859019590205902159022590235902459025590265902759028590295903059031590325903359034590355903659037590385903959040590415904259043590445904559046590475904859049590505905159052590535905459055590565905759058590595906059061590625906359064590655906659067590685906959070590715907259073590745907559076590775907859079590805908159082590835908459085590865908759088590895909059091590925909359094590955909659097590985909959100591015910259103591045910559106591075910859109591105911159112591135911459115591165911759118591195912059121591225912359124591255912659127591285912959130591315913259133591345913559136591375913859139591405914159142591435914459145591465914759148591495915059151591525915359154591555915659157591585915959160591615916259163591645916559166591675916859169591705917159172591735917459175591765917759178591795918059181591825918359184591855918659187591885918959190591915919259193591945919559196591975919859199592005920159202592035920459205592065920759208592095921059211592125921359214592155921659217592185921959220592215922259223592245922559226592275922859229592305923159232592335923459235592365923759238592395924059241592425924359244592455924659247592485924959250592515925259253592545925559256592575925859259592605926159262592635926459265592665926759268592695927059271592725927359274592755927659277592785927959280592815928259283592845928559286592875928859289592905929159292592935929459295592965929759298592995930059301593025930359304593055930659307593085930959310593115931259313593145931559316593175931859319593205932159322593235932459325593265932759328593295933059331593325933359334593355933659337593385933959340593415934259343593445934559346593475934859349593505935159352593535935459355593565935759358593595936059361593625936359364593655936659367593685936959370593715937259373593745937559376593775937859379593805938159382593835938459385593865938759388593895939059391593925939359394593955939659397593985939959400594015940259403594045940559406594075940859409594105941159412594135941459415594165941759418594195942059421594225942359424594255942659427594285942959430594315943259433594345943559436594375943859439594405944159442594435944459445594465944759448594495945059451594525945359454594555945659457594585945959460594615946259463594645946559466594675946859469594705947159472594735947459475594765947759478594795948059481594825948359484594855948659487594885948959490594915949259493594945949559496594975949859499595005950159502595035950459505595065950759508595095951059511595125951359514595155951659517595185951959520595215952259523595245952559526595275952859529595305953159532595335953459535595365953759538595395954059541595425954359544595455954659547595485954959550595515955259553595545955559556595575955859559595605956159562595635956459565595665956759568595695957059571595725957359574595755957659577595785957959580595815958259583595845958559586595875958859589595905959159592595935959459595595965959759598595995960059601596025960359604596055960659607596085960959610596115961259613596145961559616596175961859619596205962159622596235962459625596265962759628596295963059631596325963359634596355963659637596385963959640596415964259643596445964559646596475964859649596505965159652596535965459655596565965759658596595966059661596625966359664596655966659667596685966959670596715967259673596745967559676596775967859679596805968159682596835968459685596865968759688596895969059691596925969359694596955969659697596985969959700597015970259703597045970559706597075970859709597105971159712597135971459715597165971759718597195972059721597225972359724597255972659727597285972959730597315973259733597345973559736597375973859739597405974159742597435974459745597465974759748597495975059751597525975359754597555975659757597585975959760597615976259763597645976559766597675976859769597705977159772597735977459775597765977759778597795978059781597825978359784597855978659787597885978959790597915979259793597945979559796597975979859799598005980159802598035980459805598065980759808598095981059811598125981359814598155981659817598185981959820598215982259823598245982559826598275982859829598305983159832598335983459835598365983759838598395984059841598425984359844598455984659847598485984959850598515985259853598545985559856598575985859859598605986159862598635986459865598665986759868598695987059871598725987359874598755987659877598785987959880598815988259883598845988559886598875988859889598905989159892598935989459895598965989759898598995990059901599025990359904599055990659907599085990959910599115991259913599145991559916599175991859919599205992159922599235992459925599265992759928599295993059931599325993359934599355993659937599385993959940599415994259943599445994559946599475994859949599505995159952599535995459955599565995759958599595996059961599625996359964599655996659967599685996959970599715997259973599745997559976599775997859979599805998159982599835998459985599865998759988599895999059991599925999359994599955999659997599985999960000600016000260003600046000560006600076000860009600106001160012600136001460015600166001760018600196002060021600226002360024600256002660027600286002960030600316003260033600346003560036600376003860039600406004160042600436004460045600466004760048600496005060051600526005360054600556005660057600586005960060600616006260063600646006560066600676006860069600706007160072600736007460075600766007760078600796008060081600826008360084600856008660087600886008960090600916009260093600946009560096600976009860099601006010160102601036010460105601066010760108601096011060111601126011360114601156011660117601186011960120601216012260123601246012560126601276012860129601306013160132601336013460135601366013760138601396014060141601426014360144601456014660147601486014960150601516015260153601546015560156601576015860159601606016160162601636016460165601666016760168601696017060171601726017360174601756017660177601786017960180601816018260183601846018560186601876018860189601906019160192601936019460195601966019760198601996020060201602026020360204602056020660207602086020960210602116021260213602146021560216602176021860219602206022160222602236022460225602266022760228602296023060231602326023360234602356023660237602386023960240602416024260243602446024560246602476024860249602506025160252602536025460255602566025760258602596026060261602626026360264602656026660267602686026960270602716027260273602746027560276602776027860279602806028160282602836028460285602866028760288602896029060291602926029360294602956029660297602986029960300603016030260303603046030560306603076030860309603106031160312603136031460315603166031760318603196032060321603226032360324603256032660327603286032960330603316033260333603346033560336603376033860339603406034160342603436034460345603466034760348603496035060351603526035360354603556035660357603586035960360603616036260363603646036560366603676036860369603706037160372603736037460375603766037760378603796038060381603826038360384603856038660387603886038960390603916039260393603946039560396603976039860399604006040160402604036040460405604066040760408604096041060411604126041360414604156041660417604186041960420604216042260423604246042560426604276042860429604306043160432604336043460435
  1. /**
  2. * @license Highcharts Gantt JS v9.1.1 (2021-06-04)
  3. *
  4. * (c) 2017-2021 Lars Cabrera, Torstein Honsi, Jon Arild Nygard & Oystein Moseng
  5. *
  6. * License: www.highcharts.com/license
  7. */
  8. 'use strict';
  9. (function (root, factory) {
  10. if (typeof module === 'object' && module.exports) {
  11. factory['default'] = factory;
  12. module.exports = root.document ?
  13. factory(root) :
  14. factory;
  15. } else if (typeof define === 'function' && define.amd) {
  16. define('highcharts/highcharts-gantt', function () {
  17. return factory(root);
  18. });
  19. } else {
  20. if (root.Highcharts) {
  21. root.Highcharts.error(16, true);
  22. }
  23. root.Highcharts = factory(root);
  24. }
  25. }(typeof window !== 'undefined' ? window : this, function (win) {
  26. var _modules = {};
  27. function _registerModule(obj, path, args, fn) {
  28. if (!obj.hasOwnProperty(path)) {
  29. obj[path] = fn.apply(null, args);
  30. }
  31. }
  32. _registerModule(_modules, 'Core/Globals.js', [], function () {
  33. /* *
  34. *
  35. * (c) 2010-2021 Torstein Honsi
  36. *
  37. * License: www.highcharts.com/license
  38. *
  39. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  40. *
  41. * */
  42. /* *
  43. *
  44. * Constants
  45. *
  46. * */
  47. /**
  48. * @private
  49. * @deprecated
  50. * @todo Rename UMD argument `win` to `window`; move code to `Globals.win`
  51. */
  52. var w = (typeof win !== 'undefined' ?
  53. win :
  54. typeof window !== 'undefined' ?
  55. window :
  56. {}
  57. // eslint-disable-next-line node/no-unsupported-features/es-builtins
  58. );
  59. /* *
  60. *
  61. * Namespace
  62. *
  63. * */
  64. /**
  65. * Shared Highcharts properties.
  66. */
  67. var Globals;
  68. (function (Globals) {
  69. /* *
  70. *
  71. * Constants
  72. *
  73. * */
  74. Globals.SVG_NS = 'http://www.w3.org/2000/svg', Globals.product = 'Highcharts', Globals.version = '9.1.1', Globals.win = w, Globals.doc = Globals.win.document, Globals.svg = (Globals.doc &&
  75. Globals.doc.createElementNS &&
  76. !!Globals.doc.createElementNS(Globals.SVG_NS, 'svg').createSVGRect), Globals.userAgent = (Globals.win.navigator && Globals.win.navigator.userAgent) || '', Globals.isChrome = Globals.userAgent.indexOf('Chrome') !== -1, Globals.isFirefox = Globals.userAgent.indexOf('Firefox') !== -1, Globals.isMS = /(edge|msie|trident)/i.test(Globals.userAgent) && !Globals.win.opera, Globals.isSafari = !Globals.isChrome && Globals.userAgent.indexOf('Safari') !== -1, Globals.isTouchDevice = /(Mobile|Android|Windows Phone)/.test(Globals.userAgent), Globals.isWebKit = Globals.userAgent.indexOf('AppleWebKit') !== -1, Globals.deg2rad = Math.PI * 2 / 360, Globals.hasBidiBug = (Globals.isFirefox &&
  77. parseInt(Globals.userAgent.split('Firefox/')[1], 10) < 4 // issue #38
  78. ), Globals.hasTouch = !!Globals.win.TouchEvent, Globals.marginNames = [
  79. 'plotTop',
  80. 'marginRight',
  81. 'marginBottom',
  82. 'plotLeft'
  83. ], Globals.noop = function () { }, Globals.supportsPassiveEvents = (function () {
  84. // Checks whether the browser supports passive events, (#11353).
  85. var supportsPassive = false;
  86. // Object.defineProperty doesn't work on IE as well as passive
  87. // events - instead of using polyfill, we can exclude IE totally.
  88. if (!Globals.isMS) {
  89. var opts = Object.defineProperty({}, 'passive', {
  90. get: function () {
  91. supportsPassive = true;
  92. }
  93. });
  94. if (Globals.win.addEventListener && Globals.win.removeEventListener) {
  95. Globals.win.addEventListener('testPassive', Globals.noop, opts);
  96. Globals.win.removeEventListener('testPassive', Globals.noop, opts);
  97. }
  98. }
  99. return supportsPassive;
  100. }());
  101. /**
  102. * An array containing the current chart objects in the page. A chart's
  103. * position in the array is preserved throughout the page's lifetime. When
  104. * a chart is destroyed, the array item becomes `undefined`.
  105. *
  106. * @name Highcharts.charts
  107. * @type {Array<Highcharts.Chart|undefined>}
  108. */
  109. Globals.charts = [];
  110. /**
  111. * A hook for defining additional date format specifiers. New
  112. * specifiers are defined as key-value pairs by using the
  113. * specifier as key, and a function which takes the timestamp as
  114. * value. This function returns the formatted portion of the
  115. * date.
  116. *
  117. * @sample highcharts/global/dateformats/
  118. * Adding support for week number
  119. *
  120. * @name Highcharts.dateFormats
  121. * @type {Record<string, Highcharts.TimeFormatCallbackFunction>}
  122. */
  123. Globals.dateFormats = {};
  124. /**
  125. * @private
  126. * @deprecated
  127. * @todo Use only `Core/Series/SeriesRegistry.seriesTypes`
  128. */
  129. Globals.seriesTypes = {};
  130. /**
  131. * @private
  132. */
  133. Globals.symbolSizes = {};
  134. })(Globals || (Globals = {}));
  135. /* *
  136. *
  137. * Default Export
  138. *
  139. * */
  140. return Globals;
  141. });
  142. _registerModule(_modules, 'Core/Utilities.js', [_modules['Core/Globals.js']], function (H) {
  143. /* *
  144. *
  145. * (c) 2010-2021 Torstein Honsi
  146. *
  147. * License: www.highcharts.com/license
  148. *
  149. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  150. *
  151. * */
  152. var charts = H.charts,
  153. doc = H.doc,
  154. win = H.win;
  155. /**
  156. * An animation configuration. Animation configurations can also be defined as
  157. * booleans, where `false` turns off animation and `true` defaults to a duration
  158. * of 500ms and defer of 0ms.
  159. *
  160. * @interface Highcharts.AnimationOptionsObject
  161. */ /**
  162. * A callback function to exectute when the animation finishes.
  163. * @name Highcharts.AnimationOptionsObject#complete
  164. * @type {Function|undefined}
  165. */ /**
  166. * The animation defer in milliseconds.
  167. * @name Highcharts.AnimationOptionsObject#defer
  168. * @type {number|undefined}
  169. */ /**
  170. * The animation duration in milliseconds.
  171. * @name Highcharts.AnimationOptionsObject#duration
  172. * @type {number|undefined}
  173. */ /**
  174. * The name of an easing function as defined on the `Math` object.
  175. * @name Highcharts.AnimationOptionsObject#easing
  176. * @type {string|Function|undefined}
  177. */ /**
  178. * A callback function to execute on each step of each attribute or CSS property
  179. * that's being animated. The first argument contains information about the
  180. * animation and progress.
  181. * @name Highcharts.AnimationOptionsObject#step
  182. * @type {Function|undefined}
  183. */
  184. /**
  185. * Creates a frame for the animated SVG element.
  186. *
  187. * @callback Highcharts.AnimationStepCallbackFunction
  188. *
  189. * @param {Highcharts.SVGElement} this
  190. * The SVG element to animate.
  191. *
  192. * @return {void}
  193. */
  194. /**
  195. * Interface description for a class.
  196. *
  197. * @interface Highcharts.Class<T>
  198. * @extends Function
  199. */ /**
  200. * Class costructor.
  201. * @function Highcharts.Class<T>#new
  202. * @param {...Array<*>} args
  203. * Constructor arguments.
  204. * @return {T}
  205. * Class instance.
  206. */
  207. /**
  208. * A style object with camel case property names to define visual appearance of
  209. * a SVG element or HTML element. The properties can be whatever styles are
  210. * supported on the given SVG or HTML element.
  211. *
  212. * @example
  213. * {
  214. * fontFamily: 'monospace',
  215. * fontSize: '1.2em'
  216. * }
  217. *
  218. * @interface Highcharts.CSSObject
  219. */ /**
  220. * @name Highcharts.CSSObject#[key:string]
  221. * @type {boolean|number|string|undefined}
  222. */ /**
  223. * Background style for the element.
  224. * @name Highcharts.CSSObject#background
  225. * @type {string|undefined}
  226. */ /**
  227. * Background color of the element.
  228. * @name Highcharts.CSSObject#backgroundColor
  229. * @type {Highcharts.ColorString|undefined}
  230. */ /**
  231. * Border style for the element.
  232. * @name Highcharts.CSSObject#border
  233. * @type {string|undefined}
  234. */ /**
  235. * Radius of the element border.
  236. * @name Highcharts.CSSObject#borderRadius
  237. * @type {number|undefined}
  238. */ /**
  239. * Color used in the element. The 'contrast' option is a Highcharts custom
  240. * property that results in black or white, depending on the background of the
  241. * element.
  242. * @name Highcharts.CSSObject#color
  243. * @type {'contrast'|Highcharts.ColorString|undefined}
  244. */ /**
  245. * Style of the mouse cursor when resting over the element.
  246. * @name Highcharts.CSSObject#cursor
  247. * @type {Highcharts.CursorValue|undefined}
  248. */ /**
  249. * Font family of the element text. Multiple values have to be in decreasing
  250. * preference order and separated by comma.
  251. * @name Highcharts.CSSObject#fontFamily
  252. * @type {string|undefined}
  253. */ /**
  254. * Font size of the element text.
  255. * @name Highcharts.CSSObject#fontSize
  256. * @type {string|undefined}
  257. */ /**
  258. * Font weight of the element text.
  259. * @name Highcharts.CSSObject#fontWeight
  260. * @type {string|undefined}
  261. */ /**
  262. * Height of the element.
  263. * @name Highcharts.CSSObject#height
  264. * @type {number|undefined}
  265. */ /**
  266. * Width of the element border.
  267. * @name Highcharts.CSSObject#lineWidth
  268. * @type {number|undefined}
  269. */ /**
  270. * Opacity of the element.
  271. * @name Highcharts.CSSObject#opacity
  272. * @type {number|undefined}
  273. */ /**
  274. * Space around the element content.
  275. * @name Highcharts.CSSObject#padding
  276. * @type {string|undefined}
  277. */ /**
  278. * Behaviour of the element when the mouse cursor rests over it.
  279. * @name Highcharts.CSSObject#pointerEvents
  280. * @type {string|undefined}
  281. */ /**
  282. * Positioning of the element.
  283. * @name Highcharts.CSSObject#position
  284. * @type {string|undefined}
  285. */ /**
  286. * Alignment of the element text.
  287. * @name Highcharts.CSSObject#textAlign
  288. * @type {string|undefined}
  289. */ /**
  290. * Additional decoration of the element text.
  291. * @name Highcharts.CSSObject#textDecoration
  292. * @type {string|undefined}
  293. */ /**
  294. * Outline style of the element text.
  295. * @name Highcharts.CSSObject#textOutline
  296. * @type {string|undefined}
  297. */ /**
  298. * Line break style of the element text. Highcharts SVG elements support
  299. * `ellipsis` when a `width` is set.
  300. * @name Highcharts.CSSObject#textOverflow
  301. * @type {string|undefined}
  302. */ /**
  303. * Top spacing of the element relative to the parent element.
  304. * @name Highcharts.CSSObject#top
  305. * @type {string|undefined}
  306. */ /**
  307. * Animated transition of selected element properties.
  308. * @name Highcharts.CSSObject#transition
  309. * @type {string|undefined}
  310. */ /**
  311. * Line break style of the element text.
  312. * @name Highcharts.CSSObject#whiteSpace
  313. * @type {string|undefined}
  314. */ /**
  315. * Width of the element.
  316. * @name Highcharts.CSSObject#width
  317. * @type {number|undefined}
  318. */
  319. /**
  320. * All possible cursor styles.
  321. *
  322. * @typedef {'alias'|'all-scroll'|'auto'|'cell'|'col-resize'|'context-menu'|'copy'|'crosshair'|'default'|'e-resize'|'ew-resize'|'grab'|'grabbing'|'help'|'move'|'n-resize'|'ne-resize'|'nesw-resize'|'no-drop'|'none'|'not-allowed'|'ns-resize'|'nw-resize'|'nwse-resize'|'pointer'|'progress'|'row-resize'|'s-resize'|'se-resize'|'sw-resize'|'text'|'vertical-text'|'w-resize'|'wait'|'zoom-in'|'zoom-out'} Highcharts.CursorValue
  323. */
  324. /**
  325. * All possible dash styles.
  326. *
  327. * @typedef {'Dash'|'DashDot'|'Dot'|'LongDash'|'LongDashDot'|'LongDashDotDot'|'ShortDash'|'ShortDashDot'|'ShortDashDotDot'|'ShortDot'|'Solid'} Highcharts.DashStyleValue
  328. */
  329. /**
  330. * Generic dictionary in TypeScript notation.
  331. * Use the native `AnyRecord` instead.
  332. *
  333. * @deprecated
  334. * @interface Highcharts.Dictionary<T>
  335. */ /**
  336. * @name Highcharts.Dictionary<T>#[key:string]
  337. * @type {T}
  338. */
  339. /**
  340. * The function callback to execute when the event is fired. The `this` context
  341. * contains the instance, that fired the event.
  342. *
  343. * @callback Highcharts.EventCallbackFunction<T>
  344. *
  345. * @param {T} this
  346. *
  347. * @param {Highcharts.Dictionary<*>|Event} [eventArguments]
  348. * Event arguments.
  349. *
  350. * @return {boolean|void}
  351. */
  352. /**
  353. * The event options for adding function callback.
  354. *
  355. * @interface Highcharts.EventOptionsObject
  356. */ /**
  357. * The order the event handler should be called. This opens for having one
  358. * handler be called before another, independent of in which order they were
  359. * added.
  360. * @name Highcharts.EventOptionsObject#order
  361. * @type {number}
  362. */ /**
  363. * Whether an event should be passive or not.
  364. * When set to `true`, the function specified by listener will never call
  365. * `preventDefault()`.
  366. * @name Highcharts.EventOptionsObject#passive
  367. * @type boolean
  368. */
  369. /**
  370. * Formats data as a string. Usually the data is accessible throught the `this`
  371. * keyword.
  372. *
  373. * @callback Highcharts.FormatterCallbackFunction<T>
  374. *
  375. * @param {T} this
  376. * Context to format
  377. *
  378. * @return {string}
  379. * Formatted text
  380. */
  381. /**
  382. * An object of key-value pairs for HTML attributes.
  383. *
  384. * @typedef {Highcharts.Dictionary<boolean|number|string|Function>} Highcharts.HTMLAttributes
  385. */
  386. /**
  387. * An HTML DOM element. The type is a reference to the regular HTMLElement in
  388. * the global scope.
  389. *
  390. * @typedef {global.HTMLElement} Highcharts.HTMLDOMElement
  391. *
  392. * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
  393. */
  394. /**
  395. * The iterator callback.
  396. *
  397. * @callback Highcharts.ObjectEachCallbackFunction<T>
  398. *
  399. * @param {T} this
  400. * The context.
  401. *
  402. * @param {*} value
  403. * The property value.
  404. *
  405. * @param {string} key
  406. * The property key.
  407. *
  408. * @param {*} obj
  409. * The object that objectEach is being applied to.
  410. */
  411. /**
  412. * An object containing `left` and `top` properties for the position in the
  413. * page.
  414. *
  415. * @interface Highcharts.OffsetObject
  416. */ /**
  417. * Left distance to the page border.
  418. * @name Highcharts.OffsetObject#left
  419. * @type {number}
  420. */ /**
  421. * Top distance to the page border.
  422. * @name Highcharts.OffsetObject#top
  423. * @type {number}
  424. */
  425. /**
  426. * Describes a range.
  427. *
  428. * @interface Highcharts.RangeObject
  429. */ /**
  430. * Maximum number of the range.
  431. * @name Highcharts.RangeObject#max
  432. * @type {number}
  433. */ /**
  434. * Minimum number of the range.
  435. * @name Highcharts.RangeObject#min
  436. * @type {number}
  437. */
  438. /**
  439. * If a number is given, it defines the pixel length. If a percentage string is
  440. * given, like for example `'50%'`, the setting defines a length relative to a
  441. * base size, for example the size of a container.
  442. *
  443. * @typedef {number|string} Highcharts.RelativeSize
  444. */
  445. /**
  446. * Proceed function to call original (wrapped) function.
  447. *
  448. * @callback Highcharts.WrapProceedFunction
  449. *
  450. * @param {*} [arg1]
  451. * Optional argument. Without any arguments defaults to first argument of
  452. * the wrapping function.
  453. *
  454. * @param {*} [arg2]
  455. * Optional argument. Without any arguments defaults to second argument
  456. * of the wrapping function.
  457. *
  458. * @param {*} [arg3]
  459. * Optional argument. Without any arguments defaults to third argument of
  460. * the wrapping function.
  461. *
  462. * @return {*}
  463. * Return value of the original function.
  464. */
  465. /**
  466. * The Highcharts object is the placeholder for all other members, and various
  467. * utility functions. The most important member of the namespace would be the
  468. * chart constructor.
  469. *
  470. * @example
  471. * let chart = Highcharts.chart('container', { ... });
  472. *
  473. * @namespace Highcharts
  474. */
  475. ''; // detach doclets above
  476. /**
  477. * Provide error messages for debugging, with links to online explanation. This
  478. * function can be overridden to provide custom error handling.
  479. *
  480. * @sample highcharts/chart/highcharts-error/
  481. * Custom error handler
  482. *
  483. * @function Highcharts.error
  484. *
  485. * @param {number|string} code
  486. * The error code. See
  487. * [errors.xml](https://github.com/highcharts/highcharts/blob/master/errors/errors.xml)
  488. * for available codes. If it is a string, the error message is printed
  489. * directly in the console.
  490. *
  491. * @param {boolean} [stop=false]
  492. * Whether to throw an error or just log a warning in the console.
  493. *
  494. * @param {Highcharts.Chart} [chart]
  495. * Reference to the chart that causes the error. Used in 'debugger'
  496. * module to display errors directly on the chart.
  497. * Important note: This argument is undefined for errors that lack
  498. * access to the Chart instance. In such case, the error will be
  499. * displayed on the last created chart.
  500. *
  501. * @param {Highcharts.Dictionary<string>} [params]
  502. * Additional parameters for the generated message.
  503. *
  504. * @return {void}
  505. */
  506. function error(code, stop, chart, params) {
  507. var severity = stop ? 'Highcharts error' : 'Highcharts warning';
  508. if (code === 32) {
  509. code = severity + ": Deprecated member";
  510. }
  511. var isCode = isNumber(code);
  512. var message = isCode ?
  513. severity + " #" + code + ": www.highcharts.com/errors/" + code + "/" :
  514. code.toString();
  515. var defaultHandler = function () {
  516. if (stop) {
  517. throw new Error(message);
  518. }
  519. // else ...
  520. if (win.console &&
  521. error.messages.indexOf(message) === -1 // prevent console flooting
  522. ) {
  523. console.warn(message); // eslint-disable-line no-console
  524. }
  525. };
  526. if (typeof params !== 'undefined') {
  527. var additionalMessages_1 = '';
  528. if (isCode) {
  529. message += '?';
  530. }
  531. objectEach(params, function (value, key) {
  532. additionalMessages_1 += "\n - " + key + ": " + value;
  533. if (isCode) {
  534. message += encodeURI(key) + '=' + encodeURI(value);
  535. }
  536. });
  537. message += additionalMessages_1;
  538. }
  539. fireEvent(H, 'displayError', { chart: chart, code: code, message: message, params: params }, defaultHandler);
  540. error.messages.push(message);
  541. }
  542. (function (error) {
  543. error.messages = [];
  544. })(error || (error = {}));
  545. /* eslint-disable valid-jsdoc */
  546. /**
  547. * Utility function to deep merge two or more objects and return a third object.
  548. * If the first argument is true, the contents of the second object is copied
  549. * into the first object. The merge function can also be used with a single
  550. * object argument to create a deep copy of an object.
  551. *
  552. * @function Highcharts.merge<T>
  553. *
  554. * @param {boolean} extend
  555. * Whether to extend the left-side object (a) or return a whole new
  556. * object.
  557. *
  558. * @param {T|undefined} a
  559. * The first object to extend. When only this is given, the function
  560. * returns a deep copy.
  561. *
  562. * @param {...Array<object|undefined>} [n]
  563. * An object to merge into the previous one.
  564. *
  565. * @return {T}
  566. * The merged object. If the first argument is true, the return is the
  567. * same as the second argument.
  568. */ /**
  569. * Utility function to deep merge two or more objects and return a third object.
  570. * The merge function can also be used with a single object argument to create a
  571. * deep copy of an object.
  572. *
  573. * @function Highcharts.merge<T>
  574. *
  575. * @param {T|undefined} a
  576. * The first object to extend. When only this is given, the function
  577. * returns a deep copy.
  578. *
  579. * @param {...Array<object|undefined>} [n]
  580. * An object to merge into the previous one.
  581. *
  582. * @return {T}
  583. * The merged object. If the first argument is true, the return is the
  584. * same as the second argument.
  585. */
  586. function merge() {
  587. /* eslint-enable valid-jsdoc */
  588. var i,
  589. args = arguments,
  590. ret = {};
  591. var doCopy = function (copy,
  592. original) {
  593. // An object is replacing a primitive
  594. if (typeof copy !== 'object') {
  595. copy = {};
  596. }
  597. objectEach(original, function (value, key) {
  598. // Prototype pollution (#14883)
  599. if (key === '__proto__' || key === 'constructor') {
  600. return;
  601. }
  602. // Copy the contents of objects, but not arrays or DOM nodes
  603. if (isObject(value, true) &&
  604. !isClass(value) &&
  605. !isDOMElement(value)) {
  606. copy[key] = doCopy(copy[key] || {}, value);
  607. // Primitives and arrays are copied over directly
  608. }
  609. else {
  610. copy[key] = original[key];
  611. }
  612. });
  613. return copy;
  614. };
  615. // If first argument is true, copy into the existing object. Used in
  616. // setOptions.
  617. if (args[0] === true) {
  618. ret = args[1];
  619. args = Array.prototype.slice.call(args, 2);
  620. }
  621. // For each argument, extend the return
  622. var len = args.length;
  623. for (i = 0; i < len; i++) {
  624. ret = doCopy(ret, args[i]);
  625. }
  626. return ret;
  627. }
  628. /**
  629. * Constrain a value to within a lower and upper threshold.
  630. *
  631. * @private
  632. * @param {number} value The initial value
  633. * @param {number} min The lower threshold
  634. * @param {number} max The upper threshold
  635. * @return {number} Returns a number value within min and max.
  636. */
  637. function clamp(value, min, max) {
  638. return value > min ? value < max ? value : max : min;
  639. }
  640. // eslint-disable-next-line valid-jsdoc
  641. /**
  642. * Remove settings that have not changed, to avoid unnecessary rendering or
  643. * computing (#9197).
  644. * @private
  645. */
  646. function cleanRecursively(newer, older) {
  647. var result = {};
  648. objectEach(newer, function (_val, key) {
  649. var ob;
  650. // Dive into objects (except DOM nodes)
  651. if (isObject(newer[key], true) &&
  652. !newer.nodeType && // #10044
  653. older[key]) {
  654. ob = cleanRecursively(newer[key], older[key]);
  655. if (Object.keys(ob).length) {
  656. result[key] = ob;
  657. }
  658. // Arrays, primitives and DOM nodes are copied directly
  659. }
  660. else if (isObject(newer[key]) ||
  661. newer[key] !== older[key]) {
  662. result[key] = newer[key];
  663. }
  664. });
  665. return result;
  666. }
  667. /**
  668. * Shortcut for parseInt
  669. *
  670. * @private
  671. * @function Highcharts.pInt
  672. *
  673. * @param {*} s
  674. * any
  675. *
  676. * @param {number} [mag]
  677. * Magnitude
  678. *
  679. * @return {number}
  680. * number
  681. */
  682. function pInt(s, mag) {
  683. return parseInt(s, mag || 10);
  684. }
  685. /**
  686. * Utility function to check for string type.
  687. *
  688. * @function Highcharts.isString
  689. *
  690. * @param {*} s
  691. * The item to check.
  692. *
  693. * @return {boolean}
  694. * True if the argument is a string.
  695. */
  696. function isString(s) {
  697. return typeof s === 'string';
  698. }
  699. /**
  700. * Utility function to check if an item is an array.
  701. *
  702. * @function Highcharts.isArray
  703. *
  704. * @param {*} obj
  705. * The item to check.
  706. *
  707. * @return {boolean}
  708. * True if the argument is an array.
  709. */
  710. function isArray(obj) {
  711. var str = Object.prototype.toString.call(obj);
  712. return str === '[object Array]' || str === '[object Array Iterator]';
  713. }
  714. /**
  715. * Utility function to check if an item is of type object.
  716. *
  717. * @function Highcharts.isObject
  718. *
  719. * @param {*} obj
  720. * The item to check.
  721. *
  722. * @param {boolean} [strict=false]
  723. * Also checks that the object is not an array.
  724. *
  725. * @return {boolean}
  726. * True if the argument is an object.
  727. */
  728. function isObject(obj, strict) {
  729. return (!!obj &&
  730. typeof obj === 'object' &&
  731. (!strict || !isArray(obj))); // eslint-disable-line @typescript-eslint/no-explicit-any
  732. }
  733. /**
  734. * Utility function to check if an Object is a HTML Element.
  735. *
  736. * @function Highcharts.isDOMElement
  737. *
  738. * @param {*} obj
  739. * The item to check.
  740. *
  741. * @return {boolean}
  742. * True if the argument is a HTML Element.
  743. */
  744. function isDOMElement(obj) {
  745. return isObject(obj) && typeof obj.nodeType === 'number';
  746. }
  747. /**
  748. * Utility function to check if an Object is a class.
  749. *
  750. * @function Highcharts.isClass
  751. *
  752. * @param {object|undefined} obj
  753. * The item to check.
  754. *
  755. * @return {boolean}
  756. * True if the argument is a class.
  757. */
  758. function isClass(obj) {
  759. var c = obj && obj.constructor;
  760. return !!(isObject(obj, true) &&
  761. !isDOMElement(obj) &&
  762. (c && c.name && c.name !== 'Object'));
  763. }
  764. /**
  765. * Utility function to check if an item is a number and it is finite (not NaN,
  766. * Infinity or -Infinity).
  767. *
  768. * @function Highcharts.isNumber
  769. *
  770. * @param {*} n
  771. * The item to check.
  772. *
  773. * @return {boolean}
  774. * True if the item is a finite number
  775. */
  776. function isNumber(n) {
  777. return typeof n === 'number' && !isNaN(n) && n < Infinity && n > -Infinity;
  778. }
  779. /**
  780. * Remove the last occurence of an item from an array.
  781. *
  782. * @function Highcharts.erase
  783. *
  784. * @param {Array<*>} arr
  785. * The array.
  786. *
  787. * @param {*} item
  788. * The item to remove.
  789. *
  790. * @return {void}
  791. */
  792. function erase(arr, item) {
  793. var i = arr.length;
  794. while (i--) {
  795. if (arr[i] === item) {
  796. arr.splice(i, 1);
  797. break;
  798. }
  799. }
  800. }
  801. /**
  802. * Check if an object is null or undefined.
  803. *
  804. * @function Highcharts.defined
  805. *
  806. * @param {*} obj
  807. * The object to check.
  808. *
  809. * @return {boolean}
  810. * False if the object is null or undefined, otherwise true.
  811. */
  812. function defined(obj) {
  813. return typeof obj !== 'undefined' && obj !== null;
  814. }
  815. /**
  816. * Set or get an attribute or an object of attributes. To use as a setter, pass
  817. * a key and a value, or let the second argument be a collection of keys and
  818. * values. To use as a getter, pass only a string as the second argument.
  819. *
  820. * @function Highcharts.attr
  821. *
  822. * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} elem
  823. * The DOM element to receive the attribute(s).
  824. *
  825. * @param {string|Highcharts.HTMLAttributes|Highcharts.SVGAttributes} [prop]
  826. * The property or an object of key-value pairs.
  827. *
  828. * @param {number|string} [value]
  829. * The value if a single property is set.
  830. *
  831. * @return {string|null|undefined}
  832. * When used as a getter, return the value.
  833. */
  834. function attr(elem, prop, value) {
  835. var ret;
  836. // if the prop is a string
  837. if (isString(prop)) {
  838. // set the value
  839. if (defined(value)) {
  840. elem.setAttribute(prop, value);
  841. // get the value
  842. }
  843. else if (elem && elem.getAttribute) {
  844. ret = elem.getAttribute(prop);
  845. // IE7 and below cannot get class through getAttribute (#7850)
  846. if (!ret && prop === 'class') {
  847. ret = elem.getAttribute(prop + 'Name');
  848. }
  849. }
  850. // else if prop is defined, it is a hash of key/value pairs
  851. }
  852. else {
  853. objectEach(prop, function (val, key) {
  854. elem.setAttribute(key, val);
  855. });
  856. }
  857. return ret;
  858. }
  859. /**
  860. * Check if an element is an array, and if not, make it into an array.
  861. *
  862. * @function Highcharts.splat
  863. *
  864. * @param {*} obj
  865. * The object to splat.
  866. *
  867. * @return {Array}
  868. * The produced or original array.
  869. */
  870. function splat(obj) {
  871. return isArray(obj) ? obj : [obj];
  872. }
  873. /**
  874. * Set a timeout if the delay is given, otherwise perform the function
  875. * synchronously.
  876. *
  877. * @function Highcharts.syncTimeout
  878. *
  879. * @param {Function} fn
  880. * The function callback.
  881. *
  882. * @param {number} delay
  883. * Delay in milliseconds.
  884. *
  885. * @param {*} [context]
  886. * An optional context to send to the function callback.
  887. *
  888. * @return {number}
  889. * An identifier for the timeout that can later be cleared with
  890. * Highcharts.clearTimeout. Returns -1 if there is no timeout.
  891. */
  892. function syncTimeout(fn, delay, context) {
  893. if (delay > 0) {
  894. return setTimeout(fn, delay, context);
  895. }
  896. fn.call(0, context);
  897. return -1;
  898. }
  899. /**
  900. * Internal clear timeout. The function checks that the `id` was not removed
  901. * (e.g. by `chart.destroy()`). For the details see
  902. * [issue #7901](https://github.com/highcharts/highcharts/issues/7901).
  903. *
  904. * @function Highcharts.clearTimeout
  905. *
  906. * @param {number} id
  907. * Id of a timeout.
  908. *
  909. * @return {void}
  910. */
  911. function internalClearTimeout(id) {
  912. if (defined(id)) {
  913. clearTimeout(id);
  914. }
  915. }
  916. /* eslint-disable valid-jsdoc */
  917. /**
  918. * Utility function to extend an object with the members of another.
  919. *
  920. * @function Highcharts.extend<T>
  921. *
  922. * @param {T|undefined} a
  923. * The object to be extended.
  924. *
  925. * @param {Partial<T>} b
  926. * The object to add to the first one.
  927. *
  928. * @return {T}
  929. * Object a, the original object.
  930. */
  931. function extend(a, b) {
  932. /* eslint-enable valid-jsdoc */
  933. var n;
  934. if (!a) {
  935. a = {};
  936. }
  937. for (n in b) { // eslint-disable-line guard-for-in
  938. a[n] = b[n];
  939. }
  940. return a;
  941. }
  942. /* eslint-disable valid-jsdoc */
  943. /**
  944. * Return the first value that is not null or undefined.
  945. *
  946. * @function Highcharts.pick<T>
  947. *
  948. * @param {...Array<T|null|undefined>} items
  949. * Variable number of arguments to inspect.
  950. *
  951. * @return {T}
  952. * The value of the first argument that is not null or undefined.
  953. */
  954. function pick() {
  955. var args = arguments;
  956. var length = args.length;
  957. for (var i = 0; i < length; i++) {
  958. var arg = args[i];
  959. if (typeof arg !== 'undefined' && arg !== null) {
  960. return arg;
  961. }
  962. }
  963. }
  964. /**
  965. * Set CSS on a given element.
  966. *
  967. * @function Highcharts.css
  968. *
  969. * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} el
  970. * An HTML DOM element.
  971. *
  972. * @param {Highcharts.CSSObject} styles
  973. * Style object with camel case property names.
  974. *
  975. * @return {void}
  976. */
  977. function css(el, styles) {
  978. if (H.isMS && !H.svg) { // #2686
  979. if (styles && typeof styles.opacity !== 'undefined') {
  980. styles.filter =
  981. 'alpha(opacity=' + (styles.opacity * 100) + ')';
  982. }
  983. }
  984. extend(el.style, styles);
  985. }
  986. /**
  987. * Utility function to create an HTML element with attributes and styles.
  988. *
  989. * @function Highcharts.createElement
  990. *
  991. * @param {string} tag
  992. * The HTML tag.
  993. *
  994. * @param {Highcharts.HTMLAttributes} [attribs]
  995. * Attributes as an object of key-value pairs.
  996. *
  997. * @param {Highcharts.CSSObject} [styles]
  998. * Styles as an object of key-value pairs.
  999. *
  1000. * @param {Highcharts.HTMLDOMElement} [parent]
  1001. * The parent HTML object.
  1002. *
  1003. * @param {boolean} [nopad=false]
  1004. * If true, remove all padding, border and margin.
  1005. *
  1006. * @return {Highcharts.HTMLDOMElement}
  1007. * The created DOM element.
  1008. */
  1009. function createElement(tag, attribs, styles, parent, nopad) {
  1010. var el = doc.createElement(tag);
  1011. if (attribs) {
  1012. extend(el, attribs);
  1013. }
  1014. if (nopad) {
  1015. css(el, { padding: '0', border: 'none', margin: '0' });
  1016. }
  1017. if (styles) {
  1018. css(el, styles);
  1019. }
  1020. if (parent) {
  1021. parent.appendChild(el);
  1022. }
  1023. return el;
  1024. }
  1025. // eslint-disable-next-line valid-jsdoc
  1026. /**
  1027. * Extend a prototyped class by new members.
  1028. *
  1029. * @function Highcharts.extendClass<T>
  1030. *
  1031. * @param {Highcharts.Class<T>} parent
  1032. * The parent prototype to inherit.
  1033. *
  1034. * @param {Highcharts.Dictionary<*>} members
  1035. * A collection of prototype members to add or override compared to the
  1036. * parent prototype.
  1037. *
  1038. * @return {Highcharts.Class<T>}
  1039. * A new prototype.
  1040. */
  1041. function extendClass(parent, members) {
  1042. var obj = (function () { });
  1043. obj.prototype = new parent(); // eslint-disable-line new-cap
  1044. extend(obj.prototype, members);
  1045. return obj;
  1046. }
  1047. /**
  1048. * Left-pad a string to a given length by adding a character repetetively.
  1049. *
  1050. * @function Highcharts.pad
  1051. *
  1052. * @param {number} number
  1053. * The input string or number.
  1054. *
  1055. * @param {number} [length]
  1056. * The desired string length.
  1057. *
  1058. * @param {string} [padder=0]
  1059. * The character to pad with.
  1060. *
  1061. * @return {string}
  1062. * The padded string.
  1063. */
  1064. function pad(number, length, padder) {
  1065. return new Array((length || 2) +
  1066. 1 -
  1067. String(number)
  1068. .replace('-', '')
  1069. .length).join(padder || '0') + number;
  1070. }
  1071. /**
  1072. * Return a length based on either the integer value, or a percentage of a base.
  1073. *
  1074. * @function Highcharts.relativeLength
  1075. *
  1076. * @param {Highcharts.RelativeSize} value
  1077. * A percentage string or a number.
  1078. *
  1079. * @param {number} base
  1080. * The full length that represents 100%.
  1081. *
  1082. * @param {number} [offset=0]
  1083. * A pixel offset to apply for percentage values. Used internally in
  1084. * axis positioning.
  1085. *
  1086. * @return {number}
  1087. * The computed length.
  1088. */
  1089. function relativeLength(value, base, offset) {
  1090. return (/%$/).test(value) ?
  1091. (base * parseFloat(value) / 100) + (offset || 0) :
  1092. parseFloat(value);
  1093. }
  1094. /**
  1095. * Wrap a method with extended functionality, preserving the original function.
  1096. *
  1097. * @function Highcharts.wrap
  1098. *
  1099. * @param {*} obj
  1100. * The context object that the method belongs to. In real cases, this is
  1101. * often a prototype.
  1102. *
  1103. * @param {string} method
  1104. * The name of the method to extend.
  1105. *
  1106. * @param {Highcharts.WrapProceedFunction} func
  1107. * A wrapper function callback. This function is called with the same
  1108. * arguments as the original function, except that the original function
  1109. * is unshifted and passed as the first argument.
  1110. */
  1111. function wrap(obj, method, func) {
  1112. var proceed = obj[method];
  1113. obj[method] = function () {
  1114. var args = Array.prototype.slice.call(arguments),
  1115. outerArgs = arguments,
  1116. ctx = this;
  1117. ctx.proceed = function () {
  1118. proceed.apply(ctx, arguments.length ? arguments : outerArgs);
  1119. };
  1120. args.unshift(proceed);
  1121. var ret = func.apply(this,
  1122. args);
  1123. ctx.proceed = null;
  1124. return ret;
  1125. };
  1126. }
  1127. /**
  1128. * Get the magnitude of a number.
  1129. *
  1130. * @function Highcharts.getMagnitude
  1131. *
  1132. * @param {number} num
  1133. * The number.
  1134. *
  1135. * @return {number}
  1136. * The magnitude, where 1-9 are magnitude 1, 10-99 magnitude 2 etc.
  1137. */
  1138. function getMagnitude(num) {
  1139. return Math.pow(10, Math.floor(Math.log(num) / Math.LN10));
  1140. }
  1141. /**
  1142. * Take an interval and normalize it to multiples of round numbers.
  1143. *
  1144. * @deprecated
  1145. * @function Highcharts.normalizeTickInterval
  1146. *
  1147. * @param {number} interval
  1148. * The raw, un-rounded interval.
  1149. *
  1150. * @param {Array<*>} [multiples]
  1151. * Allowed multiples.
  1152. *
  1153. * @param {number} [magnitude]
  1154. * The magnitude of the number.
  1155. *
  1156. * @param {boolean} [allowDecimals]
  1157. * Whether to allow decimals.
  1158. *
  1159. * @param {boolean} [hasTickAmount]
  1160. * If it has tickAmount, avoid landing on tick intervals lower than
  1161. * original.
  1162. *
  1163. * @return {number}
  1164. * The normalized interval.
  1165. *
  1166. * @todo
  1167. * Move this function to the Axis prototype. It is here only for historical
  1168. * reasons.
  1169. */
  1170. function normalizeTickInterval(interval, multiples, magnitude, allowDecimals, hasTickAmount) {
  1171. var i,
  1172. retInterval = interval;
  1173. // round to a tenfold of 1, 2, 2.5 or 5
  1174. magnitude = pick(magnitude, 1);
  1175. var normalized = interval / magnitude;
  1176. // multiples for a linear scale
  1177. if (!multiples) {
  1178. multiples = hasTickAmount ?
  1179. // Finer grained ticks when the tick amount is hard set, including
  1180. // when alignTicks is true on multiple axes (#4580).
  1181. [1, 1.2, 1.5, 2, 2.5, 3, 4, 5, 6, 8, 10] :
  1182. // Else, let ticks fall on rounder numbers
  1183. [1, 2, 2.5, 5, 10];
  1184. // the allowDecimals option
  1185. if (allowDecimals === false) {
  1186. if (magnitude === 1) {
  1187. multiples = multiples.filter(function (num) {
  1188. return num % 1 === 0;
  1189. });
  1190. }
  1191. else if (magnitude <= 0.1) {
  1192. multiples = [1 / magnitude];
  1193. }
  1194. }
  1195. }
  1196. // normalize the interval to the nearest multiple
  1197. for (i = 0; i < multiples.length; i++) {
  1198. retInterval = multiples[i];
  1199. // only allow tick amounts smaller than natural
  1200. if ((hasTickAmount &&
  1201. retInterval * magnitude >= interval) ||
  1202. (!hasTickAmount &&
  1203. (normalized <=
  1204. (multiples[i] +
  1205. (multiples[i + 1] || multiples[i])) / 2))) {
  1206. break;
  1207. }
  1208. }
  1209. // Multiply back to the correct magnitude. Correct floats to appropriate
  1210. // precision (#6085).
  1211. retInterval = correctFloat(retInterval * magnitude, -Math.round(Math.log(0.001) / Math.LN10));
  1212. return retInterval;
  1213. }
  1214. /**
  1215. * Sort an object array and keep the order of equal items. The ECMAScript
  1216. * standard does not specify the behaviour when items are equal.
  1217. *
  1218. * @function Highcharts.stableSort
  1219. *
  1220. * @param {Array<*>} arr
  1221. * The array to sort.
  1222. *
  1223. * @param {Function} sortFunction
  1224. * The function to sort it with, like with regular Array.prototype.sort.
  1225. *
  1226. * @return {void}
  1227. */
  1228. function stableSort(arr, sortFunction) {
  1229. // @todo It seems like Chrome since v70 sorts in a stable way internally,
  1230. // plus all other browsers do it, so over time we may be able to remove this
  1231. // function
  1232. var length = arr.length;
  1233. var sortValue,
  1234. i;
  1235. // Add index to each item
  1236. for (i = 0; i < length; i++) {
  1237. arr[i].safeI = i; // stable sort index
  1238. }
  1239. arr.sort(function (a, b) {
  1240. sortValue = sortFunction(a, b);
  1241. return sortValue === 0 ? a.safeI - b.safeI : sortValue;
  1242. });
  1243. // Remove index from items
  1244. for (i = 0; i < length; i++) {
  1245. delete arr[i].safeI; // stable sort index
  1246. }
  1247. }
  1248. /**
  1249. * Non-recursive method to find the lowest member of an array. `Math.min` raises
  1250. * a maximum call stack size exceeded error in Chrome when trying to apply more
  1251. * than 150.000 points. This method is slightly slower, but safe.
  1252. *
  1253. * @function Highcharts.arrayMin
  1254. *
  1255. * @param {Array<*>} data
  1256. * An array of numbers.
  1257. *
  1258. * @return {number}
  1259. * The lowest number.
  1260. */
  1261. function arrayMin(data) {
  1262. var i = data.length,
  1263. min = data[0];
  1264. while (i--) {
  1265. if (data[i] < min) {
  1266. min = data[i];
  1267. }
  1268. }
  1269. return min;
  1270. }
  1271. /**
  1272. * Non-recursive method to find the lowest member of an array. `Math.max` raises
  1273. * a maximum call stack size exceeded error in Chrome when trying to apply more
  1274. * than 150.000 points. This method is slightly slower, but safe.
  1275. *
  1276. * @function Highcharts.arrayMax
  1277. *
  1278. * @param {Array<*>} data
  1279. * An array of numbers.
  1280. *
  1281. * @return {number}
  1282. * The highest number.
  1283. */
  1284. function arrayMax(data) {
  1285. var i = data.length,
  1286. max = data[0];
  1287. while (i--) {
  1288. if (data[i] > max) {
  1289. max = data[i];
  1290. }
  1291. }
  1292. return max;
  1293. }
  1294. /**
  1295. * Utility method that destroys any SVGElement instances that are properties on
  1296. * the given object. It loops all properties and invokes destroy if there is a
  1297. * destroy method. The property is then delete.
  1298. *
  1299. * @function Highcharts.destroyObjectProperties
  1300. *
  1301. * @param {*} obj
  1302. * The object to destroy properties on.
  1303. *
  1304. * @param {*} [except]
  1305. * Exception, do not destroy this property, only delete it.
  1306. */
  1307. function destroyObjectProperties(obj, except) {
  1308. objectEach(obj, function (val, n) {
  1309. // If the object is non-null and destroy is defined
  1310. if (val && val !== except && val.destroy) {
  1311. // Invoke the destroy
  1312. val.destroy();
  1313. }
  1314. // Delete the property from the object.
  1315. delete obj[n];
  1316. });
  1317. }
  1318. /**
  1319. * Discard a HTML element by moving it to the bin and delete.
  1320. *
  1321. * @function Highcharts.discardElement
  1322. *
  1323. * @param {Highcharts.HTMLDOMElement} element
  1324. * The HTML node to discard.
  1325. */
  1326. function discardElement(element) {
  1327. // create a garbage bin element, not part of the DOM
  1328. if (!garbageBin) {
  1329. garbageBin = createElement('div');
  1330. }
  1331. // move the node and empty bin
  1332. if (element) {
  1333. garbageBin.appendChild(element);
  1334. }
  1335. garbageBin.innerHTML = '';
  1336. }
  1337. var garbageBin;
  1338. /**
  1339. * Fix JS round off float errors.
  1340. *
  1341. * @function Highcharts.correctFloat
  1342. *
  1343. * @param {number} num
  1344. * A float number to fix.
  1345. *
  1346. * @param {number} [prec=14]
  1347. * The precision.
  1348. *
  1349. * @return {number}
  1350. * The corrected float number.
  1351. */
  1352. function correctFloat(num, prec) {
  1353. return parseFloat(num.toPrecision(prec || 14));
  1354. }
  1355. /**
  1356. * The time unit lookup
  1357. *
  1358. * @ignore
  1359. */
  1360. var timeUnits = {
  1361. millisecond: 1,
  1362. second: 1000,
  1363. minute: 60000,
  1364. hour: 3600000,
  1365. day: 24 * 3600000,
  1366. week: 7 * 24 * 3600000,
  1367. month: 28 * 24 * 3600000,
  1368. year: 364 * 24 * 3600000
  1369. };
  1370. /**
  1371. * Easing definition
  1372. *
  1373. * @private
  1374. * @function Math.easeInOutSine
  1375. *
  1376. * @param {number} pos
  1377. * Current position, ranging from 0 to 1.
  1378. *
  1379. * @return {number}
  1380. * Ease result
  1381. */
  1382. Math.easeInOutSine = function (pos) {
  1383. return -0.5 * (Math.cos(Math.PI * pos) - 1);
  1384. };
  1385. /**
  1386. * Returns the value of a property path on a given object.
  1387. *
  1388. * @private
  1389. * @function getNestedProperty
  1390. *
  1391. * @param {string} path
  1392. * Path to the property, for example `custom.myValue`.
  1393. *
  1394. * @param {unknown} obj
  1395. * Instance containing the property on the specific path.
  1396. *
  1397. * @return {unknown}
  1398. * The unknown property value.
  1399. */
  1400. function getNestedProperty(path, parent) {
  1401. var pathElements = path.split('.');
  1402. while (pathElements.length && defined(parent)) {
  1403. var pathElement = pathElements.shift();
  1404. // Filter on the key
  1405. if (typeof pathElement === 'undefined' ||
  1406. pathElement === '__proto__') {
  1407. return; // undefined
  1408. }
  1409. var child = parent[pathElement];
  1410. // Filter on the child
  1411. if (!defined(child) ||
  1412. typeof child === 'function' ||
  1413. typeof child.nodeType === 'number' ||
  1414. child === win) {
  1415. return; // undefined
  1416. }
  1417. // Else, proceed
  1418. parent = child;
  1419. }
  1420. return parent;
  1421. }
  1422. /**
  1423. * Get the computed CSS value for given element and property, only for numerical
  1424. * properties. For width and height, the dimension of the inner box (excluding
  1425. * padding) is returned. Used for fitting the chart within the container.
  1426. *
  1427. * @function Highcharts.getStyle
  1428. *
  1429. * @param {Highcharts.HTMLDOMElement} el
  1430. * An HTML element.
  1431. *
  1432. * @param {string} prop
  1433. * The property name.
  1434. *
  1435. * @param {boolean} [toInt=true]
  1436. * Parse to integer.
  1437. *
  1438. * @return {number|string|undefined}
  1439. * The style value.
  1440. */
  1441. function getStyle(el, prop, toInt) {
  1442. var customGetStyle = (H.getStyle || // oldie getStyle
  1443. getStyle);
  1444. var style;
  1445. // For width and height, return the actual inner pixel size (#4913)
  1446. if (prop === 'width') {
  1447. var offsetWidth = Math.min(el.offsetWidth,
  1448. el.scrollWidth);
  1449. // In flex boxes, we need to use getBoundingClientRect and floor it,
  1450. // because scrollWidth doesn't support subpixel precision (#6427) ...
  1451. var boundingClientRectWidth = el.getBoundingClientRect &&
  1452. el.getBoundingClientRect().width;
  1453. // ...unless if the containing div or its parents are transform-scaled
  1454. // down, in which case the boundingClientRect can't be used as it is
  1455. // also scaled down (#9871, #10498).
  1456. if (boundingClientRectWidth < offsetWidth &&
  1457. boundingClientRectWidth >= offsetWidth - 1) {
  1458. offsetWidth = Math.floor(boundingClientRectWidth);
  1459. }
  1460. return Math.max(0, // #8377
  1461. (offsetWidth -
  1462. (customGetStyle(el, 'padding-left', true) || 0) -
  1463. (customGetStyle(el, 'padding-right', true) || 0)));
  1464. }
  1465. if (prop === 'height') {
  1466. return Math.max(0, // #8377
  1467. (Math.min(el.offsetHeight, el.scrollHeight) -
  1468. (customGetStyle(el, 'padding-top', true) || 0) -
  1469. (customGetStyle(el, 'padding-bottom', true) || 0)));
  1470. }
  1471. if (!win.getComputedStyle) {
  1472. // SVG not supported, forgot to load oldie.js?
  1473. error(27, true);
  1474. }
  1475. // Otherwise, get the computed style
  1476. var css = win.getComputedStyle(el,
  1477. undefined); // eslint-disable-line no-undefined
  1478. if (css) {
  1479. style = css.getPropertyValue(prop);
  1480. if (pick(toInt, prop !== 'opacity')) {
  1481. style = pInt(style);
  1482. }
  1483. }
  1484. return style;
  1485. }
  1486. /**
  1487. * Search for an item in an array.
  1488. *
  1489. * @function Highcharts.inArray
  1490. *
  1491. * @deprecated
  1492. *
  1493. * @param {*} item
  1494. * The item to search for.
  1495. *
  1496. * @param {Array<*>} arr
  1497. * The array or node collection to search in.
  1498. *
  1499. * @param {number} [fromIndex=0]
  1500. * The index to start searching from.
  1501. *
  1502. * @return {number}
  1503. * The index within the array, or -1 if not found.
  1504. */
  1505. function inArray(item, arr, fromIndex) {
  1506. error(32, false, void 0, { 'Highcharts.inArray': 'use Array.indexOf' });
  1507. return arr.indexOf(item, fromIndex);
  1508. }
  1509. /**
  1510. * Return the value of the first element in the array that satisfies the
  1511. * provided testing function.
  1512. *
  1513. * @function Highcharts.find<T>
  1514. *
  1515. * @param {Array<T>} arr
  1516. * The array to test.
  1517. *
  1518. * @param {Function} callback
  1519. * The callback function. The function receives the item as the first
  1520. * argument. Return `true` if this item satisfies the condition.
  1521. *
  1522. * @return {T|undefined}
  1523. * The value of the element.
  1524. */
  1525. var find = Array.prototype.find ?
  1526. function (arr,
  1527. callback) {
  1528. return arr.find(callback);
  1529. } :
  1530. // Legacy implementation. PhantomJS, IE <= 11 etc. #7223.
  1531. function (arr, callback) {
  1532. var i;
  1533. var length = arr.length;
  1534. for (i = 0; i < length; i++) {
  1535. if (callback(arr[i], i)) { // eslint-disable-line callback-return
  1536. return arr[i];
  1537. }
  1538. }
  1539. };
  1540. /**
  1541. * Returns an array of a given object's own properties.
  1542. *
  1543. * @function Highcharts.keys
  1544. * @deprecated
  1545. *
  1546. * @param {*} obj
  1547. * The object of which the properties are to be returned.
  1548. *
  1549. * @return {Array<string>}
  1550. * An array of strings that represents all the properties.
  1551. */
  1552. function keys(obj) {
  1553. error(32, false, void 0, { 'Highcharts.keys': 'use Object.keys' });
  1554. return Object.keys(obj);
  1555. }
  1556. /**
  1557. * Get the element's offset position, corrected for `overflow: auto`.
  1558. *
  1559. * @function Highcharts.offset
  1560. *
  1561. * @param {global.Element} el
  1562. * The DOM element.
  1563. *
  1564. * @return {Highcharts.OffsetObject}
  1565. * An object containing `left` and `top` properties for the position in
  1566. * the page.
  1567. */
  1568. function offset(el) {
  1569. var docElem = doc.documentElement,
  1570. box = (el.parentElement || el.parentNode) ?
  1571. el.getBoundingClientRect() :
  1572. { top: 0,
  1573. left: 0,
  1574. width: 0,
  1575. height: 0 };
  1576. return {
  1577. top: box.top + (win.pageYOffset || docElem.scrollTop) -
  1578. (docElem.clientTop || 0),
  1579. left: box.left + (win.pageXOffset || docElem.scrollLeft) -
  1580. (docElem.clientLeft || 0),
  1581. width: box.width,
  1582. height: box.height
  1583. };
  1584. }
  1585. /* eslint-disable valid-jsdoc */
  1586. /**
  1587. * Iterate over object key pairs in an object.
  1588. *
  1589. * @function Highcharts.objectEach<T>
  1590. *
  1591. * @param {*} obj
  1592. * The object to iterate over.
  1593. *
  1594. * @param {Highcharts.ObjectEachCallbackFunction<T>} fn
  1595. * The iterator callback. It passes three arguments:
  1596. * * value - The property value.
  1597. * * key - The property key.
  1598. * * obj - The object that objectEach is being applied to.
  1599. *
  1600. * @param {T} [ctx]
  1601. * The context.
  1602. *
  1603. * @return {void}
  1604. */
  1605. function objectEach(obj, fn, ctx) {
  1606. /* eslint-enable valid-jsdoc */
  1607. for (var key in obj) {
  1608. if (Object.hasOwnProperty.call(obj, key)) {
  1609. fn.call(ctx || obj[key], obj[key], key, obj);
  1610. }
  1611. }
  1612. }
  1613. /**
  1614. * Iterate over an array.
  1615. *
  1616. * @deprecated
  1617. * @function Highcharts.each
  1618. *
  1619. * @param {Array<*>} arr
  1620. * The array to iterate over.
  1621. *
  1622. * @param {Function} fn
  1623. * The iterator callback. It passes three arguments:
  1624. * - `item`: The array item.
  1625. * - `index`: The item's index in the array.
  1626. * - `arr`: The array that each is being applied to.
  1627. *
  1628. * @param {*} [ctx]
  1629. * The context.
  1630. *
  1631. * @return {void}
  1632. */
  1633. /**
  1634. * Filter an array by a callback.
  1635. *
  1636. * @deprecated
  1637. * @function Highcharts.grep
  1638. *
  1639. * @param {Array<*>} arr
  1640. * The array to filter.
  1641. *
  1642. * @param {Function} callback
  1643. * The callback function. The function receives the item as the first
  1644. * argument. Return `true` if the item is to be preserved.
  1645. *
  1646. * @return {Array<*>}
  1647. * A new, filtered array.
  1648. */
  1649. /**
  1650. * Map an array by a callback.
  1651. *
  1652. * @deprecated
  1653. * @function Highcharts.map
  1654. *
  1655. * @param {Array<*>} arr
  1656. * The array to map.
  1657. *
  1658. * @param {Function} fn
  1659. * The callback function. Return the new value for the new array.
  1660. *
  1661. * @return {Array<*>}
  1662. * A new array item with modified items.
  1663. */
  1664. /**
  1665. * Reduce an array to a single value.
  1666. *
  1667. * @deprecated
  1668. * @function Highcharts.reduce
  1669. *
  1670. * @param {Array<*>} arr
  1671. * The array to reduce.
  1672. *
  1673. * @param {Function} fn
  1674. * The callback function. Return the reduced value. Receives 4
  1675. * arguments: Accumulated/reduced value, current value, current array
  1676. * index, and the array.
  1677. *
  1678. * @param {*} initialValue
  1679. * The initial value of the accumulator.
  1680. *
  1681. * @return {*}
  1682. * The reduced value.
  1683. */
  1684. /**
  1685. * Test whether at least one element in the array passes the test implemented by
  1686. * the provided function.
  1687. *
  1688. * @deprecated
  1689. * @function Highcharts.some
  1690. *
  1691. * @param {Array<*>} arr
  1692. * The array to test
  1693. *
  1694. * @param {Function} fn
  1695. * The function to run on each item. Return truty to pass the test.
  1696. * Receives arguments `currentValue`, `index` and `array`.
  1697. *
  1698. * @param {*} ctx
  1699. * The context.
  1700. *
  1701. * @return {boolean}
  1702. */
  1703. objectEach({
  1704. map: 'map',
  1705. each: 'forEach',
  1706. grep: 'filter',
  1707. reduce: 'reduce',
  1708. some: 'some'
  1709. }, function (val, key) {
  1710. H[key] = function (arr) {
  1711. var _a;
  1712. error(32, false, void 0, (_a = {}, _a["Highcharts." + key] = "use Array." + val, _a));
  1713. return Array.prototype[val].apply(arr, [].slice.call(arguments, 1));
  1714. };
  1715. });
  1716. /* eslint-disable valid-jsdoc */
  1717. /**
  1718. * Add an event listener.
  1719. *
  1720. * @function Highcharts.addEvent<T>
  1721. *
  1722. * @param {Highcharts.Class<T>|T} el
  1723. * The element or object to add a listener to. It can be a
  1724. * {@link HTMLDOMElement}, an {@link SVGElement} or any other object.
  1725. *
  1726. * @param {string} type
  1727. * The event type.
  1728. *
  1729. * @param {Highcharts.EventCallbackFunction<T>|Function} fn
  1730. * The function callback to execute when the event is fired.
  1731. *
  1732. * @param {Highcharts.EventOptionsObject} [options]
  1733. * Options for adding the event.
  1734. *
  1735. * @return {Function}
  1736. * A callback function to remove the added event.
  1737. */
  1738. function addEvent(el, type, fn, options) {
  1739. /* eslint-enable valid-jsdoc */
  1740. if (options === void 0) { options = {}; }
  1741. // Add hcEvents to either the prototype (in case we're running addEvent on a
  1742. // class) or the instance. If hasOwnProperty('hcEvents') is false, it is
  1743. // inherited down the prototype chain, in which case we need to set the
  1744. // property on this instance (which may itself be a prototype).
  1745. var owner = typeof el === 'function' && el.prototype || el;
  1746. if (!Object.hasOwnProperty.call(owner, 'hcEvents')) {
  1747. owner.hcEvents = {};
  1748. }
  1749. var events = owner.hcEvents;
  1750. // Allow click events added to points, otherwise they will be prevented by
  1751. // the TouchPointer.pinch function after a pinch zoom operation (#7091).
  1752. if (H.Point && // without H a dependency loop occurs
  1753. el instanceof H.Point &&
  1754. el.series &&
  1755. el.series.chart) {
  1756. el.series.chart.runTrackerClick = true;
  1757. }
  1758. // Handle DOM events
  1759. // If the browser supports passive events, add it to improve performance
  1760. // on touch events (#11353).
  1761. var addEventListener = (el.addEventListener || H.addEventListenerPolyfill);
  1762. if (addEventListener) {
  1763. addEventListener.call(el, type, fn, H.supportsPassiveEvents ? {
  1764. passive: options.passive === void 0 ?
  1765. type.indexOf('touch') !== -1 : options.passive,
  1766. capture: false
  1767. } : false);
  1768. }
  1769. if (!events[type]) {
  1770. events[type] = [];
  1771. }
  1772. var eventObject = {
  1773. fn: fn,
  1774. order: typeof options.order === 'number' ? options.order : Infinity
  1775. };
  1776. events[type].push(eventObject);
  1777. // Order the calls
  1778. events[type].sort(function (a, b) { return a.order - b.order; });
  1779. // Return a function that can be called to remove this event.
  1780. return function () {
  1781. removeEvent(el, type, fn);
  1782. };
  1783. }
  1784. /* eslint-disable valid-jsdoc */
  1785. /**
  1786. * Remove an event that was added with {@link Highcharts#addEvent}.
  1787. *
  1788. * @function Highcharts.removeEvent<T>
  1789. *
  1790. * @param {Highcharts.Class<T>|T} el
  1791. * The element to remove events on.
  1792. *
  1793. * @param {string} [type]
  1794. * The type of events to remove. If undefined, all events are removed
  1795. * from the element.
  1796. *
  1797. * @param {Highcharts.EventCallbackFunction<T>} [fn]
  1798. * The specific callback to remove. If undefined, all events that match
  1799. * the element and optionally the type are removed.
  1800. *
  1801. * @return {void}
  1802. */
  1803. function removeEvent(el, type, fn) {
  1804. /* eslint-enable valid-jsdoc */
  1805. /**
  1806. * @private
  1807. * @param {string} type - event type
  1808. * @param {Highcharts.EventCallbackFunction<T>} fn - callback
  1809. * @return {void}
  1810. */
  1811. function removeOneEvent(type, fn) {
  1812. var removeEventListener = (el.removeEventListener || H.removeEventListenerPolyfill);
  1813. if (removeEventListener) {
  1814. removeEventListener.call(el, type, fn, false);
  1815. }
  1816. }
  1817. /**
  1818. * @private
  1819. * @param {any} eventCollection - collection
  1820. * @return {void}
  1821. */
  1822. function removeAllEvents(eventCollection) {
  1823. var types,
  1824. len;
  1825. if (!el.nodeName) {
  1826. return; // break on non-DOM events
  1827. }
  1828. if (type) {
  1829. types = {};
  1830. types[type] = true;
  1831. }
  1832. else {
  1833. types = eventCollection;
  1834. }
  1835. objectEach(types, function (_val, n) {
  1836. if (eventCollection[n]) {
  1837. len = eventCollection[n].length;
  1838. while (len--) {
  1839. removeOneEvent(n, eventCollection[n][len].fn);
  1840. }
  1841. }
  1842. });
  1843. }
  1844. var owner = typeof el === 'function' && el.prototype || el;
  1845. if (Object.hasOwnProperty.call(owner, 'hcEvents')) {
  1846. var events = owner.hcEvents;
  1847. if (type) {
  1848. var typeEvents = (events[type] || []);
  1849. if (fn) {
  1850. events[type] = typeEvents.filter(function (obj) {
  1851. return fn !== obj.fn;
  1852. });
  1853. removeOneEvent(type, fn);
  1854. }
  1855. else {
  1856. removeAllEvents(events);
  1857. events[type] = [];
  1858. }
  1859. }
  1860. else {
  1861. removeAllEvents(events);
  1862. delete owner.hcEvents;
  1863. }
  1864. }
  1865. }
  1866. /* eslint-disable valid-jsdoc */
  1867. /**
  1868. * Fire an event that was registered with {@link Highcharts#addEvent}.
  1869. *
  1870. * @function Highcharts.fireEvent<T>
  1871. *
  1872. * @param {T} el
  1873. * The object to fire the event on. It can be a {@link HTMLDOMElement},
  1874. * an {@link SVGElement} or any other object.
  1875. *
  1876. * @param {string} type
  1877. * The type of event.
  1878. *
  1879. * @param {Highcharts.Dictionary<*>|Event} [eventArguments]
  1880. * Custom event arguments that are passed on as an argument to the event
  1881. * handler.
  1882. *
  1883. * @param {Highcharts.EventCallbackFunction<T>|Function} [defaultFunction]
  1884. * The default function to execute if the other listeners haven't
  1885. * returned false.
  1886. *
  1887. * @return {void}
  1888. */
  1889. function fireEvent(el, type, eventArguments, defaultFunction) {
  1890. /* eslint-enable valid-jsdoc */
  1891. var e,
  1892. i;
  1893. eventArguments = eventArguments || {};
  1894. if (doc.createEvent &&
  1895. (el.dispatchEvent ||
  1896. (el.fireEvent &&
  1897. // Enable firing events on Highcharts instance.
  1898. el !== H))) {
  1899. e = doc.createEvent('Events');
  1900. e.initEvent(type, true, true);
  1901. eventArguments = extend(e, eventArguments);
  1902. if (el.dispatchEvent) {
  1903. el.dispatchEvent(eventArguments);
  1904. }
  1905. else {
  1906. el.fireEvent(type, eventArguments);
  1907. }
  1908. }
  1909. else if (el.hcEvents) {
  1910. if (!eventArguments.target) {
  1911. // We're running a custom event
  1912. extend(eventArguments, {
  1913. // Attach a simple preventDefault function to skip
  1914. // default handler if called. The built-in
  1915. // defaultPrevented property is not overwritable (#5112)
  1916. preventDefault: function () {
  1917. eventArguments.defaultPrevented = true;
  1918. },
  1919. // Setting target to native events fails with clicking
  1920. // the zoom-out button in Chrome.
  1921. target: el,
  1922. // If the type is not set, we're running a custom event
  1923. // (#2297). If it is set, we're running a browser event,
  1924. // and setting it will cause en error in IE8 (#2465).
  1925. type: type
  1926. });
  1927. }
  1928. var events = [];
  1929. var object = el;
  1930. var multilevel = false;
  1931. // Recurse up the inheritance chain and collect hcEvents set as own
  1932. // objects on the prototypes.
  1933. while (object.hcEvents) {
  1934. if (Object.hasOwnProperty.call(object, 'hcEvents') &&
  1935. object.hcEvents[type]) {
  1936. if (events.length) {
  1937. multilevel = true;
  1938. }
  1939. events.unshift.apply(events, object.hcEvents[type]);
  1940. }
  1941. object = Object.getPrototypeOf(object);
  1942. }
  1943. // For performance reasons, only sort the event handlers in case we are
  1944. // dealing with multiple levels in the prototype chain. Otherwise, the
  1945. // events are already sorted in the addEvent function.
  1946. if (multilevel) {
  1947. // Order the calls
  1948. events.sort(function (a, b) { return a.order - b.order; });
  1949. }
  1950. // Call the collected event handlers
  1951. events.forEach(function (obj) {
  1952. // If the event handler returns false, prevent the default handler
  1953. // from executing
  1954. if (obj.fn.call(el, eventArguments) === false) {
  1955. eventArguments.preventDefault();
  1956. }
  1957. });
  1958. }
  1959. // Run the default if not prevented
  1960. if (defaultFunction && !eventArguments.defaultPrevented) {
  1961. defaultFunction.call(el, eventArguments);
  1962. }
  1963. }
  1964. var serialMode;
  1965. /**
  1966. * Get a unique key for using in internal element id's and pointers. The key is
  1967. * composed of a random hash specific to this Highcharts instance, and a
  1968. * counter.
  1969. *
  1970. * @example
  1971. * let id = uniqueKey(); // => 'highcharts-x45f6hp-0'
  1972. *
  1973. * @function Highcharts.uniqueKey
  1974. *
  1975. * @return {string}
  1976. * A unique key.
  1977. */
  1978. var uniqueKey = (function () {
  1979. var hash = Math.random().toString(36).substring(2, 9) + '-';
  1980. var id = 0;
  1981. return function () {
  1982. return 'highcharts-' + (serialMode ? '' : hash) + id++;
  1983. };
  1984. }());
  1985. /**
  1986. * Activates a serial mode for element IDs provided by
  1987. * {@link Highcharts.uniqueKey}. This mode can be used in automated tests, where
  1988. * a simple comparison of two rendered SVG graphics is needed.
  1989. *
  1990. * **Note:** This is only for testing purposes and will break functionality in
  1991. * webpages with multiple charts.
  1992. *
  1993. * @example
  1994. * if (
  1995. * process &&
  1996. * process.env.NODE_ENV === 'development'
  1997. * ) {
  1998. * Highcharts.useSerialIds(true);
  1999. * }
  2000. *
  2001. * @function Highcharts.useSerialIds
  2002. *
  2003. * @param {boolean} [mode]
  2004. * Changes the state of serial mode.
  2005. *
  2006. * @return {boolean|undefined}
  2007. * State of the serial mode.
  2008. */
  2009. function useSerialIds(mode) {
  2010. return (serialMode = pick(mode, serialMode));
  2011. }
  2012. function isFunction(obj) {
  2013. return typeof obj === 'function';
  2014. }
  2015. // Register Highcharts as a plugin in jQuery
  2016. if (win.jQuery) {
  2017. /**
  2018. * Highcharts-extended JQuery.
  2019. *
  2020. * @external JQuery
  2021. */
  2022. /**
  2023. * Helper function to return the chart of the current JQuery selector
  2024. * element.
  2025. *
  2026. * @function external:JQuery#highcharts
  2027. *
  2028. * @return {Highcharts.Chart}
  2029. * The chart that is linked to the JQuery selector element.
  2030. */ /**
  2031. * Factory function to create a chart in the current JQuery selector
  2032. * element.
  2033. *
  2034. * @function external:JQuery#highcharts
  2035. *
  2036. * @param {'Chart'|'Map'|'StockChart'|string} [className]
  2037. * Name of the factory class in the Highcharts namespace.
  2038. *
  2039. * @param {Highcharts.Options} [options]
  2040. * The chart options structure.
  2041. *
  2042. * @param {Highcharts.ChartCallbackFunction} [callback]
  2043. * Function to run when the chart has loaded and and all external
  2044. * images are loaded. Defining a
  2045. * [chart.events.load](https://api.highcharts.com/highcharts/chart.events.load)
  2046. * handler is equivalent.
  2047. *
  2048. * @return {JQuery}
  2049. * The current JQuery selector.
  2050. */
  2051. win.jQuery.fn.highcharts = function () {
  2052. var args = [].slice.call(arguments);
  2053. if (this[0]) { // this[0] is the renderTo div
  2054. // Create the chart
  2055. if (args[0]) {
  2056. new H[ // eslint-disable-line computed-property-spacing, no-new
  2057. // Constructor defaults to Chart
  2058. isString(args[0]) ? args.shift() : 'Chart'](this[0], args[0], args[1]);
  2059. return this;
  2060. }
  2061. // When called without parameters or with the return argument,
  2062. // return an existing chart
  2063. return charts[attr(this[0], 'data-highcharts-chart')];
  2064. }
  2065. };
  2066. }
  2067. // TODO use named exports when supported.
  2068. var Utilities = {
  2069. addEvent: addEvent,
  2070. arrayMax: arrayMax,
  2071. arrayMin: arrayMin,
  2072. attr: attr,
  2073. clamp: clamp,
  2074. cleanRecursively: cleanRecursively,
  2075. clearTimeout: internalClearTimeout,
  2076. correctFloat: correctFloat,
  2077. createElement: createElement,
  2078. css: css,
  2079. defined: defined,
  2080. destroyObjectProperties: destroyObjectProperties,
  2081. discardElement: discardElement,
  2082. erase: erase,
  2083. error: error,
  2084. extend: extend,
  2085. extendClass: extendClass,
  2086. find: find,
  2087. fireEvent: fireEvent,
  2088. getMagnitude: getMagnitude,
  2089. getNestedProperty: getNestedProperty,
  2090. getStyle: getStyle,
  2091. inArray: inArray,
  2092. isArray: isArray,
  2093. isClass: isClass,
  2094. isDOMElement: isDOMElement,
  2095. isFunction: isFunction,
  2096. isNumber: isNumber,
  2097. isObject: isObject,
  2098. isString: isString,
  2099. keys: keys,
  2100. merge: merge,
  2101. normalizeTickInterval: normalizeTickInterval,
  2102. objectEach: objectEach,
  2103. offset: offset,
  2104. pad: pad,
  2105. pick: pick,
  2106. pInt: pInt,
  2107. relativeLength: relativeLength,
  2108. removeEvent: removeEvent,
  2109. splat: splat,
  2110. stableSort: stableSort,
  2111. syncTimeout: syncTimeout,
  2112. timeUnits: timeUnits,
  2113. uniqueKey: uniqueKey,
  2114. useSerialIds: useSerialIds,
  2115. wrap: wrap
  2116. };
  2117. return Utilities;
  2118. });
  2119. _registerModule(_modules, 'Core/Color/Palette.js', [], function () {
  2120. var palette = {
  2121. /**
  2122. * Colors for data series and points.
  2123. */
  2124. colors: [
  2125. '#7cb5ec',
  2126. '#434348',
  2127. '#90ed7d',
  2128. '#f7a35c',
  2129. '#8085e9',
  2130. '#f15c80',
  2131. '#e4d354',
  2132. '#2b908f',
  2133. '#f45b5b',
  2134. '#91e8e1'
  2135. ],
  2136. /**
  2137. * Chart background,
  2138. point stroke for markers and columns etc
  2139. */
  2140. backgroundColor: '#ffffff',
  2141. /**
  2142. * Strong text.
  2143. */
  2144. neutralColor100: '#000000',
  2145. /**
  2146. * Main text and some strokes.
  2147. */
  2148. neutralColor80: '#333333',
  2149. /**
  2150. * Axis labels,
  2151. axis title,
  2152. connector fallback.
  2153. */
  2154. neutralColor60: '#666666',
  2155. /**
  2156. * Credits text,
  2157. export menu stroke.
  2158. */
  2159. neutralColor40: '#999999',
  2160. /**
  2161. * Disabled texts,
  2162. button strokes,
  2163. crosshair etc.
  2164. */
  2165. neutralColor20: '#cccccc',
  2166. /**
  2167. * Grid lines etc.
  2168. */
  2169. neutralColor10: '#e6e6e6',
  2170. /**
  2171. * Minor grid lines etc.
  2172. */
  2173. neutralColor5: '#f2f2f2',
  2174. /**
  2175. * Tooltip backgroud,
  2176. button fills,
  2177. map null points.
  2178. */
  2179. neutralColor3: '#f7f7f7',
  2180. /**
  2181. * Drilldown clickable labels,
  2182. color axis max color.
  2183. */
  2184. highlightColor100: '#003399',
  2185. /**
  2186. * Selection marker,
  2187. menu hover,
  2188. button hover,
  2189. chart border,
  2190. navigator series.
  2191. */
  2192. highlightColor80: '#335cad',
  2193. /**
  2194. * Navigator mask fill.
  2195. */
  2196. highlightColor60: '#6685c2',
  2197. /**
  2198. * Ticks and axis line.
  2199. */
  2200. highlightColor20: '#ccd6eb',
  2201. /**
  2202. * Pressed button,
  2203. color axis min color.
  2204. */
  2205. highlightColor10: '#e6ebf5',
  2206. /**
  2207. * Positive indicator color
  2208. */
  2209. positiveColor: '#06b535',
  2210. /**
  2211. * Negative indicator color
  2212. */
  2213. negativeColor: '#f21313'
  2214. };
  2215. return palette;
  2216. });
  2217. _registerModule(_modules, 'Core/Chart/ChartDefaults.js', [_modules['Core/Color/Palette.js']], function (Palette) {
  2218. /* *
  2219. *
  2220. * (c) 2010-2021 Torstein Honsi
  2221. *
  2222. * License: www.highcharts.com/license
  2223. *
  2224. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  2225. *
  2226. * */
  2227. /* *
  2228. *
  2229. * Constants
  2230. *
  2231. * */
  2232. /**
  2233. * General options for the chart.
  2234. *
  2235. * @optionparent chart
  2236. */
  2237. var ChartDefaults = {
  2238. /**
  2239. * Default `mapData` for all series. If set to a string,
  2240. it functions
  2241. * as an index into the `Highcharts.maps` array. Otherwise it is
  2242. * interpreted as map data.
  2243. *
  2244. * @see [mapData](#series.map.mapData)
  2245. *
  2246. * @sample maps/demo/geojson
  2247. * Loading geoJSON data
  2248. * @sample maps/chart/topojson
  2249. * Loading topoJSON converted to geoJSON
  2250. *
  2251. * @type {string|Array<*>|Highcharts.GeoJSON}
  2252. * @since 5.0.0
  2253. * @product highmaps
  2254. * @apioption chart.map
  2255. */
  2256. /**
  2257. * Set lat/lon transformation definitions for the chart. If not defined,
  2258. * these are extracted from the map data.
  2259. *
  2260. * @type {*}
  2261. * @since 5.0.0
  2262. * @product highmaps
  2263. * @apioption chart.mapTransforms
  2264. */
  2265. /**
  2266. * When using multiple axis,
  2267. the ticks of two or more opposite axes
  2268. * will automatically be aligned by adding ticks to the axis or axes
  2269. * with the least ticks,
  2270. as if `tickAmount` were specified.
  2271. *
  2272. * This can be prevented by setting `alignTicks` to false. If the grid
  2273. * lines look messy,
  2274. it's a good idea to hide them for the secondary
  2275. * axis by setting `gridLineWidth` to 0.
  2276. *
  2277. * If `startOnTick` or `endOnTick` in an Axis options are set to false,
  2278. * then the `alignTicks ` will be disabled for the Axis.
  2279. *
  2280. * Disabled for logarithmic axes.
  2281. *
  2282. * @sample {highcharts} highcharts/chart/alignticks-true/
  2283. * True by default
  2284. * @sample {highcharts} highcharts/chart/alignticks-false/
  2285. * False
  2286. * @sample {highstock} stock/chart/alignticks-true/
  2287. * True by default
  2288. * @sample {highstock} stock/chart/alignticks-false/
  2289. * False
  2290. *
  2291. * @type {boolean}
  2292. * @default true
  2293. * @product highcharts highstock gantt
  2294. * @apioption chart.alignTicks
  2295. */
  2296. /**
  2297. * Set the overall animation for all chart updating. Animation can be
  2298. * disabled throughout the chart by setting it to false here. It can
  2299. * be overridden for each individual API method as a function parameter.
  2300. * The only animation not affected by this option is the initial series
  2301. * animation,
  2302. see [plotOptions.series.animation](
  2303. * #plotOptions.series.animation).
  2304. *
  2305. * The animation can either be set as a boolean or a configuration
  2306. * object. If `true`,
  2307. it will use the 'swing' jQuery easing and a
  2308. * duration of 500 ms. If used as a configuration object,
  2309. the following
  2310. * properties are supported:
  2311. *
  2312. * - `defer`: The animation delay time in milliseconds.
  2313. *
  2314. * - `duration`: The duration of the animation in milliseconds.
  2315. *
  2316. * - `easing`: A string reference to an easing function set on the
  2317. * `Math` object. See
  2318. * [the easing demo](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/series-animation-easing/).
  2319. *
  2320. * When zooming on a series with less than 100 points,
  2321. the chart redraw
  2322. * will be done with animation,
  2323. but in case of more data points,
  2324. it is
  2325. * necessary to set this option to ensure animation on zoom.
  2326. *
  2327. * @sample {highcharts} highcharts/chart/animation-none/
  2328. * Updating with no animation
  2329. * @sample {highcharts} highcharts/chart/animation-duration/
  2330. * With a longer duration
  2331. * @sample {highcharts} highcharts/chart/animation-easing/
  2332. * With a jQuery UI easing
  2333. * @sample {highmaps} maps/chart/animation-none/
  2334. * Updating with no animation
  2335. * @sample {highmaps} maps/chart/animation-duration/
  2336. * With a longer duration
  2337. *
  2338. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  2339. * @default undefined
  2340. * @apioption chart.animation
  2341. */
  2342. /**
  2343. * A CSS class name to apply to the charts container `div`,
  2344. allowing
  2345. * unique CSS styling for each chart.
  2346. *
  2347. * @type {string}
  2348. * @apioption chart.className
  2349. */
  2350. /**
  2351. * Event listeners for the chart.
  2352. *
  2353. * @apioption chart.events
  2354. */
  2355. /**
  2356. * Fires when a series is added to the chart after load time,
  2357. using the
  2358. * `addSeries` method. One parameter,
  2359. `event`,
  2360. is passed to the
  2361. * function,
  2362. containing common event information. Through
  2363. * `event.options` you can access the series options that were passed to
  2364. * the `addSeries` method. Returning false prevents the series from
  2365. * being added.
  2366. *
  2367. * @sample {highcharts} highcharts/chart/events-addseries/
  2368. * Alert on add series
  2369. * @sample {highstock} stock/chart/events-addseries/
  2370. * Alert on add series
  2371. *
  2372. * @type {Highcharts.ChartAddSeriesCallbackFunction}
  2373. * @since 1.2.0
  2374. * @context Highcharts.Chart
  2375. * @apioption chart.events.addSeries
  2376. */
  2377. /**
  2378. * Fires when clicking on the plot background. One parameter,
  2379. `event`,
  2380. * is passed to the function,
  2381. containing common event information.
  2382. *
  2383. * Information on the clicked spot can be found through `event.xAxis`
  2384. * and `event.yAxis`,
  2385. which are arrays containing the axes of each
  2386. * dimension and each axis' value at the clicked spot. The primary axes
  2387. * are `event.xAxis[0]` and `event.yAxis[0]`. Remember the unit of a
  2388. * datetime axis is milliseconds since 1970-01-01 00:00:00.
  2389. *
  2390. * ```js
  2391. * click: function(e) {
  2392. * console.log(
  2393. * Highcharts.dateFormat('%Y-%m-%d %H:%M:%S',
  2394. e.xAxis[0].value),
  2395. * e.yAxis[0].value
  2396. * )
  2397. * }
  2398. * ```
  2399. *
  2400. * @sample {highcharts} highcharts/chart/events-click/
  2401. * Alert coordinates on click
  2402. * @sample {highcharts} highcharts/chart/events-container/
  2403. * Alternatively,
  2404. attach event to container
  2405. * @sample {highstock} stock/chart/events-click/
  2406. * Alert coordinates on click
  2407. * @sample {highstock} highcharts/chart/events-container/
  2408. * Alternatively,
  2409. attach event to container
  2410. * @sample {highmaps} maps/chart/events-click/
  2411. * Record coordinates on click
  2412. * @sample {highmaps} highcharts/chart/events-container/
  2413. * Alternatively,
  2414. attach event to container
  2415. *
  2416. * @type {Highcharts.ChartClickCallbackFunction}
  2417. * @since 1.2.0
  2418. * @context Highcharts.Chart
  2419. * @apioption chart.events.click
  2420. */
  2421. /**
  2422. * Fires when the chart is finished loading. Since v4.2.2,
  2423. it also waits
  2424. * for images to be loaded,
  2425. for example from point markers. One
  2426. * parameter,
  2427. `event`,
  2428. is passed to the function,
  2429. containing common
  2430. * event information.
  2431. *
  2432. * There is also a second parameter to the chart constructor where a
  2433. * callback function can be passed to be executed on chart.load.
  2434. *
  2435. * @sample {highcharts} highcharts/chart/events-load/
  2436. * Alert on chart load
  2437. * @sample {highstock} stock/chart/events-load/
  2438. * Alert on chart load
  2439. * @sample {highmaps} maps/chart/events-load/
  2440. * Add series on chart load
  2441. *
  2442. * @type {Highcharts.ChartLoadCallbackFunction}
  2443. * @context Highcharts.Chart
  2444. * @apioption chart.events.load
  2445. */
  2446. /**
  2447. * Fires when the chart is redrawn,
  2448. either after a call to
  2449. * `chart.redraw()` or after an axis,
  2450. series or point is modified with
  2451. * the `redraw` option set to `true`. One parameter,
  2452. `event`,
  2453. is passed
  2454. * to the function,
  2455. containing common event information.
  2456. *
  2457. * @sample {highcharts} highcharts/chart/events-redraw/
  2458. * Alert on chart redraw
  2459. * @sample {highstock} stock/chart/events-redraw/
  2460. * Alert on chart redraw when adding a series or moving the
  2461. * zoomed range
  2462. * @sample {highmaps} maps/chart/events-redraw/
  2463. * Set subtitle on chart redraw
  2464. *
  2465. * @type {Highcharts.ChartRedrawCallbackFunction}
  2466. * @since 1.2.0
  2467. * @context Highcharts.Chart
  2468. * @apioption chart.events.redraw
  2469. */
  2470. /**
  2471. * Fires after initial load of the chart (directly after the `load`
  2472. * event),
  2473. and after each redraw (directly after the `redraw` event).
  2474. *
  2475. * @type {Highcharts.ChartRenderCallbackFunction}
  2476. * @since 5.0.7
  2477. * @context Highcharts.Chart
  2478. * @apioption chart.events.render
  2479. */
  2480. /**
  2481. * Fires when an area of the chart has been selected. Selection is
  2482. * enabled by setting the chart's zoomType. One parameter,
  2483. `event`,
  2484. is
  2485. * passed to the function,
  2486. containing common event information. The
  2487. * default action for the selection event is to zoom the chart to the
  2488. * selected area. It can be prevented by calling
  2489. * `event.preventDefault()` or return false.
  2490. *
  2491. * Information on the selected area can be found through `event.xAxis`
  2492. * and `event.yAxis`,
  2493. which are arrays containing the axes of each
  2494. * dimension and each axis' min and max values. The primary axes are
  2495. * `event.xAxis[0]` and `event.yAxis[0]`. Remember the unit of a
  2496. * datetime axis is milliseconds since 1970-01-01 00:00:00.
  2497. *
  2498. * ```js
  2499. * selection: function(event) {
  2500. * // log the min and max of the primary, datetime x-axis
  2501. * console.log(
  2502. * Highcharts.dateFormat(
  2503. * '%Y-%m-%d %H:%M:%S',
  2504. * event.xAxis[0].min
  2505. * ),
  2506. * Highcharts.dateFormat(
  2507. * '%Y-%m-%d %H:%M:%S',
  2508. * event.xAxis[0].max
  2509. * )
  2510. * );
  2511. * // log the min and max of the y axis
  2512. * console.log(event.yAxis[0].min, event.yAxis[0].max);
  2513. * }
  2514. * ```
  2515. *
  2516. * @sample {highcharts} highcharts/chart/events-selection/
  2517. * Report on selection and reset
  2518. * @sample {highcharts} highcharts/chart/events-selection-points/
  2519. * Select a range of points through a drag selection
  2520. * @sample {highstock} stock/chart/events-selection/
  2521. * Report on selection and reset
  2522. * @sample {highstock} highcharts/chart/events-selection-points/
  2523. * Select a range of points through a drag selection
  2524. * (Highcharts)
  2525. *
  2526. * @type {Highcharts.ChartSelectionCallbackFunction}
  2527. * @apioption chart.events.selection
  2528. */
  2529. /**
  2530. * The margin between the outer edge of the chart and the plot area.
  2531. * The numbers in the array designate top, right, bottom and left
  2532. * respectively. Use the options `marginTop`, `marginRight`,
  2533. * `marginBottom` and `marginLeft` for shorthand setting of one option.
  2534. *
  2535. * By default there is no margin. The actual space is dynamically
  2536. * calculated from the offset of axis labels, axis title, title,
  2537. * subtitle and legend in addition to the `spacingTop`, `spacingRight`,
  2538. * `spacingBottom` and `spacingLeft` options.
  2539. *
  2540. * @sample {highcharts} highcharts/chart/margins-zero/
  2541. * Zero margins
  2542. * @sample {highstock} stock/chart/margin-zero/
  2543. * Zero margins
  2544. *
  2545. * @type {number|Array<number>}
  2546. * @apioption chart.margin
  2547. */
  2548. /**
  2549. * The margin between the bottom outer edge of the chart and the plot
  2550. * area. Use this to set a fixed pixel value for the margin as opposed
  2551. * to the default dynamic margin. See also `spacingBottom`.
  2552. *
  2553. * @sample {highcharts} highcharts/chart/marginbottom/
  2554. * 100px bottom margin
  2555. * @sample {highstock} stock/chart/marginbottom/
  2556. * 100px bottom margin
  2557. * @sample {highmaps} maps/chart/margin/
  2558. * 100px margins
  2559. *
  2560. * @type {number}
  2561. * @since 2.0
  2562. * @apioption chart.marginBottom
  2563. */
  2564. /**
  2565. * The margin between the left outer edge of the chart and the plot
  2566. * area. Use this to set a fixed pixel value for the margin as opposed
  2567. * to the default dynamic margin. See also `spacingLeft`.
  2568. *
  2569. * @sample {highcharts} highcharts/chart/marginleft/
  2570. * 150px left margin
  2571. * @sample {highstock} stock/chart/marginleft/
  2572. * 150px left margin
  2573. * @sample {highmaps} maps/chart/margin/
  2574. * 100px margins
  2575. *
  2576. * @type {number}
  2577. * @since 2.0
  2578. * @apioption chart.marginLeft
  2579. */
  2580. /**
  2581. * The margin between the right outer edge of the chart and the plot
  2582. * area. Use this to set a fixed pixel value for the margin as opposed
  2583. * to the default dynamic margin. See also `spacingRight`.
  2584. *
  2585. * @sample {highcharts} highcharts/chart/marginright/
  2586. * 100px right margin
  2587. * @sample {highstock} stock/chart/marginright/
  2588. * 100px right margin
  2589. * @sample {highmaps} maps/chart/margin/
  2590. * 100px margins
  2591. *
  2592. * @type {number}
  2593. * @since 2.0
  2594. * @apioption chart.marginRight
  2595. */
  2596. /**
  2597. * The margin between the top outer edge of the chart and the plot area.
  2598. * Use this to set a fixed pixel value for the margin as opposed to
  2599. * the default dynamic margin. See also `spacingTop`.
  2600. *
  2601. * @sample {highcharts} highcharts/chart/margintop/ 100px top margin
  2602. * @sample {highstock} stock/chart/margintop/
  2603. * 100px top margin
  2604. * @sample {highmaps} maps/chart/margin/
  2605. * 100px margins
  2606. *
  2607. * @type {number}
  2608. * @since 2.0
  2609. * @apioption chart.marginTop
  2610. */
  2611. /**
  2612. * Callback function to override the default function that formats all
  2613. * the numbers in the chart. Returns a string with the formatted number.
  2614. *
  2615. * @sample highcharts/members/highcharts-numberformat
  2616. * Arabic digits in Highcharts
  2617. * @type {Highcharts.NumberFormatterCallbackFunction}
  2618. * @since 8.0.0
  2619. * @apioption chart.numberFormatter
  2620. */
  2621. /**
  2622. * Allows setting a key to switch between zooming and panning. Can be
  2623. * one of `alt`, `ctrl`, `meta` (the command key on Mac and Windows
  2624. * key on Windows) or `shift`. The keys are mapped directly to the key
  2625. * properties of the click event argument (`event.altKey`,
  2626. * `event.ctrlKey`, `event.metaKey` and `event.shiftKey`).
  2627. *
  2628. * @type {string}
  2629. * @since 4.0.3
  2630. * @product highcharts gantt
  2631. * @validvalue ["alt", "ctrl", "meta", "shift"]
  2632. * @apioption chart.panKey
  2633. */
  2634. /**
  2635. * Allow panning in a chart. Best used with [panKey](#chart.panKey)
  2636. * to combine zooming and panning.
  2637. *
  2638. * On touch devices, when the [tooltip.followTouchMove](
  2639. * #tooltip.followTouchMove) option is `true` (default), panning
  2640. * requires two fingers. To allow panning with one finger, set
  2641. * `followTouchMove` to `false`.
  2642. *
  2643. * @sample {highcharts} highcharts/chart/pankey/ Zooming and panning
  2644. * @sample {highstock} stock/chart/panning/ Zooming and xy panning
  2645. */
  2646. panning: {
  2647. /**
  2648. * Enable or disable chart panning.
  2649. *
  2650. * @type {boolean}
  2651. * @default {highcharts} false
  2652. * @default {highstock|highmaps} true
  2653. */
  2654. enabled: false,
  2655. /**
  2656. * Decides in what dimensions the user can pan the chart. Can be
  2657. * one of `x`, `y`, or `xy`.
  2658. *
  2659. * @sample {highcharts} highcharts/chart/panning-type
  2660. * Zooming and xy panning
  2661. *
  2662. * @type {string}
  2663. * @validvalue ["x", "y", "xy"]
  2664. * @default {highcharts|highstock} x
  2665. * @default {highmaps} xy
  2666. */
  2667. type: 'x'
  2668. },
  2669. /**
  2670. * Equivalent to [zoomType](#chart.zoomType), but for multitouch
  2671. * gestures only. By default, the `pinchType` is the same as the
  2672. * `zoomType` setting. However, pinching can be enabled separately in
  2673. * some cases, for example in stock charts where a mouse drag pans the
  2674. * chart, while pinching is enabled. When [tooltip.followTouchMove](
  2675. * #tooltip.followTouchMove) is true, pinchType only applies to
  2676. * two-finger touches.
  2677. *
  2678. * @type {string}
  2679. * @default {highcharts} undefined
  2680. * @default {highstock} x
  2681. * @since 3.0
  2682. * @product highcharts highstock gantt
  2683. * @validvalue ["x", "y", "xy"]
  2684. * @apioption chart.pinchType
  2685. */
  2686. /**
  2687. * Whether to apply styled mode. When in styled mode, no presentational
  2688. * attributes or CSS are applied to the chart SVG. Instead, CSS rules
  2689. * are required to style the chart. The default style sheet is
  2690. * available from `https://code.highcharts.com/css/highcharts.css`.
  2691. *
  2692. * @type {boolean}
  2693. * @default false
  2694. * @since 7.0
  2695. * @apioption chart.styledMode
  2696. */
  2697. styledMode: false,
  2698. /**
  2699. * The corner radius of the outer chart border.
  2700. *
  2701. * @sample {highcharts} highcharts/chart/borderradius/
  2702. * 20px radius
  2703. * @sample {highstock} stock/chart/border/
  2704. * 10px radius
  2705. * @sample {highmaps} maps/chart/border/
  2706. * Border options
  2707. *
  2708. */
  2709. borderRadius: 0,
  2710. /**
  2711. * In styled mode, this sets how many colors the class names
  2712. * should rotate between. With ten colors, series (or points) are
  2713. * given class names like `highcharts-color-0`, `highcharts-color-0`
  2714. * [...] `highcharts-color-9`. The equivalent in non-styled mode
  2715. * is to set colors using the [colors](#colors) setting.
  2716. *
  2717. * @since 5.0.0
  2718. */
  2719. colorCount: 10,
  2720. /**
  2721. * Alias of `type`.
  2722. *
  2723. * @sample {highcharts} highcharts/chart/defaultseriestype/
  2724. * Bar
  2725. *
  2726. * @deprecated
  2727. *
  2728. * @product highcharts
  2729. */
  2730. defaultSeriesType: 'line',
  2731. /**
  2732. * If true, the axes will scale to the remaining visible series once
  2733. * one series is hidden. If false, hiding and showing a series will
  2734. * not affect the axes or the other series. For stacks, once one series
  2735. * within the stack is hidden, the rest of the stack will close in
  2736. * around it even if the axis is not affected.
  2737. *
  2738. * @sample {highcharts} highcharts/chart/ignorehiddenseries-true/
  2739. * True by default
  2740. * @sample {highcharts} highcharts/chart/ignorehiddenseries-false/
  2741. * False
  2742. * @sample {highcharts} highcharts/chart/ignorehiddenseries-true-stacked/
  2743. * True with stack
  2744. * @sample {highstock} stock/chart/ignorehiddenseries-true/
  2745. * True by default
  2746. * @sample {highstock} stock/chart/ignorehiddenseries-false/
  2747. * False
  2748. *
  2749. * @since 1.2.0
  2750. * @product highcharts highstock gantt
  2751. */
  2752. ignoreHiddenSeries: true,
  2753. /**
  2754. * Whether to invert the axes so that the x axis is vertical and y axis
  2755. * is horizontal. When `true`, the x axis is [reversed](#xAxis.reversed)
  2756. * by default.
  2757. *
  2758. * @productdesc {highcharts}
  2759. * If a bar series is present in the chart, it will be inverted
  2760. * automatically. Inverting the chart doesn't have an effect if there
  2761. * are no cartesian series in the chart, or if the chart is
  2762. * [polar](#chart.polar).
  2763. *
  2764. * @sample {highcharts} highcharts/chart/inverted/
  2765. * Inverted line
  2766. * @sample {highstock} stock/navigator/inverted/
  2767. * Inverted stock chart
  2768. *
  2769. * @type {boolean}
  2770. * @default false
  2771. * @product highcharts highstock gantt
  2772. * @apioption chart.inverted
  2773. */
  2774. /**
  2775. * The distance between the outer edge of the chart and the content,
  2776. * like title or legend, or axis title and labels if present. The
  2777. * numbers in the array designate top, right, bottom and left
  2778. * respectively. Use the options spacingTop, spacingRight, spacingBottom
  2779. * and spacingLeft options for shorthand setting of one option.
  2780. *
  2781. * @type {Array<number>}
  2782. * @see [chart.margin](#chart.margin)
  2783. * @default [10, 10, 15, 10]
  2784. * @since 3.0.6
  2785. */
  2786. spacing: [10, 10, 15, 10],
  2787. /**
  2788. * The button that appears after a selection zoom, allowing the user
  2789. * to reset zoom.
  2790. */
  2791. resetZoomButton: {
  2792. /**
  2793. * What frame the button placement should be related to. Can be
  2794. * either `plotBox` or `spacingBox`.
  2795. *
  2796. * @sample {highcharts} highcharts/chart/resetzoombutton-relativeto/
  2797. * Relative to the chart
  2798. * @sample {highstock} highcharts/chart/resetzoombutton-relativeto/
  2799. * Relative to the chart
  2800. *
  2801. * @type {Highcharts.ButtonRelativeToValue}
  2802. * @default plot
  2803. * @since 2.2
  2804. * @apioption chart.resetZoomButton.relativeTo
  2805. */
  2806. /**
  2807. * A collection of attributes for the button. The object takes SVG
  2808. * attributes like `fill`, `stroke`, `stroke-width` or `r`, the
  2809. * border radius. The theme also supports `style`, a collection of
  2810. * CSS properties for the text. Equivalent attributes for the hover
  2811. * state are given in `theme.states.hover`.
  2812. *
  2813. * @sample {highcharts} highcharts/chart/resetzoombutton-theme/
  2814. * Theming the button
  2815. * @sample {highstock} highcharts/chart/resetzoombutton-theme/
  2816. * Theming the button
  2817. *
  2818. * @type {Highcharts.SVGAttributes}
  2819. * @since 2.2
  2820. */
  2821. theme: {
  2822. /** @internal */
  2823. zIndex: 6
  2824. },
  2825. /**
  2826. * The position of the button.
  2827. *
  2828. * @sample {highcharts} highcharts/chart/resetzoombutton-position/
  2829. * Above the plot area
  2830. * @sample {highstock} highcharts/chart/resetzoombutton-position/
  2831. * Above the plot area
  2832. * @sample {highmaps} highcharts/chart/resetzoombutton-position/
  2833. * Above the plot area
  2834. *
  2835. * @type {Highcharts.AlignObject}
  2836. * @since 2.2
  2837. */
  2838. position: {
  2839. /**
  2840. * The horizontal alignment of the button.
  2841. */
  2842. align: 'right',
  2843. /**
  2844. * The horizontal offset of the button.
  2845. */
  2846. x: -10,
  2847. /**
  2848. * The vertical alignment of the button.
  2849. *
  2850. * @type {Highcharts.VerticalAlignValue}
  2851. * @default top
  2852. * @apioption chart.resetZoomButton.position.verticalAlign
  2853. */
  2854. /**
  2855. * The vertical offset of the button.
  2856. */
  2857. y: 10
  2858. }
  2859. },
  2860. /**
  2861. * The pixel width of the plot area border.
  2862. *
  2863. * @sample {highcharts} highcharts/chart/plotborderwidth/
  2864. * 1px border
  2865. * @sample {highstock} stock/chart/plotborder/
  2866. * 2px border
  2867. * @sample {highmaps} maps/chart/plotborder/
  2868. * Plot border options
  2869. *
  2870. * @type {number}
  2871. * @default 0
  2872. * @apioption chart.plotBorderWidth
  2873. */
  2874. /**
  2875. * Whether to apply a drop shadow to the plot area. Requires that
  2876. * plotBackgroundColor be set. The shadow can be an object configuration
  2877. * containing `color`, `offsetX`, `offsetY`, `opacity` and `width`.
  2878. *
  2879. * @sample {highcharts} highcharts/chart/plotshadow/
  2880. * Plot shadow
  2881. * @sample {highstock} stock/chart/plotshadow/
  2882. * Plot shadow
  2883. * @sample {highmaps} maps/chart/plotborder/
  2884. * Plot border options
  2885. *
  2886. * @type {boolean|Highcharts.CSSObject}
  2887. * @default false
  2888. * @apioption chart.plotShadow
  2889. */
  2890. /**
  2891. * When true, cartesian charts like line, spline, area and column are
  2892. * transformed into the polar coordinate system. This produces _polar
  2893. * charts_, also known as _radar charts_.
  2894. *
  2895. * @sample {highcharts} highcharts/demo/polar/
  2896. * Polar chart
  2897. * @sample {highcharts} highcharts/demo/polar-wind-rose/
  2898. * Wind rose, stacked polar column chart
  2899. * @sample {highcharts} highcharts/demo/polar-spider/
  2900. * Spider web chart
  2901. * @sample {highcharts} highcharts/parallel-coordinates/polar/
  2902. * Star plot, multivariate data in a polar chart
  2903. *
  2904. * @type {boolean}
  2905. * @default false
  2906. * @since 2.3.0
  2907. * @product highcharts
  2908. * @requires highcharts-more
  2909. * @apioption chart.polar
  2910. */
  2911. /**
  2912. * Whether to reflow the chart to fit the width of the container div
  2913. * on resizing the window.
  2914. *
  2915. * @sample {highcharts} highcharts/chart/reflow-true/
  2916. * True by default
  2917. * @sample {highcharts} highcharts/chart/reflow-false/
  2918. * False
  2919. * @sample {highstock} stock/chart/reflow-true/
  2920. * True by default
  2921. * @sample {highstock} stock/chart/reflow-false/
  2922. * False
  2923. * @sample {highmaps} maps/chart/reflow-true/
  2924. * True by default
  2925. * @sample {highmaps} maps/chart/reflow-false/
  2926. * False
  2927. *
  2928. * @type {boolean}
  2929. * @default true
  2930. * @since 2.1
  2931. * @apioption chart.reflow
  2932. */
  2933. /**
  2934. * The HTML element where the chart will be rendered. If it is a string,
  2935. * the element by that id is used. The HTML element can also be passed
  2936. * by direct reference, or as the first argument of the chart
  2937. * constructor, in which case the option is not needed.
  2938. *
  2939. * @sample {highcharts} highcharts/chart/reflow-true/
  2940. * String
  2941. * @sample {highcharts} highcharts/chart/renderto-object/
  2942. * Object reference
  2943. * @sample {highstock} stock/chart/renderto-string/
  2944. * String
  2945. * @sample {highstock} stock/chart/renderto-object/
  2946. * Object reference
  2947. *
  2948. * @type {string|Highcharts.HTMLDOMElement}
  2949. * @apioption chart.renderTo
  2950. */
  2951. /**
  2952. * The background color of the marker square when selecting (zooming
  2953. * in on) an area of the chart.
  2954. *
  2955. * @see In styled mode, the selection marker fill is set with the
  2956. * `.highcharts-selection-marker` class.
  2957. *
  2958. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  2959. * @default rgba(51,92,173,0.25)
  2960. * @since 2.1.7
  2961. * @apioption chart.selectionMarkerFill
  2962. */
  2963. /**
  2964. * Whether to apply a drop shadow to the outer chart area. Requires
  2965. * that backgroundColor be set. The shadow can be an object
  2966. * configuration containing `color`, `offsetX`, `offsetY`, `opacity` and
  2967. * `width`.
  2968. *
  2969. * @sample {highcharts} highcharts/chart/shadow/
  2970. * Shadow
  2971. * @sample {highstock} stock/chart/shadow/
  2972. * Shadow
  2973. * @sample {highmaps} maps/chart/border/
  2974. * Chart border and shadow
  2975. *
  2976. * @type {boolean|Highcharts.CSSObject}
  2977. * @default false
  2978. * @apioption chart.shadow
  2979. */
  2980. /**
  2981. * Whether to show the axes initially. This only applies to empty charts
  2982. * where series are added dynamically, as axes are automatically added
  2983. * to cartesian series.
  2984. *
  2985. * @sample {highcharts} highcharts/chart/showaxes-false/
  2986. * False by default
  2987. * @sample {highcharts} highcharts/chart/showaxes-true/
  2988. * True
  2989. *
  2990. * @type {boolean}
  2991. * @since 1.2.5
  2992. * @product highcharts gantt
  2993. * @apioption chart.showAxes
  2994. */
  2995. /**
  2996. * The space between the bottom edge of the chart and the content (plot
  2997. * area, axis title and labels, title, subtitle or legend in top
  2998. * position).
  2999. *
  3000. * @sample {highcharts} highcharts/chart/spacingbottom/
  3001. * Spacing bottom set to 100
  3002. * @sample {highstock} stock/chart/spacingbottom/
  3003. * Spacing bottom set to 100
  3004. * @sample {highmaps} maps/chart/spacing/
  3005. * Spacing 100 all around
  3006. *
  3007. * @type {number}
  3008. * @default 15
  3009. * @since 2.1
  3010. * @apioption chart.spacingBottom
  3011. */
  3012. /**
  3013. * The space between the left edge of the chart and the content (plot
  3014. * area, axis title and labels, title, subtitle or legend in top
  3015. * position).
  3016. *
  3017. * @sample {highcharts} highcharts/chart/spacingleft/
  3018. * Spacing left set to 100
  3019. * @sample {highstock} stock/chart/spacingleft/
  3020. * Spacing left set to 100
  3021. * @sample {highmaps} maps/chart/spacing/
  3022. * Spacing 100 all around
  3023. *
  3024. * @type {number}
  3025. * @default 10
  3026. * @since 2.1
  3027. * @apioption chart.spacingLeft
  3028. */
  3029. /**
  3030. * The space between the right edge of the chart and the content (plot
  3031. * area, axis title and labels, title, subtitle or legend in top
  3032. * position).
  3033. *
  3034. * @sample {highcharts} highcharts/chart/spacingright-100/
  3035. * Spacing set to 100
  3036. * @sample {highcharts} highcharts/chart/spacingright-legend/
  3037. * Legend in right position with default spacing
  3038. * @sample {highstock} stock/chart/spacingright/
  3039. * Spacing set to 100
  3040. * @sample {highmaps} maps/chart/spacing/
  3041. * Spacing 100 all around
  3042. *
  3043. * @type {number}
  3044. * @default 10
  3045. * @since 2.1
  3046. * @apioption chart.spacingRight
  3047. */
  3048. /**
  3049. * The space between the top edge of the chart and the content (plot
  3050. * area, axis title and labels, title, subtitle or legend in top
  3051. * position).
  3052. *
  3053. * @sample {highcharts} highcharts/chart/spacingtop-100/
  3054. * A top spacing of 100
  3055. * @sample {highcharts} highcharts/chart/spacingtop-10/
  3056. * Floating chart title makes the plot area align to the default
  3057. * spacingTop of 10.
  3058. * @sample {highstock} stock/chart/spacingtop/
  3059. * A top spacing of 100
  3060. * @sample {highmaps} maps/chart/spacing/
  3061. * Spacing 100 all around
  3062. *
  3063. * @type {number}
  3064. * @default 10
  3065. * @since 2.1
  3066. * @apioption chart.spacingTop
  3067. */
  3068. /**
  3069. * Additional CSS styles to apply inline to the container `div`. Note
  3070. * that since the default font styles are applied in the renderer, it
  3071. * is ignorant of the individual chart options and must be set globally.
  3072. *
  3073. * @see In styled mode, general chart styles can be set with the
  3074. * `.highcharts-root` class.
  3075. * @sample {highcharts} highcharts/chart/style-serif-font/
  3076. * Using a serif type font
  3077. * @sample {highcharts} highcharts/css/em/
  3078. * Styled mode with relative font sizes
  3079. * @sample {highstock} stock/chart/style/
  3080. * Using a serif type font
  3081. * @sample {highmaps} maps/chart/style-serif-font/
  3082. * Using a serif type font
  3083. *
  3084. * @type {Highcharts.CSSObject}
  3085. * @default {"fontFamily": "\"Lucida Grande\", \"Lucida Sans Unicode\", Verdana, Arial, Helvetica, sans-serif","fontSize":"12px"}
  3086. * @apioption chart.style
  3087. */
  3088. /**
  3089. * The default series type for the chart. Can be any of the chart types
  3090. * listed under [plotOptions](#plotOptions) and [series](#series) or can
  3091. * be a series provided by an additional module.
  3092. *
  3093. * In TypeScript this option has no effect in sense of typing and
  3094. * instead the `type` option must always be set in the series.
  3095. *
  3096. * @sample {highcharts} highcharts/chart/type-bar/
  3097. * Bar
  3098. * @sample {highstock} stock/chart/type/
  3099. * Areaspline
  3100. * @sample {highmaps} maps/chart/type-mapline/
  3101. * Mapline
  3102. *
  3103. * @type {string}
  3104. * @default {highcharts} line
  3105. * @default {highstock} line
  3106. * @default {highmaps} map
  3107. * @since 2.1.0
  3108. * @apioption chart.type
  3109. */
  3110. /**
  3111. * Decides in what dimensions the user can zoom by dragging the mouse.
  3112. * Can be one of `x`, `y` or `xy`.
  3113. *
  3114. * @see [panKey](#chart.panKey)
  3115. *
  3116. * @sample {highcharts} highcharts/chart/zoomtype-none/
  3117. * None by default
  3118. * @sample {highcharts} highcharts/chart/zoomtype-x/
  3119. * X
  3120. * @sample {highcharts} highcharts/chart/zoomtype-y/
  3121. * Y
  3122. * @sample {highcharts} highcharts/chart/zoomtype-xy/
  3123. * Xy
  3124. * @sample {highstock} stock/demo/basic-line/
  3125. * None by default
  3126. * @sample {highstock} stock/chart/zoomtype-x/
  3127. * X
  3128. * @sample {highstock} stock/chart/zoomtype-y/
  3129. * Y
  3130. * @sample {highstock} stock/chart/zoomtype-xy/
  3131. * Xy
  3132. *
  3133. * @type {string}
  3134. * @product highcharts highstock gantt
  3135. * @validvalue ["x", "y", "xy"]
  3136. * @apioption chart.zoomType
  3137. */
  3138. /**
  3139. * Enables zooming by a single touch, in combination with
  3140. * [chart.zoomType](#chart.zoomType). When enabled, two-finger pinch
  3141. * will still work as set up by [chart.pinchType](#chart.pinchType).
  3142. * However, `zoomBySingleTouch` will interfere with touch-dragging the
  3143. * chart to read the tooltip. And especially when vertical zooming is
  3144. * enabled, it will make it hard to scroll vertically on the page.
  3145. * @since 9.0.0
  3146. * @sample highcharts/chart/zoombysingletouch
  3147. * Zoom by single touch enabled, with buttons to toggle
  3148. * @product highcharts highstock gantt
  3149. */
  3150. zoomBySingleTouch: false,
  3151. /**
  3152. * An explicit width for the chart. By default (when `null`) the width
  3153. * is calculated from the offset width of the containing element.
  3154. *
  3155. * @sample {highcharts} highcharts/chart/width/
  3156. * 800px wide
  3157. * @sample {highstock} stock/chart/width/
  3158. * 800px wide
  3159. * @sample {highmaps} maps/chart/size/
  3160. * Chart with explicit size
  3161. *
  3162. * @type {null|number|string}
  3163. */
  3164. width: null,
  3165. /**
  3166. * An explicit height for the chart. If a _number_, the height is
  3167. * given in pixels. If given a _percentage string_ (for example
  3168. * `'56%'`), the height is given as the percentage of the actual chart
  3169. * width. This allows for preserving the aspect ratio across responsive
  3170. * sizes.
  3171. *
  3172. * By default (when `null`) the height is calculated from the offset
  3173. * height of the containing element, or 400 pixels if the containing
  3174. * element's height is 0.
  3175. *
  3176. * @sample {highcharts} highcharts/chart/height/
  3177. * 500px height
  3178. * @sample {highstock} stock/chart/height/
  3179. * 300px height
  3180. * @sample {highmaps} maps/chart/size/
  3181. * Chart with explicit size
  3182. * @sample highcharts/chart/height-percent/
  3183. * Highcharts with percentage height
  3184. *
  3185. * @type {null|number|string}
  3186. */
  3187. height: null,
  3188. /**
  3189. * The color of the outer chart border.
  3190. *
  3191. * @see In styled mode, the stroke is set with the
  3192. * `.highcharts-background` class.
  3193. *
  3194. * @sample {highcharts} highcharts/chart/bordercolor/
  3195. * Brown border
  3196. * @sample {highstock} stock/chart/border/
  3197. * Brown border
  3198. * @sample {highmaps} maps/chart/border/
  3199. * Border options
  3200. *
  3201. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  3202. */
  3203. borderColor: Palette.highlightColor80,
  3204. /**
  3205. * The pixel width of the outer chart border.
  3206. *
  3207. * @see In styled mode, the stroke is set with the
  3208. * `.highcharts-background` class.
  3209. *
  3210. * @sample {highcharts} highcharts/chart/borderwidth/
  3211. * 5px border
  3212. * @sample {highstock} stock/chart/border/
  3213. * 2px border
  3214. * @sample {highmaps} maps/chart/border/
  3215. * Border options
  3216. *
  3217. * @type {number}
  3218. * @default 0
  3219. * @apioption chart.borderWidth
  3220. */
  3221. /**
  3222. * The background color or gradient for the outer chart area.
  3223. *
  3224. * @see In styled mode, the background is set with the
  3225. * `.highcharts-background` class.
  3226. *
  3227. * @sample {highcharts} highcharts/chart/backgroundcolor-color/
  3228. * Color
  3229. * @sample {highcharts} highcharts/chart/backgroundcolor-gradient/
  3230. * Gradient
  3231. * @sample {highstock} stock/chart/backgroundcolor-color/
  3232. * Color
  3233. * @sample {highstock} stock/chart/backgroundcolor-gradient/
  3234. * Gradient
  3235. * @sample {highmaps} maps/chart/backgroundcolor-color/
  3236. * Color
  3237. * @sample {highmaps} maps/chart/backgroundcolor-gradient/
  3238. * Gradient
  3239. *
  3240. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  3241. */
  3242. backgroundColor: Palette.backgroundColor,
  3243. /**
  3244. * The background color or gradient for the plot area.
  3245. *
  3246. * @see In styled mode, the plot background is set with the
  3247. * `.highcharts-plot-background` class.
  3248. *
  3249. * @sample {highcharts} highcharts/chart/plotbackgroundcolor-color/
  3250. * Color
  3251. * @sample {highcharts} highcharts/chart/plotbackgroundcolor-gradient/
  3252. * Gradient
  3253. * @sample {highstock} stock/chart/plotbackgroundcolor-color/
  3254. * Color
  3255. * @sample {highstock} stock/chart/plotbackgroundcolor-gradient/
  3256. * Gradient
  3257. * @sample {highmaps} maps/chart/plotbackgroundcolor-color/
  3258. * Color
  3259. * @sample {highmaps} maps/chart/plotbackgroundcolor-gradient/
  3260. * Gradient
  3261. *
  3262. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  3263. * @apioption chart.plotBackgroundColor
  3264. */
  3265. /**
  3266. * The URL for an image to use as the plot background. To set an image
  3267. * as the background for the entire chart, set a CSS background image
  3268. * to the container element. Note that for the image to be applied to
  3269. * exported charts, its URL needs to be accessible by the export server.
  3270. *
  3271. * @see In styled mode, a plot background image can be set with the
  3272. * `.highcharts-plot-background` class and a [custom pattern](
  3273. * https://www.highcharts.com/docs/chart-design-and-style/
  3274. * gradients-shadows-and-patterns).
  3275. *
  3276. * @sample {highcharts} highcharts/chart/plotbackgroundimage/
  3277. * Skies
  3278. * @sample {highstock} stock/chart/plotbackgroundimage/
  3279. * Skies
  3280. *
  3281. * @type {string}
  3282. * @apioption chart.plotBackgroundImage
  3283. */
  3284. /**
  3285. * The color of the inner chart or plot area border.
  3286. *
  3287. * @see In styled mode, a plot border stroke can be set with the
  3288. * `.highcharts-plot-border` class.
  3289. *
  3290. * @sample {highcharts} highcharts/chart/plotbordercolor/
  3291. * Blue border
  3292. * @sample {highstock} stock/chart/plotborder/
  3293. * Blue border
  3294. * @sample {highmaps} maps/chart/plotborder/
  3295. * Plot border options
  3296. *
  3297. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  3298. */
  3299. plotBorderColor: Palette.neutralColor20
  3300. };
  3301. /* *
  3302. *
  3303. * Default Export
  3304. *
  3305. * */
  3306. return ChartDefaults;
  3307. });
  3308. _registerModule(_modules, 'Core/Color/Color.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
  3309. /* *
  3310. *
  3311. * (c) 2010-2021 Torstein Honsi
  3312. *
  3313. * License: www.highcharts.com/license
  3314. *
  3315. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  3316. *
  3317. * */
  3318. var isNumber = U.isNumber,
  3319. merge = U.merge,
  3320. pInt = U.pInt;
  3321. /* *
  3322. *
  3323. * Class
  3324. *
  3325. * */
  3326. /* eslint-disable no-invalid-this, valid-jsdoc */
  3327. /**
  3328. * Handle color operations. Some object methods are chainable.
  3329. *
  3330. * @class
  3331. * @name Highcharts.Color
  3332. *
  3333. * @param {Highcharts.ColorType} input
  3334. * The input color in either rbga or hex format
  3335. */
  3336. var Color = /** @class */ (function () {
  3337. /* *
  3338. *
  3339. * Constructors
  3340. *
  3341. * */
  3342. function Color(input) {
  3343. // Collection of parsers. This can be extended from the outside by pushing
  3344. // parsers to Highcharts.Color.prototype.parsers.
  3345. this.parsers = [{
  3346. // RGBA color
  3347. // eslint-disable-next-line max-len
  3348. regex: /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]?(?:\.[0-9]+)?)\s*\)/,
  3349. parse: function (result) {
  3350. return [
  3351. pInt(result[1]),
  3352. pInt(result[2]),
  3353. pInt(result[3]),
  3354. parseFloat(result[4], 10)
  3355. ];
  3356. }
  3357. }, {
  3358. // RGB color
  3359. regex: /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/,
  3360. parse: function (result) {
  3361. return [pInt(result[1]), pInt(result[2]), pInt(result[3]), 1];
  3362. }
  3363. }];
  3364. this.rgba = [];
  3365. var GlobalColor = H.Color;
  3366. // Backwards compatibility, allow class overwrite
  3367. if (GlobalColor && GlobalColor !== Color) {
  3368. return new GlobalColor(input);
  3369. }
  3370. // Backwards compatibility, allow instanciation without new (#13053)
  3371. if (!(this instanceof Color)) {
  3372. return new Color(input);
  3373. }
  3374. this.init(input);
  3375. }
  3376. /* *
  3377. *
  3378. * Static Functions
  3379. *
  3380. * */
  3381. /**
  3382. * Creates a color instance out of a color string or object.
  3383. *
  3384. * @function Highcharts.Color.parse
  3385. *
  3386. * @param {Highcharts.ColorType} input
  3387. * The input color in either rbga or hex format.
  3388. *
  3389. * @return {Highcharts.Color}
  3390. * Color instance.
  3391. */
  3392. Color.parse = function (input) {
  3393. return new Color(input);
  3394. };
  3395. /* *
  3396. *
  3397. * Functions
  3398. *
  3399. * */
  3400. /**
  3401. * Parse the input color to rgba array
  3402. *
  3403. * @private
  3404. * @function Highcharts.Color#init
  3405. *
  3406. * @param {Highcharts.ColorType} input
  3407. * The input color in either rbga or hex format
  3408. *
  3409. * @return {void}
  3410. */
  3411. Color.prototype.init = function (input) {
  3412. var result,
  3413. rgba,
  3414. i,
  3415. parser,
  3416. len;
  3417. this.input = input = Color.names[input && input.toLowerCase ?
  3418. input.toLowerCase() :
  3419. ''] || input;
  3420. // Gradients
  3421. if (input && input.stops) {
  3422. this.stops = input.stops.map(function (stop) {
  3423. return new Color(stop[1]);
  3424. });
  3425. // Solid colors
  3426. }
  3427. else {
  3428. // Bitmasking as input[0] is not working for legacy IE.
  3429. if (input &&
  3430. input.charAt &&
  3431. input.charAt() === '#') {
  3432. len = input.length;
  3433. input = parseInt(input.substr(1), 16);
  3434. // Handle long-form, e.g. #AABBCC
  3435. if (len === 7) {
  3436. rgba = [
  3437. (input & 0xFF0000) >> 16,
  3438. (input & 0xFF00) >> 8,
  3439. (input & 0xFF),
  3440. 1
  3441. ];
  3442. // Handle short-form, e.g. #ABC
  3443. // In short form, the value is assumed to be the same
  3444. // for both nibbles for each component. e.g. #ABC = #AABBCC
  3445. }
  3446. else if (len === 4) {
  3447. rgba = [
  3448. (((input & 0xF00) >> 4) |
  3449. (input & 0xF00) >> 8),
  3450. (((input & 0xF0) >> 4) |
  3451. (input & 0xF0)),
  3452. ((input & 0xF) << 4) | (input & 0xF),
  3453. 1
  3454. ];
  3455. }
  3456. }
  3457. // Otherwise, check regex parsers
  3458. if (!rgba) {
  3459. i = this.parsers.length;
  3460. while (i-- && !rgba) {
  3461. parser = this.parsers[i];
  3462. result = parser.regex.exec(input);
  3463. if (result) {
  3464. rgba = parser.parse(result);
  3465. }
  3466. }
  3467. }
  3468. }
  3469. this.rgba = rgba || [];
  3470. };
  3471. /**
  3472. * Return the color or gradient stops in the specified format
  3473. *
  3474. * @function Highcharts.Color#get
  3475. *
  3476. * @param {string} [format]
  3477. * Possible values are 'a', 'rgb', 'rgba' (default).
  3478. *
  3479. * @return {Highcharts.ColorType}
  3480. * This color as a string or gradient stops.
  3481. */
  3482. Color.prototype.get = function (format) {
  3483. var input = this.input,
  3484. rgba = this.rgba,
  3485. ret;
  3486. if (typeof this.stops !== 'undefined') {
  3487. ret = merge(input);
  3488. ret.stops = [].concat(ret.stops);
  3489. this.stops.forEach(function (stop, i) {
  3490. ret.stops[i] = [
  3491. ret.stops[i][0],
  3492. stop.get(format)
  3493. ];
  3494. });
  3495. // it's NaN if gradient colors on a column chart
  3496. }
  3497. else if (rgba && isNumber(rgba[0])) {
  3498. if (format === 'rgb' || (!format && rgba[3] === 1)) {
  3499. ret = 'rgb(' + rgba[0] + ',' + rgba[1] + ',' + rgba[2] + ')';
  3500. }
  3501. else if (format === 'a') {
  3502. ret = rgba[3];
  3503. }
  3504. else {
  3505. ret = 'rgba(' + rgba.join(',') + ')';
  3506. }
  3507. }
  3508. else {
  3509. ret = input;
  3510. }
  3511. return ret;
  3512. };
  3513. /**
  3514. * Brighten the color instance.
  3515. *
  3516. * @function Highcharts.Color#brighten
  3517. *
  3518. * @param {number} alpha
  3519. * The alpha value.
  3520. *
  3521. * @return {Highcharts.Color}
  3522. * This color with modifications.
  3523. */
  3524. Color.prototype.brighten = function (alpha) {
  3525. var i,
  3526. rgba = this.rgba;
  3527. if (this.stops) {
  3528. this.stops.forEach(function (stop) {
  3529. stop.brighten(alpha);
  3530. });
  3531. }
  3532. else if (isNumber(alpha) && alpha !== 0) {
  3533. for (i = 0; i < 3; i++) {
  3534. rgba[i] += pInt(alpha * 255);
  3535. if (rgba[i] < 0) {
  3536. rgba[i] = 0;
  3537. }
  3538. if (rgba[i] > 255) {
  3539. rgba[i] = 255;
  3540. }
  3541. }
  3542. }
  3543. return this;
  3544. };
  3545. /**
  3546. * Set the color's opacity to a given alpha value.
  3547. *
  3548. * @function Highcharts.Color#setOpacity
  3549. *
  3550. * @param {number} alpha
  3551. * Opacity between 0 and 1.
  3552. *
  3553. * @return {Highcharts.Color}
  3554. * Color with modifications.
  3555. */
  3556. Color.prototype.setOpacity = function (alpha) {
  3557. this.rgba[3] = alpha;
  3558. return this;
  3559. };
  3560. /**
  3561. * Return an intermediate color between two colors.
  3562. *
  3563. * @function Highcharts.Color#tweenTo
  3564. *
  3565. * @param {Highcharts.Color} to
  3566. * The color object to tween to.
  3567. *
  3568. * @param {number} pos
  3569. * The intermediate position, where 0 is the from color (current
  3570. * color item), and 1 is the `to` color.
  3571. *
  3572. * @return {Highcharts.ColorString}
  3573. * The intermediate color in rgba notation.
  3574. */
  3575. Color.prototype.tweenTo = function (to, pos) {
  3576. // Check for has alpha, because rgba colors perform worse due to lack of
  3577. // support in WebKit.
  3578. var fromRgba = this.rgba,
  3579. toRgba = to.rgba,
  3580. hasAlpha,
  3581. ret;
  3582. // Unsupported color, return to-color (#3920, #7034)
  3583. if (!toRgba.length || !fromRgba || !fromRgba.length) {
  3584. ret = to.input || 'none';
  3585. // Interpolate
  3586. }
  3587. else {
  3588. hasAlpha = (toRgba[3] !== 1 || fromRgba[3] !== 1);
  3589. ret = (hasAlpha ? 'rgba(' : 'rgb(') +
  3590. Math.round(toRgba[0] + (fromRgba[0] - toRgba[0]) * (1 - pos)) +
  3591. ',' +
  3592. Math.round(toRgba[1] + (fromRgba[1] - toRgba[1]) * (1 - pos)) +
  3593. ',' +
  3594. Math.round(toRgba[2] + (fromRgba[2] - toRgba[2]) * (1 - pos)) +
  3595. (hasAlpha ?
  3596. (',' +
  3597. (toRgba[3] + (fromRgba[3] - toRgba[3]) * (1 - pos))) :
  3598. '') +
  3599. ')';
  3600. }
  3601. return ret;
  3602. };
  3603. /* *
  3604. *
  3605. * Static Properties
  3606. *
  3607. * */
  3608. /**
  3609. * Collection of named colors. Can be extended from the outside by adding
  3610. * colors to Highcharts.Color.names.
  3611. * @private
  3612. */
  3613. Color.names = {
  3614. white: '#ffffff',
  3615. black: '#000000'
  3616. };
  3617. return Color;
  3618. }());
  3619. /* *
  3620. *
  3621. * Default Export
  3622. *
  3623. * */
  3624. /* *
  3625. *
  3626. * API Declarations
  3627. *
  3628. * */
  3629. /**
  3630. * A valid color to be parsed and handled by Highcharts. Highcharts internally
  3631. * supports hex colors like `#ffffff`, rgb colors like `rgb(255,255,255)` and
  3632. * rgba colors like `rgba(255,255,255,1)`. Other colors may be supported by the
  3633. * browsers and displayed correctly, but Highcharts is not able to process them
  3634. * and apply concepts like opacity and brightening.
  3635. *
  3636. * @typedef {string} Highcharts.ColorString
  3637. */
  3638. /**
  3639. * A valid color type than can be parsed and handled by Highcharts. It can be a
  3640. * color string, a gradient object, or a pattern object.
  3641. *
  3642. * @typedef {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject} Highcharts.ColorType
  3643. */
  3644. /**
  3645. * Gradient options instead of a solid color.
  3646. *
  3647. * @example
  3648. * // Linear gradient used as a color option
  3649. * color: {
  3650. * linearGradient: { x1: 0, x2: 0, y1: 0, y2: 1 },
  3651. * stops: [
  3652. * [0, '#003399'], // start
  3653. * [0.5, '#ffffff'], // middle
  3654. * [1, '#3366AA'] // end
  3655. * ]
  3656. * }
  3657. *
  3658. * @interface Highcharts.GradientColorObject
  3659. */ /**
  3660. * Holds an object that defines the start position and the end position relative
  3661. * to the shape.
  3662. * @name Highcharts.GradientColorObject#linearGradient
  3663. * @type {Highcharts.LinearGradientColorObject|undefined}
  3664. */ /**
  3665. * Holds an object that defines the center position and the radius.
  3666. * @name Highcharts.GradientColorObject#radialGradient
  3667. * @type {Highcharts.RadialGradientColorObject|undefined}
  3668. */ /**
  3669. * The first item in each tuple is the position in the gradient, where 0 is the
  3670. * start of the gradient and 1 is the end of the gradient. Multiple stops can be
  3671. * applied. The second item is the color for each stop. This color can also be
  3672. * given in the rgba format.
  3673. * @name Highcharts.GradientColorObject#stops
  3674. * @type {Array<Highcharts.GradientColorStopObject>}
  3675. */
  3676. /**
  3677. * Color stop tuple.
  3678. *
  3679. * @see Highcharts.GradientColorObject
  3680. *
  3681. * @interface Highcharts.GradientColorStopObject
  3682. */ /**
  3683. * @name Highcharts.GradientColorStopObject#0
  3684. * @type {number}
  3685. */ /**
  3686. * @name Highcharts.GradientColorStopObject#1
  3687. * @type {Highcharts.ColorString}
  3688. */ /**
  3689. * @name Highcharts.GradientColorStopObject#color
  3690. * @type {Highcharts.Color|undefined}
  3691. */
  3692. /**
  3693. * Defines the start position and the end position for a gradient relative
  3694. * to the shape. Start position (x1, y1) and end position (x2, y2) are relative
  3695. * to the shape, where 0 means top/left and 1 is bottom/right.
  3696. *
  3697. * @interface Highcharts.LinearGradientColorObject
  3698. */ /**
  3699. * Start horizontal position of the gradient. Float ranges 0-1.
  3700. * @name Highcharts.LinearGradientColorObject#x1
  3701. * @type {number}
  3702. */ /**
  3703. * End horizontal position of the gradient. Float ranges 0-1.
  3704. * @name Highcharts.LinearGradientColorObject#x2
  3705. * @type {number}
  3706. */ /**
  3707. * Start vertical position of the gradient. Float ranges 0-1.
  3708. * @name Highcharts.LinearGradientColorObject#y1
  3709. * @type {number}
  3710. */ /**
  3711. * End vertical position of the gradient. Float ranges 0-1.
  3712. * @name Highcharts.LinearGradientColorObject#y2
  3713. * @type {number}
  3714. */
  3715. /**
  3716. * Defines the center position and the radius for a gradient.
  3717. *
  3718. * @interface Highcharts.RadialGradientColorObject
  3719. */ /**
  3720. * Center horizontal position relative to the shape. Float ranges 0-1.
  3721. * @name Highcharts.RadialGradientColorObject#cx
  3722. * @type {number}
  3723. */ /**
  3724. * Center vertical position relative to the shape. Float ranges 0-1.
  3725. * @name Highcharts.RadialGradientColorObject#cy
  3726. * @type {number}
  3727. */ /**
  3728. * Radius relative to the shape. Float ranges 0-1.
  3729. * @name Highcharts.RadialGradientColorObject#r
  3730. * @type {number}
  3731. */
  3732. /**
  3733. * Creates a color instance out of a color string.
  3734. *
  3735. * @function Highcharts.color
  3736. *
  3737. * @param {Highcharts.ColorType} input
  3738. * The input color in either rbga or hex format
  3739. *
  3740. * @return {Highcharts.Color}
  3741. * Color instance
  3742. */
  3743. (''); // detach doclets above
  3744. return Color;
  3745. });
  3746. _registerModule(_modules, 'Core/Time.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
  3747. /* *
  3748. *
  3749. * (c) 2010-2021 Torstein Honsi
  3750. *
  3751. * License: www.highcharts.com/license
  3752. *
  3753. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  3754. *
  3755. * */
  3756. var win = H.win;
  3757. var defined = U.defined,
  3758. error = U.error,
  3759. extend = U.extend,
  3760. isObject = U.isObject,
  3761. merge = U.merge,
  3762. objectEach = U.objectEach,
  3763. pad = U.pad,
  3764. pick = U.pick,
  3765. splat = U.splat,
  3766. timeUnits = U.timeUnits;
  3767. /* *
  3768. *
  3769. * Constants
  3770. *
  3771. * */
  3772. var hasNewSafariBug = (H.isSafari && Intl.DateTimeFormat.prototype.formatRange);
  3773. // To do: Remove this when we no longer need support for Safari < v14.1
  3774. var hasOldSafariBug = (H.isSafari && !Intl.DateTimeFormat.prototype.formatRange);
  3775. /* *
  3776. *
  3777. * Class
  3778. *
  3779. * */
  3780. /* eslint-disable no-invalid-this, valid-jsdoc */
  3781. /**
  3782. * The Time class. Time settings are applied in general for each page using
  3783. * `Highcharts.setOptions`, or individually for each Chart item through the
  3784. * [time](https://api.highcharts.com/highcharts/time) options set.
  3785. *
  3786. * The Time object is available from {@link Highcharts.Chart#time},
  3787. * which refers to `Highcharts.time` if no individual time settings are
  3788. * applied.
  3789. *
  3790. * @example
  3791. * // Apply time settings globally
  3792. * Highcharts.setOptions({
  3793. * time: {
  3794. * timezone: 'Europe/London'
  3795. * }
  3796. * });
  3797. *
  3798. * // Apply time settings by instance
  3799. * let chart = Highcharts.chart('container', {
  3800. * time: {
  3801. * timezone: 'America/New_York'
  3802. * },
  3803. * series: [{
  3804. * data: [1, 4, 3, 5]
  3805. * }]
  3806. * });
  3807. *
  3808. * // Use the Time object
  3809. * console.log(
  3810. * 'Current time in New York',
  3811. * chart.time.dateFormat('%Y-%m-%d %H:%M:%S', Date.now())
  3812. * );
  3813. *
  3814. * @since 6.0.5
  3815. *
  3816. * @class
  3817. * @name Highcharts.Time
  3818. *
  3819. * @param {Highcharts.TimeOptions} options
  3820. * Time options as defined in [chart.options.time](/highcharts/time).
  3821. */
  3822. var Time = /** @class */ (function () {
  3823. /* *
  3824. *
  3825. * Constructors
  3826. *
  3827. * */
  3828. function Time(options) {
  3829. /* *
  3830. *
  3831. * Properties
  3832. *
  3833. * */
  3834. this.options = {};
  3835. this.useUTC = false;
  3836. this.variableTimezone = false;
  3837. this.Date = win.Date;
  3838. /**
  3839. * Get the time zone offset based on the current timezone information as
  3840. * set in the global options.
  3841. *
  3842. * @function Highcharts.Time#getTimezoneOffset
  3843. *
  3844. * @param {number} timestamp
  3845. * The JavaScript timestamp to inspect.
  3846. *
  3847. * @return {number}
  3848. * The timezone offset in minutes compared to UTC.
  3849. */
  3850. this.getTimezoneOffset = this.timezoneOffsetFunction();
  3851. this.update(options);
  3852. }
  3853. /* *
  3854. *
  3855. * Functions
  3856. *
  3857. * */
  3858. /**
  3859. * Time units used in `Time.get` and `Time.set`
  3860. *
  3861. * @typedef {"Date"|"Day"|"FullYear"|"Hours"|"Milliseconds"|"Minutes"|"Month"|"Seconds"} Highcharts.TimeUnitValue
  3862. */
  3863. /**
  3864. * Get the value of a date object in given units, and subject to the Time
  3865. * object's current timezone settings. This function corresponds directly to
  3866. * JavaScripts `Date.getXXX / Date.getUTCXXX`, so instead of calling
  3867. * `date.getHours()` or `date.getUTCHours()` we will call
  3868. * `time.get('Hours')`.
  3869. *
  3870. * @function Highcharts.Time#get
  3871. *
  3872. * @param {Highcharts.TimeUnitValue} unit
  3873. * @param {Date} date
  3874. *
  3875. * @return {number}
  3876. * The given time unit
  3877. */
  3878. Time.prototype.get = function (unit, date) {
  3879. if (this.variableTimezone || this.timezoneOffset) {
  3880. var realMs = date.getTime();
  3881. var ms = realMs - this.getTimezoneOffset(date);
  3882. date.setTime(ms); // Temporary adjust to timezone
  3883. var ret = date['getUTC' + unit]();
  3884. date.setTime(realMs); // Reset
  3885. return ret;
  3886. }
  3887. // UTC time with no timezone handling
  3888. if (this.useUTC) {
  3889. return date['getUTC' + unit]();
  3890. }
  3891. // Else, local time
  3892. return date['get' + unit]();
  3893. };
  3894. /**
  3895. * Set the value of a date object in given units, and subject to the Time
  3896. * object's current timezone settings. This function corresponds directly to
  3897. * JavaScripts `Date.setXXX / Date.setUTCXXX`, so instead of calling
  3898. * `date.setHours(0)` or `date.setUTCHours(0)` we will call
  3899. * `time.set('Hours', 0)`.
  3900. *
  3901. * @function Highcharts.Time#set
  3902. *
  3903. * @param {Highcharts.TimeUnitValue} unit
  3904. * @param {Date} date
  3905. * @param {number} value
  3906. *
  3907. * @return {number}
  3908. * The epoch milliseconds of the updated date
  3909. */
  3910. Time.prototype.set = function (unit, date, value) {
  3911. // UTC time with timezone handling
  3912. if (this.variableTimezone || this.timezoneOffset) {
  3913. // For lower order time units, just set it directly using UTC
  3914. // time
  3915. if (unit === 'Milliseconds' ||
  3916. unit === 'Seconds' ||
  3917. (unit === 'Minutes' && this.getTimezoneOffset(date) % 3600000 === 0) // #13961
  3918. ) {
  3919. return date['setUTC' + unit](value);
  3920. }
  3921. // Higher order time units need to take the time zone into
  3922. // account
  3923. // Adjust by timezone
  3924. var offset = this.getTimezoneOffset(date);
  3925. var ms = date.getTime() - offset;
  3926. date.setTime(ms);
  3927. date['setUTC' + unit](value);
  3928. var newOffset = this.getTimezoneOffset(date);
  3929. ms = date.getTime() + newOffset;
  3930. return date.setTime(ms);
  3931. }
  3932. // UTC time with no timezone handling
  3933. if (this.useUTC ||
  3934. (hasNewSafariBug && unit === 'FullYear') // leap calculation in UTC only
  3935. ) {
  3936. return date['setUTC' + unit](value);
  3937. }
  3938. // Else, local time
  3939. return date['set' + unit](value);
  3940. };
  3941. /**
  3942. * Update the Time object with current options. It is called internally on
  3943. * initializing Highcharts, after running `Highcharts.setOptions` and on
  3944. * `Chart.update`.
  3945. *
  3946. * @private
  3947. * @function Highcharts.Time#update
  3948. *
  3949. * @param {Highcharts.TimeOptions} options
  3950. *
  3951. * @return {void}
  3952. */
  3953. Time.prototype.update = function (options) {
  3954. var useUTC = pick(options && options.useUTC,
  3955. true),
  3956. time = this;
  3957. this.options = options = merge(true, this.options || {}, options);
  3958. // Allow using a different Date class
  3959. this.Date = options.Date || win.Date || Date;
  3960. this.useUTC = useUTC;
  3961. this.timezoneOffset = (useUTC && options.timezoneOffset);
  3962. this.getTimezoneOffset = this.timezoneOffsetFunction();
  3963. /*
  3964. * The time object has options allowing for variable time zones, meaning
  3965. * the axis ticks or series data needs to consider this.
  3966. */
  3967. this.variableTimezone = useUTC && !!(options.getTimezoneOffset ||
  3968. options.timezone);
  3969. };
  3970. /**
  3971. * Make a time and returns milliseconds. Interprets the inputs as UTC time,
  3972. * local time or a specific timezone time depending on the current time
  3973. * settings.
  3974. *
  3975. * @function Highcharts.Time#makeTime
  3976. *
  3977. * @param {number} year
  3978. * The year
  3979. *
  3980. * @param {number} month
  3981. * The month. Zero-based, so January is 0.
  3982. *
  3983. * @param {number} [date=1]
  3984. * The day of the month
  3985. *
  3986. * @param {number} [hours=0]
  3987. * The hour of the day, 0-23.
  3988. *
  3989. * @param {number} [minutes=0]
  3990. * The minutes
  3991. *
  3992. * @param {number} [seconds=0]
  3993. * The seconds
  3994. *
  3995. * @return {number}
  3996. * The time in milliseconds since January 1st 1970.
  3997. */
  3998. Time.prototype.makeTime = function (year, month, date, hours, minutes, seconds) {
  3999. var d,
  4000. offset,
  4001. newOffset;
  4002. if (this.useUTC) {
  4003. d = this.Date.UTC.apply(0, arguments);
  4004. offset = this.getTimezoneOffset(d);
  4005. d += offset;
  4006. newOffset = this.getTimezoneOffset(d);
  4007. if (offset !== newOffset) {
  4008. d += newOffset - offset;
  4009. // A special case for transitioning from summer time to winter time.
  4010. // When the clock is set back, the same time is repeated twice, i.e.
  4011. // 02:30 am is repeated since the clock is set back from 3 am to
  4012. // 2 am. We need to make the same time as local Date does.
  4013. }
  4014. else if (offset - 36e5 === this.getTimezoneOffset(d - 36e5) &&
  4015. !hasOldSafariBug) {
  4016. d -= 36e5;
  4017. }
  4018. }
  4019. else {
  4020. d = new this.Date(year, month, pick(date, 1), pick(hours, 0), pick(minutes, 0), pick(seconds, 0)).getTime();
  4021. }
  4022. return d;
  4023. };
  4024. /**
  4025. * Sets the getTimezoneOffset function. If the `timezone` option is set, a
  4026. * default getTimezoneOffset function with that timezone is returned. If
  4027. * a `getTimezoneOffset` option is defined, it is returned. If neither are
  4028. * specified, the function using the `timezoneOffset` option or 0 offset is
  4029. * returned.
  4030. *
  4031. * @private
  4032. * @function Highcharts.Time#timezoneOffsetFunction
  4033. *
  4034. * @return {Function}
  4035. * A getTimezoneOffset function
  4036. */
  4037. Time.prototype.timezoneOffsetFunction = function () {
  4038. var time = this,
  4039. options = this.options,
  4040. moment = options.moment || win.moment;
  4041. if (!this.useUTC) {
  4042. return function (timestamp) {
  4043. return new Date(timestamp.toString()).getTimezoneOffset() * 60000;
  4044. };
  4045. }
  4046. if (options.timezone) {
  4047. if (!moment) {
  4048. // getTimezoneOffset-function stays undefined because it depends
  4049. // on Moment.js
  4050. error(25);
  4051. }
  4052. else {
  4053. return function (timestamp) {
  4054. return -moment.tz(timestamp, options.timezone).utcOffset() * 60000;
  4055. };
  4056. }
  4057. }
  4058. // If not timezone is set, look for the getTimezoneOffset callback
  4059. if (this.useUTC && options.getTimezoneOffset) {
  4060. return function (timestamp) {
  4061. return options.getTimezoneOffset(timestamp.valueOf()) * 60000;
  4062. };
  4063. }
  4064. // Last, use the `timezoneOffset` option if set
  4065. return function () {
  4066. return (time.timezoneOffset || 0) * 60000;
  4067. };
  4068. };
  4069. /**
  4070. * Formats a JavaScript date timestamp (milliseconds since Jan 1st 1970)
  4071. * into a human readable date string. The available format keys are listed
  4072. * below. Additional formats can be given in the
  4073. * {@link Highcharts.dateFormats} hook.
  4074. *
  4075. * Supported format keys:
  4076. * - `%a`: Short weekday, like 'Mon'
  4077. * - `%A`: Long weekday, like 'Monday'
  4078. * - `%d`: Two digit day of the month, 01 to 31
  4079. * - `%e`: Day of the month, 1 through 31
  4080. * - `%w`: Day of the week, 0 through 6
  4081. * - `%b`: Short month, like 'Jan'
  4082. * - `%B`: Long month, like 'January'
  4083. * - `%m`: Two digit month number, 01 through 12
  4084. * - `%y`: Two digits year, like 09 for 2009
  4085. * - `%Y`: Four digits year, like 2009
  4086. * - `%H`: Two digits hours in 24h format, 00 through 23
  4087. * - `%k`: Hours in 24h format, 0 through 23
  4088. * - `%I`: Two digits hours in 12h format, 00 through 11
  4089. * - `%l`: Hours in 12h format, 1 through 12
  4090. * - `%M`: Two digits minutes, 00 through 59
  4091. * - `%p`: Upper case AM or PM
  4092. * - `%P`: Lower case AM or PM
  4093. * - `%S`: Two digits seconds, 00 through 59
  4094. * - `%L`: Milliseconds (naming from Ruby)
  4095. *
  4096. * @example
  4097. * const time = new Highcharts.Time();
  4098. * const s = time.dateFormat('%Y-%m-%d %H:%M:%S', Date.UTC(2020, 0, 1));
  4099. * console.log(s); // => 2020-01-01 00:00:00
  4100. *
  4101. * @function Highcharts.Time#dateFormat
  4102. *
  4103. * @param {string} format
  4104. * The desired format where various time representations are
  4105. * prefixed with %.
  4106. *
  4107. * @param {number} [timestamp]
  4108. * The JavaScript timestamp.
  4109. *
  4110. * @param {boolean} [capitalize=false]
  4111. * Upper case first letter in the return.
  4112. *
  4113. * @return {string}
  4114. * The formatted date.
  4115. */
  4116. Time.prototype.dateFormat = function (format, timestamp, capitalize) {
  4117. if (!defined(timestamp) || isNaN(timestamp)) {
  4118. return (H.defaultOptions.lang &&
  4119. H.defaultOptions.lang.invalidDate ||
  4120. '');
  4121. }
  4122. format = pick(format, '%Y-%m-%d %H:%M:%S');
  4123. var time = this, date = new this.Date(timestamp),
  4124. // get the basic time values
  4125. hours = this.get('Hours', date), day = this.get('Day', date), dayOfMonth = this.get('Date', date), month = this.get('Month', date), fullYear = this.get('FullYear', date), lang = H.defaultOptions.lang, langWeekdays = (lang && lang.weekdays), shortWeekdays = (lang && lang.shortWeekdays),
  4126. // List all format keys. Custom formats can be added from the
  4127. // outside.
  4128. replacements = extend({
  4129. // Day
  4130. // Short weekday, like 'Mon'
  4131. a: shortWeekdays ?
  4132. shortWeekdays[day] :
  4133. langWeekdays[day].substr(0, 3),
  4134. // Long weekday, like 'Monday'
  4135. A: langWeekdays[day],
  4136. // Two digit day of the month, 01 to 31
  4137. d: pad(dayOfMonth),
  4138. // Day of the month, 1 through 31
  4139. e: pad(dayOfMonth, 2, ' '),
  4140. // Day of the week, 0 through 6
  4141. w: day,
  4142. // Week (none implemented)
  4143. // 'W': weekNumber(),
  4144. // Month
  4145. // Short month, like 'Jan'
  4146. b: lang.shortMonths[month],
  4147. // Long month, like 'January'
  4148. B: lang.months[month],
  4149. // Two digit month number, 01 through 12
  4150. m: pad(month + 1),
  4151. // Month number, 1 through 12 (#8150)
  4152. o: month + 1,
  4153. // Year
  4154. // Two digits year, like 09 for 2009
  4155. y: fullYear.toString().substr(2, 2),
  4156. // Four digits year, like 2009
  4157. Y: fullYear,
  4158. // Time
  4159. // Two digits hours in 24h format, 00 through 23
  4160. H: pad(hours),
  4161. // Hours in 24h format, 0 through 23
  4162. k: hours,
  4163. // Two digits hours in 12h format, 00 through 11
  4164. I: pad((hours % 12) || 12),
  4165. // Hours in 12h format, 1 through 12
  4166. l: (hours % 12) || 12,
  4167. // Two digits minutes, 00 through 59
  4168. M: pad(this.get('Minutes', date)),
  4169. // Upper case AM or PM
  4170. p: hours < 12 ? 'AM' : 'PM',
  4171. // Lower case AM or PM
  4172. P: hours < 12 ? 'am' : 'pm',
  4173. // Two digits seconds, 00 through 59
  4174. S: pad(date.getSeconds()),
  4175. // Milliseconds (naming from Ruby)
  4176. L: pad(Math.floor(timestamp % 1000), 3)
  4177. }, H.dateFormats);
  4178. // Do the replaces
  4179. objectEach(replacements, function (val, key) {
  4180. // Regex would do it in one line, but this is faster
  4181. while (format.indexOf('%' + key) !== -1) {
  4182. format = format.replace('%' + key, typeof val === 'function' ? val.call(time, timestamp) : val);
  4183. }
  4184. });
  4185. // Optionally capitalize the string and return
  4186. return capitalize ?
  4187. (format.substr(0, 1).toUpperCase() +
  4188. format.substr(1)) :
  4189. format;
  4190. };
  4191. /**
  4192. * Resolve legacy formats of dateTimeLabelFormats (strings and arrays) into
  4193. * an object.
  4194. * @private
  4195. * @param {string|Array<T>|Highcharts.Dictionary<T>} f - General format description
  4196. * @return {Highcharts.Dictionary<T>} - The object definition
  4197. */
  4198. Time.prototype.resolveDTLFormat = function (f) {
  4199. if (!isObject(f, true)) { // check for string or array
  4200. f = splat(f);
  4201. return {
  4202. main: f[0],
  4203. from: f[1],
  4204. to: f[2]
  4205. };
  4206. }
  4207. return f;
  4208. };
  4209. /**
  4210. * Return an array with time positions distributed on round time values
  4211. * right and right after min and max. Used in datetime axes as well as for
  4212. * grouping data on a datetime axis.
  4213. *
  4214. * @function Highcharts.Time#getTimeTicks
  4215. *
  4216. * @param {Highcharts.TimeNormalizedObject} normalizedInterval
  4217. * The interval in axis values (ms) and the count
  4218. *
  4219. * @param {number} [min]
  4220. * The minimum in axis values
  4221. *
  4222. * @param {number} [max]
  4223. * The maximum in axis values
  4224. *
  4225. * @param {number} [startOfWeek=1]
  4226. *
  4227. * @return {Highcharts.AxisTickPositionsArray}
  4228. */
  4229. Time.prototype.getTimeTicks = function (normalizedInterval, min, max, startOfWeek) {
  4230. var time = this,
  4231. Date = time.Date,
  4232. tickPositions = [],
  4233. higherRanks = {},
  4234. // When crossing DST, use the max. Resolves #6278.
  4235. minDate = new Date(min),
  4236. interval = normalizedInterval.unitRange,
  4237. count = normalizedInterval.count || 1;
  4238. var i,
  4239. minYear, // used in months and years as a basis for Date.UTC()
  4240. variableDayLength,
  4241. minDay;
  4242. startOfWeek = pick(startOfWeek, 1);
  4243. if (defined(min)) { // #1300
  4244. time.set('Milliseconds', minDate, interval >= timeUnits.second ?
  4245. 0 : // #3935
  4246. count * Math.floor(time.get('Milliseconds', minDate) / count)); // #3652, #3654
  4247. if (interval >= timeUnits.second) { // second
  4248. time.set('Seconds', minDate, interval >= timeUnits.minute ?
  4249. 0 : // #3935
  4250. count * Math.floor(time.get('Seconds', minDate) / count));
  4251. }
  4252. if (interval >= timeUnits.minute) { // minute
  4253. time.set('Minutes', minDate, interval >= timeUnits.hour ?
  4254. 0 :
  4255. count * Math.floor(time.get('Minutes', minDate) / count));
  4256. }
  4257. if (interval >= timeUnits.hour) { // hour
  4258. time.set('Hours', minDate, interval >= timeUnits.day ?
  4259. 0 :
  4260. count * Math.floor(time.get('Hours', minDate) / count));
  4261. }
  4262. if (interval >= timeUnits.day) { // day
  4263. time.set('Date', minDate, interval >= timeUnits.month ?
  4264. 1 :
  4265. Math.max(1, count * Math.floor(time.get('Date', minDate) / count)));
  4266. }
  4267. if (interval >= timeUnits.month) { // month
  4268. time.set('Month', minDate, interval >= timeUnits.year ? 0 :
  4269. count * Math.floor(time.get('Month', minDate) / count));
  4270. minYear = time.get('FullYear', minDate);
  4271. }
  4272. if (interval >= timeUnits.year) { // year
  4273. minYear -= minYear % count;
  4274. time.set('FullYear', minDate, minYear);
  4275. }
  4276. // week is a special case that runs outside the hierarchy
  4277. if (interval === timeUnits.week) {
  4278. // get start of current week, independent of count
  4279. minDay = time.get('Day', minDate);
  4280. time.set('Date', minDate, (time.get('Date', minDate) -
  4281. minDay + startOfWeek +
  4282. // We don't want to skip days that are before
  4283. // startOfWeek (#7051)
  4284. (minDay < startOfWeek ? -7 : 0)));
  4285. }
  4286. // Get basics for variable time spans
  4287. minYear = time.get('FullYear', minDate);
  4288. var minMonth = time.get('Month', minDate), minDateDate = time.get('Date', minDate), minHours = time.get('Hours', minDate);
  4289. // Redefine min to the floored/rounded minimum time (#7432)
  4290. min = minDate.getTime();
  4291. // Handle local timezone offset
  4292. if ((time.variableTimezone || !time.useUTC) && defined(max)) {
  4293. // Detect whether we need to take the DST crossover into
  4294. // consideration. If we're crossing over DST, the day length may
  4295. // be 23h or 25h and we need to compute the exact clock time for
  4296. // each tick instead of just adding hours. This comes at a cost,
  4297. // so first we find out if it is needed (#4951).
  4298. variableDayLength = (
  4299. // Long range, assume we're crossing over.
  4300. max - min > 4 * timeUnits.month ||
  4301. // Short range, check if min and max are in different time
  4302. // zones.
  4303. time.getTimezoneOffset(min) !==
  4304. time.getTimezoneOffset(max));
  4305. }
  4306. // Iterate and add tick positions at appropriate values
  4307. var t = minDate.getTime();
  4308. i = 1;
  4309. while (t < max) {
  4310. tickPositions.push(t);
  4311. // if the interval is years, use Date.UTC to increase years
  4312. if (interval === timeUnits.year) {
  4313. t = time.makeTime(minYear + i * count, 0);
  4314. // if the interval is months, use Date.UTC to increase months
  4315. }
  4316. else if (interval === timeUnits.month) {
  4317. t = time.makeTime(minYear, minMonth + i * count);
  4318. // if we're using global time, the interval is not fixed as it
  4319. // jumps one hour at the DST crossover
  4320. }
  4321. else if (variableDayLength &&
  4322. (interval === timeUnits.day || interval === timeUnits.week)) {
  4323. t = time.makeTime(minYear, minMonth, minDateDate +
  4324. i * count * (interval === timeUnits.day ? 1 : 7));
  4325. }
  4326. else if (variableDayLength &&
  4327. interval === timeUnits.hour &&
  4328. count > 1) {
  4329. // make sure higher ranks are preserved across DST (#6797,
  4330. // #7621)
  4331. t = time.makeTime(minYear, minMonth, minDateDate, minHours + i * count);
  4332. // else, the interval is fixed and we use simple addition
  4333. }
  4334. else {
  4335. t += interval * count;
  4336. }
  4337. i++;
  4338. }
  4339. // push the last time
  4340. tickPositions.push(t);
  4341. // Handle higher ranks. Mark new days if the time is on midnight
  4342. // (#950, #1649, #1760, #3349). Use a reasonable dropout threshold
  4343. // to prevent looping over dense data grouping (#6156).
  4344. if (interval <= timeUnits.hour && tickPositions.length < 10000) {
  4345. tickPositions.forEach(function (t) {
  4346. if (
  4347. // Speed optimization, no need to run dateFormat unless
  4348. // we're on a full or half hour
  4349. t % 1800000 === 0 &&
  4350. // Check for local or global midnight
  4351. time.dateFormat('%H%M%S%L', t) === '000000000') {
  4352. higherRanks[t] = 'day';
  4353. }
  4354. });
  4355. }
  4356. }
  4357. // record information on the chosen unit - for dynamic label formatter
  4358. tickPositions.info = extend(normalizedInterval, {
  4359. higherRanks: higherRanks,
  4360. totalRange: interval * count
  4361. });
  4362. return tickPositions;
  4363. };
  4364. return Time;
  4365. }());
  4366. /**
  4367. * Normalized interval.
  4368. *
  4369. * @interface Highcharts.TimeNormalizedObject
  4370. */ /**
  4371. * The count.
  4372. *
  4373. * @name Highcharts.TimeNormalizedObject#count
  4374. * @type {number}
  4375. */ /**
  4376. * The interval in axis values (ms).
  4377. *
  4378. * @name Highcharts.TimeNormalizedObject#unitRange
  4379. * @type {number}
  4380. */
  4381. /**
  4382. * Function of an additional date format specifier.
  4383. *
  4384. * @callback Highcharts.TimeFormatCallbackFunction
  4385. *
  4386. * @param {number} timestamp
  4387. * The time to format.
  4388. *
  4389. * @return {string}
  4390. * The formatted portion of the date.
  4391. */
  4392. /**
  4393. * Time ticks.
  4394. *
  4395. * @interface Highcharts.AxisTickPositionsArray
  4396. * @extends global.Array<number>
  4397. */ /**
  4398. * @name Highcharts.AxisTickPositionsArray#info
  4399. * @type {Highcharts.TimeTicksInfoObject|undefined}
  4400. */
  4401. /**
  4402. * A callback to return the time zone offset for a given datetime. It
  4403. * takes the timestamp in terms of milliseconds since January 1 1970,
  4404. * and returns the timezone offset in minutes. This provides a hook
  4405. * for drawing time based charts in specific time zones using their
  4406. * local DST crossover dates, with the help of external libraries.
  4407. *
  4408. * @callback Highcharts.TimezoneOffsetCallbackFunction
  4409. *
  4410. * @param {number} timestamp
  4411. * Timestamp in terms of milliseconds since January 1 1970.
  4412. *
  4413. * @return {number}
  4414. * Timezone offset in minutes.
  4415. */
  4416. /**
  4417. * Allows to manually load the `moment.js` library from Highcharts options
  4418. * instead of the `window`.
  4419. * In case of loading the library from a `script` tag,
  4420. * this option is not needed, it will be loaded from there by default.
  4421. *
  4422. * @type {function}
  4423. * @since 8.2.0
  4424. * @apioption time.moment
  4425. */
  4426. ''; // keeps doclets above in JS file
  4427. return Time;
  4428. });
  4429. _registerModule(_modules, 'Core/DefaultOptions.js', [_modules['Core/Globals.js'], _modules['Core/Chart/ChartDefaults.js'], _modules['Core/Color/Color.js'], _modules['Core/Color/Palette.js'], _modules['Core/Time.js'], _modules['Core/Utilities.js']], function (H, ChartDefaults, Color, palette, Time, U) {
  4430. /* *
  4431. *
  4432. * (c) 2010-2021 Torstein Honsi
  4433. *
  4434. * License: www.highcharts.com/license
  4435. *
  4436. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  4437. *
  4438. * */
  4439. var isTouchDevice = H.isTouchDevice,
  4440. svg = H.svg;
  4441. var color = Color.parse;
  4442. var merge = U.merge;
  4443. /* *
  4444. *
  4445. * API Declarations
  4446. *
  4447. * */
  4448. /**
  4449. * @typedef {"plotBox"|"spacingBox"} Highcharts.ButtonRelativeToValue
  4450. */
  4451. /**
  4452. * Gets fired when a series is added to the chart after load time, using the
  4453. * `addSeries` method. Returning `false` prevents the series from being added.
  4454. *
  4455. * @callback Highcharts.ChartAddSeriesCallbackFunction
  4456. *
  4457. * @param {Highcharts.Chart} this
  4458. * The chart on which the event occured.
  4459. *
  4460. * @param {Highcharts.ChartAddSeriesEventObject} event
  4461. * The event that occured.
  4462. */
  4463. /**
  4464. * Contains common event information. Through the `options` property you can
  4465. * access the series options that were passed to the `addSeries` method.
  4466. *
  4467. * @interface Highcharts.ChartAddSeriesEventObject
  4468. */ /**
  4469. * The series options that were passed to the `addSeries` method.
  4470. * @name Highcharts.ChartAddSeriesEventObject#options
  4471. * @type {Highcharts.SeriesOptionsType}
  4472. */ /**
  4473. * Prevents the default behaviour of the event.
  4474. * @name Highcharts.ChartAddSeriesEventObject#preventDefault
  4475. * @type {Function}
  4476. */ /**
  4477. * The event target.
  4478. * @name Highcharts.ChartAddSeriesEventObject#target
  4479. * @type {Highcharts.Chart}
  4480. */ /**
  4481. * The event type.
  4482. * @name Highcharts.ChartAddSeriesEventObject#type
  4483. * @type {"addSeries"}
  4484. */
  4485. /**
  4486. * Gets fired when clicking on the plot background.
  4487. *
  4488. * @callback Highcharts.ChartClickCallbackFunction
  4489. *
  4490. * @param {Highcharts.Chart} this
  4491. * The chart on which the event occured.
  4492. *
  4493. * @param {Highcharts.PointerEventObject} event
  4494. * The event that occured.
  4495. */
  4496. /**
  4497. * Contains an axes of the clicked spot.
  4498. *
  4499. * @interface Highcharts.ChartClickEventAxisObject
  4500. */ /**
  4501. * Axis at the clicked spot.
  4502. * @name Highcharts.ChartClickEventAxisObject#axis
  4503. * @type {Highcharts.Axis}
  4504. */ /**
  4505. * Axis value at the clicked spot.
  4506. * @name Highcharts.ChartClickEventAxisObject#value
  4507. * @type {number}
  4508. */
  4509. /**
  4510. * Contains information about the clicked spot on the chart. Remember the unit
  4511. * of a datetime axis is milliseconds since 1970-01-01 00:00:00.
  4512. *
  4513. * @interface Highcharts.ChartClickEventObject
  4514. * @extends Highcharts.PointerEventObject
  4515. */ /**
  4516. * Information about the x-axis on the clicked spot.
  4517. * @name Highcharts.ChartClickEventObject#xAxis
  4518. * @type {Array<Highcharts.ChartClickEventAxisObject>}
  4519. */ /**
  4520. * Information about the y-axis on the clicked spot.
  4521. * @name Highcharts.ChartClickEventObject#yAxis
  4522. * @type {Array<Highcharts.ChartClickEventAxisObject>}
  4523. */ /**
  4524. * Information about the z-axis on the clicked spot.
  4525. * @name Highcharts.ChartClickEventObject#zAxis
  4526. * @type {Array<Highcharts.ChartClickEventAxisObject>|undefined}
  4527. */
  4528. /**
  4529. * Gets fired when the chart is finished loading.
  4530. *
  4531. * @callback Highcharts.ChartLoadCallbackFunction
  4532. *
  4533. * @param {Highcharts.Chart} this
  4534. * The chart on which the event occured.
  4535. *
  4536. * @param {global.Event} event
  4537. * The event that occured.
  4538. */
  4539. /**
  4540. * Fires when the chart is redrawn, either after a call to `chart.redraw()` or
  4541. * after an axis, series or point is modified with the `redraw` option set to
  4542. * `true`.
  4543. *
  4544. * @callback Highcharts.ChartRedrawCallbackFunction
  4545. *
  4546. * @param {Highcharts.Chart} this
  4547. * The chart on which the event occured.
  4548. *
  4549. * @param {global.Event} event
  4550. * The event that occured.
  4551. */
  4552. /**
  4553. * Gets fired after initial load of the chart (directly after the `load` event),
  4554. * and after each redraw (directly after the `redraw` event).
  4555. *
  4556. * @callback Highcharts.ChartRenderCallbackFunction
  4557. *
  4558. * @param {Highcharts.Chart} this
  4559. * The chart on which the event occured.
  4560. *
  4561. * @param {global.Event} event
  4562. * The event that occured.
  4563. */
  4564. /**
  4565. * Gets fired when an area of the chart has been selected. The default action
  4566. * for the selection event is to zoom the chart to the selected area. It can be
  4567. * prevented by calling `event.preventDefault()` or return false.
  4568. *
  4569. * @callback Highcharts.ChartSelectionCallbackFunction
  4570. *
  4571. * @param {Highcharts.Chart} this
  4572. * The chart on which the event occured.
  4573. *
  4574. * @param {global.ChartSelectionContextObject} event
  4575. * Event informations
  4576. *
  4577. * @return {boolean|undefined}
  4578. * Return false to prevent the default action, usually zoom.
  4579. */
  4580. /**
  4581. * The primary axes are `xAxis[0]` and `yAxis[0]`. Remember the unit of a
  4582. * datetime axis is milliseconds since 1970-01-01 00:00:00.
  4583. *
  4584. * @interface Highcharts.ChartSelectionContextObject
  4585. * @extends global.Event
  4586. */ /**
  4587. * Arrays containing the axes of each dimension and each axis' min and max
  4588. * values.
  4589. * @name Highcharts.ChartSelectionContextObject#xAxis
  4590. * @type {Array<Highcharts.ChartSelectionAxisContextObject>}
  4591. */ /**
  4592. * Arrays containing the axes of each dimension and each axis' min and max
  4593. * values.
  4594. * @name Highcharts.ChartSelectionContextObject#yAxis
  4595. * @type {Array<Highcharts.ChartSelectionAxisContextObject>}
  4596. */
  4597. /**
  4598. * Axis context of the selection.
  4599. *
  4600. * @interface Highcharts.ChartSelectionAxisContextObject
  4601. */ /**
  4602. * The selected Axis.
  4603. * @name Highcharts.ChartSelectionAxisContextObject#axis
  4604. * @type {Highcharts.Axis}
  4605. */ /**
  4606. * The maximum axis value, either automatic or set manually.
  4607. * @name Highcharts.ChartSelectionAxisContextObject#max
  4608. * @type {number}
  4609. */ /**
  4610. * The minimum axis value, either automatic or set manually.
  4611. * @name Highcharts.ChartSelectionAxisContextObject#min
  4612. * @type {number}
  4613. */
  4614. (''); // detach doclets above
  4615. /* *
  4616. *
  4617. * API Options
  4618. *
  4619. * */
  4620. /**
  4621. * Global default settings.
  4622. *
  4623. * @name Highcharts.defaultOptions
  4624. * @type {Highcharts.Options}
  4625. */ /**
  4626. * @optionparent
  4627. */
  4628. var defaultOptions = {
  4629. /**
  4630. * An array containing the default colors for the chart's series. When
  4631. * all colors are used, new colors are pulled from the start again.
  4632. *
  4633. * Default colors can also be set on a series or series.type basis,
  4634. * see [column.colors](#plotOptions.column.colors),
  4635. * [pie.colors](#plotOptions.pie.colors).
  4636. *
  4637. * In styled mode, the colors option doesn't exist. Instead, colors
  4638. * are defined in CSS and applied either through series or point class
  4639. * names, or through the [chart.colorCount](#chart.colorCount) option.
  4640. *
  4641. *
  4642. * ### Legacy
  4643. *
  4644. * In Highcharts 3.x, the default colors were:
  4645. * ```js
  4646. * colors: ['#2f7ed8', '#0d233a', '#8bbc21', '#910000', '#1aadce',
  4647. * '#492970', '#f28f43', '#77a1e5', '#c42525', '#a6c96a']
  4648. * ```
  4649. *
  4650. * In Highcharts 2.x, the default colors were:
  4651. * ```js
  4652. * colors: ['#4572A7', '#AA4643', '#89A54E', '#80699B', '#3D96AE',
  4653. * '#DB843D', '#92A8CD', '#A47D7C', '#B5CA92']
  4654. * ```
  4655. *
  4656. * @sample {highcharts} highcharts/chart/colors/
  4657. * Assign a global color theme
  4658. *
  4659. * @type {Array<Highcharts.ColorString>}
  4660. * @default ["#7cb5ec", "#434348", "#90ed7d", "#f7a35c", "#8085e9",
  4661. * "#f15c80", "#e4d354", "#2b908f", "#f45b5b", "#91e8e1"]
  4662. */
  4663. colors: palette.colors,
  4664. /**
  4665. * Styled mode only. Configuration object for adding SVG definitions for
  4666. * reusable elements. See [gradients, shadows and
  4667. * patterns](https://www.highcharts.com/docs/chart-design-and-style/gradients-shadows-and-patterns)
  4668. * for more information and code examples.
  4669. *
  4670. * @type {*}
  4671. * @since 5.0.0
  4672. * @apioption defs
  4673. */
  4674. /**
  4675. * @ignore-option
  4676. */
  4677. symbols: ['circle', 'diamond', 'square', 'triangle', 'triangle-down'],
  4678. /**
  4679. * The language object is global and it can't be set on each chart
  4680. * initialization. Instead, use `Highcharts.setOptions` to set it before any
  4681. * chart is initialized.
  4682. *
  4683. * ```js
  4684. * Highcharts.setOptions({
  4685. * lang: {
  4686. * months: [
  4687. * 'Janvier', 'Février', 'Mars', 'Avril',
  4688. * 'Mai', 'Juin', 'Juillet', 'Août',
  4689. * 'Septembre', 'Octobre', 'Novembre', 'Décembre'
  4690. * ],
  4691. * weekdays: [
  4692. * 'Dimanche', 'Lundi', 'Mardi', 'Mercredi',
  4693. * 'Jeudi', 'Vendredi', 'Samedi'
  4694. * ]
  4695. * }
  4696. * });
  4697. * ```
  4698. */
  4699. lang: {
  4700. /**
  4701. * The loading text that appears when the chart is set into the loading
  4702. * state following a call to `chart.showLoading`.
  4703. */
  4704. loading: 'Loading...',
  4705. /**
  4706. * An array containing the months names. Corresponds to the `%B` format
  4707. * in `Highcharts.dateFormat()`.
  4708. *
  4709. * @type {Array<string>}
  4710. * @default ["January", "February", "March", "April", "May", "June",
  4711. * "July", "August", "September", "October", "November",
  4712. * "December"]
  4713. */
  4714. months: [
  4715. 'January', 'February', 'March', 'April', 'May', 'June', 'July',
  4716. 'August', 'September', 'October', 'November', 'December'
  4717. ],
  4718. /**
  4719. * An array containing the months names in abbreviated form. Corresponds
  4720. * to the `%b` format in `Highcharts.dateFormat()`.
  4721. *
  4722. * @type {Array<string>}
  4723. * @default ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
  4724. * "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
  4725. */
  4726. shortMonths: [
  4727. 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul',
  4728. 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
  4729. ],
  4730. /**
  4731. * An array containing the weekday names.
  4732. *
  4733. * @type {Array<string>}
  4734. * @default ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
  4735. * "Friday", "Saturday"]
  4736. */
  4737. weekdays: [
  4738. 'Sunday', 'Monday', 'Tuesday', 'Wednesday',
  4739. 'Thursday', 'Friday', 'Saturday'
  4740. ],
  4741. /**
  4742. * Short week days, starting Sunday. If not specified, Highcharts uses
  4743. * the first three letters of the `lang.weekdays` option.
  4744. *
  4745. * @sample highcharts/lang/shortweekdays/
  4746. * Finnish two-letter abbreviations
  4747. *
  4748. * @type {Array<string>}
  4749. * @since 4.2.4
  4750. * @apioption lang.shortWeekdays
  4751. */
  4752. /**
  4753. * What to show in a date field for invalid dates. Defaults to an empty
  4754. * string.
  4755. *
  4756. * @type {string}
  4757. * @since 4.1.8
  4758. * @product highcharts highstock
  4759. * @apioption lang.invalidDate
  4760. */
  4761. /**
  4762. * The title appearing on hovering the zoom in button. The text itself
  4763. * defaults to "+" and can be changed in the button options.
  4764. *
  4765. * @type {string}
  4766. * @default Zoom in
  4767. * @product highmaps
  4768. * @apioption lang.zoomIn
  4769. */
  4770. /**
  4771. * The title appearing on hovering the zoom out button. The text itself
  4772. * defaults to "-" and can be changed in the button options.
  4773. *
  4774. * @type {string}
  4775. * @default Zoom out
  4776. * @product highmaps
  4777. * @apioption lang.zoomOut
  4778. */
  4779. /**
  4780. * The default decimal point used in the `Highcharts.numberFormat`
  4781. * method unless otherwise specified in the function arguments.
  4782. *
  4783. * @since 1.2.2
  4784. */
  4785. decimalPoint: '.',
  4786. /**
  4787. * [Metric prefixes](https://en.wikipedia.org/wiki/Metric_prefix) used
  4788. * to shorten high numbers in axis labels. Replacing any of the
  4789. * positions with `null` causes the full number to be written. Setting
  4790. * `numericSymbols` to `null` disables shortening altogether.
  4791. *
  4792. * @sample {highcharts} highcharts/lang/numericsymbols/
  4793. * Replacing the symbols with text
  4794. * @sample {highstock} highcharts/lang/numericsymbols/
  4795. * Replacing the symbols with text
  4796. *
  4797. * @type {Array<string>}
  4798. * @default ["k", "M", "G", "T", "P", "E"]
  4799. * @since 2.3.0
  4800. */
  4801. numericSymbols: ['k', 'M', 'G', 'T', 'P', 'E'],
  4802. /**
  4803. * The magnitude of [numericSymbols](#lang.numericSymbol) replacements.
  4804. * Use 10000 for Japanese, Korean and various Chinese locales, which
  4805. * use symbols for 10^4, 10^8 and 10^12.
  4806. *
  4807. * @sample highcharts/lang/numericsymbolmagnitude/
  4808. * 10000 magnitude for Japanese
  4809. *
  4810. * @type {number}
  4811. * @default 1000
  4812. * @since 5.0.3
  4813. * @apioption lang.numericSymbolMagnitude
  4814. */
  4815. /**
  4816. * The text for the label appearing when a chart is zoomed.
  4817. *
  4818. * @since 1.2.4
  4819. */
  4820. resetZoom: 'Reset zoom',
  4821. /**
  4822. * The tooltip title for the label appearing when a chart is zoomed.
  4823. *
  4824. * @since 1.2.4
  4825. */
  4826. resetZoomTitle: 'Reset zoom level 1:1',
  4827. /**
  4828. * The default thousands separator used in the `Highcharts.numberFormat`
  4829. * method unless otherwise specified in the function arguments. Defaults
  4830. * to a single space character, which is recommended in
  4831. * [ISO 31-0](https://en.wikipedia.org/wiki/ISO_31-0#Numbers) and works
  4832. * across Anglo-American and continental European languages.
  4833. *
  4834. * @default \u0020
  4835. * @since 1.2.2
  4836. */
  4837. thousandsSep: ' '
  4838. },
  4839. /**
  4840. * Global options that don't apply to each chart. These options, like
  4841. * the `lang` options, must be set using the `Highcharts.setOptions`
  4842. * method.
  4843. *
  4844. * ```js
  4845. * Highcharts.setOptions({
  4846. * global: {
  4847. * useUTC: false
  4848. * }
  4849. * });
  4850. * ```
  4851. */
  4852. /**
  4853. * _Canvg rendering for Android 2.x is removed as of Highcharts 5.0\.
  4854. * Use the [libURL](#exporting.libURL) option to configure exporting._
  4855. *
  4856. * The URL to the additional file to lazy load for Android 2.x devices.
  4857. * These devices don't support SVG, so we download a helper file that
  4858. * contains [canvg](https://github.com/canvg/canvg), its dependency
  4859. * rbcolor, and our own CanVG Renderer class. To avoid hotlinking to
  4860. * our site, you can install canvas-tools.js on your own server and
  4861. * change this option accordingly.
  4862. *
  4863. * @deprecated
  4864. *
  4865. * @type {string}
  4866. * @default https://code.highcharts.com/{version}/modules/canvas-tools.js
  4867. * @product highcharts highmaps
  4868. * @apioption global.canvasToolsURL
  4869. */
  4870. /**
  4871. * This option is deprecated since v6.0.5. Instead, use
  4872. * [time.useUTC](#time.useUTC) that supports individual time settings
  4873. * per chart.
  4874. *
  4875. * @deprecated
  4876. *
  4877. * @type {boolean}
  4878. * @apioption global.useUTC
  4879. */
  4880. /**
  4881. * This option is deprecated since v6.0.5. Instead, use
  4882. * [time.Date](#time.Date) that supports individual time settings
  4883. * per chart.
  4884. *
  4885. * @deprecated
  4886. *
  4887. * @type {Function}
  4888. * @product highcharts highstock
  4889. * @apioption global.Date
  4890. */
  4891. /**
  4892. * This option is deprecated since v6.0.5. Instead, use
  4893. * [time.getTimezoneOffset](#time.getTimezoneOffset) that supports
  4894. * individual time settings per chart.
  4895. *
  4896. * @deprecated
  4897. *
  4898. * @type {Function}
  4899. * @product highcharts highstock
  4900. * @apioption global.getTimezoneOffset
  4901. */
  4902. /**
  4903. * This option is deprecated since v6.0.5. Instead, use
  4904. * [time.timezone](#time.timezone) that supports individual time
  4905. * settings per chart.
  4906. *
  4907. * @deprecated
  4908. *
  4909. * @type {string}
  4910. * @product highcharts highstock
  4911. * @apioption global.timezone
  4912. */
  4913. /**
  4914. * This option is deprecated since v6.0.5. Instead, use
  4915. * [time.timezoneOffset](#time.timezoneOffset) that supports individual
  4916. * time settings per chart.
  4917. *
  4918. * @deprecated
  4919. *
  4920. * @type {number}
  4921. * @product highcharts highstock
  4922. * @apioption global.timezoneOffset
  4923. */
  4924. global: {},
  4925. /**
  4926. * Time options that can apply globally or to individual charts. These
  4927. * settings affect how `datetime` axes are laid out, how tooltips are
  4928. * formatted, how series
  4929. * [pointIntervalUnit](#plotOptions.series.pointIntervalUnit) works and how
  4930. * the Highcharts Stock range selector handles time.
  4931. *
  4932. * The common use case is that all charts in the same Highcharts object
  4933. * share the same time settings, in which case the global settings are set
  4934. * using `setOptions`.
  4935. *
  4936. * ```js
  4937. * // Apply time settings globally
  4938. * Highcharts.setOptions({
  4939. * time: {
  4940. * timezone: 'Europe/London'
  4941. * }
  4942. * });
  4943. * // Apply time settings by instance
  4944. * let chart = Highcharts.chart('container', {
  4945. * time: {
  4946. * timezone: 'America/New_York'
  4947. * },
  4948. * series: [{
  4949. * data: [1, 4, 3, 5]
  4950. * }]
  4951. * });
  4952. *
  4953. * // Use the Time object
  4954. * console.log(
  4955. * 'Current time in New York',
  4956. * chart.time.dateFormat('%Y-%m-%d %H:%M:%S', Date.now())
  4957. * );
  4958. * ```
  4959. *
  4960. * Since v6.0.5, the time options were moved from the `global` obect to the
  4961. * `time` object, and time options can be set on each individual chart.
  4962. *
  4963. * @sample {highcharts|highstock}
  4964. * highcharts/time/timezone/
  4965. * Set the timezone globally
  4966. * @sample {highcharts}
  4967. * highcharts/time/individual/
  4968. * Set the timezone per chart instance
  4969. * @sample {highstock}
  4970. * stock/time/individual/
  4971. * Set the timezone per chart instance
  4972. *
  4973. * @since 6.0.5
  4974. * @optionparent time
  4975. */
  4976. time: {
  4977. /**
  4978. * A custom `Date` class for advanced date handling. For example,
  4979. * [JDate](https://github.com/tahajahangir/jdate) can be hooked in to
  4980. * handle Jalali dates.
  4981. *
  4982. * @type {*}
  4983. * @since 4.0.4
  4984. * @product highcharts highstock gantt
  4985. */
  4986. Date: void 0,
  4987. /**
  4988. * A callback to return the time zone offset for a given datetime. It
  4989. * takes the timestamp in terms of milliseconds since January 1 1970,
  4990. * and returns the timezone offset in minutes. This provides a hook
  4991. * for drawing time based charts in specific time zones using their
  4992. * local DST crossover dates, with the help of external libraries.
  4993. *
  4994. * @see [global.timezoneOffset](#global.timezoneOffset)
  4995. *
  4996. * @sample {highcharts|highstock} highcharts/time/gettimezoneoffset/
  4997. * Use moment.js to draw Oslo time regardless of browser locale
  4998. *
  4999. * @type {Highcharts.TimezoneOffsetCallbackFunction}
  5000. * @since 4.1.0
  5001. * @product highcharts highstock gantt
  5002. */
  5003. getTimezoneOffset: void 0,
  5004. /**
  5005. * Requires [moment.js](https://momentjs.com/). If the timezone option
  5006. * is specified, it creates a default
  5007. * [getTimezoneOffset](#time.getTimezoneOffset) function that looks
  5008. * up the specified timezone in moment.js. If moment.js is not included,
  5009. * this throws a Highcharts error in the console, but does not crash the
  5010. * chart.
  5011. *
  5012. * @see [getTimezoneOffset](#time.getTimezoneOffset)
  5013. *
  5014. * @sample {highcharts|highstock} highcharts/time/timezone/
  5015. * Europe/Oslo
  5016. *
  5017. * @type {string}
  5018. * @since 5.0.7
  5019. * @product highcharts highstock gantt
  5020. */
  5021. timezone: void 0,
  5022. /**
  5023. * The timezone offset in minutes. Positive values are west, negative
  5024. * values are east of UTC, as in the ECMAScript
  5025. * [getTimezoneOffset](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset)
  5026. * method. Use this to display UTC based data in a predefined time zone.
  5027. *
  5028. * @see [time.getTimezoneOffset](#time.getTimezoneOffset)
  5029. *
  5030. * @sample {highcharts|highstock} highcharts/time/timezoneoffset/
  5031. * Timezone offset
  5032. *
  5033. * @since 3.0.8
  5034. * @product highcharts highstock gantt
  5035. */
  5036. timezoneOffset: 0,
  5037. /**
  5038. * Whether to use UTC time for axis scaling, tickmark placement and
  5039. * time display in `Highcharts.dateFormat`. Advantages of using UTC
  5040. * is that the time displays equally regardless of the user agent's
  5041. * time zone settings. Local time can be used when the data is loaded
  5042. * in real time or when correct Daylight Saving Time transitions are
  5043. * required.
  5044. *
  5045. * @sample {highcharts} highcharts/time/useutc-true/
  5046. * True by default
  5047. * @sample {highcharts} highcharts/time/useutc-false/
  5048. * False
  5049. */
  5050. useUTC: true
  5051. },
  5052. chart: ChartDefaults,
  5053. /**
  5054. * The chart's main title.
  5055. *
  5056. * @sample {highmaps} maps/title/title/
  5057. * Title options demonstrated
  5058. */
  5059. title: {
  5060. /**
  5061. * When the title is floating, the plot area will not move to make space
  5062. * for it.
  5063. *
  5064. * @sample {highcharts} highcharts/chart/zoomtype-none/
  5065. * False by default
  5066. * @sample {highcharts} highcharts/title/floating/
  5067. * True - title on top of the plot area
  5068. * @sample {highstock} stock/chart/title-floating/
  5069. * True - title on top of the plot area
  5070. *
  5071. * @type {boolean}
  5072. * @default false
  5073. * @since 2.1
  5074. * @apioption title.floating
  5075. */
  5076. /**
  5077. * CSS styles for the title. Use this for font styling, but use `align`,
  5078. * `x` and `y` for text alignment.
  5079. *
  5080. * In styled mode, the title style is given in the `.highcharts-title`
  5081. * class.
  5082. *
  5083. * @sample {highcharts} highcharts/title/style/
  5084. * Custom color and weight
  5085. * @sample {highstock} stock/chart/title-style/
  5086. * Custom color and weight
  5087. * @sample highcharts/css/titles/
  5088. * Styled mode
  5089. *
  5090. * @type {Highcharts.CSSObject}
  5091. * @default {highcharts|highmaps} { "color": "#333333", "fontSize": "18px" }
  5092. * @default {highstock} { "color": "#333333", "fontSize": "16px" }
  5093. * @apioption title.style
  5094. */
  5095. /**
  5096. * Whether to
  5097. * [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  5098. * to render the text.
  5099. *
  5100. * @type {boolean}
  5101. * @default false
  5102. * @apioption title.useHTML
  5103. */
  5104. /**
  5105. * The vertical alignment of the title. Can be one of `"top"`,
  5106. * `"middle"` and `"bottom"`. When a value is given, the title behaves
  5107. * as if [floating](#title.floating) were `true`.
  5108. *
  5109. * @sample {highcharts} highcharts/title/verticalalign/
  5110. * Chart title in bottom right corner
  5111. * @sample {highstock} stock/chart/title-verticalalign/
  5112. * Chart title in bottom right corner
  5113. *
  5114. * @type {Highcharts.VerticalAlignValue}
  5115. * @since 2.1
  5116. * @apioption title.verticalAlign
  5117. */
  5118. /**
  5119. * The x position of the title relative to the alignment within
  5120. * `chart.spacingLeft` and `chart.spacingRight`.
  5121. *
  5122. * @sample {highcharts} highcharts/title/align/
  5123. * Aligned to the plot area (x = 70px = margin left - spacing
  5124. * left)
  5125. * @sample {highstock} stock/chart/title-align/
  5126. * Aligned to the plot area (x = 50px = margin left - spacing
  5127. * left)
  5128. *
  5129. * @type {number}
  5130. * @default 0
  5131. * @since 2.0
  5132. * @apioption title.x
  5133. */
  5134. /**
  5135. * The y position of the title relative to the alignment within
  5136. * [chart.spacingTop](#chart.spacingTop) and [chart.spacingBottom](
  5137. * #chart.spacingBottom). By default it depends on the font size.
  5138. *
  5139. * @sample {highcharts} highcharts/title/y/
  5140. * Title inside the plot area
  5141. * @sample {highstock} stock/chart/title-verticalalign/
  5142. * Chart title in bottom right corner
  5143. *
  5144. * @type {number}
  5145. * @since 2.0
  5146. * @apioption title.y
  5147. */
  5148. /**
  5149. * The title of the chart. To disable the title, set the `text` to
  5150. * `undefined`.
  5151. *
  5152. * @sample {highcharts} highcharts/title/text/
  5153. * Custom title
  5154. * @sample {highstock} stock/chart/title-text/
  5155. * Custom title
  5156. *
  5157. * @default {highcharts|highmaps} Chart title
  5158. * @default {highstock} undefined
  5159. */
  5160. text: 'Chart title',
  5161. /**
  5162. * The horizontal alignment of the title. Can be one of "left", "center"
  5163. * and "right".
  5164. *
  5165. * @sample {highcharts} highcharts/title/align/
  5166. * Aligned to the plot area (x = 70px = margin left - spacing
  5167. * left)
  5168. * @sample {highstock} stock/chart/title-align/
  5169. * Aligned to the plot area (x = 50px = margin left - spacing
  5170. * left)
  5171. *
  5172. * @type {Highcharts.AlignValue}
  5173. * @since 2.0
  5174. */
  5175. align: 'center',
  5176. /**
  5177. * The margin between the title and the plot area, or if a subtitle
  5178. * is present, the margin between the subtitle and the plot area.
  5179. *
  5180. * @sample {highcharts} highcharts/title/margin-50/
  5181. * A chart title margin of 50
  5182. * @sample {highcharts} highcharts/title/margin-subtitle/
  5183. * The same margin applied with a subtitle
  5184. * @sample {highstock} stock/chart/title-margin/
  5185. * A chart title margin of 50
  5186. *
  5187. * @since 2.1
  5188. */
  5189. margin: 15,
  5190. /**
  5191. * Adjustment made to the title width, normally to reserve space for
  5192. * the exporting burger menu.
  5193. *
  5194. * @sample highcharts/title/widthadjust/
  5195. * Wider menu, greater padding
  5196. *
  5197. * @since 4.2.5
  5198. */
  5199. widthAdjust: -44
  5200. },
  5201. /**
  5202. * The chart's subtitle. This can be used both to display a subtitle below
  5203. * the main title, and to display random text anywhere in the chart. The
  5204. * subtitle can be updated after chart initialization through the
  5205. * `Chart.setTitle` method.
  5206. *
  5207. * @sample {highmaps} maps/title/subtitle/
  5208. * Subtitle options demonstrated
  5209. */
  5210. subtitle: {
  5211. /**
  5212. * When the subtitle is floating, the plot area will not move to make
  5213. * space for it.
  5214. *
  5215. * @sample {highcharts} highcharts/subtitle/floating/
  5216. * Floating title and subtitle
  5217. * @sample {highstock} stock/chart/subtitle-footnote
  5218. * Footnote floating at bottom right of plot area
  5219. *
  5220. * @type {boolean}
  5221. * @default false
  5222. * @since 2.1
  5223. * @apioption subtitle.floating
  5224. */
  5225. /**
  5226. * CSS styles for the title.
  5227. *
  5228. * In styled mode, the subtitle style is given in the
  5229. * `.highcharts-subtitle` class.
  5230. *
  5231. * @sample {highcharts} highcharts/subtitle/style/
  5232. * Custom color and weight
  5233. * @sample {highcharts} highcharts/css/titles/
  5234. * Styled mode
  5235. * @sample {highstock} stock/chart/subtitle-style
  5236. * Custom color and weight
  5237. * @sample {highstock} highcharts/css/titles/
  5238. * Styled mode
  5239. * @sample {highmaps} highcharts/css/titles/
  5240. * Styled mode
  5241. *
  5242. * @type {Highcharts.CSSObject}
  5243. * @default {"color": "#666666"}
  5244. * @apioption subtitle.style
  5245. */
  5246. /**
  5247. * Whether to
  5248. * [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  5249. * to render the text.
  5250. *
  5251. * @type {boolean}
  5252. * @default false
  5253. * @apioption subtitle.useHTML
  5254. */
  5255. /**
  5256. * The vertical alignment of the title. Can be one of `"top"`,
  5257. * `"middle"` and `"bottom"`. When middle, the subtitle behaves as
  5258. * floating.
  5259. *
  5260. * @sample {highcharts} highcharts/subtitle/verticalalign/
  5261. * Footnote at the bottom right of plot area
  5262. * @sample {highstock} stock/chart/subtitle-footnote
  5263. * Footnote at the bottom right of plot area
  5264. *
  5265. * @type {Highcharts.VerticalAlignValue}
  5266. * @since 2.1
  5267. * @apioption subtitle.verticalAlign
  5268. */
  5269. /**
  5270. * The x position of the subtitle relative to the alignment within
  5271. * `chart.spacingLeft` and `chart.spacingRight`.
  5272. *
  5273. * @sample {highcharts} highcharts/subtitle/align/
  5274. * Footnote at right of plot area
  5275. * @sample {highstock} stock/chart/subtitle-footnote
  5276. * Footnote at the bottom right of plot area
  5277. *
  5278. * @type {number}
  5279. * @default 0
  5280. * @since 2.0
  5281. * @apioption subtitle.x
  5282. */
  5283. /**
  5284. * The y position of the subtitle relative to the alignment within
  5285. * `chart.spacingTop` and `chart.spacingBottom`. By default the subtitle
  5286. * is laid out below the title unless the title is floating.
  5287. *
  5288. * @sample {highcharts} highcharts/subtitle/verticalalign/
  5289. * Footnote at the bottom right of plot area
  5290. * @sample {highstock} stock/chart/subtitle-footnote
  5291. * Footnote at the bottom right of plot area
  5292. *
  5293. * @type {number}
  5294. * @since 2.0
  5295. * @apioption subtitle.y
  5296. */
  5297. /**
  5298. * The subtitle of the chart.
  5299. *
  5300. * @sample {highcharts|highstock} highcharts/subtitle/text/
  5301. * Custom subtitle
  5302. * @sample {highcharts|highstock} highcharts/subtitle/text-formatted/
  5303. * Formatted and linked text.
  5304. */
  5305. text: '',
  5306. /**
  5307. * The horizontal alignment of the subtitle. Can be one of "left",
  5308. * "center" and "right".
  5309. *
  5310. * @sample {highcharts} highcharts/subtitle/align/
  5311. * Footnote at right of plot area
  5312. * @sample {highstock} stock/chart/subtitle-footnote
  5313. * Footnote at bottom right of plot area
  5314. *
  5315. * @type {Highcharts.AlignValue}
  5316. * @since 2.0
  5317. */
  5318. align: 'center',
  5319. /**
  5320. * Adjustment made to the subtitle width, normally to reserve space
  5321. * for the exporting burger menu.
  5322. *
  5323. * @see [title.widthAdjust](#title.widthAdjust)
  5324. *
  5325. * @sample highcharts/title/widthadjust/
  5326. * Wider menu, greater padding
  5327. *
  5328. * @since 4.2.5
  5329. */
  5330. widthAdjust: -44
  5331. },
  5332. /**
  5333. * The chart's caption, which will render below the chart and will be part
  5334. * of exported charts. The caption can be updated after chart initialization
  5335. * through the `Chart.update` or `Chart.caption.update` methods.
  5336. *
  5337. * @sample highcharts/caption/text/
  5338. * A chart with a caption
  5339. * @since 7.2.0
  5340. */
  5341. caption: {
  5342. /**
  5343. * When the caption is floating, the plot area will not move to make
  5344. * space for it.
  5345. *
  5346. * @type {boolean}
  5347. * @default false
  5348. * @apioption caption.floating
  5349. */
  5350. /**
  5351. * The margin between the caption and the plot area.
  5352. */
  5353. margin: 15,
  5354. /**
  5355. * CSS styles for the caption.
  5356. *
  5357. * In styled mode, the caption style is given in the
  5358. * `.highcharts-caption` class.
  5359. *
  5360. * @sample {highcharts} highcharts/css/titles/
  5361. * Styled mode
  5362. *
  5363. * @type {Highcharts.CSSObject}
  5364. * @default {"color": "#666666"}
  5365. * @apioption caption.style
  5366. */
  5367. /**
  5368. * Whether to
  5369. * [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  5370. * to render the text.
  5371. *
  5372. * @type {boolean}
  5373. * @default false
  5374. * @apioption caption.useHTML
  5375. */
  5376. /**
  5377. * The x position of the caption relative to the alignment within
  5378. * `chart.spacingLeft` and `chart.spacingRight`.
  5379. *
  5380. * @type {number}
  5381. * @default 0
  5382. * @apioption caption.x
  5383. */
  5384. /**
  5385. * The y position of the caption relative to the alignment within
  5386. * `chart.spacingTop` and `chart.spacingBottom`.
  5387. *
  5388. * @type {number}
  5389. * @apioption caption.y
  5390. */
  5391. /**
  5392. * The caption text of the chart.
  5393. *
  5394. * @sample {highcharts} highcharts/caption/text/
  5395. * Custom caption
  5396. */
  5397. text: '',
  5398. /**
  5399. * The horizontal alignment of the caption. Can be one of "left",
  5400. * "center" and "right".
  5401. *
  5402. * @type {Highcharts.AlignValue}
  5403. */
  5404. align: 'left',
  5405. /**
  5406. * The vertical alignment of the caption. Can be one of `"top"`,
  5407. * `"middle"` and `"bottom"`. When middle, the caption behaves as
  5408. * floating.
  5409. *
  5410. * @type {Highcharts.VerticalAlignValue}
  5411. */
  5412. verticalAlign: 'bottom'
  5413. },
  5414. /**
  5415. * The plotOptions is a wrapper object for config objects for each series
  5416. * type. The config objects for each series can also be overridden for
  5417. * each series item as given in the series array.
  5418. *
  5419. * Configuration options for the series are given in three levels. Options
  5420. * for all series in a chart are given in the [plotOptions.series](
  5421. * #plotOptions.series) object. Then options for all series of a specific
  5422. * type are given in the plotOptions of that type, for example
  5423. * `plotOptions.line`. Next, options for one single series are given in
  5424. * [the series array](#series).
  5425. */
  5426. plotOptions: {},
  5427. /**
  5428. * HTML labels that can be positioned anywhere in the chart area.
  5429. *
  5430. * This option is deprecated since v7.1.2. Instead, use
  5431. * [annotations](#annotations) that support labels.
  5432. *
  5433. * @deprecated
  5434. * @product highcharts highstock
  5435. */
  5436. labels: {
  5437. /**
  5438. * An HTML label that can be positioned anywhere in the chart area.
  5439. *
  5440. * @deprecated
  5441. * @type {Array<*>}
  5442. * @apioption labels.items
  5443. */
  5444. /**
  5445. * Inner HTML or text for the label.
  5446. *
  5447. * @deprecated
  5448. * @type {string}
  5449. * @apioption labels.items.html
  5450. */
  5451. /**
  5452. * CSS styles for each label. To position the label, use left and top
  5453. * like this:
  5454. * ```js
  5455. * style: {
  5456. * left: '100px',
  5457. * top: '100px'
  5458. * }
  5459. * ```
  5460. *
  5461. * @deprecated
  5462. * @type {Highcharts.CSSObject}
  5463. * @apioption labels.items.style
  5464. */
  5465. /**
  5466. * Shared CSS styles for all labels.
  5467. *
  5468. * @deprecated
  5469. * @type {Highcharts.CSSObject}
  5470. * @default {"color": "#333333", "position": "absolute"}
  5471. */
  5472. style: {
  5473. /**
  5474. * @ignore-option
  5475. */
  5476. position: 'absolute',
  5477. /**
  5478. * @ignore-option
  5479. */
  5480. color: palette.neutralColor80
  5481. }
  5482. },
  5483. /**
  5484. * The legend is a box containing a symbol and name for each series
  5485. * item or point item in the chart. Each series (or points in case
  5486. * of pie charts) is represented by a symbol and its name in the legend.
  5487. *
  5488. * It is possible to override the symbol creator function and create
  5489. * [custom legend symbols](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/studies/legend-custom-symbol/).
  5490. *
  5491. * @productdesc {highmaps}
  5492. * A Highmaps legend by default contains one legend item per series, but if
  5493. * a `colorAxis` is defined, the axis will be displayed in the legend.
  5494. * Either as a gradient, or as multiple legend items for `dataClasses`.
  5495. */
  5496. legend: {
  5497. /**
  5498. * The background color of the legend.
  5499. *
  5500. * @see In styled mode, the legend background fill can be applied with
  5501. * the `.highcharts-legend-box` class.
  5502. *
  5503. * @sample {highcharts} highcharts/legend/backgroundcolor/
  5504. * Yellowish background
  5505. * @sample {highstock} stock/legend/align/
  5506. * Various legend options
  5507. * @sample {highmaps} maps/legend/border-background/
  5508. * Border and background options
  5509. *
  5510. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  5511. * @apioption legend.backgroundColor
  5512. */
  5513. /**
  5514. * The width of the drawn border around the legend.
  5515. *
  5516. * @see In styled mode, the legend border stroke width can be applied
  5517. * with the `.highcharts-legend-box` class.
  5518. *
  5519. * @sample {highcharts} highcharts/legend/borderwidth/
  5520. * 2px border width
  5521. * @sample {highstock} stock/legend/align/
  5522. * Various legend options
  5523. * @sample {highmaps} maps/legend/border-background/
  5524. * Border and background options
  5525. *
  5526. * @type {number}
  5527. * @default 0
  5528. * @apioption legend.borderWidth
  5529. */
  5530. /**
  5531. * Enable or disable the legend. There is also a series-specific option,
  5532. * [showInLegend](#plotOptions.series.showInLegend), that can hide the
  5533. * series from the legend. In some series types this is `false` by
  5534. * default, so it must set to `true` in order to show the legend for the
  5535. * series.
  5536. *
  5537. * @sample {highcharts} highcharts/legend/enabled-false/ Legend disabled
  5538. * @sample {highstock} stock/legend/align/ Various legend options
  5539. * @sample {highmaps} maps/legend/enabled-false/ Legend disabled
  5540. *
  5541. * @default {highstock} false
  5542. * @default {highmaps} true
  5543. * @default {gantt} false
  5544. */
  5545. enabled: true,
  5546. /**
  5547. * The horizontal alignment of the legend box within the chart area.
  5548. * Valid values are `left`, `center` and `right`.
  5549. *
  5550. * In the case that the legend is aligned in a corner position, the
  5551. * `layout` option will determine whether to place it above/below
  5552. * or on the side of the plot area.
  5553. *
  5554. * @sample {highcharts} highcharts/legend/align/
  5555. * Legend at the right of the chart
  5556. * @sample {highstock} stock/legend/align/
  5557. * Various legend options
  5558. * @sample {highmaps} maps/legend/alignment/
  5559. * Legend alignment
  5560. *
  5561. * @type {Highcharts.AlignValue}
  5562. * @since 2.0
  5563. */
  5564. align: 'center',
  5565. /**
  5566. * If the [layout](legend.layout) is `horizontal` and the legend items
  5567. * span over two lines or more, whether to align the items into vertical
  5568. * columns. Setting this to `false` makes room for more items, but will
  5569. * look more messy.
  5570. *
  5571. * @since 6.1.0
  5572. */
  5573. alignColumns: true,
  5574. /**
  5575. * A CSS class name to apply to the legend group.
  5576. */
  5577. className: 'highcharts-no-tooltip',
  5578. /**
  5579. * When the legend is floating, the plot area ignores it and is allowed
  5580. * to be placed below it.
  5581. *
  5582. * @sample {highcharts} highcharts/legend/floating-false/
  5583. * False by default
  5584. * @sample {highcharts} highcharts/legend/floating-true/
  5585. * True
  5586. * @sample {highmaps} maps/legend/alignment/
  5587. * Floating legend
  5588. *
  5589. * @type {boolean}
  5590. * @default false
  5591. * @since 2.1
  5592. * @apioption legend.floating
  5593. */
  5594. /**
  5595. * The layout of the legend items. Can be one of `horizontal` or
  5596. * `vertical` or `proximate`. When `proximate`, the legend items will be
  5597. * placed as close as possible to the graphs they're representing,
  5598. * except in inverted charts or when the legend position doesn't allow
  5599. * it.
  5600. *
  5601. * @sample {highcharts} highcharts/legend/layout-horizontal/
  5602. * Horizontal by default
  5603. * @sample {highcharts} highcharts/legend/layout-vertical/
  5604. * Vertical
  5605. * @sample highcharts/legend/layout-proximate
  5606. * Labels proximate to the data
  5607. * @sample {highstock} stock/legend/layout-horizontal/
  5608. * Horizontal by default
  5609. * @sample {highmaps} maps/legend/padding-itemmargin/
  5610. * Vertical with data classes
  5611. * @sample {highmaps} maps/legend/layout-vertical/
  5612. * Vertical with color axis gradient
  5613. *
  5614. * @validvalue ["horizontal", "vertical", "proximate"]
  5615. */
  5616. layout: 'horizontal',
  5617. /**
  5618. * In a legend with horizontal layout, the itemDistance defines the
  5619. * pixel distance between each item.
  5620. *
  5621. * @sample {highcharts} highcharts/legend/layout-horizontal/
  5622. * 50px item distance
  5623. * @sample {highstock} highcharts/legend/layout-horizontal/
  5624. * 50px item distance
  5625. *
  5626. * @type {number}
  5627. * @default {highcharts} 20
  5628. * @default {highstock} 20
  5629. * @default {highmaps} 8
  5630. * @since 3.0.3
  5631. * @apioption legend.itemDistance
  5632. */
  5633. /**
  5634. * The pixel bottom margin for each legend item.
  5635. *
  5636. * @sample {highcharts|highstock} highcharts/legend/padding-itemmargin/
  5637. * Padding and item margins demonstrated
  5638. * @sample {highmaps} maps/legend/padding-itemmargin/
  5639. * Padding and item margins demonstrated
  5640. *
  5641. * @type {number}
  5642. * @default 0
  5643. * @since 2.2.0
  5644. * @apioption legend.itemMarginBottom
  5645. */
  5646. /**
  5647. * The pixel top margin for each legend item.
  5648. *
  5649. * @sample {highcharts|highstock} highcharts/legend/padding-itemmargin/
  5650. * Padding and item margins demonstrated
  5651. * @sample {highmaps} maps/legend/padding-itemmargin/
  5652. * Padding and item margins demonstrated
  5653. *
  5654. * @type {number}
  5655. * @default 0
  5656. * @since 2.2.0
  5657. * @apioption legend.itemMarginTop
  5658. */
  5659. /**
  5660. * The width for each legend item. By default the items are laid out
  5661. * successively. In a [horizontal layout](legend.layout), if the items
  5662. * are laid out across two rows or more, they will be vertically aligned
  5663. * depending on the [legend.alignColumns](legend.alignColumns) option.
  5664. *
  5665. * @sample {highcharts} highcharts/legend/itemwidth-default/
  5666. * Undefined by default
  5667. * @sample {highcharts} highcharts/legend/itemwidth-80/
  5668. * 80 for aligned legend items
  5669. *
  5670. * @type {number}
  5671. * @since 2.0
  5672. * @apioption legend.itemWidth
  5673. */
  5674. /**
  5675. * A [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
  5676. * for each legend label. Available variables relates to properties on
  5677. * the series, or the point in case of pies.
  5678. *
  5679. * @type {string}
  5680. * @default {name}
  5681. * @since 1.3
  5682. * @apioption legend.labelFormat
  5683. */
  5684. /* eslint-disable valid-jsdoc */
  5685. /**
  5686. * Callback function to format each of the series' labels. The `this`
  5687. * keyword refers to the series object, or the point object in case of
  5688. * pie charts. By default the series or point name is printed.
  5689. *
  5690. * @productdesc {highmaps}
  5691. * In Highmaps the context can also be a data class in case of a
  5692. * `colorAxis`.
  5693. *
  5694. * @sample {highcharts} highcharts/legend/labelformatter/
  5695. * Add text
  5696. * @sample {highmaps} maps/legend/labelformatter/
  5697. * Data classes with label formatter
  5698. *
  5699. * @type {Highcharts.FormatterCallbackFunction<Point|Series>}
  5700. */
  5701. labelFormatter: function () {
  5702. /** eslint-enable valid-jsdoc */
  5703. return this.name;
  5704. },
  5705. /**
  5706. * Line height for the legend items. Deprecated as of 2.1\. Instead,
  5707. * the line height for each item can be set using
  5708. * `itemStyle.lineHeight`, and the padding between items using
  5709. * `itemMarginTop` and `itemMarginBottom`.
  5710. *
  5711. * @sample {highcharts} highcharts/legend/lineheight/
  5712. * Setting padding
  5713. *
  5714. * @deprecated
  5715. *
  5716. * @type {number}
  5717. * @default 16
  5718. * @since 2.0
  5719. * @product highcharts gantt
  5720. * @apioption legend.lineHeight
  5721. */
  5722. /**
  5723. * If the plot area sized is calculated automatically and the legend is
  5724. * not floating, the legend margin is the space between the legend and
  5725. * the axis labels or plot area.
  5726. *
  5727. * @sample {highcharts} highcharts/legend/margin-default/
  5728. * 12 pixels by default
  5729. * @sample {highcharts} highcharts/legend/margin-30/
  5730. * 30 pixels
  5731. *
  5732. * @type {number}
  5733. * @default 12
  5734. * @since 2.1
  5735. * @apioption legend.margin
  5736. */
  5737. /**
  5738. * Maximum pixel height for the legend. When the maximum height is
  5739. * extended, navigation will show.
  5740. *
  5741. * @type {number}
  5742. * @since 2.3.0
  5743. * @apioption legend.maxHeight
  5744. */
  5745. /**
  5746. * The color of the drawn border around the legend.
  5747. *
  5748. * @see In styled mode, the legend border stroke can be applied with the
  5749. * `.highcharts-legend-box` class.
  5750. *
  5751. * @sample {highcharts} highcharts/legend/bordercolor/
  5752. * Brown border
  5753. * @sample {highstock} stock/legend/align/
  5754. * Various legend options
  5755. * @sample {highmaps} maps/legend/border-background/
  5756. * Border and background options
  5757. *
  5758. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  5759. */
  5760. borderColor: palette.neutralColor40,
  5761. /**
  5762. * The border corner radius of the legend.
  5763. *
  5764. * @sample {highcharts} highcharts/legend/borderradius-default/
  5765. * Square by default
  5766. * @sample {highcharts} highcharts/legend/borderradius-round/
  5767. * 5px rounded
  5768. * @sample {highmaps} maps/legend/border-background/
  5769. * Border and background options
  5770. */
  5771. borderRadius: 0,
  5772. /**
  5773. * Options for the paging or navigation appearing when the legend is
  5774. * overflown. Navigation works well on screen, but not in static
  5775. * exported images. One way of working around that is to
  5776. * [increase the chart height in
  5777. * export](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/legend/navigation-enabled-false/).
  5778. */
  5779. navigation: {
  5780. /**
  5781. * How to animate the pages when navigating up or down. A value of
  5782. * `true` applies the default navigation given in the
  5783. * `chart.animation` option. Additional options can be given as an
  5784. * object containing values for easing and duration.
  5785. *
  5786. * @sample {highcharts} highcharts/legend/navigation/
  5787. * Legend page navigation demonstrated
  5788. * @sample {highstock} highcharts/legend/navigation/
  5789. * Legend page navigation demonstrated
  5790. *
  5791. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  5792. * @default true
  5793. * @since 2.2.4
  5794. * @apioption legend.navigation.animation
  5795. */
  5796. /**
  5797. * The pixel size of the up and down arrows in the legend paging
  5798. * navigation.
  5799. *
  5800. * @sample {highcharts} highcharts/legend/navigation/
  5801. * Legend page navigation demonstrated
  5802. * @sample {highstock} highcharts/legend/navigation/
  5803. * Legend page navigation demonstrated
  5804. *
  5805. * @type {number}
  5806. * @default 12
  5807. * @since 2.2.4
  5808. * @apioption legend.navigation.arrowSize
  5809. */
  5810. /**
  5811. * Whether to enable the legend navigation. In most cases, disabling
  5812. * the navigation results in an unwanted overflow.
  5813. *
  5814. * See also the [adapt chart to legend](
  5815. * https://www.highcharts.com/products/plugin-registry/single/8/Adapt-Chart-To-Legend)
  5816. * plugin for a solution to extend the chart height to make room for
  5817. * the legend, optionally in exported charts only.
  5818. *
  5819. * @type {boolean}
  5820. * @default true
  5821. * @since 4.2.4
  5822. * @apioption legend.navigation.enabled
  5823. */
  5824. /**
  5825. * Text styles for the legend page navigation.
  5826. *
  5827. * @see In styled mode, the navigation items are styled with the
  5828. * `.highcharts-legend-navigation` class.
  5829. *
  5830. * @sample {highcharts} highcharts/legend/navigation/
  5831. * Legend page navigation demonstrated
  5832. * @sample {highstock} highcharts/legend/navigation/
  5833. * Legend page navigation demonstrated
  5834. *
  5835. * @type {Highcharts.CSSObject}
  5836. * @since 2.2.4
  5837. * @apioption legend.navigation.style
  5838. */
  5839. /**
  5840. * The color for the active up or down arrow in the legend page
  5841. * navigation.
  5842. *
  5843. * @see In styled mode, the active arrow be styled with the
  5844. * `.highcharts-legend-nav-active` class.
  5845. *
  5846. * @sample {highcharts} highcharts/legend/navigation/
  5847. * Legend page navigation demonstrated
  5848. * @sample {highstock} highcharts/legend/navigation/
  5849. * Legend page navigation demonstrated
  5850. *
  5851. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  5852. * @since 2.2.4
  5853. */
  5854. activeColor: palette.highlightColor100,
  5855. /**
  5856. * The color of the inactive up or down arrow in the legend page
  5857. * navigation. .
  5858. *
  5859. * @see In styled mode, the inactive arrow be styled with the
  5860. * `.highcharts-legend-nav-inactive` class.
  5861. *
  5862. * @sample {highcharts} highcharts/legend/navigation/
  5863. * Legend page navigation demonstrated
  5864. * @sample {highstock} highcharts/legend/navigation/
  5865. * Legend page navigation demonstrated
  5866. *
  5867. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  5868. * @since 2.2.4
  5869. */
  5870. inactiveColor: palette.neutralColor20
  5871. },
  5872. /**
  5873. * The inner padding of the legend box.
  5874. *
  5875. * @sample {highcharts|highstock} highcharts/legend/padding-itemmargin/
  5876. * Padding and item margins demonstrated
  5877. * @sample {highmaps} maps/legend/padding-itemmargin/
  5878. * Padding and item margins demonstrated
  5879. *
  5880. * @type {number}
  5881. * @default 8
  5882. * @since 2.2.0
  5883. * @apioption legend.padding
  5884. */
  5885. /**
  5886. * Whether to reverse the order of the legend items compared to the
  5887. * order of the series or points as defined in the configuration object.
  5888. *
  5889. * @see [yAxis.reversedStacks](#yAxis.reversedStacks),
  5890. * [series.legendIndex](#series.legendIndex)
  5891. *
  5892. * @sample {highcharts} highcharts/legend/reversed/
  5893. * Stacked bar with reversed legend
  5894. *
  5895. * @type {boolean}
  5896. * @default false
  5897. * @since 1.2.5
  5898. * @apioption legend.reversed
  5899. */
  5900. /**
  5901. * Whether to show the symbol on the right side of the text rather than
  5902. * the left side. This is common in Arabic and Hebrew.
  5903. *
  5904. * @sample {highcharts} highcharts/legend/rtl/
  5905. * Symbol to the right
  5906. *
  5907. * @type {boolean}
  5908. * @default false
  5909. * @since 2.2
  5910. * @apioption legend.rtl
  5911. */
  5912. /**
  5913. * CSS styles for the legend area. In the 1.x versions the position
  5914. * of the legend area was determined by CSS. In 2.x, the position is
  5915. * determined by properties like `align`, `verticalAlign`, `x` and `y`,
  5916. * but the styles are still parsed for backwards compatibility.
  5917. *
  5918. * @deprecated
  5919. *
  5920. * @type {Highcharts.CSSObject}
  5921. * @product highcharts highstock
  5922. * @apioption legend.style
  5923. */
  5924. /**
  5925. * CSS styles for each legend item. Only a subset of CSS is supported,
  5926. * notably those options related to text. The default `textOverflow`
  5927. * property makes long texts truncate. Set it to `undefined` to wrap
  5928. * text instead. A `width` property can be added to control the text
  5929. * width.
  5930. *
  5931. * @see In styled mode, the legend items can be styled with the
  5932. * `.highcharts-legend-item` class.
  5933. *
  5934. * @sample {highcharts} highcharts/legend/itemstyle/
  5935. * Bold black text
  5936. * @sample {highmaps} maps/legend/itemstyle/
  5937. * Item text styles
  5938. *
  5939. * @type {Highcharts.CSSObject}
  5940. * @default {"color": "#333333", "cursor": "pointer", "fontSize": "12px", "fontWeight": "bold", "textOverflow": "ellipsis"}
  5941. */
  5942. itemStyle: {
  5943. /**
  5944. * @ignore
  5945. */
  5946. color: palette.neutralColor80,
  5947. /**
  5948. * @ignore
  5949. */
  5950. cursor: 'pointer',
  5951. /**
  5952. * @ignore
  5953. */
  5954. fontSize: '12px',
  5955. /**
  5956. * @ignore
  5957. */
  5958. fontWeight: 'bold',
  5959. /**
  5960. * @ignore
  5961. */
  5962. textOverflow: 'ellipsis'
  5963. },
  5964. /**
  5965. * CSS styles for each legend item in hover mode. Only a subset of
  5966. * CSS is supported, notably those options related to text. Properties
  5967. * are inherited from `style` unless overridden here.
  5968. *
  5969. * @see In styled mode, the hovered legend items can be styled with
  5970. * the `.highcharts-legend-item:hover` pesudo-class.
  5971. *
  5972. * @sample {highcharts} highcharts/legend/itemhoverstyle/
  5973. * Red on hover
  5974. * @sample {highmaps} maps/legend/itemstyle/
  5975. * Item text styles
  5976. *
  5977. * @type {Highcharts.CSSObject}
  5978. * @default {"color": "#000000"}
  5979. */
  5980. itemHoverStyle: {
  5981. /**
  5982. * @ignore
  5983. */
  5984. color: palette.neutralColor100
  5985. },
  5986. /**
  5987. * CSS styles for each legend item when the corresponding series or
  5988. * point is hidden. Only a subset of CSS is supported, notably those
  5989. * options related to text. Properties are inherited from `style`
  5990. * unless overridden here.
  5991. *
  5992. * @see In styled mode, the hidden legend items can be styled with
  5993. * the `.highcharts-legend-item-hidden` class.
  5994. *
  5995. * @sample {highcharts} highcharts/legend/itemhiddenstyle/
  5996. * Darker gray color
  5997. *
  5998. * @type {Highcharts.CSSObject}
  5999. * @default {"color": "#cccccc"}
  6000. */
  6001. itemHiddenStyle: {
  6002. /**
  6003. * @ignore
  6004. */
  6005. color: palette.neutralColor20
  6006. },
  6007. /**
  6008. * Whether to apply a drop shadow to the legend. A `backgroundColor`
  6009. * also needs to be applied for this to take effect. The shadow can be
  6010. * an object configuration containing `color`, `offsetX`, `offsetY`,
  6011. * `opacity` and `width`.
  6012. *
  6013. * @sample {highcharts} highcharts/legend/shadow/
  6014. * White background and drop shadow
  6015. * @sample {highstock} stock/legend/align/
  6016. * Various legend options
  6017. * @sample {highmaps} maps/legend/border-background/
  6018. * Border and background options
  6019. *
  6020. * @type {boolean|Highcharts.CSSObject}
  6021. */
  6022. shadow: false,
  6023. /**
  6024. * Default styling for the checkbox next to a legend item when
  6025. * `showCheckbox` is true.
  6026. *
  6027. * @type {Highcharts.CSSObject}
  6028. * @default {"width": "13px", "height": "13px", "position":"absolute"}
  6029. */
  6030. itemCheckboxStyle: {
  6031. /**
  6032. * @ignore
  6033. */
  6034. position: 'absolute',
  6035. /**
  6036. * @ignore
  6037. */
  6038. width: '13px',
  6039. /**
  6040. * @ignore
  6041. */
  6042. height: '13px'
  6043. },
  6044. // itemWidth: undefined,
  6045. /**
  6046. * When this is true, the legend symbol width will be the same as
  6047. * the symbol height, which in turn defaults to the font size of the
  6048. * legend items.
  6049. *
  6050. * @since 5.0.0
  6051. */
  6052. squareSymbol: true,
  6053. /**
  6054. * The pixel height of the symbol for series types that use a rectangle
  6055. * in the legend. Defaults to the font size of legend items.
  6056. *
  6057. * @productdesc {highmaps}
  6058. * In Highmaps, when the symbol is the gradient of a vertical color
  6059. * axis, the height defaults to 200.
  6060. *
  6061. * @sample {highmaps} maps/legend/layout-vertical-sized/
  6062. * Sized vertical gradient
  6063. * @sample {highmaps} maps/legend/padding-itemmargin/
  6064. * No distance between data classes
  6065. *
  6066. * @type {number}
  6067. * @since 3.0.8
  6068. * @apioption legend.symbolHeight
  6069. */
  6070. /**
  6071. * The border radius of the symbol for series types that use a rectangle
  6072. * in the legend. Defaults to half the `symbolHeight`.
  6073. *
  6074. * @sample {highcharts} highcharts/legend/symbolradius/
  6075. * Round symbols
  6076. * @sample {highstock} highcharts/legend/symbolradius/
  6077. * Round symbols
  6078. * @sample {highmaps} highcharts/legend/symbolradius/
  6079. * Round symbols
  6080. *
  6081. * @type {number}
  6082. * @since 3.0.8
  6083. * @apioption legend.symbolRadius
  6084. */
  6085. /**
  6086. * The pixel width of the legend item symbol. When the `squareSymbol`
  6087. * option is set, this defaults to the `symbolHeight`, otherwise 16.
  6088. *
  6089. * @productdesc {highmaps}
  6090. * In Highmaps, when the symbol is the gradient of a horizontal color
  6091. * axis, the width defaults to 200.
  6092. *
  6093. * @sample {highcharts} highcharts/legend/symbolwidth/
  6094. * Greater symbol width and padding
  6095. * @sample {highmaps} maps/legend/padding-itemmargin/
  6096. * Padding and item margins demonstrated
  6097. * @sample {highmaps} maps/legend/layout-vertical-sized/
  6098. * Sized vertical gradient
  6099. *
  6100. * @type {number}
  6101. * @apioption legend.symbolWidth
  6102. */
  6103. /**
  6104. * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  6105. * to render the legend item texts.
  6106. *
  6107. * Prior to 4.1.7, when using HTML, [legend.navigation](
  6108. * #legend.navigation) was disabled.
  6109. *
  6110. * @type {boolean}
  6111. * @default false
  6112. * @apioption legend.useHTML
  6113. */
  6114. /**
  6115. * The width of the legend box. If a number is set, it translates to
  6116. * pixels. Since v7.0.2 it allows setting a percent string of the full
  6117. * chart width, for example `40%`.
  6118. *
  6119. * Defaults to the full chart width for legends below or above the
  6120. * chart, half the chart width for legends to the left and right.
  6121. *
  6122. * @sample {highcharts} highcharts/legend/width/
  6123. * Aligned to the plot area
  6124. * @sample {highcharts} highcharts/legend/width-percent/
  6125. * A percent of the chart width
  6126. *
  6127. * @type {number|string}
  6128. * @since 2.0
  6129. * @apioption legend.width
  6130. */
  6131. /**
  6132. * The pixel padding between the legend item symbol and the legend
  6133. * item text.
  6134. *
  6135. * @sample {highcharts} highcharts/legend/symbolpadding/
  6136. * Greater symbol width and padding
  6137. */
  6138. symbolPadding: 5,
  6139. /**
  6140. * The vertical alignment of the legend box. Can be one of `top`,
  6141. * `middle` or `bottom`. Vertical position can be further determined
  6142. * by the `y` option.
  6143. *
  6144. * In the case that the legend is aligned in a corner position, the
  6145. * `layout` option will determine whether to place it above/below
  6146. * or on the side of the plot area.
  6147. *
  6148. * When the [layout](#legend.layout) option is `proximate`, the
  6149. * `verticalAlign` option doesn't apply.
  6150. *
  6151. * @sample {highcharts} highcharts/legend/verticalalign/
  6152. * Legend 100px from the top of the chart
  6153. * @sample {highstock} stock/legend/align/
  6154. * Various legend options
  6155. * @sample {highmaps} maps/legend/alignment/
  6156. * Legend alignment
  6157. *
  6158. * @type {Highcharts.VerticalAlignValue}
  6159. * @since 2.0
  6160. */
  6161. verticalAlign: 'bottom',
  6162. // width: undefined,
  6163. /**
  6164. * The x offset of the legend relative to its horizontal alignment
  6165. * `align` within chart.spacingLeft and chart.spacingRight. Negative
  6166. * x moves it to the left, positive x moves it to the right.
  6167. *
  6168. * @sample {highcharts} highcharts/legend/width/
  6169. * Aligned to the plot area
  6170. *
  6171. * @since 2.0
  6172. */
  6173. x: 0,
  6174. /**
  6175. * The vertical offset of the legend relative to it's vertical alignment
  6176. * `verticalAlign` within chart.spacingTop and chart.spacingBottom.
  6177. * Negative y moves it up, positive y moves it down.
  6178. *
  6179. * @sample {highcharts} highcharts/legend/verticalalign/
  6180. * Legend 100px from the top of the chart
  6181. * @sample {highstock} stock/legend/align/
  6182. * Various legend options
  6183. * @sample {highmaps} maps/legend/alignment/
  6184. * Legend alignment
  6185. *
  6186. * @since 2.0
  6187. */
  6188. y: 0,
  6189. /**
  6190. * A title to be added on top of the legend.
  6191. *
  6192. * @sample {highcharts} highcharts/legend/title/
  6193. * Legend title
  6194. * @sample {highmaps} maps/legend/alignment/
  6195. * Legend with title
  6196. *
  6197. * @since 3.0
  6198. */
  6199. title: {
  6200. /**
  6201. * A text or HTML string for the title.
  6202. *
  6203. * @type {string}
  6204. * @since 3.0
  6205. * @apioption legend.title.text
  6206. */
  6207. /**
  6208. * Generic CSS styles for the legend title.
  6209. *
  6210. * @see In styled mode, the legend title is styled with the
  6211. * `.highcharts-legend-title` class.
  6212. *
  6213. * @type {Highcharts.CSSObject}
  6214. * @default {"fontWeight": "bold"}
  6215. * @since 3.0
  6216. */
  6217. style: {
  6218. /**
  6219. * @ignore
  6220. */
  6221. fontWeight: 'bold'
  6222. }
  6223. }
  6224. },
  6225. /**
  6226. * The loading options control the appearance of the loading screen
  6227. * that covers the plot area on chart operations. This screen only
  6228. * appears after an explicit call to `chart.showLoading()`. It is a
  6229. * utility for developers to communicate to the end user that something
  6230. * is going on, for example while retrieving new data via an XHR connection.
  6231. * The "Loading..." text itself is not part of this configuration
  6232. * object, but part of the `lang` object.
  6233. */
  6234. loading: {
  6235. /**
  6236. * The duration in milliseconds of the fade out effect.
  6237. *
  6238. * @sample highcharts/loading/hideduration/
  6239. * Fade in and out over a second
  6240. *
  6241. * @type {number}
  6242. * @default 100
  6243. * @since 1.2.0
  6244. * @apioption loading.hideDuration
  6245. */
  6246. /**
  6247. * The duration in milliseconds of the fade in effect.
  6248. *
  6249. * @sample highcharts/loading/hideduration/
  6250. * Fade in and out over a second
  6251. *
  6252. * @type {number}
  6253. * @default 100
  6254. * @since 1.2.0
  6255. * @apioption loading.showDuration
  6256. */
  6257. /**
  6258. * CSS styles for the loading label `span`.
  6259. *
  6260. * @see In styled mode, the loading label is styled with the
  6261. * `.highcharts-loading-inner` class.
  6262. *
  6263. * @sample {highcharts|highmaps} highcharts/loading/labelstyle/
  6264. * Vertically centered
  6265. * @sample {highstock} stock/loading/general/
  6266. * Label styles
  6267. *
  6268. * @type {Highcharts.CSSObject}
  6269. * @default {"fontWeight": "bold", "position": "relative", "top": "45%"}
  6270. * @since 1.2.0
  6271. */
  6272. labelStyle: {
  6273. /**
  6274. * @ignore
  6275. */
  6276. fontWeight: 'bold',
  6277. /**
  6278. * @ignore
  6279. */
  6280. position: 'relative',
  6281. /**
  6282. * @ignore
  6283. */
  6284. top: '45%'
  6285. },
  6286. /**
  6287. * CSS styles for the loading screen that covers the plot area.
  6288. *
  6289. * In styled mode, the loading label is styled with the
  6290. * `.highcharts-loading` class.
  6291. *
  6292. * @sample {highcharts|highmaps} highcharts/loading/style/
  6293. * Gray plot area, white text
  6294. * @sample {highstock} stock/loading/general/
  6295. * Gray plot area, white text
  6296. *
  6297. * @type {Highcharts.CSSObject}
  6298. * @default {"position": "absolute", "backgroundColor": "#ffffff", "opacity": 0.5, "textAlign": "center"}
  6299. * @since 1.2.0
  6300. */
  6301. style: {
  6302. /**
  6303. * @ignore
  6304. */
  6305. position: 'absolute',
  6306. /**
  6307. * @ignore
  6308. */
  6309. backgroundColor: palette.backgroundColor,
  6310. /**
  6311. * @ignore
  6312. */
  6313. opacity: 0.5,
  6314. /**
  6315. * @ignore
  6316. */
  6317. textAlign: 'center'
  6318. }
  6319. },
  6320. /**
  6321. * Options for the tooltip that appears when the user hovers over a
  6322. * series or point.
  6323. *
  6324. * @declare Highcharts.TooltipOptions
  6325. */
  6326. tooltip: {
  6327. /**
  6328. * The color of the tooltip border. When `undefined`, the border takes
  6329. * the color of the corresponding series or point.
  6330. *
  6331. * @sample {highcharts} highcharts/tooltip/bordercolor-default/
  6332. * Follow series by default
  6333. * @sample {highcharts} highcharts/tooltip/bordercolor-black/
  6334. * Black border
  6335. * @sample {highstock} stock/tooltip/general/
  6336. * Styled tooltip
  6337. * @sample {highmaps} maps/tooltip/background-border/
  6338. * Background and border demo
  6339. *
  6340. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  6341. * @apioption tooltip.borderColor
  6342. */
  6343. /**
  6344. * A CSS class name to apply to the tooltip's container div,
  6345. * allowing unique CSS styling for each chart.
  6346. *
  6347. * @type {string}
  6348. * @apioption tooltip.className
  6349. */
  6350. /**
  6351. * Since 4.1, the crosshair definitions are moved to the Axis object
  6352. * in order for a better separation from the tooltip. See
  6353. * [xAxis.crosshair](#xAxis.crosshair).
  6354. *
  6355. * @sample {highcharts} highcharts/tooltip/crosshairs-x/
  6356. * Enable a crosshair for the x value
  6357. *
  6358. * @deprecated
  6359. *
  6360. * @type {*}
  6361. * @default true
  6362. * @apioption tooltip.crosshairs
  6363. */
  6364. /**
  6365. * Distance from point to tooltip in pixels.
  6366. *
  6367. * @type {number}
  6368. * @default 16
  6369. * @apioption tooltip.distance
  6370. */
  6371. /**
  6372. * Whether the tooltip should follow the mouse as it moves across
  6373. * columns, pie slices and other point types with an extent.
  6374. * By default it behaves this way for pie, polygon, map, sankey
  6375. * and wordcloud series by override in the `plotOptions`
  6376. * for those series types.
  6377. *
  6378. * Does not apply if [split](#tooltip.split) is `true`.
  6379. *
  6380. * For touch moves to behave the same way, [followTouchMove](
  6381. * #tooltip.followTouchMove) must be `true` also.
  6382. *
  6383. * @type {boolean}
  6384. * @default {highcharts} false
  6385. * @default {highstock} false
  6386. * @default {highmaps} true
  6387. * @since 3.0
  6388. * @apioption tooltip.followPointer
  6389. */
  6390. /**
  6391. * Whether the tooltip should update as the finger moves on a touch
  6392. * device. If this is `true` and [chart.panning](#chart.panning) is
  6393. * set,`followTouchMove` will take over one-finger touches, so the user
  6394. * needs to use two fingers for zooming and panning.
  6395. *
  6396. * Note the difference to [followPointer](#tooltip.followPointer) that
  6397. * only defines the _position_ of the tooltip. If `followPointer` is
  6398. * false in for example a column series, the tooltip will show above or
  6399. * below the column, but as `followTouchMove` is true, the tooltip will
  6400. * jump from column to column as the user swipes across the plot area.
  6401. *
  6402. * @type {boolean}
  6403. * @default {highcharts} true
  6404. * @default {highstock} true
  6405. * @default {highmaps} false
  6406. * @since 3.0.1
  6407. * @apioption tooltip.followTouchMove
  6408. */
  6409. /**
  6410. * Callback function to format the text of the tooltip from scratch. In
  6411. * case of single or [shared](#tooltip.shared) tooltips, a string should
  6412. * be returned. In case of [split](#tooltip.split) tooltips, it should
  6413. * return an array where the first item is the header, and subsequent
  6414. * items are mapped to the points. Return `false` to disable tooltip for
  6415. * a specific point on series.
  6416. *
  6417. * A subset of HTML is supported. Unless `useHTML` is true, the HTML of
  6418. * the tooltip is parsed and converted to SVG, therefore this isn't a
  6419. * complete HTML renderer. The following HTML tags are supported: `b`,
  6420. * `br`, `em`, `i`, `span`, `strong`. Spans can be styled with a `style`
  6421. * attribute, but only text-related CSS, that is shared with SVG, is
  6422. * handled.
  6423. *
  6424. * The available data in the formatter differ a bit depending on whether
  6425. * the tooltip is shared or split, or belongs to a single point. In a
  6426. * shared/split tooltip, all properties except `x`, which is common for
  6427. * all points, are kept in an array, `this.points`.
  6428. *
  6429. * Available data are:
  6430. *
  6431. * - **this.percentage (not shared) /**
  6432. * **this.points[i].percentage (shared)**:
  6433. * Stacked series and pies only. The point's percentage of the total.
  6434. *
  6435. * - **this.point (not shared) / this.points[i].point (shared)**:
  6436. * The point object. The point name, if defined, is available through
  6437. * `this.point.name`.
  6438. *
  6439. * - **this.points**:
  6440. * In a shared tooltip, this is an array containing all other
  6441. * properties for each point.
  6442. *
  6443. * - **this.series (not shared) / this.points[i].series (shared)**:
  6444. * The series object. The series name is available through
  6445. * `this.series.name`.
  6446. *
  6447. * - **this.total (not shared) / this.points[i].total (shared)**:
  6448. * Stacked series only. The total value at this point's x value.
  6449. *
  6450. * - **this.x**:
  6451. * The x value. This property is the same regardless of the tooltip
  6452. * being shared or not.
  6453. *
  6454. * - **this.y (not shared) / this.points[i].y (shared)**:
  6455. * The y value.
  6456. *
  6457. * @sample {highcharts} highcharts/tooltip/formatter-simple/
  6458. * Simple string formatting
  6459. * @sample {highcharts} highcharts/tooltip/formatter-shared/
  6460. * Formatting with shared tooltip
  6461. * @sample {highcharts|highstock} highcharts/tooltip/formatter-split/
  6462. * Formatting with split tooltip
  6463. * @sample highcharts/tooltip/formatter-conditional-default/
  6464. * Extending default formatter
  6465. * @sample {highstock} stock/tooltip/formatter/
  6466. * Formatting with shared tooltip
  6467. * @sample {highmaps} maps/tooltip/formatter/
  6468. * String formatting
  6469. *
  6470. * @type {Highcharts.TooltipFormatterCallbackFunction}
  6471. * @apioption tooltip.formatter
  6472. */
  6473. /**
  6474. * Callback function to format the text of the tooltip for
  6475. * visible null points.
  6476. * Works analogously to [formatter](#tooltip.formatter).
  6477. *
  6478. * @sample highcharts/plotoptions/series-nullformat
  6479. * Format data label and tooltip for null point.
  6480. *
  6481. * @type {Highcharts.TooltipFormatterCallbackFunction}
  6482. * @apioption tooltip.nullFormatter
  6483. */
  6484. /**
  6485. * The number of milliseconds to wait until the tooltip is hidden when
  6486. * mouse out from a point or chart.
  6487. *
  6488. * @type {number}
  6489. * @default 500
  6490. * @since 3.0
  6491. * @apioption tooltip.hideDelay
  6492. */
  6493. /**
  6494. * Whether to allow the tooltip to render outside the chart's SVG
  6495. * element box. By default (`false`), the tooltip is rendered within the
  6496. * chart's SVG element, which results in the tooltip being aligned
  6497. * inside the chart area. For small charts, this may result in clipping
  6498. * or overlapping. When `true`, a separate SVG element is created and
  6499. * overlaid on the page, allowing the tooltip to be aligned inside the
  6500. * page itself.
  6501. *
  6502. * Defaults to `true` if `chart.scrollablePlotArea` is activated,
  6503. * otherwise `false`.
  6504. *
  6505. * @sample highcharts/tooltip/outside
  6506. * Small charts with tooltips outside
  6507. *
  6508. * @type {boolean|undefined}
  6509. * @default undefined
  6510. * @since 6.1.1
  6511. * @apioption tooltip.outside
  6512. */
  6513. /**
  6514. * A callback function for formatting the HTML output for a single point
  6515. * in the tooltip. Like the `pointFormat` string, but with more
  6516. * flexibility.
  6517. *
  6518. * @type {Highcharts.FormatterCallbackFunction<Highcharts.Point>}
  6519. * @since 4.1.0
  6520. * @context Highcharts.Point
  6521. * @apioption tooltip.pointFormatter
  6522. */
  6523. /**
  6524. * A callback function to place the tooltip in a default position. The
  6525. * callback receives three parameters: `labelWidth`, `labelHeight` and
  6526. * `point`, where point contains values for `plotX` and `plotY` telling
  6527. * where the reference point is in the plot area. Add `chart.plotLeft`
  6528. * and `chart.plotTop` to get the full coordinates.
  6529. *
  6530. * Since v7, when [tooltip.split](#tooltip.split) option is enabled,
  6531. * positioner is called for each of the boxes separately, including
  6532. * xAxis header. xAxis header is not a point, instead `point` argument
  6533. * contains info:
  6534. * `{ plotX: Number, plotY: Number, isHeader: Boolean }`
  6535. *
  6536. *
  6537. * The return should be an object containing x and y values, for example
  6538. * `{ x: 100, y: 100 }`.
  6539. *
  6540. * @sample {highcharts} highcharts/tooltip/positioner/
  6541. * A fixed tooltip position
  6542. * @sample {highstock} stock/tooltip/positioner/
  6543. * A fixed tooltip position on top of the chart
  6544. * @sample {highmaps} maps/tooltip/positioner/
  6545. * A fixed tooltip position
  6546. * @sample {highstock} stock/tooltip/split-positioner/
  6547. * Split tooltip with fixed positions
  6548. * @sample {highstock} stock/tooltip/positioner-scrollable-plotarea/
  6549. * Scrollable plot area combined with tooltip positioner
  6550. *
  6551. * @type {Highcharts.TooltipPositionerCallbackFunction}
  6552. * @since 2.2.4
  6553. * @apioption tooltip.positioner
  6554. */
  6555. /**
  6556. * The name of a symbol to use for the border around the tooltip. Can
  6557. * be one of: `"callout"`, `"circle"` or `"rect"`. When
  6558. * [tooltip.split](#tooltip.split)
  6559. * option is enabled, shape is applied to all boxes except header, which
  6560. * is controlled by
  6561. * [tooltip.headerShape](#tooltip.headerShape).
  6562. *
  6563. * Custom callbacks for symbol path generation can also be added to
  6564. * `Highcharts.SVGRenderer.prototype.symbols` the same way as for
  6565. * [series.marker.symbol](plotOptions.line.marker.symbol).
  6566. *
  6567. * @type {Highcharts.TooltipShapeValue}
  6568. * @default callout
  6569. * @since 4.0
  6570. * @apioption tooltip.shape
  6571. */
  6572. /**
  6573. * The name of a symbol to use for the border around the tooltip
  6574. * header. Applies only when [tooltip.split](#tooltip.split) is
  6575. * enabled.
  6576. *
  6577. * Custom callbacks for symbol path generation can also be added to
  6578. * `Highcharts.SVGRenderer.prototype.symbols` the same way as for
  6579. * [series.marker.symbol](plotOptions.line.marker.symbol).
  6580. *
  6581. * @see [tooltip.shape](#tooltip.shape)
  6582. *
  6583. * @sample {highstock} stock/tooltip/split-positioner/
  6584. * Different shapes for header and split boxes
  6585. *
  6586. * @type {Highcharts.TooltipShapeValue}
  6587. * @default callout
  6588. * @validvalue ["callout", "square"]
  6589. * @since 7.0
  6590. * @apioption tooltip.headerShape
  6591. */
  6592. /**
  6593. * When the tooltip is shared, the entire plot area will capture mouse
  6594. * movement or touch events. Tooltip texts for series types with ordered
  6595. * data (not pie, scatter, flags etc) will be shown in a single bubble.
  6596. * This is recommended for single series charts and for tablet/mobile
  6597. * optimized charts.
  6598. *
  6599. * See also [tooltip.split](#tooltip.split), that is better suited for
  6600. * charts with many series, especially line-type series. The
  6601. * `tooltip.split` option takes precedence over `tooltip.shared`.
  6602. *
  6603. * @sample {highcharts} highcharts/tooltip/shared-false/
  6604. * False by default
  6605. * @sample {highcharts} highcharts/tooltip/shared-true/
  6606. * True
  6607. * @sample {highcharts} highcharts/tooltip/shared-x-crosshair/
  6608. * True with x axis crosshair
  6609. * @sample {highcharts} highcharts/tooltip/shared-true-mixed-types/
  6610. * True with mixed series types
  6611. *
  6612. * @type {boolean}
  6613. * @default false
  6614. * @since 2.1
  6615. * @product highcharts highstock
  6616. * @apioption tooltip.shared
  6617. */
  6618. /**
  6619. * Split the tooltip into one label per series, with the header close
  6620. * to the axis. This is recommended over [shared](#tooltip.shared)
  6621. * tooltips for charts with multiple line series, generally making them
  6622. * easier to read. This option takes precedence over `tooltip.shared`.
  6623. *
  6624. * @productdesc {highstock} In Highcharts Stock, tooltips are split
  6625. * by default since v6.0.0. Stock charts typically contain
  6626. * multi-dimension points and multiple panes, making split tooltips
  6627. * the preferred layout over
  6628. * the previous `shared` tooltip.
  6629. *
  6630. * @sample highcharts/tooltip/split/
  6631. * Split tooltip
  6632. * @sample {highcharts|highstock} highcharts/tooltip/formatter-split/
  6633. * Split tooltip and custom formatter callback
  6634. *
  6635. * @type {boolean}
  6636. * @default {highcharts} false
  6637. * @default {highstock} true
  6638. * @since 5.0.0
  6639. * @product highcharts highstock
  6640. * @apioption tooltip.split
  6641. */
  6642. /**
  6643. * Prevents the tooltip from switching or closing, when touched or
  6644. * pointed.
  6645. *
  6646. * @sample highcharts/tooltip/stickoncontact/
  6647. * Tooltip sticks on pointer contact
  6648. *
  6649. * @type {boolean}
  6650. * @since 8.0.1
  6651. * @apioption tooltip.stickOnContact
  6652. */
  6653. /**
  6654. * Use HTML to render the contents of the tooltip instead of SVG. Using
  6655. * HTML allows advanced formatting like tables and images in the
  6656. * tooltip. It is also recommended for rtl languages as it works around
  6657. * rtl bugs in early Firefox.
  6658. *
  6659. * @sample {highcharts|highstock} highcharts/tooltip/footerformat/
  6660. * A table for value alignment
  6661. * @sample {highcharts|highstock} highcharts/tooltip/fullhtml/
  6662. * Full HTML tooltip
  6663. * @sample {highmaps} maps/tooltip/usehtml/
  6664. * Pure HTML tooltip
  6665. *
  6666. * @type {boolean}
  6667. * @default false
  6668. * @since 2.2
  6669. * @apioption tooltip.useHTML
  6670. */
  6671. /**
  6672. * How many decimals to show in each series' y value. This is
  6673. * overridable in each series' tooltip options object. The default is to
  6674. * preserve all decimals.
  6675. *
  6676. * @sample {highcharts|highstock} highcharts/tooltip/valuedecimals/
  6677. * Set decimals, prefix and suffix for the value
  6678. * @sample {highmaps} maps/tooltip/valuedecimals/
  6679. * Set decimals, prefix and suffix for the value
  6680. *
  6681. * @type {number}
  6682. * @since 2.2
  6683. * @apioption tooltip.valueDecimals
  6684. */
  6685. /**
  6686. * A string to prepend to each series' y value. Overridable in each
  6687. * series' tooltip options object.
  6688. *
  6689. * @sample {highcharts|highstock} highcharts/tooltip/valuedecimals/
  6690. * Set decimals, prefix and suffix for the value
  6691. * @sample {highmaps} maps/tooltip/valuedecimals/
  6692. * Set decimals, prefix and suffix for the value
  6693. *
  6694. * @type {string}
  6695. * @since 2.2
  6696. * @apioption tooltip.valuePrefix
  6697. */
  6698. /**
  6699. * A string to append to each series' y value. Overridable in each
  6700. * series' tooltip options object.
  6701. *
  6702. * @sample {highcharts|highstock} highcharts/tooltip/valuedecimals/
  6703. * Set decimals, prefix and suffix for the value
  6704. * @sample {highmaps} maps/tooltip/valuedecimals/
  6705. * Set decimals, prefix and suffix for the value
  6706. *
  6707. * @type {string}
  6708. * @since 2.2
  6709. * @apioption tooltip.valueSuffix
  6710. */
  6711. /**
  6712. * The format for the date in the tooltip header if the X axis is a
  6713. * datetime axis. The default is a best guess based on the smallest
  6714. * distance between points in the chart.
  6715. *
  6716. * @sample {highcharts} highcharts/tooltip/xdateformat/
  6717. * A different format
  6718. *
  6719. * @type {string}
  6720. * @product highcharts highstock gantt
  6721. * @apioption tooltip.xDateFormat
  6722. */
  6723. /**
  6724. * How many decimals to show for the `point.change` value when the
  6725. * `series.compare` option is set. This is overridable in each series'
  6726. * tooltip options object. The default is to preserve all decimals.
  6727. *
  6728. * @type {number}
  6729. * @since 1.0.1
  6730. * @product highstock
  6731. * @apioption tooltip.changeDecimals
  6732. */
  6733. /**
  6734. * Enable or disable the tooltip.
  6735. *
  6736. * @sample {highcharts} highcharts/tooltip/enabled/
  6737. * Disabled
  6738. * @sample {highcharts} highcharts/plotoptions/series-point-events-mouseover/
  6739. * Disable tooltip and show values on chart instead
  6740. */
  6741. enabled: true,
  6742. /**
  6743. * Enable or disable animation of the tooltip.
  6744. *
  6745. * @type {boolean}
  6746. * @default true
  6747. * @since 2.3.0
  6748. */
  6749. animation: svg,
  6750. /**
  6751. * The radius of the rounded border corners.
  6752. *
  6753. * @sample {highcharts} highcharts/tooltip/bordercolor-default/
  6754. * 5px by default
  6755. * @sample {highcharts} highcharts/tooltip/borderradius-0/
  6756. * Square borders
  6757. * @sample {highmaps} maps/tooltip/background-border/
  6758. * Background and border demo
  6759. */
  6760. borderRadius: 3,
  6761. /**
  6762. * For series on datetime axes, the date format in the tooltip's
  6763. * header will by default be guessed based on the closest data points.
  6764. * This member gives the default string representations used for
  6765. * each unit. For an overview of the replacement codes, see
  6766. * [dateFormat](/class-reference/Highcharts#.dateFormat).
  6767. *
  6768. * @see [xAxis.dateTimeLabelFormats](#xAxis.dateTimeLabelFormats)
  6769. *
  6770. * @type {Highcharts.Dictionary<string>}
  6771. * @product highcharts highstock gantt
  6772. */
  6773. dateTimeLabelFormats: {
  6774. /** @internal */
  6775. millisecond: '%A, %b %e, %H:%M:%S.%L',
  6776. /** @internal */
  6777. second: '%A, %b %e, %H:%M:%S',
  6778. /** @internal */
  6779. minute: '%A, %b %e, %H:%M',
  6780. /** @internal */
  6781. hour: '%A, %b %e, %H:%M',
  6782. /** @internal */
  6783. day: '%A, %b %e, %Y',
  6784. /** @internal */
  6785. week: 'Week from %A, %b %e, %Y',
  6786. /** @internal */
  6787. month: '%B %Y',
  6788. /** @internal */
  6789. year: '%Y'
  6790. },
  6791. /**
  6792. * A string to append to the tooltip format.
  6793. *
  6794. * @sample {highcharts} highcharts/tooltip/footerformat/
  6795. * A table for value alignment
  6796. * @sample {highmaps} maps/tooltip/format/
  6797. * Format demo
  6798. *
  6799. * @since 2.2
  6800. */
  6801. footerFormat: '',
  6802. /**
  6803. * Padding inside the tooltip, in pixels.
  6804. *
  6805. * @since 5.0.0
  6806. */
  6807. padding: 8,
  6808. /**
  6809. * Proximity snap for graphs or single points. It defaults to 10 for
  6810. * mouse-powered devices and 25 for touch devices.
  6811. *
  6812. * Note that in most cases the whole plot area captures the mouse
  6813. * movement, and in these cases `tooltip.snap` doesn't make sense. This
  6814. * applies when [stickyTracking](#plotOptions.series.stickyTracking)
  6815. * is `true` (default) and when the tooltip is [shared](#tooltip.shared)
  6816. * or [split](#tooltip.split).
  6817. *
  6818. * @sample {highcharts} highcharts/tooltip/bordercolor-default/
  6819. * 10 px by default
  6820. * @sample {highcharts} highcharts/tooltip/snap-50/
  6821. * 50 px on graph
  6822. *
  6823. * @type {number}
  6824. * @default 10/25
  6825. * @since 1.2.0
  6826. * @product highcharts highstock
  6827. */
  6828. snap: isTouchDevice ? 25 : 10,
  6829. /**
  6830. * The HTML of the tooltip header line. Variables are enclosed by
  6831. * curly brackets. Available variables are `point.key`, `series.name`,
  6832. * `series.color` and other members from the `point` and `series`
  6833. * objects. The `point.key` variable contains the category name, x
  6834. * value or datetime string depending on the type of axis. For datetime
  6835. * axes, the `point.key` date format can be set using
  6836. * `tooltip.xDateFormat`.
  6837. *
  6838. * @sample {highcharts} highcharts/tooltip/footerformat/
  6839. * An HTML table in the tooltip
  6840. * @sample {highstock} highcharts/tooltip/footerformat/
  6841. * An HTML table in the tooltip
  6842. * @sample {highmaps} maps/tooltip/format/
  6843. * Format demo
  6844. *
  6845. * @type {string}
  6846. * @apioption tooltip.headerFormat
  6847. */
  6848. headerFormat: '<span style="font-size: 10px">{point.key}</span><br/>',
  6849. /**
  6850. * The HTML of the null point's line in the tooltip. Works analogously
  6851. * to [pointFormat](#tooltip.pointFormat).
  6852. *
  6853. * @sample {highcharts} highcharts/plotoptions/series-nullformat
  6854. * Format data label and tooltip for null point.
  6855. *
  6856. * @type {string}
  6857. * @apioption tooltip.nullFormat
  6858. */
  6859. /**
  6860. * The HTML of the point's line in the tooltip. Variables are enclosed
  6861. * by curly brackets. Available variables are `point.x`, `point.y`,
  6862. * `series.name` and `series.color` and other properties on the same
  6863. * form. Furthermore, `point.y` can be extended by the
  6864. * `tooltip.valuePrefix` and `tooltip.valueSuffix` variables. This can
  6865. * also be overridden for each series, which makes it a good hook for
  6866. * displaying units.
  6867. *
  6868. * In styled mode, the dot is colored by a class name rather
  6869. * than the point color.
  6870. *
  6871. * @sample {highcharts} highcharts/tooltip/pointformat/
  6872. * A different point format with value suffix
  6873. * @sample {highmaps} maps/tooltip/format/
  6874. * Format demo
  6875. *
  6876. * @type {string}
  6877. * @since 2.2
  6878. * @apioption tooltip.pointFormat
  6879. */
  6880. pointFormat: '<span style="color:{point.color}">\u25CF</span> {series.name}: <b>{point.y}</b><br/>',
  6881. /**
  6882. * The background color or gradient for the tooltip.
  6883. *
  6884. * In styled mode, the stroke width is set in the
  6885. * `.highcharts-tooltip-box` class.
  6886. *
  6887. * @sample {highcharts} highcharts/tooltip/backgroundcolor-solid/
  6888. * Yellowish background
  6889. * @sample {highcharts} highcharts/tooltip/backgroundcolor-gradient/
  6890. * Gradient
  6891. * @sample {highcharts} highcharts/css/tooltip-border-background/
  6892. * Tooltip in styled mode
  6893. * @sample {highstock} stock/tooltip/general/
  6894. * Custom tooltip
  6895. * @sample {highstock} highcharts/css/tooltip-border-background/
  6896. * Tooltip in styled mode
  6897. * @sample {highmaps} maps/tooltip/background-border/
  6898. * Background and border demo
  6899. * @sample {highmaps} highcharts/css/tooltip-border-background/
  6900. * Tooltip in styled mode
  6901. *
  6902. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  6903. */
  6904. backgroundColor: color(palette.neutralColor3)
  6905. .setOpacity(0.85).get(),
  6906. /**
  6907. * The pixel width of the tooltip border.
  6908. *
  6909. * In styled mode, the stroke width is set in the
  6910. * `.highcharts-tooltip-box` class.
  6911. *
  6912. * @sample {highcharts} highcharts/tooltip/bordercolor-default/
  6913. * 2px by default
  6914. * @sample {highcharts} highcharts/tooltip/borderwidth/
  6915. * No border (shadow only)
  6916. * @sample {highcharts} highcharts/css/tooltip-border-background/
  6917. * Tooltip in styled mode
  6918. * @sample {highstock} stock/tooltip/general/
  6919. * Custom tooltip
  6920. * @sample {highstock} highcharts/css/tooltip-border-background/
  6921. * Tooltip in styled mode
  6922. * @sample {highmaps} maps/tooltip/background-border/
  6923. * Background and border demo
  6924. * @sample {highmaps} highcharts/css/tooltip-border-background/
  6925. * Tooltip in styled mode
  6926. */
  6927. borderWidth: 1,
  6928. /**
  6929. * Whether to apply a drop shadow to the tooltip.
  6930. *
  6931. * @sample {highcharts} highcharts/tooltip/bordercolor-default/
  6932. * True by default
  6933. * @sample {highcharts} highcharts/tooltip/shadow/
  6934. * False
  6935. * @sample {highmaps} maps/tooltip/positioner/
  6936. * Fixed tooltip position, border and shadow disabled
  6937. *
  6938. * @type {boolean|Highcharts.ShadowOptionsObject}
  6939. */
  6940. shadow: true,
  6941. /**
  6942. * CSS styles for the tooltip. The tooltip can also be styled through
  6943. * the CSS class `.highcharts-tooltip`.
  6944. *
  6945. * Note that the default `pointerEvents` style makes the tooltip ignore
  6946. * mouse events, so in order to use clickable tooltips, this value must
  6947. * be set to `auto`.
  6948. *
  6949. * @sample {highcharts} highcharts/tooltip/style/
  6950. * Greater padding, bold text
  6951. *
  6952. * @type {Highcharts.CSSObject}
  6953. */
  6954. style: {
  6955. /** @internal */
  6956. color: palette.neutralColor80,
  6957. /** @internal */
  6958. cursor: 'default',
  6959. /** @internal */
  6960. fontSize: '12px',
  6961. /** @internal */
  6962. whiteSpace: 'nowrap'
  6963. }
  6964. },
  6965. /**
  6966. * Highchart by default puts a credits label in the lower right corner
  6967. * of the chart. This can be changed using these options.
  6968. */
  6969. credits: {
  6970. /**
  6971. * Credits for map source to be concatenated with conventional credit
  6972. * text. By default this is a format string that collects copyright
  6973. * information from the map if available.
  6974. *
  6975. * @see [mapTextFull](#credits.mapTextFull)
  6976. * @see [text](#credits.text)
  6977. *
  6978. * @type {string}
  6979. * @default \u00a9 <a href="{geojson.copyrightUrl}">{geojson.copyrightShort}</a>
  6980. * @since 4.2.2
  6981. * @product highmaps
  6982. * @apioption credits.mapText
  6983. */
  6984. /**
  6985. * Detailed credits for map source to be displayed on hover of credits
  6986. * text. By default this is a format string that collects copyright
  6987. * information from the map if available.
  6988. *
  6989. * @see [mapText](#credits.mapText)
  6990. * @see [text](#credits.text)
  6991. *
  6992. * @type {string}
  6993. * @default {geojson.copyright}
  6994. * @since 4.2.2
  6995. * @product highmaps
  6996. * @apioption credits.mapTextFull
  6997. */
  6998. /**
  6999. * Whether to show the credits text.
  7000. *
  7001. * @sample {highcharts} highcharts/credits/enabled-false/
  7002. * Credits disabled
  7003. * @sample {highstock} stock/credits/enabled/
  7004. * Credits disabled
  7005. * @sample {highmaps} maps/credits/enabled-false/
  7006. * Credits disabled
  7007. */
  7008. enabled: true,
  7009. /**
  7010. * The URL for the credits label.
  7011. *
  7012. * @sample {highcharts} highcharts/credits/href/
  7013. * Custom URL and text
  7014. * @sample {highmaps} maps/credits/customized/
  7015. * Custom URL and text
  7016. */
  7017. href: 'https://www.highcharts.com?credits',
  7018. /**
  7019. * Position configuration for the credits label.
  7020. *
  7021. * @sample {highcharts} highcharts/credits/position-left/
  7022. * Left aligned
  7023. * @sample {highcharts} highcharts/credits/position-left/
  7024. * Left aligned
  7025. * @sample {highmaps} maps/credits/customized/
  7026. * Left aligned
  7027. * @sample {highmaps} maps/credits/customized/
  7028. * Left aligned
  7029. *
  7030. * @type {Highcharts.AlignObject}
  7031. * @since 2.1
  7032. */
  7033. position: {
  7034. /** @internal */
  7035. align: 'right',
  7036. /** @internal */
  7037. x: -10,
  7038. /** @internal */
  7039. verticalAlign: 'bottom',
  7040. /** @internal */
  7041. y: -5
  7042. },
  7043. /**
  7044. * CSS styles for the credits label.
  7045. *
  7046. * @see In styled mode, credits styles can be set with the
  7047. * `.highcharts-credits` class.
  7048. *
  7049. * @type {Highcharts.CSSObject}
  7050. */
  7051. style: {
  7052. /** @internal */
  7053. cursor: 'pointer',
  7054. /** @internal */
  7055. color: palette.neutralColor40,
  7056. /** @internal */
  7057. fontSize: '9px'
  7058. },
  7059. /**
  7060. * The text for the credits label.
  7061. *
  7062. * @productdesc {highmaps}
  7063. * If a map is loaded as GeoJSON, the text defaults to
  7064. * `Highcharts @ {map-credits}`. Otherwise, it defaults to
  7065. * `Highcharts.com`.
  7066. *
  7067. * @sample {highcharts} highcharts/credits/href/
  7068. * Custom URL and text
  7069. * @sample {highmaps} maps/credits/customized/
  7070. * Custom URL and text
  7071. */
  7072. text: 'Highcharts.com'
  7073. }
  7074. };
  7075. /* eslint-disable spaced-comment */
  7076. defaultOptions.chart.styledMode = false;
  7077. '';
  7078. var defaultTime = new Time(merge(defaultOptions.global,
  7079. defaultOptions.time));
  7080. /**
  7081. * Get the updated default options. Until 3.0.7, merely exposing defaultOptions
  7082. * for outside modules wasn't enough because the setOptions method created a new
  7083. * object.
  7084. *
  7085. * @function Highcharts.getOptions
  7086. *
  7087. * @return {Highcharts.Options}
  7088. */
  7089. function getOptions() {
  7090. return defaultOptions;
  7091. }
  7092. /**
  7093. * Merge the default options with custom options and return the new options
  7094. * structure. Commonly used for defining reusable templates.
  7095. *
  7096. * @sample highcharts/global/useutc-false Setting a global option
  7097. * @sample highcharts/members/setoptions Applying a global theme
  7098. *
  7099. * @function Highcharts.setOptions
  7100. *
  7101. * @param {Highcharts.Options} options
  7102. * The new custom chart options.
  7103. *
  7104. * @return {Highcharts.Options}
  7105. * Updated options.
  7106. */
  7107. function setOptions(options) {
  7108. // Copy in the default options
  7109. merge(true, defaultOptions, options);
  7110. // Update the time object
  7111. if (options.time || options.global) {
  7112. if (H.time) {
  7113. H.time.update(merge(defaultOptions.global, defaultOptions.time, options.global, options.time));
  7114. }
  7115. else {
  7116. /**
  7117. * Global `Time` object with default options. Since v6.0.5, time
  7118. * settings can be applied individually for each chart. If no
  7119. * individual settings apply, this `Time` object is shared by all
  7120. * instances.
  7121. *
  7122. * @name Highcharts.time
  7123. * @type {Highcharts.Time}
  7124. */
  7125. H.time = defaultTime;
  7126. }
  7127. }
  7128. return defaultOptions;
  7129. }
  7130. /* *
  7131. *
  7132. * Default Export
  7133. *
  7134. * */
  7135. var DefaultOptions = {
  7136. defaultOptions: defaultOptions,
  7137. defaultTime: defaultTime,
  7138. getOptions: getOptions,
  7139. setOptions: setOptions
  7140. };
  7141. return DefaultOptions;
  7142. });
  7143. _registerModule(_modules, 'Core/Animation/Fx.js', [_modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (Color, H, U) {
  7144. /* *
  7145. *
  7146. * (c) 2010-2021 Torstein Honsi
  7147. *
  7148. * License: www.highcharts.com/license
  7149. *
  7150. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  7151. *
  7152. * */
  7153. var color = Color.parse;
  7154. var win = H.win;
  7155. var isNumber = U.isNumber,
  7156. objectEach = U.objectEach;
  7157. /* eslint-disable no-invalid-this, valid-jsdoc */
  7158. /**
  7159. * An animator object used internally. One instance applies to one property
  7160. * (attribute or style prop) on one element. Animation is always initiated
  7161. * through {@link SVGElement#animate}.
  7162. *
  7163. * @example
  7164. * let rect = renderer.rect(0, 0, 10, 10).add();
  7165. * rect.animate({ width: 100 });
  7166. *
  7167. * @private
  7168. * @class
  7169. * @name Highcharts.Fx
  7170. */
  7171. var Fx = /** @class */ (function () {
  7172. /* *
  7173. *
  7174. * Constructors
  7175. *
  7176. * */
  7177. /**
  7178. *
  7179. * @param {Highcharts.HTMLDOMElement|Highcharts.SVGElement} elem
  7180. * The element to animate.
  7181. *
  7182. * @param {Partial<Highcharts.AnimationOptionsObject>} options
  7183. * Animation options.
  7184. *
  7185. * @param {string} prop
  7186. * The single attribute or CSS property to animate.
  7187. */
  7188. function Fx(elem, options, prop) {
  7189. this.pos = NaN;
  7190. this.options = options;
  7191. this.elem = elem;
  7192. this.prop = prop;
  7193. }
  7194. /* *
  7195. *
  7196. * Functions
  7197. *
  7198. * */
  7199. /**
  7200. * Set the current step of a path definition on SVGElement.
  7201. *
  7202. * @function Highcharts.Fx#dSetter
  7203. *
  7204. * @return {void}
  7205. */
  7206. Fx.prototype.dSetter = function () {
  7207. var paths = this.paths,
  7208. start = paths && paths[0],
  7209. end = paths && paths[1],
  7210. now = this.now || 0;
  7211. var path = [];
  7212. // Land on the final path without adjustment points appended in the ends
  7213. if (now === 1 || !start || !end) {
  7214. path = this.toD || [];
  7215. }
  7216. else if (start.length === end.length && now < 1) {
  7217. for (var i = 0; i < end.length; i++) {
  7218. // Tween between the start segment and the end segment. Start
  7219. // with a copy of the end segment and tween the appropriate
  7220. // numerics
  7221. var startSeg = start[i];
  7222. var endSeg = end[i];
  7223. var tweenSeg = [];
  7224. for (var j = 0; j < endSeg.length; j++) {
  7225. var startItem = startSeg[j];
  7226. var endItem = endSeg[j];
  7227. // Tween numbers
  7228. if (isNumber(startItem) &&
  7229. isNumber(endItem) &&
  7230. // Arc boolean flags
  7231. !(endSeg[0] === 'A' && (j === 4 || j === 5))) {
  7232. tweenSeg[j] = startItem + now * (endItem - startItem);
  7233. // Strings, take directly from the end segment
  7234. }
  7235. else {
  7236. tweenSeg[j] = endItem;
  7237. }
  7238. }
  7239. path.push(tweenSeg);
  7240. }
  7241. // If animation is finished or length not matching, land on right value
  7242. }
  7243. else {
  7244. path = end;
  7245. }
  7246. this.elem.attr('d', path, void 0, true);
  7247. };
  7248. /**
  7249. * Update the element with the current animation step.
  7250. *
  7251. * @function Highcharts.Fx#update
  7252. *
  7253. * @return {void}
  7254. */
  7255. Fx.prototype.update = function () {
  7256. var elem = this.elem,
  7257. prop = this.prop, // if destroyed, it is null
  7258. now = this.now,
  7259. step = this.options.step;
  7260. // Animation setter defined from outside
  7261. if (this[prop + 'Setter']) {
  7262. this[prop + 'Setter']();
  7263. // Other animations on SVGElement
  7264. }
  7265. else if (elem.attr) {
  7266. if (elem.element) {
  7267. elem.attr(prop, now, null, true);
  7268. }
  7269. // HTML styles, raw HTML content like container size
  7270. }
  7271. else {
  7272. elem.style[prop] = now + this.unit;
  7273. }
  7274. if (step) {
  7275. step.call(elem, now, this);
  7276. }
  7277. };
  7278. /**
  7279. * Run an animation.
  7280. *
  7281. * @function Highcharts.Fx#run
  7282. *
  7283. * @param {number} from
  7284. * The current value, value to start from.
  7285. *
  7286. * @param {number} to
  7287. * The end value, value to land on.
  7288. *
  7289. * @param {string} unit
  7290. * The property unit, for example `px`.
  7291. *
  7292. * @return {void}
  7293. */
  7294. Fx.prototype.run = function (from, to, unit) {
  7295. var self = this,
  7296. options = self.options,
  7297. timer = function (gotoEnd) {
  7298. return timer.stopped ? false : self.step(gotoEnd);
  7299. }, requestAnimationFrame = win.requestAnimationFrame ||
  7300. function (step) {
  7301. setTimeout(step, 13);
  7302. }, step = function () {
  7303. for (var i = 0; i < Fx.timers.length; i++) {
  7304. if (!Fx.timers[i]()) {
  7305. Fx.timers.splice(i--, 1);
  7306. }
  7307. }
  7308. if (Fx.timers.length) {
  7309. requestAnimationFrame(step);
  7310. }
  7311. };
  7312. if (from === to && !this.elem['forceAnimate:' + this.prop]) {
  7313. delete options.curAnim[this.prop];
  7314. if (options.complete && Object.keys(options.curAnim).length === 0) {
  7315. options.complete.call(this.elem);
  7316. }
  7317. }
  7318. else { // #7166
  7319. this.startTime = +new Date();
  7320. this.start = from;
  7321. this.end = to;
  7322. this.unit = unit;
  7323. this.now = this.start;
  7324. this.pos = 0;
  7325. timer.elem = this.elem;
  7326. timer.prop = this.prop;
  7327. if (timer() && Fx.timers.push(timer) === 1) {
  7328. requestAnimationFrame(step);
  7329. }
  7330. }
  7331. };
  7332. /**
  7333. * Run a single step in the animation.
  7334. *
  7335. * @function Highcharts.Fx#step
  7336. *
  7337. * @param {boolean} [gotoEnd]
  7338. * Whether to go to the endpoint of the animation after abort.
  7339. *
  7340. * @return {boolean}
  7341. * Returns `true` if animation continues.
  7342. */
  7343. Fx.prototype.step = function (gotoEnd) {
  7344. var t = +new Date(),
  7345. options = this.options,
  7346. elem = this.elem,
  7347. complete = options.complete,
  7348. duration = options.duration,
  7349. curAnim = options.curAnim;
  7350. var ret,
  7351. done;
  7352. if (elem.attr && !elem.element) { // #2616, element is destroyed
  7353. ret = false;
  7354. }
  7355. else if (gotoEnd || t >= duration + this.startTime) {
  7356. this.now = this.end;
  7357. this.pos = 1;
  7358. this.update();
  7359. curAnim[this.prop] = true;
  7360. done = true;
  7361. objectEach(curAnim, function (val) {
  7362. if (val !== true) {
  7363. done = false;
  7364. }
  7365. });
  7366. if (done && complete) {
  7367. complete.call(elem);
  7368. }
  7369. ret = false;
  7370. }
  7371. else {
  7372. this.pos = options.easing((t - this.startTime) / duration);
  7373. this.now = this.start + ((this.end - this.start) * this.pos);
  7374. this.update();
  7375. ret = true;
  7376. }
  7377. return ret;
  7378. };
  7379. /**
  7380. * Prepare start and end values so that the path can be animated one to one.
  7381. *
  7382. * @function Highcharts.Fx#initPath
  7383. *
  7384. * @param {Highcharts.SVGElement} elem
  7385. * The SVGElement item.
  7386. *
  7387. * @param {Highcharts.SVGPathArray|undefined} fromD
  7388. * Starting path definition.
  7389. *
  7390. * @param {Highcharts.SVGPathArray} toD
  7391. * Ending path definition.
  7392. *
  7393. * @return {Array<Highcharts.SVGPathArray,Highcharts.SVGPathArray>}
  7394. * An array containing start and end paths in array form so that
  7395. * they can be animated in parallel.
  7396. */
  7397. Fx.prototype.initPath = function (elem, fromD, toD) {
  7398. var startX = elem.startX,
  7399. endX = elem.endX,
  7400. end = toD.slice(), // copy
  7401. isArea = elem.isArea,
  7402. positionFactor = isArea ? 2 : 1;
  7403. var shift,
  7404. fullLength,
  7405. i,
  7406. reverse,
  7407. start = fromD && fromD.slice(); // copy
  7408. if (!start) {
  7409. return [end,
  7410. end];
  7411. }
  7412. /**
  7413. * If shifting points, prepend a dummy point to the end path.
  7414. * @private
  7415. * @param {Highcharts.SVGPathArray} arr - array
  7416. * @param {Highcharts.SVGPathArray} other - array
  7417. * @return {void}
  7418. */
  7419. function prepend(arr, other) {
  7420. while (arr.length < fullLength) {
  7421. // Move to, line to or curve to?
  7422. var moveSegment = arr[0],
  7423. otherSegment = other[fullLength - arr.length];
  7424. if (otherSegment && moveSegment[0] === 'M') {
  7425. if (otherSegment[0] === 'C') {
  7426. arr[0] = [
  7427. 'C',
  7428. moveSegment[1],
  7429. moveSegment[2],
  7430. moveSegment[1],
  7431. moveSegment[2],
  7432. moveSegment[1],
  7433. moveSegment[2]
  7434. ];
  7435. }
  7436. else {
  7437. arr[0] = ['L', moveSegment[1], moveSegment[2]];
  7438. }
  7439. }
  7440. // Prepend a copy of the first point
  7441. arr.unshift(moveSegment);
  7442. // For areas, the bottom path goes back again to the left, so we
  7443. // need to append a copy of the last point.
  7444. if (isArea) {
  7445. var z = arr.pop();
  7446. arr.push(arr[arr.length - 1], z); // append point and the Z
  7447. }
  7448. }
  7449. }
  7450. /**
  7451. * Copy and append last point until the length matches the end length.
  7452. * @private
  7453. * @param {Highcharts.SVGPathArray} arr - array
  7454. * @param {Highcharts.SVGPathArray} other - array
  7455. * @return {void}
  7456. */
  7457. function append(arr, other) {
  7458. while (arr.length < fullLength) {
  7459. // Pull out the slice that is going to be appended or inserted.
  7460. // In a line graph, the positionFactor is 1, and the last point
  7461. // is sliced out. In an area graph, the positionFactor is 2,
  7462. // causing the middle two points to be sliced out, since an area
  7463. // path starts at left, follows the upper path then turns and
  7464. // follows the bottom back.
  7465. var segmentToAdd = arr[Math.floor(arr.length / positionFactor) - 1].slice();
  7466. // Disable the first control point of curve segments
  7467. if (segmentToAdd[0] === 'C') {
  7468. segmentToAdd[1] = segmentToAdd[5];
  7469. segmentToAdd[2] = segmentToAdd[6];
  7470. }
  7471. if (!isArea) {
  7472. arr.push(segmentToAdd);
  7473. }
  7474. else {
  7475. var lowerSegmentToAdd = arr[Math.floor(arr.length / positionFactor)].slice();
  7476. arr.splice(arr.length / 2, 0, segmentToAdd, lowerSegmentToAdd);
  7477. }
  7478. }
  7479. }
  7480. // For sideways animation, find out how much we need to shift to get the
  7481. // start path Xs to match the end path Xs.
  7482. if (startX && endX && endX.length) {
  7483. for (i = 0; i < startX.length; i++) {
  7484. // Moving left, new points coming in on right
  7485. if (startX[i] === endX[0]) {
  7486. shift = i;
  7487. break;
  7488. // Moving right
  7489. }
  7490. else if (startX[0] ===
  7491. endX[endX.length - startX.length + i]) {
  7492. shift = i;
  7493. reverse = true;
  7494. break;
  7495. // Fixed from the right side, "scaling" left
  7496. }
  7497. else if (startX[startX.length - 1] ===
  7498. endX[endX.length - startX.length + i]) {
  7499. shift = startX.length - i;
  7500. break;
  7501. }
  7502. }
  7503. if (typeof shift === 'undefined') {
  7504. start = [];
  7505. }
  7506. }
  7507. if (start.length && isNumber(shift)) {
  7508. // The common target length for the start and end array, where both
  7509. // arrays are padded in opposite ends
  7510. fullLength = end.length + shift * positionFactor;
  7511. if (!reverse) {
  7512. prepend(end, start);
  7513. append(start, end);
  7514. }
  7515. else {
  7516. prepend(start, end);
  7517. append(end, start);
  7518. }
  7519. }
  7520. return [start, end];
  7521. };
  7522. /**
  7523. * Handle animation of the color attributes directly.
  7524. *
  7525. * @function Highcharts.Fx#fillSetter
  7526. *
  7527. * @return {void}
  7528. */
  7529. Fx.prototype.fillSetter = function () {
  7530. Fx.prototype.strokeSetter.apply(this, arguments);
  7531. };
  7532. /**
  7533. * Handle animation of the color attributes directly.
  7534. *
  7535. * @function Highcharts.Fx#strokeSetter
  7536. *
  7537. * @return {void}
  7538. */
  7539. Fx.prototype.strokeSetter = function () {
  7540. this.elem.attr(this.prop, color(this.start).tweenTo(color(this.end), this.pos), null, true);
  7541. };
  7542. /* *
  7543. *
  7544. * Static properties
  7545. *
  7546. * */
  7547. Fx.timers = [];
  7548. return Fx;
  7549. }());
  7550. /* *
  7551. *
  7552. * Default Export
  7553. *
  7554. * */
  7555. return Fx;
  7556. });
  7557. _registerModule(_modules, 'Core/Animation/AnimationUtilities.js', [_modules['Core/Animation/Fx.js'], _modules['Core/Utilities.js']], function (Fx, U) {
  7558. /* *
  7559. *
  7560. * (c) 2010-2021 Torstein Honsi
  7561. *
  7562. * License: www.highcharts.com/license
  7563. *
  7564. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  7565. *
  7566. * */
  7567. var defined = U.defined,
  7568. getStyle = U.getStyle,
  7569. isArray = U.isArray,
  7570. isNumber = U.isNumber,
  7571. isObject = U.isObject,
  7572. merge = U.merge,
  7573. objectEach = U.objectEach,
  7574. pick = U.pick;
  7575. /**
  7576. * Set the global animation to either a given value, or fall back to the given
  7577. * chart's animation option.
  7578. *
  7579. * @function Highcharts.setAnimation
  7580. *
  7581. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>|undefined} animation
  7582. * The animation object.
  7583. *
  7584. * @param {Highcharts.Chart} chart
  7585. * The chart instance.
  7586. *
  7587. * @todo
  7588. * This function always relates to a chart, and sets a property on the renderer,
  7589. * so it should be moved to the SVGRenderer.
  7590. */
  7591. function setAnimation(animation, chart) {
  7592. chart.renderer.globalAnimation = pick(animation, chart.options.chart.animation, true);
  7593. }
  7594. /**
  7595. * Get the animation in object form, where a disabled animation is always
  7596. * returned as `{ duration: 0 }`.
  7597. *
  7598. * @function Highcharts.animObject
  7599. *
  7600. * @param {boolean|Highcharts.AnimationOptionsObject} [animation=0]
  7601. * An animation setting. Can be an object with duration, complete and
  7602. * easing properties, or a boolean to enable or disable.
  7603. *
  7604. * @return {Highcharts.AnimationOptionsObject}
  7605. * An object with at least a duration property.
  7606. */
  7607. function animObject(animation) {
  7608. return isObject(animation) ?
  7609. merge({ duration: 500, defer: 0 }, animation) :
  7610. { duration: animation ? 500 : 0, defer: 0 };
  7611. }
  7612. /**
  7613. * Get the defer as a number value from series animation options.
  7614. *
  7615. * @function Highcharts.getDeferredAnimation
  7616. *
  7617. * @param {Highcharts.Chart} chart
  7618. * The chart instance.
  7619. *
  7620. * @param {boolean|Highcharts.AnimationOptionsObject} animation
  7621. * An animation setting. Can be an object with duration, complete and
  7622. * easing properties, or a boolean to enable or disable.
  7623. *
  7624. * @param {Highcharts.Series} [series]
  7625. * Series to defer animation.
  7626. *
  7627. * @return {number}
  7628. * The numeric value.
  7629. */
  7630. function getDeferredAnimation(chart, animation, series) {
  7631. var labelAnimation = animObject(animation);
  7632. var s = series ? [series] : chart.series;
  7633. var defer = 0;
  7634. var duration = 0;
  7635. s.forEach(function (series) {
  7636. var seriesAnim = animObject(series.options.animation);
  7637. defer = animation && defined(animation.defer) ?
  7638. labelAnimation.defer :
  7639. Math.max(defer, seriesAnim.duration + seriesAnim.defer);
  7640. duration = Math.min(labelAnimation.duration, seriesAnim.duration);
  7641. });
  7642. // Disable defer for exporting
  7643. if (chart.renderer.forExport) {
  7644. defer = 0;
  7645. }
  7646. var anim = {
  7647. defer: Math.max(0,
  7648. defer - duration),
  7649. duration: Math.min(defer,
  7650. duration)
  7651. };
  7652. return anim;
  7653. }
  7654. /**
  7655. * The global animate method, which uses Fx to create individual animators.
  7656. *
  7657. * @function Highcharts.animate
  7658. *
  7659. * @param {Highcharts.HTMLDOMElement|Highcharts.SVGElement} el
  7660. * The element to animate.
  7661. *
  7662. * @param {Highcharts.CSSObject|Highcharts.SVGAttributes} params
  7663. * An object containing key-value pairs of the properties to animate.
  7664. * Supports numeric as pixel-based CSS properties for HTML objects and
  7665. * attributes for SVGElements.
  7666. *
  7667. * @param {Partial<Highcharts.AnimationOptionsObject>} [opt]
  7668. * Animation options.
  7669. *
  7670. * @return {void}
  7671. */
  7672. function animate(el, params, opt) {
  7673. var start,
  7674. unit = '',
  7675. end,
  7676. fx,
  7677. args;
  7678. if (!isObject(opt)) { // Number or undefined/null
  7679. args = arguments;
  7680. opt = {
  7681. duration: args[2],
  7682. easing: args[3],
  7683. complete: args[4]
  7684. };
  7685. }
  7686. if (!isNumber(opt.duration)) {
  7687. opt.duration = 400;
  7688. }
  7689. opt.easing = typeof opt.easing === 'function' ?
  7690. opt.easing :
  7691. (Math[opt.easing] || Math.easeInOutSine);
  7692. opt.curAnim = merge(params);
  7693. objectEach(params, function (val, prop) {
  7694. // Stop current running animation of this property
  7695. stop(el, prop);
  7696. fx = new Fx(el, opt, prop);
  7697. end = void 0;
  7698. if (prop === 'd' && isArray(params.d)) {
  7699. fx.paths = fx.initPath(el, el.pathArray, params.d);
  7700. fx.toD = params.d;
  7701. start = 0;
  7702. end = 1;
  7703. }
  7704. else if (el.attr) {
  7705. start = el.attr(prop);
  7706. }
  7707. else {
  7708. start = parseFloat(getStyle(el, prop)) || 0;
  7709. if (prop !== 'opacity') {
  7710. unit = 'px';
  7711. }
  7712. }
  7713. if (!end) {
  7714. end = val;
  7715. }
  7716. if (typeof end === 'string' && end.match('px')) {
  7717. end = end.replace(/px/g, ''); // #4351
  7718. }
  7719. fx.run(start, end, unit);
  7720. });
  7721. }
  7722. /**
  7723. * Stop running animation.
  7724. *
  7725. * @function Highcharts.stop
  7726. *
  7727. * @param {Highcharts.SVGElement} el
  7728. * The SVGElement to stop animation on.
  7729. *
  7730. * @param {string} [prop]
  7731. * The property to stop animating. If given, the stop method will stop a
  7732. * single property from animating, while others continue.
  7733. *
  7734. * @return {void}
  7735. *
  7736. * @todo
  7737. * A possible extension to this would be to stop a single property, when
  7738. * we want to continue animating others. Then assign the prop to the timer
  7739. * in the Fx.run method, and check for the prop here. This would be an
  7740. * improvement in all cases where we stop the animation from .attr. Instead of
  7741. * stopping everything, we can just stop the actual attributes we're setting.
  7742. */
  7743. function stop(el, prop) {
  7744. var i = Fx.timers.length;
  7745. // Remove timers related to this element (#4519)
  7746. while (i--) {
  7747. if (Fx.timers[i].elem === el && (!prop || prop === Fx.timers[i].prop)) {
  7748. Fx.timers[i].stopped = true; // #4667
  7749. }
  7750. }
  7751. }
  7752. var animationExports = {
  7753. animate: animate,
  7754. animObject: animObject,
  7755. getDeferredAnimation: getDeferredAnimation,
  7756. setAnimation: setAnimation,
  7757. stop: stop
  7758. };
  7759. return animationExports;
  7760. });
  7761. _registerModule(_modules, 'Core/Renderer/HTML/AST.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
  7762. /* *
  7763. *
  7764. * (c) 2010-2020 Torstein Honsi
  7765. *
  7766. * License: www.highcharts.com/license
  7767. *
  7768. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  7769. *
  7770. * */
  7771. var SVG_NS = H.SVG_NS;
  7772. var attr = U.attr,
  7773. createElement = U.createElement,
  7774. discardElement = U.discardElement,
  7775. error = U.error,
  7776. isString = U.isString,
  7777. objectEach = U.objectEach,
  7778. splat = U.splat;
  7779. /* *
  7780. *
  7781. * Constants
  7782. *
  7783. * */
  7784. // In IE8, DOMParser is undefined. IE9 and PhantomJS are only able to parse XML.
  7785. var hasValidDOMParser = (function () {
  7786. try {
  7787. return Boolean(new DOMParser().parseFromString('', 'text/html'));
  7788. }
  7789. catch (e) {
  7790. return false;
  7791. }
  7792. }());
  7793. /* *
  7794. *
  7795. * Class
  7796. *
  7797. * */
  7798. /**
  7799. * The AST class represents an abstract syntax tree of HTML or SVG content. It
  7800. * can take HTML as an argument, parse it, optionally transform it to SVG, then
  7801. * perform sanitation before inserting it into the DOM.
  7802. *
  7803. * @class
  7804. * @name Highcharts.AST
  7805. *
  7806. * @param {string|Array<Highcharts.ASTNode>} source
  7807. * Either an HTML string or an ASTNode list to populate the tree.
  7808. */
  7809. var AST = /** @class */ (function () {
  7810. // Construct an AST from HTML markup, or wrap an array of existing AST nodes
  7811. function AST(source) {
  7812. this.nodes = typeof source === 'string' ?
  7813. this.parseMarkup(source) : source;
  7814. }
  7815. /**
  7816. * Filter an object of SVG or HTML attributes against the allow list.
  7817. *
  7818. * @static
  7819. *
  7820. * @function Highcharts.AST#filterUserAttributes
  7821. *
  7822. * @param {Highcharts.SVGAttributes} attributes The attributes to filter
  7823. *
  7824. * @return {Highcharts.SVGAttributes}
  7825. * The filtered attributes
  7826. */
  7827. AST.filterUserAttributes = function (attributes) {
  7828. objectEach(attributes, function (val, key) {
  7829. var valid = true;
  7830. if (AST.allowedAttributes.indexOf(key) === -1) {
  7831. valid = false;
  7832. }
  7833. if (['background', 'dynsrc', 'href', 'lowsrc', 'src']
  7834. .indexOf(key) !== -1) {
  7835. valid = isString(val) && AST.allowedReferences.some(function (ref) { return val.indexOf(ref) === 0; });
  7836. }
  7837. if (!valid) {
  7838. error("Highcharts warning: Invalid attribute '" + key + "' in config");
  7839. delete attributes[key];
  7840. }
  7841. });
  7842. return attributes;
  7843. };
  7844. /**
  7845. * Utility function to set html content for an element by passing in a
  7846. * markup string. The markup is safely parsed by the AST class to avoid
  7847. * XSS vulnerabilities. This function should be used instead of setting
  7848. * `innerHTML` in all cases where the content is not fully trusted.
  7849. *
  7850. * @static
  7851. *
  7852. * @function Highcharts.AST#setElementHTML
  7853. *
  7854. * @param {SVGDOMElement|HTMLDOMElement} el The node to set content of
  7855. * @param {string} html The markup string
  7856. */
  7857. AST.setElementHTML = function (el, html) {
  7858. el.innerHTML = ''; // Clear previous
  7859. if (html) {
  7860. var ast = new AST(html);
  7861. ast.addToDOM(el);
  7862. }
  7863. };
  7864. /**
  7865. * Add the tree defined as a hierarchical JS structure to the DOM
  7866. *
  7867. * @function Highcharts.AST#addToDOM
  7868. *
  7869. * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} parent
  7870. * The node where it should be added
  7871. *
  7872. * @return {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement}
  7873. * The inserted node.
  7874. */
  7875. AST.prototype.addToDOM = function (parent) {
  7876. /**
  7877. * @private
  7878. * @param {Highcharts.ASTNode} subtree - HTML/SVG definition
  7879. * @param {Element} [subParent] - parent node
  7880. * @return {Highcharts.SVGDOMElement|Highcharts.HTMLDOMElement} The inserted node.
  7881. */
  7882. function recurse(subtree, subParent) {
  7883. var ret;
  7884. splat(subtree).forEach(function (item) {
  7885. var tagName = item.tagName;
  7886. var textNode = item.textContent ?
  7887. H.doc.createTextNode(item.textContent) :
  7888. void 0;
  7889. var node;
  7890. if (tagName) {
  7891. if (tagName === '#text') {
  7892. node = textNode;
  7893. }
  7894. else if (AST.allowedTags.indexOf(tagName) !== -1) {
  7895. var NS = tagName === 'svg' ?
  7896. SVG_NS :
  7897. (subParent.namespaceURI || SVG_NS);
  7898. var element = H.doc.createElementNS(NS,
  7899. tagName);
  7900. var attributes_1 = item.attributes || {};
  7901. // Apply attributes from root of AST node, legacy from
  7902. // from before TextBuilder
  7903. objectEach(item, function (val, key) {
  7904. if (key !== 'tagName' &&
  7905. key !== 'attributes' &&
  7906. key !== 'children' &&
  7907. key !== 'textContent') {
  7908. attributes_1[key] = val;
  7909. }
  7910. });
  7911. attr(element, AST.filterUserAttributes(attributes_1));
  7912. // Add text content
  7913. if (textNode) {
  7914. element.appendChild(textNode);
  7915. }
  7916. // Recurse
  7917. recurse(item.children || [], element);
  7918. node = element;
  7919. }
  7920. else {
  7921. error("Highcharts warning: Invalid tagName '" + tagName + "' in config");
  7922. }
  7923. }
  7924. // Add to the tree
  7925. if (node) {
  7926. subParent.appendChild(node);
  7927. }
  7928. ret = node;
  7929. });
  7930. // Return last node added (on top level it's the only one)
  7931. return ret;
  7932. }
  7933. return recurse(this.nodes, parent);
  7934. };
  7935. /**
  7936. * Parse HTML/SVG markup into AST Node objects. Used internally from the
  7937. * constructor.
  7938. *
  7939. * @private
  7940. *
  7941. * @function Highcharts.AST#getNodesFromMarkup
  7942. *
  7943. * @param {string} markup The markup string.
  7944. *
  7945. * @return {Array<Highcharts.ASTNode>} The parsed nodes.
  7946. */
  7947. AST.prototype.parseMarkup = function (markup) {
  7948. var nodes = [];
  7949. var doc;
  7950. var body;
  7951. if (hasValidDOMParser) {
  7952. doc = new DOMParser().parseFromString(markup, 'text/html');
  7953. }
  7954. else {
  7955. body = createElement('div');
  7956. body.innerHTML = markup;
  7957. doc = { body: body };
  7958. }
  7959. var appendChildNodes = function (node,
  7960. addTo) {
  7961. var tagName = node.nodeName.toLowerCase();
  7962. // Add allowed tags
  7963. var astNode = {
  7964. tagName: tagName
  7965. };
  7966. if (tagName === '#text') {
  7967. var textContent = node.textContent || '';
  7968. // Whitespace text node, don't append it to the AST
  7969. if (/^[\s]*$/.test(textContent)) {
  7970. return;
  7971. }
  7972. astNode.textContent = textContent;
  7973. }
  7974. var parsedAttributes = node.attributes;
  7975. // Add attributes
  7976. if (parsedAttributes) {
  7977. var attributes_2 = {};
  7978. [].forEach.call(parsedAttributes, function (attrib) {
  7979. attributes_2[attrib.name] = attrib.value;
  7980. });
  7981. astNode.attributes = attributes_2;
  7982. }
  7983. // Handle children
  7984. if (node.childNodes.length) {
  7985. var children_1 = [];
  7986. [].forEach.call(node.childNodes, function (childNode) {
  7987. appendChildNodes(childNode, children_1);
  7988. });
  7989. if (children_1.length) {
  7990. astNode.children = children_1;
  7991. }
  7992. }
  7993. addTo.push(astNode);
  7994. };
  7995. [].forEach.call(doc.body.childNodes, function (childNode) { return appendChildNodes(childNode, nodes); });
  7996. if (body) {
  7997. discardElement(body);
  7998. }
  7999. return nodes;
  8000. };
  8001. /**
  8002. * The list of allowed SVG or HTML tags, used for sanitizing potentially
  8003. * harmful content from the chart configuration before adding to the DOM.
  8004. *
  8005. * @example
  8006. * // Allow a custom, trusted tag
  8007. * Highcharts.AST.allowedTags.push('blink'); // ;)
  8008. *
  8009. * @name Highcharts.AST.allowedTags
  8010. * @static
  8011. */
  8012. AST.allowedTags = [
  8013. 'a',
  8014. 'b',
  8015. 'br',
  8016. 'button',
  8017. 'caption',
  8018. 'circle',
  8019. 'clipPath',
  8020. 'code',
  8021. 'dd',
  8022. 'defs',
  8023. 'div',
  8024. 'dl',
  8025. 'dt',
  8026. 'em',
  8027. 'feComponentTransfer',
  8028. 'feFuncA',
  8029. 'feFuncB',
  8030. 'feFuncG',
  8031. 'feFuncR',
  8032. 'feGaussianBlur',
  8033. 'feOffset',
  8034. 'feMerge',
  8035. 'feMergeNode',
  8036. 'filter',
  8037. 'h1',
  8038. 'h2',
  8039. 'h3',
  8040. 'h4',
  8041. 'h5',
  8042. 'h6',
  8043. 'hr',
  8044. 'i',
  8045. 'img',
  8046. 'li',
  8047. 'linearGradient',
  8048. 'marker',
  8049. 'ol',
  8050. 'p',
  8051. 'path',
  8052. 'pattern',
  8053. 'pre',
  8054. 'rect',
  8055. 'small',
  8056. 'span',
  8057. 'stop',
  8058. 'strong',
  8059. 'style',
  8060. 'sub',
  8061. 'sup',
  8062. 'svg',
  8063. 'table',
  8064. 'text',
  8065. 'thead',
  8066. 'tbody',
  8067. 'tspan',
  8068. 'td',
  8069. 'th',
  8070. 'tr',
  8071. 'u',
  8072. 'ul',
  8073. '#text'
  8074. ];
  8075. /**
  8076. * The list of allowed SVG or HTML attributes, used for sanitizing
  8077. * potentially harmful content from the chart configuration before adding to
  8078. * the DOM.
  8079. *
  8080. * @example
  8081. * // Allow a custom, trusted attribute
  8082. * Highcharts.AST.allowedAttributes.push('data-value');
  8083. *
  8084. * @name Highcharts.AST.allowedAttributes
  8085. * @static
  8086. */
  8087. AST.allowedAttributes = [
  8088. 'aria-controls',
  8089. 'aria-describedby',
  8090. 'aria-expanded',
  8091. 'aria-haspopup',
  8092. 'aria-hidden',
  8093. 'aria-label',
  8094. 'aria-labelledby',
  8095. 'aria-live',
  8096. 'aria-pressed',
  8097. 'aria-readonly',
  8098. 'aria-roledescription',
  8099. 'aria-selected',
  8100. 'class',
  8101. 'clip-path',
  8102. 'color',
  8103. 'colspan',
  8104. 'cx',
  8105. 'cy',
  8106. 'd',
  8107. 'dx',
  8108. 'dy',
  8109. 'disabled',
  8110. 'fill',
  8111. 'height',
  8112. 'href',
  8113. 'id',
  8114. 'in',
  8115. 'markerHeight',
  8116. 'markerWidth',
  8117. 'offset',
  8118. 'opacity',
  8119. 'orient',
  8120. 'padding',
  8121. 'paddingLeft',
  8122. 'paddingRight',
  8123. 'patternUnits',
  8124. 'r',
  8125. 'refX',
  8126. 'refY',
  8127. 'role',
  8128. 'scope',
  8129. 'slope',
  8130. 'src',
  8131. 'startOffset',
  8132. 'stdDeviation',
  8133. 'stroke',
  8134. 'stroke-linecap',
  8135. 'stroke-width',
  8136. 'style',
  8137. 'tableValues',
  8138. 'result',
  8139. 'rowspan',
  8140. 'summary',
  8141. 'target',
  8142. 'tabindex',
  8143. 'text-align',
  8144. 'textAnchor',
  8145. 'textLength',
  8146. 'type',
  8147. 'valign',
  8148. 'width',
  8149. 'x',
  8150. 'x1',
  8151. 'x2',
  8152. 'y',
  8153. 'y1',
  8154. 'y2',
  8155. 'zIndex'
  8156. ];
  8157. /**
  8158. * The list of allowed references for referring attributes like `href` and
  8159. * `src`. Attribute values will only be allowed if they start with one of
  8160. * these strings.
  8161. *
  8162. * @example
  8163. * // Allow tel:
  8164. * Highcharts.AST.allowedReferences.push('tel:');
  8165. *
  8166. * @name Highcharts.AST.allowedReferences
  8167. * @static
  8168. */
  8169. AST.allowedReferences = [
  8170. 'https://',
  8171. 'http://',
  8172. 'mailto:',
  8173. '/',
  8174. '../',
  8175. './',
  8176. '#'
  8177. ];
  8178. return AST;
  8179. }());
  8180. /* *
  8181. *
  8182. * Default Export
  8183. *
  8184. * */
  8185. /* *
  8186. *
  8187. * API Declarations
  8188. *
  8189. * */
  8190. /**
  8191. * Serialized form of an SVG/HTML definition, including children.
  8192. *
  8193. * @interface Highcharts.ASTNode
  8194. */ /**
  8195. * @name Highcharts.ASTNode#attributes
  8196. * @type {Highcharts.SVGAttributes|undefined}
  8197. */ /**
  8198. * @name Highcharts.ASTNode#children
  8199. * @type {Array<Highcharts.ASTNode>|undefined}
  8200. */ /**
  8201. * @name Highcharts.ASTNode#tagName
  8202. * @type {string|undefined}
  8203. */ /**
  8204. * @name Highcharts.ASTNode#textContent
  8205. * @type {string|undefined}
  8206. */
  8207. ''; // detach doclets above
  8208. return AST;
  8209. });
  8210. _registerModule(_modules, 'Core/FormatUtilities.js', [_modules['Core/DefaultOptions.js'], _modules['Core/Utilities.js']], function (D, U) {
  8211. /* *
  8212. *
  8213. * (c) 2010-2021 Torstein Honsi
  8214. *
  8215. * License: www.highcharts.com/license
  8216. *
  8217. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  8218. *
  8219. * */
  8220. var defaultOptions = D.defaultOptions,
  8221. defaultTime = D.defaultTime;
  8222. var getNestedProperty = U.getNestedProperty,
  8223. isNumber = U.isNumber,
  8224. pick = U.pick,
  8225. pInt = U.pInt;
  8226. /* *
  8227. *
  8228. * Functions
  8229. *
  8230. * */
  8231. /**
  8232. * Formats a JavaScript date timestamp (milliseconds since Jan 1st 1970) into a
  8233. * human readable date string. The format is a subset of the formats for PHP's
  8234. * [strftime](https://www.php.net/manual/en/function.strftime.php) function.
  8235. * Additional formats can be given in the {@link Highcharts.dateFormats} hook.
  8236. *
  8237. * Since v6.0.5, all internal dates are formatted through the
  8238. * {@link Highcharts.Chart#time} instance to respect chart-level time settings.
  8239. * The `Highcharts.dateFormat` function only reflects global time settings set
  8240. * with `setOptions`.
  8241. *
  8242. * Supported format keys:
  8243. * - `%a`: Short weekday, like 'Mon'
  8244. * - `%A`: Long weekday, like 'Monday'
  8245. * - `%d`: Two digit day of the month, 01 to 31
  8246. * - `%e`: Day of the month, 1 through 31
  8247. * - `%w`: Day of the week, 0 through 6
  8248. * - `%b`: Short month, like 'Jan'
  8249. * - `%B`: Long month, like 'January'
  8250. * - `%m`: Two digit month number, 01 through 12
  8251. * - `%y`: Two digits year, like 09 for 2009
  8252. * - `%Y`: Four digits year, like 2009
  8253. * - `%H`: Two digits hours in 24h format, 00 through 23
  8254. * - `%k`: Hours in 24h format, 0 through 23
  8255. * - `%I`: Two digits hours in 12h format, 00 through 11
  8256. * - `%l`: Hours in 12h format, 1 through 12
  8257. * - `%M`: Two digits minutes, 00 through 59
  8258. * - `%p`: Upper case AM or PM
  8259. * - `%P`: Lower case AM or PM
  8260. * - `%S`: Two digits seconds, 00 through 59
  8261. * - `%L`: Milliseconds (naming from Ruby)
  8262. *
  8263. * @function Highcharts.dateFormat
  8264. *
  8265. * @param {string} format
  8266. * The desired format where various time representations are prefixed
  8267. * with `%`.
  8268. *
  8269. * @param {number} timestamp
  8270. * The JavaScript timestamp.
  8271. *
  8272. * @param {boolean} [capitalize=false]
  8273. * Upper case first letter in the return.
  8274. *
  8275. * @return {string}
  8276. * The formatted date.
  8277. */
  8278. function dateFormat(format, timestamp, capitalize) {
  8279. return defaultTime.dateFormat(format, timestamp, capitalize);
  8280. }
  8281. /**
  8282. * Format a string according to a subset of the rules of Python's String.format
  8283. * method.
  8284. *
  8285. * @example
  8286. * let s = Highcharts.format(
  8287. * 'The {color} fox was {len:.2f} feet long',
  8288. * { color: 'red', len: Math.PI }
  8289. * );
  8290. * // => The red fox was 3.14 feet long
  8291. *
  8292. * @function Highcharts.format
  8293. *
  8294. * @param {string} str
  8295. * The string to format.
  8296. *
  8297. * @param {Record<string, *>} ctx
  8298. * The context, a collection of key-value pairs where each key is
  8299. * replaced by its value.
  8300. *
  8301. * @param {Highcharts.Chart} [chart]
  8302. * A `Chart` instance used to get numberFormatter and time.
  8303. *
  8304. * @return {string}
  8305. * The formatted string.
  8306. */
  8307. function format(str, ctx, chart) {
  8308. var splitter = '{',
  8309. isInside = false,
  8310. segment,
  8311. valueAndFormat,
  8312. val,
  8313. index;
  8314. var floatRegex = /f$/;
  8315. var decRegex = /\.([0-9])/;
  8316. var lang = defaultOptions.lang;
  8317. var time = chart && chart.time || defaultTime;
  8318. var numberFormatter = chart && chart.numberFormatter || numberFormat;
  8319. var ret = [];
  8320. while (str) {
  8321. index = str.indexOf(splitter);
  8322. if (index === -1) {
  8323. break;
  8324. }
  8325. segment = str.slice(0, index);
  8326. if (isInside) { // we're on the closing bracket looking back
  8327. valueAndFormat = segment.split(':');
  8328. val = getNestedProperty(valueAndFormat.shift() || '', ctx);
  8329. // Format the replacement
  8330. if (valueAndFormat.length && typeof val === 'number') {
  8331. segment = valueAndFormat.join(':');
  8332. if (floatRegex.test(segment)) { // float
  8333. var decimals = parseInt((segment.match(decRegex) || ['', '-1'])[1], 10);
  8334. if (val !== null) {
  8335. val = numberFormatter(val, decimals, lang.decimalPoint, segment.indexOf(',') > -1 ? lang.thousandsSep : '');
  8336. }
  8337. }
  8338. else {
  8339. val = time.dateFormat(segment, val);
  8340. }
  8341. }
  8342. // Push the result and advance the cursor
  8343. ret.push(val);
  8344. }
  8345. else {
  8346. ret.push(segment);
  8347. }
  8348. str = str.slice(index + 1); // the rest
  8349. isInside = !isInside; // toggle
  8350. splitter = isInside ? '}' : '{'; // now look for next matching bracket
  8351. }
  8352. ret.push(str);
  8353. return ret.join('');
  8354. }
  8355. /**
  8356. * Format a number and return a string based on input settings.
  8357. *
  8358. * @sample highcharts/members/highcharts-numberformat/
  8359. * Custom number format
  8360. *
  8361. * @function Highcharts.numberFormat
  8362. *
  8363. * @param {number} number
  8364. * The input number to format.
  8365. *
  8366. * @param {number} decimals
  8367. * The amount of decimals. A value of -1 preserves the amount in the
  8368. * input number.
  8369. *
  8370. * @param {string} [decimalPoint]
  8371. * The decimal point, defaults to the one given in the lang options, or
  8372. * a dot.
  8373. *
  8374. * @param {string} [thousandsSep]
  8375. * The thousands separator, defaults to the one given in the lang
  8376. * options, or a space character.
  8377. *
  8378. * @return {string}
  8379. * The formatted number.
  8380. */
  8381. function numberFormat(number, decimals, decimalPoint, thousandsSep) {
  8382. number = +number || 0;
  8383. decimals = +decimals;
  8384. var ret,
  8385. fractionDigits;
  8386. var lang = defaultOptions.lang, origDec = (number.toString().split('.')[1] || '').split('e')[0].length, exponent = number.toString().split('e'), firstDecimals = decimals;
  8387. if (decimals === -1) {
  8388. // Preserve decimals. Not huge numbers (#3793).
  8389. decimals = Math.min(origDec, 20);
  8390. }
  8391. else if (!isNumber(decimals)) {
  8392. decimals = 2;
  8393. }
  8394. else if (decimals && exponent[1] && exponent[1] < 0) {
  8395. // Expose decimals from exponential notation (#7042)
  8396. fractionDigits = decimals + +exponent[1];
  8397. if (fractionDigits >= 0) {
  8398. // remove too small part of the number while keeping the notation
  8399. exponent[0] = (+exponent[0]).toExponential(fractionDigits)
  8400. .split('e')[0];
  8401. decimals = fractionDigits;
  8402. }
  8403. else {
  8404. // fractionDigits < 0
  8405. exponent[0] = exponent[0].split('.')[0] || 0;
  8406. if (decimals < 20) {
  8407. // use number instead of exponential notation (#7405)
  8408. number = (exponent[0] * Math.pow(10, exponent[1]))
  8409. .toFixed(decimals);
  8410. }
  8411. else {
  8412. // or zero
  8413. number = 0;
  8414. }
  8415. exponent[1] = 0;
  8416. }
  8417. }
  8418. // Add another decimal to avoid rounding errors of float numbers. (#4573)
  8419. // Then use toFixed to handle rounding.
  8420. var roundedNumber = (Math.abs(exponent[1] ? exponent[0] : number) +
  8421. Math.pow(10, -Math.max(decimals,
  8422. origDec) - 1)).toFixed(decimals);
  8423. // A string containing the positive integer component of the number
  8424. var strinteger = String(pInt(roundedNumber));
  8425. // Leftover after grouping into thousands. Can be 0, 1 or 2.
  8426. var thousands = strinteger.length > 3 ? strinteger.length % 3 : 0;
  8427. // Language
  8428. decimalPoint = pick(decimalPoint, lang.decimalPoint);
  8429. thousandsSep = pick(thousandsSep, lang.thousandsSep);
  8430. // Start building the return
  8431. ret = number < 0 ? '-' : '';
  8432. // Add the leftover after grouping into thousands. For example, in the
  8433. // number 42 000 000, this line adds 42.
  8434. ret += thousands ? strinteger.substr(0, thousands) + thousandsSep : '';
  8435. if (+exponent[1] < 0 && !firstDecimals) {
  8436. ret = '0';
  8437. }
  8438. else {
  8439. // Add the remaining thousands groups, joined by the thousands separator
  8440. ret += strinteger
  8441. .substr(thousands)
  8442. .replace(/(\d{3})(?=\d)/g, '$1' + thousandsSep);
  8443. }
  8444. // Add the decimal point and the decimal component
  8445. if (decimals) {
  8446. // Get the decimal component
  8447. ret += decimalPoint + roundedNumber.slice(-decimals);
  8448. }
  8449. if (exponent[1] && +ret !== 0) {
  8450. ret += 'e' + exponent[1];
  8451. }
  8452. return ret;
  8453. }
  8454. /* *
  8455. *
  8456. * Default Export
  8457. *
  8458. * */
  8459. var FormatUtilities = {
  8460. dateFormat: dateFormat,
  8461. format: format,
  8462. numberFormat: numberFormat
  8463. };
  8464. return FormatUtilities;
  8465. });
  8466. _registerModule(_modules, 'Core/Renderer/SVG/SVGElement.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Renderer/HTML/AST.js'], _modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Core/Color/Palette.js'], _modules['Core/Utilities.js']], function (A, AST, Color, H, palette, U) {
  8467. /* *
  8468. *
  8469. * (c) 2010-2021 Torstein Honsi
  8470. *
  8471. * License: www.highcharts.com/license
  8472. *
  8473. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  8474. *
  8475. * */
  8476. var animate = A.animate,
  8477. animObject = A.animObject,
  8478. stop = A.stop;
  8479. var deg2rad = H.deg2rad,
  8480. doc = H.doc,
  8481. hasTouch = H.hasTouch,
  8482. noop = H.noop,
  8483. svg = H.svg,
  8484. SVG_NS = H.SVG_NS,
  8485. win = H.win;
  8486. var addEvent = U.addEvent,
  8487. attr = U.attr,
  8488. createElement = U.createElement,
  8489. css = U.css,
  8490. defined = U.defined,
  8491. erase = U.erase,
  8492. extend = U.extend,
  8493. fireEvent = U.fireEvent,
  8494. isArray = U.isArray,
  8495. isFunction = U.isFunction,
  8496. isNumber = U.isNumber,
  8497. isString = U.isString,
  8498. merge = U.merge,
  8499. objectEach = U.objectEach,
  8500. pick = U.pick,
  8501. pInt = U.pInt,
  8502. syncTimeout = U.syncTimeout,
  8503. uniqueKey = U.uniqueKey;
  8504. /* *
  8505. *
  8506. * Class
  8507. *
  8508. * */
  8509. /* eslint-disable no-invalid-this, valid-jsdoc */
  8510. /**
  8511. * The SVGElement prototype is a JavaScript wrapper for SVG elements used in the
  8512. * rendering layer of Highcharts. Combined with the
  8513. * {@link Highcharts.SVGRenderer}
  8514. * object, these prototypes allow freeform annotation in the charts or even in
  8515. * HTML pages without instanciating a chart. The SVGElement can also wrap HTML
  8516. * labels, when `text` or `label` elements are created with the `useHTML`
  8517. * parameter.
  8518. *
  8519. * The SVGElement instances are created through factory functions on the
  8520. * {@link Highcharts.SVGRenderer}
  8521. * object, like
  8522. * {@link Highcharts.SVGRenderer#rect|rect},
  8523. * {@link Highcharts.SVGRenderer#path|path},
  8524. * {@link Highcharts.SVGRenderer#text|text},
  8525. * {@link Highcharts.SVGRenderer#label|label},
  8526. * {@link Highcharts.SVGRenderer#g|g}
  8527. * and more.
  8528. *
  8529. * @class
  8530. * @name Highcharts.SVGElement
  8531. */
  8532. var SVGElement = /** @class */ (function () {
  8533. function SVGElement() {
  8534. /* *
  8535. *
  8536. * Properties
  8537. *
  8538. * */
  8539. this.element = void 0;
  8540. this.onEvents = {};
  8541. this.opacity = 1; // Default base for animation
  8542. this.renderer = void 0;
  8543. this.SVG_NS = SVG_NS;
  8544. // Custom attributes used for symbols, these should be filtered out when
  8545. // setting SVGElement attributes (#9375).
  8546. this.symbolCustomAttribs = [
  8547. 'x',
  8548. 'y',
  8549. 'width',
  8550. 'height',
  8551. 'r',
  8552. 'start',
  8553. 'end',
  8554. 'innerR',
  8555. 'anchorX',
  8556. 'anchorY',
  8557. 'rounded'
  8558. ];
  8559. }
  8560. // @todo public zIndex?: number;
  8561. /* *
  8562. *
  8563. * Functions
  8564. *
  8565. * */
  8566. /**
  8567. * Get the current value of an attribute or pseudo attribute,
  8568. * used mainly for animation. Called internally from
  8569. * the {@link Highcharts.SVGRenderer#attr} function.
  8570. *
  8571. * @private
  8572. * @function Highcharts.SVGElement#_defaultGetter
  8573. *
  8574. * @param {string} key
  8575. * Property key.
  8576. *
  8577. * @return {number|string}
  8578. * Property value.
  8579. */
  8580. SVGElement.prototype._defaultGetter = function (key) {
  8581. var ret = pick(this[key + 'Value'], // align getter
  8582. this[key],
  8583. this.element ? this.element.getAttribute(key) : null, 0);
  8584. if (/^[\-0-9\.]+$/.test(ret)) { // is numerical
  8585. ret = parseFloat(ret);
  8586. }
  8587. return ret;
  8588. };
  8589. /**
  8590. * @private
  8591. * @function Highcharts.SVGElement#_defaultSetter
  8592. *
  8593. * @param {string} value
  8594. *
  8595. * @param {string} key
  8596. *
  8597. * @param {Highcharts.SVGDOMElement} element
  8598. *
  8599. * @return {void}
  8600. */
  8601. SVGElement.prototype._defaultSetter = function (value, key, element) {
  8602. element.setAttribute(key, value);
  8603. };
  8604. /**
  8605. * Add the element to the DOM. All elements must be added this way.
  8606. *
  8607. * @sample highcharts/members/renderer-g
  8608. * Elements added to a group
  8609. *
  8610. * @function Highcharts.SVGElement#add
  8611. *
  8612. * @param {Highcharts.SVGElement} [parent]
  8613. * The parent item to add it to. If undefined, the element is added
  8614. * to the {@link Highcharts.SVGRenderer.box}.
  8615. *
  8616. * @return {Highcharts.SVGElement}
  8617. * Returns the SVGElement for chaining.
  8618. */
  8619. SVGElement.prototype.add = function (parent) {
  8620. var renderer = this.renderer,
  8621. element = this.element;
  8622. var inserted;
  8623. if (parent) {
  8624. this.parentGroup = parent;
  8625. }
  8626. // Mark as inverted
  8627. this.parentInverted = parent && parent.inverted;
  8628. // Build formatted text
  8629. if (typeof this.textStr !== 'undefined' &&
  8630. this.element.nodeName === 'text' // Not for SVGLabel instances
  8631. ) {
  8632. renderer.buildText(this);
  8633. }
  8634. // Mark as added
  8635. this.added = true;
  8636. // If we're adding to renderer root, or other elements in the group
  8637. // have a z index, we need to handle it
  8638. if (!parent || parent.handleZ || this.zIndex) {
  8639. inserted = this.zIndexSetter();
  8640. }
  8641. // If zIndex is not handled, append at the end
  8642. if (!inserted) {
  8643. (parent ?
  8644. parent.element :
  8645. renderer.box).appendChild(element);
  8646. }
  8647. // fire an event for internal hooks
  8648. if (this.onAdd) {
  8649. this.onAdd();
  8650. }
  8651. return this;
  8652. };
  8653. /**
  8654. * Add a class name to an element.
  8655. *
  8656. * @function Highcharts.SVGElement#addClass
  8657. *
  8658. * @param {string} className
  8659. * The new class name to add.
  8660. *
  8661. * @param {boolean} [replace=false]
  8662. * When true, the existing class name(s) will be overwritten with the new
  8663. * one. When false, the new one is added.
  8664. *
  8665. * @return {Highcharts.SVGElement}
  8666. * Return the SVG element for chainability.
  8667. */
  8668. SVGElement.prototype.addClass = function (className, replace) {
  8669. var currentClassName = replace ? '' : (this.attr('class') || '');
  8670. // Trim the string and remove duplicates
  8671. className = (className || '')
  8672. .split(/ /g)
  8673. .reduce(function (newClassName, name) {
  8674. if (currentClassName.indexOf(name) === -1) {
  8675. newClassName.push(name);
  8676. }
  8677. return newClassName;
  8678. }, (currentClassName ?
  8679. [currentClassName] :
  8680. []))
  8681. .join(' ');
  8682. if (className !== currentClassName) {
  8683. this.attr('class', className);
  8684. }
  8685. return this;
  8686. };
  8687. /**
  8688. * This method is executed in the end of `attr()`, after setting all
  8689. * attributes in the hash. In can be used to efficiently consolidate
  8690. * multiple attributes in one SVG property -- e.g., translate, rotate and
  8691. * scale are merged in one "transform" attribute in the SVG node.
  8692. *
  8693. * @private
  8694. * @function Highcharts.SVGElement#afterSetters
  8695. */
  8696. SVGElement.prototype.afterSetters = function () {
  8697. // Update transform. Do this outside the loop to prevent redundant
  8698. // updating for batch setting of attributes.
  8699. if (this.doTransform) {
  8700. this.updateTransform();
  8701. this.doTransform = false;
  8702. }
  8703. };
  8704. /**
  8705. * Align the element relative to the chart or another box.
  8706. *
  8707. * @function Highcharts.SVGElement#align
  8708. *
  8709. * @param {Highcharts.AlignObject} [alignOptions]
  8710. * The alignment options. The function can be called without this
  8711. * parameter in order to re-align an element after the box has been
  8712. * updated.
  8713. *
  8714. * @param {boolean} [alignByTranslate]
  8715. * Align element by translation.
  8716. *
  8717. * @param {string|Highcharts.BBoxObject} [box]
  8718. * The box to align to, needs a width and height. When the box is a
  8719. * string, it refers to an object in the Renderer. For example, when
  8720. * box is `spacingBox`, it refers to `Renderer.spacingBox` which
  8721. * holds `width`, `height`, `x` and `y` properties.
  8722. *
  8723. * @return {Highcharts.SVGElement} Returns the SVGElement for chaining.
  8724. */
  8725. SVGElement.prototype.align = function (alignOptions, alignByTranslate, box) {
  8726. var attribs = {},
  8727. renderer = this.renderer,
  8728. alignedObjects = renderer.alignedObjects;
  8729. var x,
  8730. y,
  8731. alignTo,
  8732. alignFactor,
  8733. vAlignFactor;
  8734. // First call on instanciate
  8735. if (alignOptions) {
  8736. this.alignOptions = alignOptions;
  8737. this.alignByTranslate = alignByTranslate;
  8738. if (!box || isString(box)) {
  8739. this.alignTo = alignTo = box || 'renderer';
  8740. // prevent duplicates, like legendGroup after resize
  8741. erase(alignedObjects, this);
  8742. alignedObjects.push(this);
  8743. box = void 0; // reassign it below
  8744. }
  8745. // When called on resize, no arguments are supplied
  8746. }
  8747. else {
  8748. alignOptions = this.alignOptions;
  8749. alignByTranslate = this.alignByTranslate;
  8750. alignTo = this.alignTo;
  8751. }
  8752. box = pick(box, renderer[alignTo], alignTo === 'scrollablePlotBox' ? renderer.plotBox : void 0, renderer);
  8753. // Assign variables
  8754. var align = alignOptions.align,
  8755. vAlign = alignOptions.verticalAlign;
  8756. // default: left align
  8757. x = (box.x || 0) + (alignOptions.x || 0);
  8758. // default: top align
  8759. y = (box.y || 0) + (alignOptions.y || 0);
  8760. // Align
  8761. if (align === 'right') {
  8762. alignFactor = 1;
  8763. }
  8764. else if (align === 'center') {
  8765. alignFactor = 2;
  8766. }
  8767. if (alignFactor) {
  8768. x += (box.width - (alignOptions.width || 0)) /
  8769. alignFactor;
  8770. }
  8771. attribs[alignByTranslate ? 'translateX' : 'x'] = Math.round(x);
  8772. // Vertical align
  8773. if (vAlign === 'bottom') {
  8774. vAlignFactor = 1;
  8775. }
  8776. else if (vAlign === 'middle') {
  8777. vAlignFactor = 2;
  8778. }
  8779. if (vAlignFactor) {
  8780. y += (box.height - (alignOptions.height || 0)) /
  8781. vAlignFactor;
  8782. }
  8783. attribs[alignByTranslate ? 'translateY' : 'y'] = Math.round(y);
  8784. // Animate only if already placed
  8785. this[this.placed ? 'animate' : 'attr'](attribs);
  8786. this.placed = true;
  8787. this.alignAttr = attribs;
  8788. return this;
  8789. };
  8790. /**
  8791. * @private
  8792. * @function Highcharts.SVGElement#alignSetter
  8793. * @param {"left"|"center"|"right"} value
  8794. */
  8795. SVGElement.prototype.alignSetter = function (value) {
  8796. var convert = {
  8797. left: 'start',
  8798. center: 'middle',
  8799. right: 'end'
  8800. };
  8801. if (convert[value]) {
  8802. this.alignValue = value;
  8803. this.element.setAttribute('text-anchor', convert[value]);
  8804. }
  8805. };
  8806. /**
  8807. * Animate to given attributes or CSS properties.
  8808. *
  8809. * @sample highcharts/members/element-on/
  8810. * Setting some attributes by animation
  8811. *
  8812. * @function Highcharts.SVGElement#animate
  8813. *
  8814. * @param {Highcharts.SVGAttributes} params
  8815. * SVG attributes or CSS to animate.
  8816. *
  8817. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [options]
  8818. * Animation options.
  8819. *
  8820. * @param {Function} [complete]
  8821. * Function to perform at the end of animation.
  8822. *
  8823. * @return {Highcharts.SVGElement}
  8824. * Returns the SVGElement for chaining.
  8825. */
  8826. SVGElement.prototype.animate = function (params, options, complete) {
  8827. var _this = this;
  8828. var animOptions = animObject(pick(options,
  8829. this.renderer.globalAnimation,
  8830. true)),
  8831. deferTime = animOptions.defer;
  8832. // When the page is hidden save resources in the background by not
  8833. // running animation at all (#9749).
  8834. if (pick(doc.hidden, doc.msHidden, doc.webkitHidden, false)) {
  8835. animOptions.duration = 0;
  8836. }
  8837. if (animOptions.duration !== 0) {
  8838. // allows using a callback with the global animation without
  8839. // overwriting it
  8840. if (complete) {
  8841. animOptions.complete = complete;
  8842. }
  8843. // If defer option is defined delay the animation #12901
  8844. syncTimeout(function () {
  8845. if (_this.element) {
  8846. animate(_this, params, animOptions);
  8847. }
  8848. }, deferTime);
  8849. }
  8850. else {
  8851. this.attr(params, void 0, complete);
  8852. // Call the end step synchronously
  8853. objectEach(params, function (val, prop) {
  8854. if (animOptions.step) {
  8855. animOptions.step.call(this, val, { prop: prop, pos: 1, elem: this });
  8856. }
  8857. }, this);
  8858. }
  8859. return this;
  8860. };
  8861. /**
  8862. * Apply a text outline through a custom CSS property, by copying the text
  8863. * element and apply stroke to the copy. Used internally. Contrast checks at
  8864. * [example](https://jsfiddle.net/highcharts/43soe9m1/2/).
  8865. *
  8866. * @example
  8867. * // Specific color
  8868. * text.css({
  8869. * textOutline: '1px black'
  8870. * });
  8871. * // Automatic contrast
  8872. * text.css({
  8873. * color: '#000000', // black text
  8874. * textOutline: '1px contrast' // => white outline
  8875. * });
  8876. *
  8877. * @private
  8878. * @function Highcharts.SVGElement#applyTextOutline
  8879. *
  8880. * @param {string} textOutline
  8881. * A custom CSS `text-outline` setting, defined by `width color`.
  8882. */
  8883. SVGElement.prototype.applyTextOutline = function (textOutline) {
  8884. var elem = this.element,
  8885. hasContrast = textOutline.indexOf('contrast') !== -1,
  8886. styles = {};
  8887. // When the text shadow is set to contrast, use dark stroke for light
  8888. // text and vice versa.
  8889. if (hasContrast) {
  8890. styles.textOutline = textOutline = textOutline.replace(/contrast/g, this.renderer.getContrast(elem.style.fill));
  8891. }
  8892. // Extract the stroke width and color
  8893. var parts = textOutline.split(' ');
  8894. var color = parts[parts.length - 1];
  8895. var strokeWidth = parts[0];
  8896. if (strokeWidth && strokeWidth !== 'none' && H.svg) {
  8897. this.fakeTS = true; // Fake text shadow
  8898. // In order to get the right y position of the clone,
  8899. // copy over the y setter
  8900. this.ySetter = this.xSetter;
  8901. // Since the stroke is applied on center of the actual outline, we
  8902. // need to double it to get the correct stroke-width outside the
  8903. // glyphs.
  8904. strokeWidth = strokeWidth.replace(/(^[\d\.]+)(.*?)$/g, function (match, digit, unit) {
  8905. return (2 * Number(digit)) + unit;
  8906. });
  8907. // Remove shadows from previous runs.
  8908. this.removeTextOutline();
  8909. var outline_1 = doc.createElementNS(SVG_NS, 'tspan');
  8910. attr(outline_1, {
  8911. 'class': 'highcharts-text-outline',
  8912. fill: color,
  8913. stroke: color,
  8914. 'stroke-width': strokeWidth,
  8915. 'stroke-linejoin': 'round'
  8916. });
  8917. // For each of the tspans and text nodes, create a copy in the
  8918. // outline.
  8919. [].forEach.call(elem.childNodes, function (childNode) {
  8920. var clone = childNode.cloneNode(true);
  8921. if (clone.removeAttribute) {
  8922. ['fill', 'stroke', 'stroke-width', 'stroke'].forEach(function (prop) { return clone.removeAttribute(prop); });
  8923. }
  8924. outline_1.appendChild(clone);
  8925. });
  8926. // Insert an absolutely positioned break before the original text
  8927. // to keep it in place
  8928. var br_1 = doc.createElementNS(SVG_NS, 'tspan');
  8929. br_1.textContent = '\u200B';
  8930. // Copy x and y if not null
  8931. ['x', 'y'].forEach(function (key) {
  8932. var value = elem.getAttribute(key);
  8933. if (value) {
  8934. br_1.setAttribute(key, value);
  8935. }
  8936. });
  8937. // Insert the outline
  8938. outline_1.appendChild(br_1);
  8939. elem.insertBefore(outline_1, elem.firstChild);
  8940. }
  8941. };
  8942. /**
  8943. * @function Highcharts.SVGElement#attr
  8944. * @param {string} key
  8945. * @return {number|string}
  8946. */ /**
  8947. * Apply native and custom attributes to the SVG elements.
  8948. *
  8949. * In order to set the rotation center for rotation, set x and y to 0 and
  8950. * use `translateX` and `translateY` attributes to position the element
  8951. * instead.
  8952. *
  8953. * Attributes frequently used in Highcharts are `fill`, `stroke`,
  8954. * `stroke-width`.
  8955. *
  8956. * @sample highcharts/members/renderer-rect/
  8957. * Setting some attributes
  8958. *
  8959. * @example
  8960. * // Set multiple attributes
  8961. * element.attr({
  8962. * stroke: 'red',
  8963. * fill: 'blue',
  8964. * x: 10,
  8965. * y: 10
  8966. * });
  8967. *
  8968. * // Set a single attribute
  8969. * element.attr('stroke', 'red');
  8970. *
  8971. * // Get an attribute
  8972. * element.attr('stroke'); // => 'red'
  8973. *
  8974. * @function Highcharts.SVGElement#attr
  8975. *
  8976. * @param {string|Highcharts.SVGAttributes} [hash]
  8977. * The native and custom SVG attributes.
  8978. *
  8979. * @param {number|string|Highcharts.SVGPathArray} [val]
  8980. * If the type of the first argument is `string`, the second can be a
  8981. * value, which will serve as a single attribute setter. If the first
  8982. * argument is a string and the second is undefined, the function
  8983. * serves as a getter and the current value of the property is
  8984. * returned.
  8985. *
  8986. * @param {Function} [complete]
  8987. * A callback function to execute after setting the attributes. This
  8988. * makes the function compliant and interchangeable with the
  8989. * {@link SVGElement#animate} function.
  8990. *
  8991. * @param {boolean} [continueAnimation=true]
  8992. * Used internally when `.attr` is called as part of an animation
  8993. * step. Otherwise, calling `.attr` for an attribute will stop
  8994. * animation for that attribute.
  8995. *
  8996. * @return {Highcharts.SVGElement}
  8997. * If used as a setter, it returns the current
  8998. * {@link Highcharts.SVGElement} so the calls can be chained. If
  8999. * used as a getter, the current value of the attribute is returned.
  9000. */
  9001. SVGElement.prototype.attr = function (hash, val, complete, continueAnimation) {
  9002. var element = this.element,
  9003. symbolCustomAttribs = this.symbolCustomAttribs;
  9004. var key,
  9005. hasSetSymbolSize,
  9006. ret = this,
  9007. skipAttr,
  9008. setter;
  9009. // single key-value pair
  9010. if (typeof hash === 'string' && typeof val !== 'undefined') {
  9011. key = hash;
  9012. hash = {};
  9013. hash[key] = val;
  9014. }
  9015. // used as a getter: first argument is a string, second is undefined
  9016. if (typeof hash === 'string') {
  9017. ret = (this[hash + 'Getter'] ||
  9018. this._defaultGetter).call(this, hash, element);
  9019. // setter
  9020. }
  9021. else {
  9022. objectEach(hash, function eachAttribute(val, key) {
  9023. skipAttr = false;
  9024. // Unless .attr is from the animator update, stop current
  9025. // running animation of this property
  9026. if (!continueAnimation) {
  9027. stop(this, key);
  9028. }
  9029. // Special handling of symbol attributes
  9030. if (this.symbolName &&
  9031. symbolCustomAttribs.indexOf(key) !== -1) {
  9032. if (!hasSetSymbolSize) {
  9033. this.symbolAttr(hash);
  9034. hasSetSymbolSize = true;
  9035. }
  9036. skipAttr = true;
  9037. }
  9038. if (this.rotation && (key === 'x' || key === 'y')) {
  9039. this.doTransform = true;
  9040. }
  9041. if (!skipAttr) {
  9042. setter = (this[key + 'Setter'] ||
  9043. this._defaultSetter);
  9044. setter.call(this, val, key, element);
  9045. // Let the shadow follow the main element
  9046. if (!this.styledMode &&
  9047. this.shadows &&
  9048. /^(width|height|visibility|x|y|d|transform|cx|cy|r)$/.test(key)) {
  9049. this.updateShadows(key, val, setter);
  9050. }
  9051. }
  9052. }, this);
  9053. this.afterSetters();
  9054. }
  9055. // In accordance with animate, run a complete callback
  9056. if (complete) {
  9057. complete.call(this);
  9058. }
  9059. return ret;
  9060. };
  9061. /**
  9062. * Apply a clipping rectangle to this element.
  9063. *
  9064. * @function Highcharts.SVGElement#clip
  9065. *
  9066. * @param {Highcharts.ClipRectElement} [clipRect]
  9067. * The clipping rectangle. If skipped, the current clip is removed.
  9068. *
  9069. * @return {Highcharts.SVGElement}
  9070. * Returns the SVG element to allow chaining.
  9071. */
  9072. SVGElement.prototype.clip = function (clipRect) {
  9073. return this.attr('clip-path', clipRect ?
  9074. 'url(' + this.renderer.url + '#' + clipRect.id + ')' :
  9075. 'none');
  9076. };
  9077. /**
  9078. * Calculate the coordinates needed for drawing a rectangle crisply and
  9079. * return the calculated attributes.
  9080. *
  9081. * @function Highcharts.SVGElement#crisp
  9082. *
  9083. * @param {Highcharts.RectangleObject} rect
  9084. * Rectangle to crisp.
  9085. *
  9086. * @param {number} [strokeWidth]
  9087. * The stroke width to consider when computing crisp positioning. It can
  9088. * also be set directly on the rect parameter.
  9089. *
  9090. * @return {Highcharts.RectangleObject}
  9091. * The modified rectangle arguments.
  9092. */
  9093. SVGElement.prototype.crisp = function (rect, strokeWidth) {
  9094. var wrapper = this;
  9095. strokeWidth = strokeWidth || rect.strokeWidth || 0;
  9096. // Math.round because strokeWidth can sometimes have roundoff errors
  9097. var normalizer = Math.round(strokeWidth) % 2 / 2;
  9098. // normalize for crisp edges
  9099. rect.x = Math.floor(rect.x || wrapper.x || 0) + normalizer;
  9100. rect.y = Math.floor(rect.y || wrapper.y || 0) + normalizer;
  9101. rect.width = Math.floor((rect.width || wrapper.width || 0) - 2 * normalizer);
  9102. rect.height = Math.floor((rect.height || wrapper.height || 0) - 2 * normalizer);
  9103. if (defined(rect.strokeWidth)) {
  9104. rect.strokeWidth = strokeWidth;
  9105. }
  9106. return rect;
  9107. };
  9108. /**
  9109. * Build and apply an SVG gradient out of a common JavaScript configuration
  9110. * object. This function is called from the attribute setters. An event
  9111. * hook is added for supporting other complex color types.
  9112. *
  9113. * @private
  9114. * @function Highcharts.SVGElement#complexColor
  9115. *
  9116. * @param {Highcharts.GradientColorObject|Highcharts.PatternObject} colorOptions
  9117. * The gradient or pattern options structure.
  9118. *
  9119. * @param {string} prop
  9120. * The property to apply, can either be `fill` or `stroke`.
  9121. *
  9122. * @param {Highcharts.SVGDOMElement} elem
  9123. * SVG element to apply the gradient on.
  9124. */
  9125. SVGElement.prototype.complexColor = function (colorOptions, prop, elem) {
  9126. var renderer = this.renderer;
  9127. var colorObject,
  9128. gradName,
  9129. gradAttr,
  9130. radAttr,
  9131. gradients,
  9132. stops,
  9133. stopColor,
  9134. stopOpacity,
  9135. radialReference,
  9136. id,
  9137. key = [],
  9138. value;
  9139. fireEvent(this.renderer, 'complexColor', {
  9140. args: arguments
  9141. }, function () {
  9142. // Apply linear or radial gradients
  9143. if (colorOptions.radialGradient) {
  9144. gradName = 'radialGradient';
  9145. }
  9146. else if (colorOptions.linearGradient) {
  9147. gradName = 'linearGradient';
  9148. }
  9149. if (gradName) {
  9150. gradAttr = colorOptions[gradName];
  9151. gradients = renderer.gradients;
  9152. stops = colorOptions.stops;
  9153. radialReference = elem.radialReference;
  9154. // Keep < 2.2 kompatibility
  9155. if (isArray(gradAttr)) {
  9156. colorOptions[gradName] = gradAttr = {
  9157. x1: gradAttr[0],
  9158. y1: gradAttr[1],
  9159. x2: gradAttr[2],
  9160. y2: gradAttr[3],
  9161. gradientUnits: 'userSpaceOnUse'
  9162. };
  9163. }
  9164. // Correct the radial gradient for the radial reference system
  9165. if (gradName === 'radialGradient' &&
  9166. radialReference &&
  9167. !defined(gradAttr.gradientUnits)) {
  9168. // Save the radial attributes for updating
  9169. radAttr = gradAttr;
  9170. gradAttr = merge(gradAttr, renderer.getRadialAttr(radialReference, radAttr), { gradientUnits: 'userSpaceOnUse' });
  9171. }
  9172. // Build the unique key to detect whether we need to create a
  9173. // new element (#1282)
  9174. objectEach(gradAttr, function (value, n) {
  9175. if (n !== 'id') {
  9176. key.push(n, value);
  9177. }
  9178. });
  9179. objectEach(stops, function (val) {
  9180. key.push(val);
  9181. });
  9182. key = key.join(',');
  9183. // Check if a gradient object with the same config object is
  9184. // created within this renderer
  9185. if (gradients[key]) {
  9186. id = gradients[key].attr('id');
  9187. }
  9188. else {
  9189. // Set the id and create the element
  9190. gradAttr.id = id = uniqueKey();
  9191. var gradientObject_1 = gradients[key] =
  9192. renderer.createElement(gradName)
  9193. .attr(gradAttr)
  9194. .add(renderer.defs);
  9195. gradientObject_1.radAttr = radAttr;
  9196. // The gradient needs to keep a list of stops to be able to
  9197. // destroy them
  9198. gradientObject_1.stops = [];
  9199. stops.forEach(function (stop) {
  9200. if (stop[1].indexOf('rgba') === 0) {
  9201. colorObject = Color.parse(stop[1]);
  9202. stopColor = colorObject.get('rgb');
  9203. stopOpacity = colorObject.get('a');
  9204. }
  9205. else {
  9206. stopColor = stop[1];
  9207. stopOpacity = 1;
  9208. }
  9209. var stopObject = renderer.createElement('stop').attr({
  9210. offset: stop[0],
  9211. 'stop-color': stopColor,
  9212. 'stop-opacity': stopOpacity
  9213. }).add(gradientObject_1);
  9214. // Add the stop element to the gradient
  9215. gradientObject_1.stops.push(stopObject);
  9216. });
  9217. }
  9218. // Set the reference to the gradient object
  9219. value = 'url(' + renderer.url + '#' + id + ')';
  9220. elem.setAttribute(prop, value);
  9221. elem.gradient = key;
  9222. // Allow the color to be concatenated into tooltips formatters
  9223. // etc. (#2995)
  9224. colorOptions.toString = function () {
  9225. return value;
  9226. };
  9227. }
  9228. });
  9229. };
  9230. /**
  9231. * Set styles for the element. In addition to CSS styles supported by
  9232. * native SVG and HTML elements, there are also some custom made for
  9233. * Highcharts, like `width`, `ellipsis` and `textOverflow` for SVG text
  9234. * elements.
  9235. *
  9236. * @sample highcharts/members/renderer-text-on-chart/
  9237. * Styled text
  9238. *
  9239. * @function Highcharts.SVGElement#css
  9240. *
  9241. * @param {Highcharts.CSSObject} styles
  9242. * The new CSS styles.
  9243. *
  9244. * @return {Highcharts.SVGElement}
  9245. * Return the SVG element for chaining.
  9246. */
  9247. SVGElement.prototype.css = function (styles) {
  9248. var oldStyles = this.styles, newStyles = {}, elem = this.element,
  9249. // These CSS properties are interpreted internally by the SVG
  9250. // renderer, but are not supported by SVG and should not be added to
  9251. // the DOM. In styled mode, no CSS should find its way to the DOM
  9252. // whatsoever (#6173, #6474).
  9253. svgPseudoProps = ['textOutline', 'textOverflow', 'width'];
  9254. var textWidth,
  9255. serializedCss = '',
  9256. hyphenate,
  9257. hasNew = !oldStyles;
  9258. // convert legacy
  9259. if (styles && styles.color) {
  9260. styles.fill = styles.color;
  9261. }
  9262. // Filter out existing styles to increase performance (#2640)
  9263. if (oldStyles) {
  9264. objectEach(styles, function (style, n) {
  9265. if (oldStyles && oldStyles[n] !== style) {
  9266. newStyles[n] = style;
  9267. hasNew = true;
  9268. }
  9269. });
  9270. }
  9271. if (hasNew) {
  9272. // Merge the new styles with the old ones
  9273. if (oldStyles) {
  9274. styles = extend(oldStyles, newStyles);
  9275. }
  9276. // Get the text width from style
  9277. if (styles) {
  9278. // Previously set, unset it (#8234)
  9279. if (styles.width === null || styles.width === 'auto') {
  9280. delete this.textWidth;
  9281. // Apply new
  9282. }
  9283. else if (elem.nodeName.toLowerCase() === 'text' &&
  9284. styles.width) {
  9285. textWidth = this.textWidth = pInt(styles.width);
  9286. }
  9287. }
  9288. // store object
  9289. this.styles = styles;
  9290. if (textWidth && (!svg && this.renderer.forExport)) {
  9291. delete styles.width;
  9292. }
  9293. // Serialize and set style attribute
  9294. if (elem.namespaceURI === this.SVG_NS) { // #7633
  9295. hyphenate = function (a, b) {
  9296. return '-' + b.toLowerCase();
  9297. };
  9298. objectEach(styles, function (style, n) {
  9299. if (svgPseudoProps.indexOf(n) === -1) {
  9300. serializedCss +=
  9301. n.replace(/([A-Z])/g, hyphenate) + ':' +
  9302. style + ';';
  9303. }
  9304. });
  9305. if (serializedCss) {
  9306. attr(elem, 'style', serializedCss); // #1881
  9307. }
  9308. }
  9309. else {
  9310. css(elem, styles);
  9311. }
  9312. if (this.added) {
  9313. // Rebuild text after added. Cache mechanisms in the buildText
  9314. // will prevent building if there are no significant changes.
  9315. if (this.element.nodeName === 'text') {
  9316. this.renderer.buildText(this);
  9317. }
  9318. // Apply text outline after added
  9319. if (styles && styles.textOutline) {
  9320. this.applyTextOutline(styles.textOutline);
  9321. }
  9322. }
  9323. }
  9324. return this;
  9325. };
  9326. /**
  9327. * @private
  9328. * @function Highcharts.SVGElement#dashstyleSetter
  9329. * @param {string} value
  9330. */
  9331. SVGElement.prototype.dashstyleSetter = function (value) {
  9332. var i,
  9333. strokeWidth = this['stroke-width'];
  9334. // If "inherit", like maps in IE, assume 1 (#4981). With HC5 and the new
  9335. // strokeWidth function, we should be able to use that instead.
  9336. if (strokeWidth === 'inherit') {
  9337. strokeWidth = 1;
  9338. }
  9339. value = value && value.toLowerCase();
  9340. if (value) {
  9341. var v = value
  9342. .replace('shortdashdotdot', '3,1,1,1,1,1,')
  9343. .replace('shortdashdot', '3,1,1,1')
  9344. .replace('shortdot', '1,1,')
  9345. .replace('shortdash', '3,1,')
  9346. .replace('longdash', '8,3,')
  9347. .replace(/dot/g, '1,3,')
  9348. .replace('dash', '4,3,')
  9349. .replace(/,$/, '')
  9350. .split(','); // ending comma
  9351. i = v.length;
  9352. while (i--) {
  9353. v[i] = '' + (pInt(v[i]) * pick(strokeWidth, NaN));
  9354. }
  9355. value = v.join(',').replace(/NaN/g, 'none'); // #3226
  9356. this.element.setAttribute('stroke-dasharray', value);
  9357. }
  9358. };
  9359. /**
  9360. * Destroy the element and element wrapper and clear up the DOM and event
  9361. * hooks.
  9362. *
  9363. * @function Highcharts.SVGElement#destroy
  9364. */
  9365. SVGElement.prototype.destroy = function () {
  9366. var wrapper = this,
  9367. element = wrapper.element || {},
  9368. renderer = wrapper.renderer,
  9369. ownerSVGElement = element.ownerSVGElement;
  9370. var parentToClean = (renderer.isSVG &&
  9371. element.nodeName === 'SPAN' &&
  9372. wrapper.parentGroup ||
  9373. void 0),
  9374. grandParent,
  9375. i;
  9376. // remove events
  9377. element.onclick = element.onmouseout = element.onmouseover =
  9378. element.onmousemove = element.point = null;
  9379. stop(wrapper); // stop running animations
  9380. if (wrapper.clipPath && ownerSVGElement) {
  9381. var clipPath_1 = wrapper.clipPath;
  9382. // Look for existing references to this clipPath and remove them
  9383. // before destroying the element (#6196).
  9384. // The upper case version is for Edge
  9385. [].forEach.call(ownerSVGElement.querySelectorAll('[clip-path],[CLIP-PATH]'), function (el) {
  9386. if (el.getAttribute('clip-path').indexOf(clipPath_1.element.id) > -1) {
  9387. el.removeAttribute('clip-path');
  9388. }
  9389. });
  9390. wrapper.clipPath = clipPath_1.destroy();
  9391. }
  9392. // Destroy stops in case this is a gradient object @todo old code?
  9393. if (wrapper.stops) {
  9394. for (i = 0; i < wrapper.stops.length; i++) {
  9395. wrapper.stops[i].destroy();
  9396. }
  9397. wrapper.stops.length = 0;
  9398. wrapper.stops = void 0;
  9399. }
  9400. // remove element
  9401. wrapper.safeRemoveChild(element);
  9402. if (!renderer.styledMode) {
  9403. wrapper.destroyShadows();
  9404. }
  9405. // In case of useHTML, clean up empty containers emulating SVG groups
  9406. // (#1960, #2393, #2697).
  9407. while (parentToClean &&
  9408. parentToClean.div &&
  9409. parentToClean.div.childNodes.length === 0) {
  9410. grandParent = parentToClean.parentGroup;
  9411. wrapper.safeRemoveChild(parentToClean.div);
  9412. delete parentToClean.div;
  9413. parentToClean = grandParent;
  9414. }
  9415. // remove from alignObjects
  9416. if (wrapper.alignTo) {
  9417. erase(renderer.alignedObjects, wrapper);
  9418. }
  9419. objectEach(wrapper, function (val, key) {
  9420. // Destroy child elements of a group
  9421. if (wrapper[key] &&
  9422. wrapper[key].parentGroup === wrapper &&
  9423. wrapper[key].destroy) {
  9424. wrapper[key].destroy();
  9425. }
  9426. // Delete all properties
  9427. delete wrapper[key];
  9428. });
  9429. return;
  9430. };
  9431. /**
  9432. * Destroy shadows on the element.
  9433. *
  9434. * @private
  9435. * @function Highcharts.SVGElement#destroyShadows
  9436. *
  9437. * @return {void}
  9438. */
  9439. SVGElement.prototype.destroyShadows = function () {
  9440. (this.shadows || []).forEach(function (shadow) {
  9441. this.safeRemoveChild(shadow);
  9442. }, this);
  9443. this.shadows = void 0;
  9444. };
  9445. /**
  9446. * @private
  9447. */
  9448. SVGElement.prototype.destroyTextPath = function (elem, path) {
  9449. var textElement = elem.getElementsByTagName('text')[0];
  9450. var childNodes;
  9451. if (textElement) {
  9452. // Remove textPath attributes
  9453. textElement.removeAttribute('dx');
  9454. textElement.removeAttribute('dy');
  9455. // Remove ID's:
  9456. path.element.setAttribute('id', '');
  9457. // Check if textElement includes textPath,
  9458. if (this.textPathWrapper &&
  9459. textElement.getElementsByTagName('textPath').length) {
  9460. // Move nodes to <text>
  9461. childNodes = this.textPathWrapper.element.childNodes;
  9462. // Now move all <tspan>'s and text nodes to the <textPath> node
  9463. while (childNodes.length) {
  9464. textElement.appendChild(childNodes[0]);
  9465. }
  9466. // Remove <textPath> from the DOM
  9467. textElement.removeChild(this.textPathWrapper.element);
  9468. }
  9469. }
  9470. else if (elem.getAttribute('dx') || elem.getAttribute('dy')) {
  9471. // Remove textPath attributes from elem
  9472. // to get correct text-outline position
  9473. elem.removeAttribute('dx');
  9474. elem.removeAttribute('dy');
  9475. }
  9476. if (this.textPathWrapper) {
  9477. // Set textPathWrapper to undefined and destroy it
  9478. this.textPathWrapper = this.textPathWrapper.destroy();
  9479. }
  9480. };
  9481. /**
  9482. * @private
  9483. * @function Highcharts.SVGElement#dSettter
  9484. * @param {number|string|Highcharts.SVGPathArray} value
  9485. * @param {string} key
  9486. * @param {Highcharts.SVGDOMElement} element
  9487. */
  9488. SVGElement.prototype.dSetter = function (value, key, element) {
  9489. if (isArray(value)) {
  9490. // Backwards compatibility, convert one-dimensional array into an
  9491. // array of segments
  9492. if (typeof value[0] === 'string') {
  9493. value = this.renderer.pathToSegments(value);
  9494. }
  9495. this.pathArray = value;
  9496. value = value.reduce(function (acc, seg, i) {
  9497. if (!seg || !seg.join) {
  9498. return (seg || '').toString();
  9499. }
  9500. return (i ? acc + ' ' : '') + seg.join(' ');
  9501. }, '');
  9502. }
  9503. if (/(NaN| {2}|^$)/.test(value)) {
  9504. value = 'M 0 0';
  9505. }
  9506. // Check for cache before resetting. Resetting causes disturbance in the
  9507. // DOM, causing flickering in some cases in Edge/IE (#6747). Also
  9508. // possible performance gain.
  9509. if (this[key] !== value) {
  9510. element.setAttribute(key, value);
  9511. this[key] = value;
  9512. }
  9513. };
  9514. /**
  9515. * Fade out an element by animating its opacity down to 0, and hide it on
  9516. * complete. Used internally for the tooltip.
  9517. *
  9518. * @function Highcharts.SVGElement#fadeOut
  9519. *
  9520. * @param {number} [duration=150]
  9521. * The fade duration in milliseconds.
  9522. */
  9523. SVGElement.prototype.fadeOut = function (duration) {
  9524. var elemWrapper = this;
  9525. elemWrapper.animate({
  9526. opacity: 0
  9527. }, {
  9528. duration: pick(duration, 150),
  9529. complete: function () {
  9530. // #3088, assuming we're only using this for tooltips
  9531. elemWrapper.attr({ y: -9999 }).hide();
  9532. }
  9533. });
  9534. };
  9535. /**
  9536. * @private
  9537. * @function Highcharts.SVGElement#fillSetter
  9538. * @param {Highcharts.ColorType} value
  9539. * @param {string} key
  9540. * @param {Highcharts.SVGDOMElement} element
  9541. */
  9542. SVGElement.prototype.fillSetter = function (value, key, element) {
  9543. if (typeof value === 'string') {
  9544. element.setAttribute(key, value);
  9545. }
  9546. else if (value) {
  9547. this.complexColor(value, key, element);
  9548. }
  9549. };
  9550. /**
  9551. * Get the bounding box (width, height, x and y) for the element. Generally
  9552. * used to get rendered text size. Since this is called a lot in charts,
  9553. * the results are cached based on text properties, in order to save DOM
  9554. * traffic. The returned bounding box includes the rotation, so for example
  9555. * a single text line of rotation 90 will report a greater height, and a
  9556. * width corresponding to the line-height.
  9557. *
  9558. * @sample highcharts/members/renderer-on-chart/
  9559. * Draw a rectangle based on a text's bounding box
  9560. *
  9561. * @function Highcharts.SVGElement#getBBox
  9562. *
  9563. * @param {boolean} [reload]
  9564. * Skip the cache and get the updated DOM bouding box.
  9565. *
  9566. * @param {number} [rot]
  9567. * Override the element's rotation. This is internally used on axis
  9568. * labels with a value of 0 to find out what the bounding box would
  9569. * be have been if it were not rotated.
  9570. *
  9571. * @return {Highcharts.BBoxObject}
  9572. * The bounding box with `x`, `y`, `width` and `height` properties.
  9573. */
  9574. SVGElement.prototype.getBBox = function (reload, rot) {
  9575. var wrapper = this,
  9576. renderer = wrapper.renderer,
  9577. element = wrapper.element,
  9578. styles = wrapper.styles,
  9579. textStr = wrapper.textStr,
  9580. cache = renderer.cache,
  9581. cacheKeys = renderer.cacheKeys,
  9582. isSVG = element.namespaceURI === wrapper.SVG_NS,
  9583. rotation = pick(rot,
  9584. wrapper.rotation, 0),
  9585. fontSize = renderer.styledMode ? (element &&
  9586. SVGElement.prototype.getStyle.call(element, 'font-size')) : (styles && styles.fontSize);
  9587. var bBox, // = wrapper.bBox,
  9588. width,
  9589. height,
  9590. toggleTextShadowShim,
  9591. cacheKey;
  9592. // Avoid undefined and null (#7316)
  9593. if (defined(textStr)) {
  9594. cacheKey = textStr.toString();
  9595. // Since numbers are monospaced, and numerical labels appear a lot
  9596. // in a chart, we assume that a label of n characters has the same
  9597. // bounding box as others of the same length. Unless there is inner
  9598. // HTML in the label. In that case, leave the numbers as is (#5899).
  9599. if (cacheKey.indexOf('<') === -1) {
  9600. cacheKey = cacheKey.replace(/[0-9]/g, '0');
  9601. }
  9602. // Properties that affect bounding box
  9603. cacheKey += [
  9604. '',
  9605. rotation,
  9606. fontSize,
  9607. wrapper.textWidth,
  9608. styles && styles.textOverflow,
  9609. styles && styles.fontWeight // #12163
  9610. ].join(',');
  9611. }
  9612. if (cacheKey && !reload) {
  9613. bBox = cache[cacheKey];
  9614. }
  9615. // No cache found
  9616. if (!bBox) {
  9617. // SVG elements
  9618. if (isSVG || renderer.forExport) {
  9619. try { // Fails in Firefox if the container has display: none.
  9620. // When the text shadow shim is used, we need to hide the
  9621. // fake shadows to get the correct bounding box (#3872)
  9622. toggleTextShadowShim = this.fakeTS && function (display) {
  9623. var outline = element.querySelector('.highcharts-text-outline');
  9624. if (outline) {
  9625. css(outline, { display: display });
  9626. }
  9627. };
  9628. // Workaround for #3842, Firefox reporting wrong bounding
  9629. // box for shadows
  9630. if (isFunction(toggleTextShadowShim)) {
  9631. toggleTextShadowShim('none');
  9632. }
  9633. bBox = element.getBBox ?
  9634. // SVG: use extend because IE9 is not allowed to change
  9635. // width and height in case of rotation (below)
  9636. extend({}, element.getBBox()) : {
  9637. // Legacy IE in export mode
  9638. width: element.offsetWidth,
  9639. height: element.offsetHeight
  9640. };
  9641. // #3842
  9642. if (isFunction(toggleTextShadowShim)) {
  9643. toggleTextShadowShim('');
  9644. }
  9645. }
  9646. catch (e) {
  9647. '';
  9648. }
  9649. // If the bBox is not set, the try-catch block above failed. The
  9650. // other condition is for Opera that returns a width of
  9651. // -Infinity on hidden elements.
  9652. if (!bBox || bBox.width < 0) {
  9653. bBox = { width: 0, height: 0 };
  9654. }
  9655. // VML Renderer or useHTML within SVG
  9656. }
  9657. else {
  9658. bBox = wrapper.htmlGetBBox();
  9659. }
  9660. // True SVG elements as well as HTML elements in modern browsers
  9661. // using the .useHTML option need to compensated for rotation
  9662. if (renderer.isSVG) {
  9663. width = bBox.width;
  9664. height = bBox.height;
  9665. // Workaround for wrong bounding box in IE, Edge and Chrome on
  9666. // Windows. With Highcharts' default font, IE and Edge report
  9667. // a box height of 16.899 and Chrome rounds it to 17. If this
  9668. // stands uncorrected, it results in more padding added below
  9669. // the text than above when adding a label border or background.
  9670. // Also vertical positioning is affected.
  9671. // https://jsfiddle.net/highcharts/em37nvuj/
  9672. // (#1101, #1505, #1669, #2568, #6213).
  9673. if (isSVG) {
  9674. bBox.height = height = ({
  9675. '11px,17': 14,
  9676. '13px,20': 16
  9677. }[styles &&
  9678. styles.fontSize + ',' + Math.round(height)] ||
  9679. height);
  9680. }
  9681. // Adjust for rotated text
  9682. if (rotation) {
  9683. var rad = rotation * deg2rad;
  9684. bBox.width = Math.abs(height * Math.sin(rad)) +
  9685. Math.abs(width * Math.cos(rad));
  9686. bBox.height = Math.abs(height * Math.cos(rad)) +
  9687. Math.abs(width * Math.sin(rad));
  9688. }
  9689. }
  9690. // Cache it. When loading a chart in a hidden iframe in Firefox and
  9691. // IE/Edge, the bounding box height is 0, so don't cache it (#5620).
  9692. if (cacheKey && bBox.height > 0) {
  9693. // Rotate (#4681)
  9694. while (cacheKeys.length > 250) {
  9695. delete cache[cacheKeys.shift()];
  9696. }
  9697. if (!cache[cacheKey]) {
  9698. cacheKeys.push(cacheKey);
  9699. }
  9700. cache[cacheKey] = bBox;
  9701. }
  9702. }
  9703. return bBox;
  9704. };
  9705. /**
  9706. * Get the computed style. Only in styled mode.
  9707. *
  9708. * @example
  9709. * chart.series[0].points[0].graphic.getStyle('stroke-width'); // => '1px'
  9710. *
  9711. * @function Highcharts.SVGElement#getStyle
  9712. *
  9713. * @param {string} prop
  9714. * The property name to check for.
  9715. *
  9716. * @return {string}
  9717. * The current computed value.
  9718. */
  9719. SVGElement.prototype.getStyle = function (prop) {
  9720. return win
  9721. .getComputedStyle(this.element || this, '')
  9722. .getPropertyValue(prop);
  9723. };
  9724. /**
  9725. * Check if an element has the given class name.
  9726. *
  9727. * @function Highcharts.SVGElement#hasClass
  9728. *
  9729. * @param {string} className
  9730. * The class name to check for.
  9731. *
  9732. * @return {boolean}
  9733. * Whether the class name is found.
  9734. */
  9735. SVGElement.prototype.hasClass = function (className) {
  9736. return ('' + this.attr('class'))
  9737. .split(' ')
  9738. .indexOf(className) !== -1;
  9739. };
  9740. /**
  9741. * Hide the element, similar to setting the `visibility` attribute to
  9742. * `hidden`.
  9743. *
  9744. * @function Highcharts.SVGElement#hide
  9745. *
  9746. * @param {boolean} [hideByTranslation=false]
  9747. * The flag to determine if element should be hidden by moving out
  9748. * of the viewport. Used for example for dataLabels.
  9749. *
  9750. * @return {Highcharts.SVGElement}
  9751. * Returns the SVGElement for chaining.
  9752. */
  9753. SVGElement.prototype.hide = function (hideByTranslation) {
  9754. if (hideByTranslation) {
  9755. this.attr({ y: -9999 });
  9756. }
  9757. else {
  9758. this.attr({ visibility: 'hidden' });
  9759. }
  9760. return this;
  9761. };
  9762. /**
  9763. * @private
  9764. */
  9765. SVGElement.prototype.htmlGetBBox = function () {
  9766. return { height: 0, width: 0, x: 0, y: 0 };
  9767. };
  9768. /**
  9769. * Initialize the SVG element. This function only exists to make the
  9770. * initialization process overridable. It should not be called directly.
  9771. *
  9772. * @function Highcharts.SVGElement#init
  9773. *
  9774. * @param {Highcharts.SVGRenderer} renderer
  9775. * The SVGRenderer instance to initialize to.
  9776. *
  9777. * @param {string} nodeName
  9778. * The SVG node name.
  9779. */
  9780. SVGElement.prototype.init = function (renderer, nodeName) {
  9781. /**
  9782. * The primary DOM node. Each `SVGElement` instance wraps a main DOM
  9783. * node, but may also represent more nodes.
  9784. *
  9785. * @name Highcharts.SVGElement#element
  9786. * @type {Highcharts.SVGDOMElement|Highcharts.HTMLDOMElement}
  9787. */
  9788. this.element = nodeName === 'span' ?
  9789. createElement(nodeName) :
  9790. doc.createElementNS(this.SVG_NS, nodeName);
  9791. /**
  9792. * The renderer that the SVGElement belongs to.
  9793. *
  9794. * @name Highcharts.SVGElement#renderer
  9795. * @type {Highcharts.SVGRenderer}
  9796. */
  9797. this.renderer = renderer;
  9798. fireEvent(this, 'afterInit');
  9799. };
  9800. /**
  9801. * Invert a group, rotate and flip. This is used internally on inverted
  9802. * charts, where the points and graphs are drawn as if not inverted, then
  9803. * the series group elements are inverted.
  9804. *
  9805. * @function Highcharts.SVGElement#invert
  9806. *
  9807. * @param {boolean} inverted
  9808. * Whether to invert or not. An inverted shape can be un-inverted by
  9809. * setting it to false.
  9810. *
  9811. * @return {Highcharts.SVGElement}
  9812. * Return the SVGElement for chaining.
  9813. */
  9814. SVGElement.prototype.invert = function (inverted) {
  9815. this.inverted = inverted;
  9816. this.updateTransform();
  9817. return this;
  9818. };
  9819. /**
  9820. * Add an event listener. This is a simple setter that replaces the
  9821. * previous event of the same type added by this function, as opposed to
  9822. * the {@link Highcharts#addEvent} function.
  9823. *
  9824. * @sample highcharts/members/element-on/
  9825. * A clickable rectangle
  9826. *
  9827. * @function Highcharts.SVGElement#on
  9828. *
  9829. * @param {string} eventType
  9830. * The event type.
  9831. *
  9832. * @param {Function} handler
  9833. * The handler callback.
  9834. *
  9835. * @return {Highcharts.SVGElement}
  9836. * The SVGElement for chaining.
  9837. */
  9838. SVGElement.prototype.on = function (eventType, handler) {
  9839. var onEvents = this.onEvents;
  9840. if (onEvents[eventType]) {
  9841. // Unbind existing event
  9842. onEvents[eventType]();
  9843. }
  9844. onEvents[eventType] = addEvent(this.element, eventType, handler);
  9845. return this;
  9846. };
  9847. /**
  9848. * @private
  9849. * @function Highcharts.SVGElement#opacitySetter
  9850. * @param {string} value
  9851. * @param {string} key
  9852. * @param {Highcharts.SVGDOMElement} element
  9853. */
  9854. SVGElement.prototype.opacitySetter = function (value, key, element) {
  9855. // Round off to avoid float errors, like tests where opacity lands on
  9856. // 9.86957e-06 instead of 0
  9857. var opacity = Number(Number(value).toFixed(3));
  9858. this.opacity = opacity;
  9859. element.setAttribute(key, opacity);
  9860. };
  9861. /**
  9862. * Remove a class name from the element.
  9863. *
  9864. * @function Highcharts.SVGElement#removeClass
  9865. *
  9866. * @param {string|RegExp} className
  9867. * The class name to remove.
  9868. *
  9869. * @return {Highcharts.SVGElement} Returns the SVG element for chainability.
  9870. */
  9871. SVGElement.prototype.removeClass = function (className) {
  9872. return this.attr('class', ('' + this.attr('class'))
  9873. .replace(isString(className) ?
  9874. new RegExp("(^| )" + className + "( |$)") : // #12064, #13590
  9875. className, ' ')
  9876. .replace(/ +/g, ' ')
  9877. .trim());
  9878. };
  9879. /**
  9880. *
  9881. * @private
  9882. */
  9883. SVGElement.prototype.removeTextOutline = function () {
  9884. var outline = this.element
  9885. .querySelector('tspan.highcharts-text-outline');
  9886. if (outline) {
  9887. this.safeRemoveChild(outline);
  9888. }
  9889. };
  9890. /**
  9891. * Removes an element from the DOM.
  9892. *
  9893. * @private
  9894. * @function Highcharts.SVGElement#safeRemoveChild
  9895. *
  9896. * @param {Highcharts.SVGDOMElement|Highcharts.HTMLDOMElement} element
  9897. * The DOM node to remove.
  9898. */
  9899. SVGElement.prototype.safeRemoveChild = function (element) {
  9900. var parentNode = element.parentNode;
  9901. if (parentNode) {
  9902. parentNode.removeChild(element);
  9903. }
  9904. };
  9905. /**
  9906. * Set the coordinates needed to draw a consistent radial gradient across
  9907. * a shape regardless of positioning inside the chart. Used on pie slices
  9908. * to make all the slices have the same radial reference point.
  9909. *
  9910. * @function Highcharts.SVGElement#setRadialReference
  9911. *
  9912. * @param {Array<number>} coordinates
  9913. * The center reference. The format is `[centerX, centerY, diameter]` in
  9914. * pixels.
  9915. *
  9916. * @return {Highcharts.SVGElement}
  9917. * Returns the SVGElement for chaining.
  9918. */
  9919. SVGElement.prototype.setRadialReference = function (coordinates) {
  9920. var existingGradient = (this.element.gradient &&
  9921. this.renderer.gradients[this.element.gradient]);
  9922. this.element.radialReference = coordinates;
  9923. // On redrawing objects with an existing gradient, the gradient needs
  9924. // to be repositioned (#3801)
  9925. if (existingGradient && existingGradient.radAttr) {
  9926. existingGradient.animate(this.renderer.getRadialAttr(coordinates, existingGradient.radAttr));
  9927. }
  9928. return this;
  9929. };
  9930. /**
  9931. * @private
  9932. * @function Highcharts.SVGElement#setTextPath
  9933. * @param {Highcharts.SVGElement} path
  9934. * Path to follow.
  9935. * @param {Highcharts.DataLabelsTextPathOptionsObject} textPathOptions
  9936. * Options.
  9937. * @return {Highcharts.SVGElement}
  9938. * Returns the SVGElement for chaining.
  9939. */
  9940. SVGElement.prototype.setTextPath = function (path, textPathOptions) {
  9941. var elem = this.element,
  9942. textNode = this.text ? this.text.element : elem,
  9943. attribsMap = {
  9944. textAnchor: 'text-anchor'
  9945. };
  9946. var adder = false,
  9947. textPathElement,
  9948. textPathId,
  9949. textPathWrapper = this.textPathWrapper,
  9950. firstTime = !textPathWrapper;
  9951. // Defaults
  9952. textPathOptions = merge(true, {
  9953. enabled: true,
  9954. attributes: {
  9955. dy: -5,
  9956. startOffset: '50%',
  9957. textAnchor: 'middle'
  9958. }
  9959. }, textPathOptions);
  9960. var attrs = AST.filterUserAttributes(textPathOptions.attributes);
  9961. if (path && textPathOptions && textPathOptions.enabled) {
  9962. // In case of fixed width for a text, string is rebuilt
  9963. // (e.g. ellipsis is applied), so we need to rebuild textPath too
  9964. if (textPathWrapper &&
  9965. textPathWrapper.element.parentNode === null) {
  9966. // When buildText functionality was triggered again
  9967. // and deletes textPathWrapper parentNode
  9968. firstTime = true;
  9969. textPathWrapper = textPathWrapper.destroy();
  9970. }
  9971. else if (textPathWrapper) {
  9972. // Case after drillup when spans were added into
  9973. // the DOM outside the textPathWrapper parentGroup
  9974. this.removeTextOutline.call(textPathWrapper.parentGroup);
  9975. }
  9976. // label() has padding, text() doesn't
  9977. if (this.options && this.options.padding) {
  9978. attrs.dx = -this.options.padding;
  9979. }
  9980. if (!textPathWrapper) {
  9981. // Create <textPath>, defer the DOM adder
  9982. this.textPathWrapper = textPathWrapper =
  9983. this.renderer.createElement('textPath');
  9984. adder = true;
  9985. }
  9986. textPathElement = textPathWrapper.element;
  9987. // Set ID for the path
  9988. textPathId = path.element.getAttribute('id');
  9989. if (!textPathId) {
  9990. path.element.setAttribute('id', textPathId = uniqueKey());
  9991. }
  9992. // Change DOM structure, by placing <textPath> tag in <text>
  9993. if (firstTime) {
  9994. // Adjust the position
  9995. textNode.setAttribute('y', 0); // Firefox
  9996. if (isNumber(attrs.dx)) {
  9997. textNode.setAttribute('x', -attrs.dx);
  9998. }
  9999. // Move all <tspan>'s and text nodes to the <textPath> node. Do
  10000. // not move other elements like <title> or <path>
  10001. var childNodes = [].slice.call(textNode.childNodes);
  10002. for (var i = 0; i < childNodes.length; i++) {
  10003. var childNode = childNodes[i];
  10004. if (childNode.nodeType === Node.TEXT_NODE ||
  10005. childNode.nodeName === 'tspan') {
  10006. textPathElement.appendChild(childNode);
  10007. }
  10008. }
  10009. }
  10010. // Add <textPath> to the DOM
  10011. if (adder && textPathWrapper) {
  10012. textPathWrapper.add({ element: textNode });
  10013. }
  10014. // Set basic options:
  10015. // Use `setAttributeNS` because Safari needs this..
  10016. textPathElement.setAttributeNS('http://www.w3.org/1999/xlink', 'href', this.renderer.url + '#' + textPathId);
  10017. // Presentation attributes:
  10018. // dx/dy options must by set on <text> (parent),
  10019. // the rest should be set on <textPath>
  10020. if (defined(attrs.dy)) {
  10021. textPathElement.parentNode
  10022. .setAttribute('dy', attrs.dy);
  10023. delete attrs.dy;
  10024. }
  10025. if (defined(attrs.dx)) {
  10026. textPathElement.parentNode
  10027. .setAttribute('dx', attrs.dx);
  10028. delete attrs.dx;
  10029. }
  10030. // Additional attributes
  10031. objectEach(attrs, function (val, key) {
  10032. textPathElement.setAttribute(attribsMap[key] || key, val);
  10033. });
  10034. // Remove translation, text that follows path does not need that
  10035. elem.removeAttribute('transform');
  10036. // Remove shadows and text outlines
  10037. this.removeTextOutline.call(textPathWrapper);
  10038. // Remove background and border for label(), see #10545
  10039. // Alternatively, we can disable setting background rects in
  10040. // series.drawDataLabels()
  10041. if (this.text && !this.renderer.styledMode) {
  10042. this.attr({
  10043. fill: 'none',
  10044. 'stroke-width': 0
  10045. });
  10046. }
  10047. // Disable some functions
  10048. this.updateTransform = noop;
  10049. this.applyTextOutline = noop;
  10050. }
  10051. else if (textPathWrapper) {
  10052. // Reset to prototype
  10053. delete this.updateTransform;
  10054. delete this.applyTextOutline;
  10055. // Restore DOM structure:
  10056. this.destroyTextPath(elem, path);
  10057. // Bring attributes back
  10058. this.updateTransform();
  10059. // Set textOutline back for text()
  10060. if (this.options && this.options.rotation) {
  10061. this.applyTextOutline(this.options.style.textOutline);
  10062. }
  10063. }
  10064. return this;
  10065. };
  10066. /**
  10067. * Add a shadow to the element. Must be called after the element is added to
  10068. * the DOM. In styled mode, this method is not used, instead use `defs` and
  10069. * filters.
  10070. *
  10071. * @example
  10072. * renderer.rect(10, 100, 100, 100)
  10073. * .attr({ fill: 'red' })
  10074. * .shadow(true);
  10075. *
  10076. * @function Highcharts.SVGElement#shadow
  10077. *
  10078. * @param {boolean|Highcharts.ShadowOptionsObject} [shadowOptions]
  10079. * The shadow options. If `true`, the default options are applied. If
  10080. * `false`, the current shadow will be removed.
  10081. *
  10082. * @param {Highcharts.SVGElement} [group]
  10083. * The SVG group element where the shadows will be applied. The
  10084. * default is to add it to the same parent as the current element.
  10085. * Internally, this is ised for pie slices, where all the shadows are
  10086. * added to an element behind all the slices.
  10087. *
  10088. * @param {boolean} [cutOff]
  10089. * Used internally for column shadows.
  10090. *
  10091. * @return {Highcharts.SVGElement}
  10092. * Returns the SVGElement for chaining.
  10093. */
  10094. SVGElement.prototype.shadow = function (shadowOptions, group, cutOff) {
  10095. var shadows = [],
  10096. element = this.element,
  10097. oldShadowOptions = this.oldShadowOptions,
  10098. defaultShadowOptions = {
  10099. color: palette.neutralColor100,
  10100. offsetX: this.parentInverted ? -1 : 1,
  10101. offsetY: this.parentInverted ? -1 : 1,
  10102. opacity: 0.15,
  10103. width: 3
  10104. };
  10105. var i,
  10106. shadow,
  10107. strokeWidth,
  10108. shadowElementOpacity,
  10109. update = false,
  10110. // compensate for inverted plot area
  10111. transform,
  10112. options;
  10113. if (shadowOptions === true) {
  10114. options = defaultShadowOptions;
  10115. }
  10116. else if (typeof shadowOptions === 'object') {
  10117. options = extend(defaultShadowOptions, shadowOptions);
  10118. }
  10119. // Update shadow when options change (#12091).
  10120. if (options) {
  10121. // Go over each key to look for change
  10122. if (options && oldShadowOptions) {
  10123. objectEach(options, function (value, key) {
  10124. if (value !== oldShadowOptions[key]) {
  10125. update = true;
  10126. }
  10127. });
  10128. }
  10129. if (update) {
  10130. this.destroyShadows();
  10131. }
  10132. this.oldShadowOptions = options;
  10133. }
  10134. if (!options) {
  10135. this.destroyShadows();
  10136. }
  10137. else if (!this.shadows) {
  10138. shadowElementOpacity = options.opacity / options.width;
  10139. transform = this.parentInverted ?
  10140. "translate(" + options.offsetY + ", " + options.offsetX + ")" :
  10141. "translate(" + options.offsetX + ", " + options.offsetY + ")";
  10142. for (i = 1; i <= options.width; i++) {
  10143. shadow = element.cloneNode(false);
  10144. strokeWidth = (options.width * 2) + 1 - (2 * i);
  10145. attr(shadow, {
  10146. stroke: (shadowOptions.color ||
  10147. palette.neutralColor100),
  10148. 'stroke-opacity': shadowElementOpacity * i,
  10149. 'stroke-width': strokeWidth,
  10150. transform: transform,
  10151. fill: 'none'
  10152. });
  10153. shadow.setAttribute('class', (shadow.getAttribute('class') || '') + ' highcharts-shadow');
  10154. if (cutOff) {
  10155. attr(shadow, 'height', Math.max(attr(shadow, 'height') - strokeWidth, 0));
  10156. shadow.cutHeight = strokeWidth;
  10157. }
  10158. if (group) {
  10159. group.element.appendChild(shadow);
  10160. }
  10161. else if (element.parentNode) {
  10162. element.parentNode.insertBefore(shadow, element);
  10163. }
  10164. shadows.push(shadow);
  10165. }
  10166. this.shadows = shadows;
  10167. }
  10168. return this;
  10169. };
  10170. /**
  10171. * Show the element after it has been hidden.
  10172. *
  10173. * @function Highcharts.SVGElement#show
  10174. *
  10175. * @param {boolean} [inherit=false]
  10176. * Set the visibility attribute to `inherit` rather than `visible`.
  10177. * The difference is that an element with `visibility="visible"`
  10178. * will be visible even if the parent is hidden.
  10179. *
  10180. * @return {Highcharts.SVGElement}
  10181. * Returns the SVGElement for chaining.
  10182. */
  10183. SVGElement.prototype.show = function (inherit) {
  10184. return this.attr({ visibility: inherit ? 'inherit' : 'visible' });
  10185. };
  10186. /**
  10187. * WebKit and Batik have problems with a stroke-width of zero, so in this
  10188. * case we remove the stroke attribute altogether. #1270, #1369, #3065,
  10189. * #3072.
  10190. *
  10191. * @private
  10192. * @function Highcharts.SVGElement#strokeSetter
  10193. * @param {number|string|ColorType} value
  10194. * @param {string} key
  10195. * @param {Highcharts.SVGDOMElement} element
  10196. */
  10197. SVGElement.prototype.strokeSetter = function (value, key, element) {
  10198. this[key] = value;
  10199. // Only apply the stroke attribute if the stroke width is defined and
  10200. // larger than 0
  10201. if (this.stroke && this['stroke-width']) {
  10202. // Use prototype as instance may be overridden
  10203. SVGElement.prototype.fillSetter.call(this, this.stroke, 'stroke', element);
  10204. element.setAttribute('stroke-width', this['stroke-width']);
  10205. this.hasStroke = true;
  10206. }
  10207. else if (key === 'stroke-width' && value === 0 && this.hasStroke) {
  10208. element.removeAttribute('stroke');
  10209. this.hasStroke = false;
  10210. }
  10211. else if (this.renderer.styledMode && this['stroke-width']) {
  10212. element.setAttribute('stroke-width', this['stroke-width']);
  10213. this.hasStroke = true;
  10214. }
  10215. };
  10216. /**
  10217. * Get the computed stroke width in pixel values. This is used extensively
  10218. * when drawing shapes to ensure the shapes are rendered crisp and
  10219. * positioned correctly relative to each other. Using
  10220. * `shape-rendering: crispEdges` leaves us less control over positioning,
  10221. * for example when we want to stack columns next to each other, or position
  10222. * things pixel-perfectly within the plot box.
  10223. *
  10224. * The common pattern when placing a shape is:
  10225. * - Create the SVGElement and add it to the DOM. In styled mode, it will
  10226. * now receive a stroke width from the style sheet. In classic mode we
  10227. * will add the `stroke-width` attribute.
  10228. * - Read the computed `elem.strokeWidth()`.
  10229. * - Place it based on the stroke width.
  10230. *
  10231. * @function Highcharts.SVGElement#strokeWidth
  10232. *
  10233. * @return {number}
  10234. * The stroke width in pixels. Even if the given stroke widtch (in CSS or by
  10235. * attributes) is based on `em` or other units, the pixel size is returned.
  10236. */
  10237. SVGElement.prototype.strokeWidth = function () {
  10238. // In non-styled mode, read the stroke width as set by .attr
  10239. if (!this.renderer.styledMode) {
  10240. return this['stroke-width'] || 0;
  10241. }
  10242. // In styled mode, read computed stroke width
  10243. var val = this.getStyle('stroke-width');
  10244. var ret = 0,
  10245. dummy;
  10246. // Read pixel values directly
  10247. if (val.indexOf('px') === val.length - 2) {
  10248. ret = pInt(val);
  10249. // Other values like em, pt etc need to be measured
  10250. }
  10251. else if (val !== '') {
  10252. dummy = doc.createElementNS(SVG_NS, 'rect');
  10253. attr(dummy, {
  10254. width: val,
  10255. 'stroke-width': 0
  10256. });
  10257. this.element.parentNode.appendChild(dummy);
  10258. ret = dummy.getBBox().width;
  10259. dummy.parentNode.removeChild(dummy);
  10260. }
  10261. return ret;
  10262. };
  10263. /**
  10264. * If one of the symbol size affecting parameters are changed,
  10265. * check all the others only once for each call to an element's
  10266. * .attr() method
  10267. *
  10268. * @private
  10269. * @function Highcharts.SVGElement#symbolAttr
  10270. *
  10271. * @param {Highcharts.SVGAttributes} hash
  10272. * The attributes to set.
  10273. */
  10274. SVGElement.prototype.symbolAttr = function (hash) {
  10275. var wrapper = this;
  10276. [
  10277. 'x',
  10278. 'y',
  10279. 'r',
  10280. 'start',
  10281. 'end',
  10282. 'width',
  10283. 'height',
  10284. 'innerR',
  10285. 'anchorX',
  10286. 'anchorY',
  10287. 'clockwise'
  10288. ].forEach(function (key) {
  10289. wrapper[key] = pick(hash[key], wrapper[key]);
  10290. });
  10291. wrapper.attr({
  10292. d: wrapper.renderer.symbols[wrapper.symbolName](wrapper.x, wrapper.y, wrapper.width, wrapper.height, wrapper)
  10293. });
  10294. };
  10295. /**
  10296. * @private
  10297. * @function Highcharts.SVGElement#textSetter
  10298. * @param {string} value
  10299. */
  10300. SVGElement.prototype.textSetter = function (value) {
  10301. if (value !== this.textStr) {
  10302. // Delete size caches when the text changes
  10303. // delete this.bBox; // old code in series-label
  10304. delete this.textPxLength;
  10305. this.textStr = value;
  10306. if (this.added) {
  10307. this.renderer.buildText(this);
  10308. }
  10309. }
  10310. };
  10311. /**
  10312. * @private
  10313. * @function Highcharts.SVGElement#titleSetter
  10314. * @param {string} value
  10315. */
  10316. SVGElement.prototype.titleSetter = function (value) {
  10317. var el = this.element;
  10318. var titleNode = el.getElementsByTagName('title')[0] ||
  10319. doc.createElementNS(this.SVG_NS, 'title');
  10320. // Move to first child
  10321. if (el.insertBefore) {
  10322. el.insertBefore(titleNode, el.firstChild);
  10323. }
  10324. else {
  10325. el.appendChild(titleNode);
  10326. }
  10327. // Replace text content and escape markup
  10328. titleNode.textContent =
  10329. // #3276, #3895
  10330. String(pick(value, ''))
  10331. .replace(/<[^>]*>/g, '')
  10332. .replace(/&lt;/g, '<')
  10333. .replace(/&gt;/g, '>');
  10334. };
  10335. /**
  10336. * Bring the element to the front. Alternatively, a new zIndex can be set.
  10337. *
  10338. * @sample highcharts/members/element-tofront/
  10339. * Click an element to bring it to front
  10340. *
  10341. * @function Highcharts.SVGElement#toFront
  10342. *
  10343. * @return {Highcharts.SVGElement}
  10344. * Returns the SVGElement for chaining.
  10345. */
  10346. SVGElement.prototype.toFront = function () {
  10347. var element = this.element;
  10348. element.parentNode.appendChild(element);
  10349. return this;
  10350. };
  10351. /**
  10352. * Move an object and its children by x and y values.
  10353. *
  10354. * @function Highcharts.SVGElement#translate
  10355. *
  10356. * @param {number} x
  10357. * The x value.
  10358. *
  10359. * @param {number} y
  10360. * The y value.
  10361. *
  10362. * @return {Highcharts.SVGElement}
  10363. */
  10364. SVGElement.prototype.translate = function (x, y) {
  10365. return this.attr({
  10366. translateX: x,
  10367. translateY: y
  10368. });
  10369. };
  10370. /**
  10371. * Update the shadow elements with new attributes.
  10372. *
  10373. * @private
  10374. * @function Highcharts.SVGElement#updateShadows
  10375. *
  10376. * @param {string} key
  10377. * The attribute name.
  10378. *
  10379. * @param {number} value
  10380. * The value of the attribute.
  10381. *
  10382. * @param {Function} setter
  10383. * The setter function, inherited from the parent wrapper.
  10384. */
  10385. SVGElement.prototype.updateShadows = function (key, value, setter) {
  10386. var shadows = this.shadows;
  10387. if (shadows) {
  10388. var i = shadows.length;
  10389. while (i--) {
  10390. setter.call(shadows[i], key === 'height' ?
  10391. Math.max(value - (shadows[i].cutHeight || 0), 0) :
  10392. key === 'd' ? this.d : value, key, shadows[i]);
  10393. }
  10394. }
  10395. };
  10396. /**
  10397. * Update the transform attribute based on internal properties. Deals with
  10398. * the custom `translateX`, `translateY`, `rotation`, `scaleX` and `scaleY`
  10399. * attributes and updates the SVG `transform` attribute.
  10400. *
  10401. * @private
  10402. * @function Highcharts.SVGElement#updateTransform
  10403. */
  10404. SVGElement.prototype.updateTransform = function () {
  10405. var wrapper = this,
  10406. scaleX = wrapper.scaleX,
  10407. scaleY = wrapper.scaleY,
  10408. inverted = wrapper.inverted,
  10409. rotation = wrapper.rotation,
  10410. matrix = wrapper.matrix,
  10411. element = wrapper.element;
  10412. var translateX = wrapper.translateX || 0,
  10413. translateY = wrapper.translateY || 0;
  10414. // Flipping affects translate as adjustment for flipping around the
  10415. // group's axis
  10416. if (inverted) {
  10417. translateX += wrapper.width;
  10418. translateY += wrapper.height;
  10419. }
  10420. // Apply translate. Nearly all transformed elements have translation,
  10421. // so instead of checking for translate = 0, do it always (#1767,
  10422. // #1846).
  10423. var transform = ['translate(' + translateX + ',' + translateY + ')'];
  10424. // apply matrix
  10425. if (defined(matrix)) {
  10426. transform.push('matrix(' + matrix.join(',') + ')');
  10427. }
  10428. // apply rotation
  10429. if (inverted) {
  10430. transform.push('rotate(90) scale(-1,1)');
  10431. }
  10432. else if (rotation) { // text rotation
  10433. transform.push('rotate(' + rotation + ' ' +
  10434. pick(this.rotationOriginX, element.getAttribute('x'), 0) +
  10435. ' ' +
  10436. pick(this.rotationOriginY, element.getAttribute('y') || 0) + ')');
  10437. }
  10438. // apply scale
  10439. if (defined(scaleX) || defined(scaleY)) {
  10440. transform.push('scale(' + pick(scaleX, 1) + ' ' + pick(scaleY, 1) + ')');
  10441. }
  10442. if (transform.length) {
  10443. element.setAttribute('transform', transform.join(' '));
  10444. }
  10445. };
  10446. /**
  10447. * @private
  10448. * @function Highcharts.SVGElement#visibilitySetter
  10449. *
  10450. * @param {string} value
  10451. *
  10452. * @param {string} key
  10453. *
  10454. * @param {Highcharts.SVGDOMElement} element
  10455. *
  10456. * @return {void}
  10457. */
  10458. SVGElement.prototype.visibilitySetter = function (value, key, element) {
  10459. // IE9-11 doesn't handle visibilty:inherit well, so we remove the
  10460. // attribute instead (#2881, #3909)
  10461. if (value === 'inherit') {
  10462. element.removeAttribute(key);
  10463. }
  10464. else if (this[key] !== value) { // #6747
  10465. element.setAttribute(key, value);
  10466. }
  10467. this[key] = value;
  10468. };
  10469. /**
  10470. * @private
  10471. * @function Highcharts.SVGElement#xGetter
  10472. *
  10473. * @param {string} key
  10474. *
  10475. * @return {number|string|null}
  10476. */
  10477. SVGElement.prototype.xGetter = function (key) {
  10478. if (this.element.nodeName === 'circle') {
  10479. if (key === 'x') {
  10480. key = 'cx';
  10481. }
  10482. else if (key === 'y') {
  10483. key = 'cy';
  10484. }
  10485. }
  10486. return this._defaultGetter(key);
  10487. };
  10488. /**
  10489. * @private
  10490. * @function Highcharts.SVGElement#zIndexSetter
  10491. * @param {number} [value]
  10492. * @param {string} [key]
  10493. * @return {boolean}
  10494. */
  10495. SVGElement.prototype.zIndexSetter = function (value, key) {
  10496. var renderer = this.renderer,
  10497. parentGroup = this.parentGroup,
  10498. parentWrapper = parentGroup || renderer,
  10499. parentNode = parentWrapper.element || renderer.box,
  10500. element = this.element,
  10501. svgParent = parentNode === renderer.box;
  10502. var childNodes,
  10503. otherElement,
  10504. otherZIndex,
  10505. inserted = false,
  10506. undefinedOtherZIndex,
  10507. run = this.added,
  10508. i;
  10509. if (defined(value)) {
  10510. // So we can read it for other elements in the group
  10511. element.setAttribute('data-z-index', value);
  10512. value = +value;
  10513. if (this[key] === value) {
  10514. // Only update when needed (#3865)
  10515. run = false;
  10516. }
  10517. }
  10518. else if (defined(this[key])) {
  10519. element.removeAttribute('data-z-index');
  10520. }
  10521. this[key] = value;
  10522. // Insert according to this and other elements' zIndex. Before .add() is
  10523. // called, nothing is done. Then on add, or by later calls to
  10524. // zIndexSetter, the node is placed on the right place in the DOM.
  10525. if (run) {
  10526. value = this.zIndex;
  10527. if (value && parentGroup) {
  10528. parentGroup.handleZ = true;
  10529. }
  10530. childNodes = parentNode.childNodes;
  10531. for (i = childNodes.length - 1; i >= 0 && !inserted; i--) {
  10532. otherElement = childNodes[i];
  10533. otherZIndex = otherElement.getAttribute('data-z-index');
  10534. undefinedOtherZIndex = !defined(otherZIndex);
  10535. if (otherElement !== element) {
  10536. if (
  10537. // Negative zIndex versus no zIndex:
  10538. // On all levels except the highest. If the parent is
  10539. // <svg>, then we don't want to put items before <desc>
  10540. // or <defs>
  10541. value < 0 &&
  10542. undefinedOtherZIndex &&
  10543. !svgParent &&
  10544. !i) {
  10545. parentNode.insertBefore(element, childNodes[i]);
  10546. inserted = true;
  10547. }
  10548. else if (
  10549. // Insert after the first element with a lower zIndex
  10550. pInt(otherZIndex) <= value ||
  10551. // If negative zIndex, add this before first undefined
  10552. // zIndex element
  10553. (undefinedOtherZIndex &&
  10554. (!defined(value) || value >= 0))) {
  10555. parentNode.insertBefore(element, childNodes[i + 1] || null // null for oldIE export
  10556. );
  10557. inserted = true;
  10558. }
  10559. }
  10560. }
  10561. if (!inserted) {
  10562. parentNode.insertBefore(element, childNodes[svgParent ? 3 : 0] || null // null for oldIE
  10563. );
  10564. inserted = true;
  10565. }
  10566. }
  10567. return inserted;
  10568. };
  10569. return SVGElement;
  10570. }());
  10571. // Some shared setters and getters
  10572. SVGElement.prototype['stroke-widthSetter'] = SVGElement.prototype.strokeSetter;
  10573. SVGElement.prototype.yGetter = SVGElement.prototype.xGetter;
  10574. SVGElement.prototype.matrixSetter =
  10575. SVGElement.prototype.rotationOriginXSetter =
  10576. SVGElement.prototype.rotationOriginYSetter =
  10577. SVGElement.prototype.rotationSetter =
  10578. SVGElement.prototype.scaleXSetter =
  10579. SVGElement.prototype.scaleYSetter =
  10580. SVGElement.prototype.translateXSetter =
  10581. SVGElement.prototype.translateYSetter =
  10582. SVGElement.prototype.verticalAlignSetter = function (value, key) {
  10583. this[key] = value;
  10584. this.doTransform = true;
  10585. };
  10586. /* *
  10587. *
  10588. * API Declarations
  10589. *
  10590. * */
  10591. /**
  10592. * Reference to the global SVGElement class as a workaround for a name conflict
  10593. * in the Highcharts namespace.
  10594. *
  10595. * @global
  10596. * @typedef {global.SVGElement} GlobalSVGElement
  10597. *
  10598. * @see https://developer.mozilla.org/en-US/docs/Web/API/SVGElement
  10599. */
  10600. /**
  10601. * The horizontal alignment of an element.
  10602. *
  10603. * @typedef {"center"|"left"|"right"} Highcharts.AlignValue
  10604. */
  10605. /**
  10606. * Options to align the element relative to the chart or another box.
  10607. *
  10608. * @interface Highcharts.AlignObject
  10609. */ /**
  10610. * Horizontal alignment. Can be one of `left`, `center` and `right`.
  10611. *
  10612. * @name Highcharts.AlignObject#align
  10613. * @type {Highcharts.AlignValue|undefined}
  10614. *
  10615. * @default left
  10616. */ /**
  10617. * Vertical alignment. Can be one of `top`, `middle` and `bottom`.
  10618. *
  10619. * @name Highcharts.AlignObject#verticalAlign
  10620. * @type {Highcharts.VerticalAlignValue|undefined}
  10621. *
  10622. * @default top
  10623. */ /**
  10624. * Horizontal pixel offset from alignment.
  10625. *
  10626. * @name Highcharts.AlignObject#x
  10627. * @type {number|undefined}
  10628. *
  10629. * @default 0
  10630. */ /**
  10631. * Vertical pixel offset from alignment.
  10632. *
  10633. * @name Highcharts.AlignObject#y
  10634. * @type {number|undefined}
  10635. *
  10636. * @default 0
  10637. */ /**
  10638. * Use the `transform` attribute with translateX and translateY custom
  10639. * attributes to align this elements rather than `x` and `y` attributes.
  10640. *
  10641. * @name Highcharts.AlignObject#alignByTranslate
  10642. * @type {boolean|undefined}
  10643. *
  10644. * @default false
  10645. */
  10646. /**
  10647. * Bounding box of an element.
  10648. *
  10649. * @interface Highcharts.BBoxObject
  10650. * @extends Highcharts.PositionObject
  10651. */ /**
  10652. * Height of the bounding box.
  10653. *
  10654. * @name Highcharts.BBoxObject#height
  10655. * @type {number}
  10656. */ /**
  10657. * Width of the bounding box.
  10658. *
  10659. * @name Highcharts.BBoxObject#width
  10660. * @type {number}
  10661. */ /**
  10662. * Horizontal position of the bounding box.
  10663. *
  10664. * @name Highcharts.BBoxObject#x
  10665. * @type {number}
  10666. */ /**
  10667. * Vertical position of the bounding box.
  10668. *
  10669. * @name Highcharts.BBoxObject#y
  10670. * @type {number}
  10671. */
  10672. /**
  10673. * An object of key-value pairs for SVG attributes. Attributes in Highcharts
  10674. * elements for the most parts correspond to SVG, but some are specific to
  10675. * Highcharts, like `zIndex`, `rotation`, `rotationOriginX`,
  10676. * `rotationOriginY`, `translateX`, `translateY`, `scaleX` and `scaleY`. SVG
  10677. * attributes containing a hyphen are _not_ camel-cased, they should be
  10678. * quoted to preserve the hyphen.
  10679. *
  10680. * @example
  10681. * {
  10682. * 'stroke': '#ff0000', // basic
  10683. * 'stroke-width': 2, // hyphenated
  10684. * 'rotation': 45 // custom
  10685. * 'd': ['M', 10, 10, 'L', 30, 30, 'z'] // path definition, note format
  10686. * }
  10687. *
  10688. * @interface Highcharts.SVGAttributes
  10689. */ /**
  10690. * @name Highcharts.SVGAttributes#[key:string]
  10691. * @type {*}
  10692. */ /**
  10693. * @name Highcharts.SVGAttributes#d
  10694. * @type {string|Highcharts.SVGPathArray|undefined}
  10695. */ /**
  10696. * @name Highcharts.SVGAttributes#fill
  10697. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject|undefined}
  10698. */ /**
  10699. * @name Highcharts.SVGAttributes#inverted
  10700. * @type {boolean|undefined}
  10701. */ /**
  10702. * @name Highcharts.SVGAttributes#matrix
  10703. * @type {Array<number>|undefined}
  10704. */ /**
  10705. * @name Highcharts.SVGAttributes#rotation
  10706. * @type {number|undefined}
  10707. */ /**
  10708. * @name Highcharts.SVGAttributes#rotationOriginX
  10709. * @type {number|undefined}
  10710. */ /**
  10711. * @name Highcharts.SVGAttributes#rotationOriginY
  10712. * @type {number|undefined}
  10713. */ /**
  10714. * @name Highcharts.SVGAttributes#scaleX
  10715. * @type {number|undefined}
  10716. */ /**
  10717. * @name Highcharts.SVGAttributes#scaleY
  10718. * @type {number|undefined}
  10719. */ /**
  10720. * @name Highcharts.SVGAttributes#stroke
  10721. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject|undefined}
  10722. */ /**
  10723. * @name Highcharts.SVGAttributes#style
  10724. * @type {string|Highcharts.CSSObject|undefined}
  10725. */ /**
  10726. * @name Highcharts.SVGAttributes#translateX
  10727. * @type {number|undefined}
  10728. */ /**
  10729. * @name Highcharts.SVGAttributes#translateY
  10730. * @type {number|undefined}
  10731. */ /**
  10732. * @name Highcharts.SVGAttributes#zIndex
  10733. * @type {number|undefined}
  10734. */
  10735. /**
  10736. * An SVG DOM element. The type is a reference to the regular SVGElement in the
  10737. * global scope.
  10738. *
  10739. * @typedef {globals.GlobalSVGElement} Highcharts.SVGDOMElement
  10740. *
  10741. * @see https://developer.mozilla.org/en-US/docs/Web/API/SVGElement
  10742. */
  10743. /**
  10744. * The vertical alignment of an element.
  10745. *
  10746. * @typedef {"bottom"|"middle"|"top"} Highcharts.VerticalAlignValue
  10747. */
  10748. ''; // detach doclets above
  10749. return SVGElement;
  10750. });
  10751. _registerModule(_modules, 'Core/Renderer/RendererRegistry.js', [_modules['Core/Globals.js']], function (H) {
  10752. /* *
  10753. *
  10754. * (c) 2010-2021 Torstein Honsi
  10755. *
  10756. * License: www.highcharts.com/license
  10757. *
  10758. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  10759. *
  10760. * */
  10761. /* *
  10762. *
  10763. * Namespace
  10764. *
  10765. * */
  10766. var RendererRegistry;
  10767. (function (RendererRegistry) {
  10768. /* *
  10769. *
  10770. * Static Properties
  10771. *
  10772. * */
  10773. var defaultRenderer;
  10774. RendererRegistry.rendererTypes = {};
  10775. /* *
  10776. *
  10777. * Static Functions
  10778. *
  10779. * */
  10780. /**
  10781. * Gets a registered renderer class. If no renderer type is provided or the
  10782. * requested renderer was not founded, the default renderer is returned.
  10783. *
  10784. * @param {string} [rendererType]
  10785. * Renderer type or the default renderer.
  10786. *
  10787. * @return {Highcharts.Class<Highcharts.SVGRenderer>}
  10788. * Returns the requested renderer class or the default renderer class.
  10789. */
  10790. function getRendererType(rendererType) {
  10791. if (rendererType === void 0) { rendererType = defaultRenderer; }
  10792. return (RendererRegistry.rendererTypes[rendererType] || RendererRegistry.rendererTypes[defaultRenderer]);
  10793. }
  10794. RendererRegistry.getRendererType = getRendererType;
  10795. /**
  10796. * Register a renderer class.
  10797. *
  10798. * @param {string} rendererType
  10799. * Renderer type to register.
  10800. *
  10801. * @param {Highcharts.Class<Highcharts.SVGRenderer>} rendererClass
  10802. * Returns the requested renderer class or the default renderer class.
  10803. *
  10804. * @param {boolean} setAsDefault
  10805. * Sets the renderer class as the default renderer.
  10806. */
  10807. function registerRendererType(rendererType, rendererClass, setAsDefault) {
  10808. RendererRegistry.rendererTypes[rendererType] = rendererClass;
  10809. if (!defaultRenderer || setAsDefault) {
  10810. defaultRenderer = rendererType;
  10811. H.Renderer = rendererClass; // compatibility
  10812. }
  10813. }
  10814. RendererRegistry.registerRendererType = registerRendererType;
  10815. })(RendererRegistry || (RendererRegistry = {}));
  10816. /* *
  10817. *
  10818. * Export
  10819. *
  10820. * */
  10821. return RendererRegistry;
  10822. });
  10823. _registerModule(_modules, 'Core/Renderer/SVG/SVGLabel.js', [_modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Utilities.js']], function (SVGElement, U) {
  10824. /* *
  10825. *
  10826. * (c) 2010-2021 Torstein Honsi
  10827. *
  10828. * License: www.highcharts.com/license
  10829. *
  10830. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  10831. *
  10832. * */
  10833. var __extends = (this && this.__extends) || (function () {
  10834. var extendStatics = function (d,
  10835. b) {
  10836. extendStatics = Object.setPrototypeOf ||
  10837. ({ __proto__: [] } instanceof Array && function (d,
  10838. b) { d.__proto__ = b; }) ||
  10839. function (d,
  10840. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  10841. return extendStatics(d, b);
  10842. };
  10843. return function (d, b) {
  10844. extendStatics(d, b);
  10845. function __() { this.constructor = d; }
  10846. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  10847. };
  10848. })();
  10849. var defined = U.defined,
  10850. extend = U.extend,
  10851. isNumber = U.isNumber,
  10852. merge = U.merge,
  10853. pick = U.pick,
  10854. removeEvent = U.removeEvent;
  10855. /* *
  10856. *
  10857. * Class
  10858. *
  10859. * */
  10860. /**
  10861. * SVG label to render text.
  10862. * @private
  10863. * @class
  10864. * @name Highcharts.SVGLabel
  10865. * @augments Highcharts.SVGElement
  10866. */
  10867. var SVGLabel = /** @class */ (function (_super) {
  10868. __extends(SVGLabel, _super);
  10869. /* *
  10870. *
  10871. * Constructors
  10872. *
  10873. * */
  10874. function SVGLabel(renderer, str, x, y, shape, anchorX, anchorY, useHTML, baseline, className) {
  10875. var _this = _super.call(this) || this;
  10876. _this.paddingLeftSetter = _this.paddingSetter;
  10877. _this.paddingRightSetter = _this.paddingSetter;
  10878. _this.init(renderer, 'g');
  10879. _this.textStr = str;
  10880. _this.x = x;
  10881. _this.y = y;
  10882. _this.anchorX = anchorX;
  10883. _this.anchorY = anchorY;
  10884. _this.baseline = baseline;
  10885. _this.className = className;
  10886. _this.addClass(className === 'button' ?
  10887. 'highcharts-no-tooltip' :
  10888. 'highcharts-label');
  10889. if (className) {
  10890. _this.addClass('highcharts-' + className);
  10891. }
  10892. _this.text = renderer.text('', 0, 0, useHTML).attr({ zIndex: 1 });
  10893. // Validate the shape argument
  10894. var hasBGImage;
  10895. if (typeof shape === 'string') {
  10896. hasBGImage = /^url\((.*?)\)$/.test(shape);
  10897. if (hasBGImage || _this.renderer.symbols[shape]) {
  10898. _this.symbolKey = shape;
  10899. }
  10900. }
  10901. _this.bBox = SVGLabel.emptyBBox;
  10902. _this.padding = 3;
  10903. _this.baselineOffset = 0;
  10904. _this.needsBox = renderer.styledMode || hasBGImage;
  10905. _this.deferredAttr = {};
  10906. _this.alignFactor = 0;
  10907. return _this;
  10908. }
  10909. /* *
  10910. *
  10911. * Functions
  10912. *
  10913. * */
  10914. SVGLabel.prototype.alignSetter = function (value) {
  10915. var alignFactor = ({
  10916. left: 0,
  10917. center: 0.5,
  10918. right: 1
  10919. })[value];
  10920. if (alignFactor !== this.alignFactor) {
  10921. this.alignFactor = alignFactor;
  10922. // Bounding box exists, means we're dynamically changing
  10923. if (this.bBox && isNumber(this.xSetting)) {
  10924. this.attr({ x: this.xSetting }); // #5134
  10925. }
  10926. }
  10927. };
  10928. SVGLabel.prototype.anchorXSetter = function (value, key) {
  10929. this.anchorX = value;
  10930. this.boxAttr(key, Math.round(value) - this.getCrispAdjust() - this.xSetting);
  10931. };
  10932. SVGLabel.prototype.anchorYSetter = function (value, key) {
  10933. this.anchorY = value;
  10934. this.boxAttr(key, value - this.ySetting);
  10935. };
  10936. /*
  10937. * Set a box attribute, or defer it if the box is not yet created
  10938. */
  10939. SVGLabel.prototype.boxAttr = function (key, value) {
  10940. if (this.box) {
  10941. this.box.attr(key, value);
  10942. }
  10943. else {
  10944. this.deferredAttr[key] = value;
  10945. }
  10946. };
  10947. /*
  10948. * Pick up some properties and apply them to the text instead of the
  10949. * wrapper.
  10950. */
  10951. SVGLabel.prototype.css = function (styles) {
  10952. if (styles) {
  10953. var textStyles_1 = {};
  10954. // Create a copy to avoid altering the original object
  10955. // (#537)
  10956. styles = merge(styles);
  10957. SVGLabel.textProps.forEach(function (prop) {
  10958. if (typeof styles[prop] !== 'undefined') {
  10959. textStyles_1[prop] = styles[prop];
  10960. delete styles[prop];
  10961. }
  10962. });
  10963. this.text.css(textStyles_1);
  10964. var isWidth = 'width' in textStyles_1, isFontStyle = ('fontSize' in textStyles_1 || 'fontWeight' in textStyles_1);
  10965. // Update existing text, box (#9400, #12163)
  10966. if (isFontStyle) {
  10967. this.updateTextPadding();
  10968. }
  10969. else if (isWidth) {
  10970. this.updateBoxSize();
  10971. }
  10972. }
  10973. return SVGElement.prototype.css.call(this, styles);
  10974. };
  10975. /*
  10976. * Destroy and release memory.
  10977. */
  10978. SVGLabel.prototype.destroy = function () {
  10979. // Added by button implementation
  10980. removeEvent(this.element, 'mouseenter');
  10981. removeEvent(this.element, 'mouseleave');
  10982. if (this.text) {
  10983. this.text.destroy();
  10984. }
  10985. if (this.box) {
  10986. this.box = this.box.destroy();
  10987. }
  10988. // Call base implementation to destroy the rest
  10989. SVGElement.prototype.destroy.call(this);
  10990. return void 0;
  10991. };
  10992. SVGLabel.prototype.fillSetter = function (value, key) {
  10993. if (value) {
  10994. this.needsBox = true;
  10995. }
  10996. // for animation getter (#6776)
  10997. this.fill = value;
  10998. this.boxAttr(key, value);
  10999. };
  11000. /*
  11001. * Return the bounding box of the box, not the group.
  11002. */
  11003. SVGLabel.prototype.getBBox = function () {
  11004. // If we have a text string and the DOM bBox was 0, it typically means
  11005. // that the label was first rendered hidden, so we need to update the
  11006. // bBox (#15246)
  11007. if (this.textStr && this.bBox.width === 0 && this.bBox.height === 0) {
  11008. this.updateBoxSize();
  11009. }
  11010. var padding = this.padding;
  11011. var paddingLeft = pick(this.paddingLeft,
  11012. padding);
  11013. return {
  11014. width: this.width,
  11015. height: this.height,
  11016. x: this.bBox.x - paddingLeft,
  11017. y: this.bBox.y - padding
  11018. };
  11019. };
  11020. SVGLabel.prototype.getCrispAdjust = function () {
  11021. return this.renderer.styledMode && this.box ?
  11022. this.box.strokeWidth() % 2 / 2 :
  11023. (this['stroke-width'] ? parseInt(this['stroke-width'], 10) : 0) % 2 / 2;
  11024. };
  11025. SVGLabel.prototype.heightSetter = function (value) {
  11026. this.heightSetting = value;
  11027. };
  11028. // Event handling. In case of useHTML, we need to make sure that events
  11029. // are captured on the span as well, and that mouseenter/mouseleave
  11030. // between the SVG group and the HTML span are not treated as real
  11031. // enter/leave events. #13310.
  11032. SVGLabel.prototype.on = function (eventType, handler) {
  11033. var label = this;
  11034. var text = label.text;
  11035. var span = text && text.element.tagName === 'SPAN' ? text : void 0;
  11036. var selectiveHandler;
  11037. if (span) {
  11038. selectiveHandler = function (e) {
  11039. if ((eventType === 'mouseenter' ||
  11040. eventType === 'mouseleave') &&
  11041. e.relatedTarget instanceof Element &&
  11042. (
  11043. // #14110
  11044. label.element.compareDocumentPosition(e.relatedTarget) & Node.DOCUMENT_POSITION_CONTAINED_BY ||
  11045. span.element.compareDocumentPosition(e.relatedTarget) & Node.DOCUMENT_POSITION_CONTAINED_BY)) {
  11046. return;
  11047. }
  11048. handler.call(label.element, e);
  11049. };
  11050. span.on(eventType, selectiveHandler);
  11051. }
  11052. SVGElement.prototype.on.call(label, eventType, selectiveHandler || handler);
  11053. return label;
  11054. };
  11055. /*
  11056. * After the text element is added, get the desired size of the border
  11057. * box and add it before the text in the DOM.
  11058. */
  11059. SVGLabel.prototype.onAdd = function () {
  11060. var str = this.textStr;
  11061. this.text.add(this);
  11062. this.attr({
  11063. // Alignment is available now (#3295, 0 not rendered if given
  11064. // as a value)
  11065. text: (defined(str) ? str : ''),
  11066. x: this.x,
  11067. y: this.y
  11068. });
  11069. if (this.box && defined(this.anchorX)) {
  11070. this.attr({
  11071. anchorX: this.anchorX,
  11072. anchorY: this.anchorY
  11073. });
  11074. }
  11075. };
  11076. SVGLabel.prototype.paddingSetter = function (value, key) {
  11077. if (!isNumber(value)) {
  11078. this[key] = void 0;
  11079. }
  11080. else if (value !== this[key]) {
  11081. this[key] = value;
  11082. this.updateTextPadding();
  11083. }
  11084. };
  11085. SVGLabel.prototype.rSetter = function (value, key) {
  11086. this.boxAttr(key, value);
  11087. };
  11088. SVGLabel.prototype.shadow = function (b) {
  11089. if (b && !this.renderer.styledMode) {
  11090. this.updateBoxSize();
  11091. if (this.box) {
  11092. this.box.shadow(b);
  11093. }
  11094. }
  11095. return this;
  11096. };
  11097. SVGLabel.prototype.strokeSetter = function (value, key) {
  11098. // for animation getter (#6776)
  11099. this.stroke = value;
  11100. this.boxAttr(key, value);
  11101. };
  11102. SVGLabel.prototype['stroke-widthSetter'] = function (value, key) {
  11103. if (value) {
  11104. this.needsBox = true;
  11105. }
  11106. this['stroke-width'] = value;
  11107. this.boxAttr(key, value);
  11108. };
  11109. SVGLabel.prototype['text-alignSetter'] = function (value) {
  11110. this.textAlign = value;
  11111. };
  11112. SVGLabel.prototype.textSetter = function (text) {
  11113. if (typeof text !== 'undefined') {
  11114. // Must use .attr to ensure transforms are done (#10009)
  11115. this.text.attr({ text: text });
  11116. }
  11117. this.updateTextPadding();
  11118. };
  11119. /*
  11120. * This function runs after the label is added to the DOM (when the bounding
  11121. * box is available), and after the text of the label is updated to detect
  11122. * the new bounding box and reflect it in the border box.
  11123. */
  11124. SVGLabel.prototype.updateBoxSize = function () {
  11125. var style = this.text.element.style,
  11126. attribs = {},
  11127. padding = this.padding,
  11128. // #12165 error when width is null (auto)
  11129. // #12163 when fontweight: bold, recalculate bBox withot cache
  11130. // #3295 && 3514 box failure when string equals 0
  11131. bBox = this.bBox = (((!isNumber(this.widthSetting) ||
  11132. !isNumber(this.heightSetting) ||
  11133. this.textAlign) && defined(this.text.textStr)) ?
  11134. this.text.getBBox() :
  11135. SVGLabel.emptyBBox);
  11136. var crispAdjust;
  11137. this.width = this.getPaddedWidth();
  11138. this.height = (this.heightSetting || bBox.height || 0) + 2 * padding;
  11139. var metrics = this.renderer.fontMetrics(style && style.fontSize,
  11140. this.text);
  11141. // Update the label-scoped y offset. Math.min because of inline
  11142. // style (#9400)
  11143. this.baselineOffset = padding + Math.min(
  11144. // When applicable, use the font size of the first line (#15707)
  11145. (this.text.firstLineMetrics || metrics).b,
  11146. // When the height is 0, there is no bBox, so go with the font
  11147. // metrics. Highmaps CSS demos.
  11148. bBox.height || Infinity);
  11149. // #15491: Vertical centering
  11150. if (this.heightSetting) {
  11151. this.baselineOffset += (this.heightSetting - metrics.h) / 2;
  11152. }
  11153. if (this.needsBox) {
  11154. // Create the border box if it is not already present
  11155. if (!this.box) {
  11156. // Symbol definition exists (#5324)
  11157. var box = this.box = this.symbolKey ?
  11158. this.renderer.symbol(this.symbolKey) :
  11159. this.renderer.rect();
  11160. box.addClass(// Don't use label className for buttons
  11161. (this.className === 'button' ? '' : 'highcharts-label-box') +
  11162. (this.className ? ' highcharts-' + this.className + '-box' : ''));
  11163. box.add(this);
  11164. }
  11165. crispAdjust = this.getCrispAdjust();
  11166. attribs.x = crispAdjust;
  11167. attribs.y = (this.baseline ? -this.baselineOffset : 0) + crispAdjust;
  11168. // Apply the box attributes
  11169. attribs.width = Math.round(this.width);
  11170. attribs.height = Math.round(this.height);
  11171. this.box.attr(extend(attribs, this.deferredAttr));
  11172. this.deferredAttr = {};
  11173. }
  11174. };
  11175. /*
  11176. * This function runs after setting text or padding, but only if padding
  11177. * is changed.
  11178. */
  11179. SVGLabel.prototype.updateTextPadding = function () {
  11180. var text = this.text;
  11181. this.updateBoxSize();
  11182. // Determine y based on the baseline
  11183. var textY = this.baseline ? 0 : this.baselineOffset;
  11184. var textX = pick(this.paddingLeft,
  11185. this.padding);
  11186. // compensate for alignment
  11187. if (defined(this.widthSetting) &&
  11188. this.bBox &&
  11189. (this.textAlign === 'center' || this.textAlign === 'right')) {
  11190. textX += { center: 0.5, right: 1 }[this.textAlign] *
  11191. (this.widthSetting - this.bBox.width);
  11192. }
  11193. // update if anything changed
  11194. if (textX !== text.x || textY !== text.y) {
  11195. text.attr('x', textX);
  11196. // #8159 - prevent misplaced data labels in treemap
  11197. // (useHTML: true)
  11198. if (text.hasBoxWidthChanged) {
  11199. this.bBox = text.getBBox(true);
  11200. }
  11201. if (typeof textY !== 'undefined') {
  11202. text.attr('y', textY);
  11203. }
  11204. }
  11205. // record current values
  11206. text.x = textX;
  11207. text.y = textY;
  11208. };
  11209. SVGLabel.prototype.widthSetter = function (value) {
  11210. // width:auto => null
  11211. this.widthSetting = isNumber(value) ? value : void 0;
  11212. };
  11213. SVGLabel.prototype.getPaddedWidth = function () {
  11214. var padding = this.padding;
  11215. var paddingLeft = pick(this.paddingLeft,
  11216. padding);
  11217. var paddingRight = pick(this.paddingRight,
  11218. padding);
  11219. return (this.widthSetting || this.bBox.width || 0) + paddingLeft + paddingRight;
  11220. };
  11221. SVGLabel.prototype.xSetter = function (value) {
  11222. this.x = value; // for animation getter
  11223. if (this.alignFactor) {
  11224. value -= this.alignFactor * this.getPaddedWidth();
  11225. // Force animation even when setting to the same value (#7898)
  11226. this['forceAnimate:x'] = true;
  11227. }
  11228. this.xSetting = Math.round(value);
  11229. this.attr('translateX', this.xSetting);
  11230. };
  11231. SVGLabel.prototype.ySetter = function (value) {
  11232. this.ySetting = this.y = Math.round(value);
  11233. this.attr('translateY', this.ySetting);
  11234. };
  11235. /* *
  11236. *
  11237. * Static Properties
  11238. *
  11239. * */
  11240. SVGLabel.emptyBBox = { width: 0, height: 0, x: 0, y: 0 };
  11241. /**
  11242. * For labels, these CSS properties are applied to the `text` node directly.
  11243. *
  11244. * @private
  11245. * @name Highcharts.SVGLabel#textProps
  11246. * @type {Array<string>}
  11247. */
  11248. SVGLabel.textProps = [
  11249. 'color', 'direction', 'fontFamily', 'fontSize', 'fontStyle',
  11250. 'fontWeight', 'lineHeight', 'textAlign', 'textDecoration',
  11251. 'textOutline', 'textOverflow', 'width'
  11252. ];
  11253. return SVGLabel;
  11254. }(SVGElement));
  11255. return SVGLabel;
  11256. });
  11257. _registerModule(_modules, 'Core/Renderer/SVG/Symbols.js', [_modules['Core/Utilities.js']], function (U) {
  11258. /* *
  11259. *
  11260. * (c) 2010-2021 Torstein Honsi
  11261. *
  11262. * License: www.highcharts.com/license
  11263. *
  11264. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  11265. *
  11266. * */
  11267. var defined = U.defined,
  11268. isNumber = U.isNumber,
  11269. pick = U.pick;
  11270. /* *
  11271. *
  11272. * Functions
  11273. *
  11274. * */
  11275. /* eslint-disable require-jsdoc, valid-jsdoc */
  11276. function arc(x, y, w, h, options) {
  11277. var arc = [];
  11278. if (options) {
  11279. var start = options.start || 0,
  11280. rx = pick(options.r,
  11281. w),
  11282. ry = pick(options.r,
  11283. h || w),
  11284. proximity = 0.001,
  11285. fullCircle = (Math.abs((options.end || 0) - start - 2 * Math.PI) <
  11286. proximity),
  11287. // Substract a small number to prevent cos and sin of start
  11288. // and end from becoming equal on 360 arcs (related: #1561)
  11289. end = (options.end || 0) - proximity,
  11290. innerRadius = options.innerR,
  11291. open_1 = pick(options.open,
  11292. fullCircle),
  11293. cosStart = Math.cos(start),
  11294. sinStart = Math.sin(start),
  11295. cosEnd = Math.cos(end),
  11296. sinEnd = Math.sin(end),
  11297. // Proximity takes care of rounding errors around PI (#6971)
  11298. longArc = pick(options.longArc,
  11299. end - start - Math.PI < proximity ? 0 : 1);
  11300. arc.push([
  11301. 'M',
  11302. x + rx * cosStart,
  11303. y + ry * sinStart
  11304. ], [
  11305. 'A',
  11306. rx,
  11307. ry,
  11308. 0,
  11309. longArc,
  11310. pick(options.clockwise, 1),
  11311. x + rx * cosEnd,
  11312. y + ry * sinEnd
  11313. ]);
  11314. if (defined(innerRadius)) {
  11315. arc.push(open_1 ?
  11316. [
  11317. 'M',
  11318. x + innerRadius * cosEnd,
  11319. y + innerRadius * sinEnd
  11320. ] : [
  11321. 'L',
  11322. x + innerRadius * cosEnd,
  11323. y + innerRadius * sinEnd
  11324. ], [
  11325. 'A',
  11326. innerRadius,
  11327. innerRadius,
  11328. 0,
  11329. longArc,
  11330. // Clockwise - opposite to the outer arc clockwise
  11331. defined(options.clockwise) ? 1 - options.clockwise : 0,
  11332. x + innerRadius * cosStart,
  11333. y + innerRadius * sinStart
  11334. ]);
  11335. }
  11336. if (!open_1) {
  11337. arc.push(['Z']);
  11338. }
  11339. }
  11340. return arc;
  11341. }
  11342. /**
  11343. * Callout shape used for default tooltips, also used for rounded
  11344. * rectangles in VML
  11345. */
  11346. function callout(x, y, w, h, options) {
  11347. var arrowLength = 6,
  11348. halfDistance = 6,
  11349. r = Math.min((options && options.r) || 0,
  11350. w,
  11351. h),
  11352. safeDistance = r + halfDistance,
  11353. anchorX = options && options.anchorX,
  11354. anchorY = options && options.anchorY || 0;
  11355. var path = roundedRect(x,
  11356. y,
  11357. w,
  11358. h, { r: r });
  11359. if (!isNumber(anchorX)) {
  11360. return path;
  11361. }
  11362. // Anchor on right side
  11363. if (x + anchorX >= w) {
  11364. // Chevron
  11365. if (anchorY > y + safeDistance &&
  11366. anchorY < y + h - safeDistance) {
  11367. path.splice(3, 1, ['L', x + w, anchorY - halfDistance], ['L', x + w + arrowLength, anchorY], ['L', x + w, anchorY + halfDistance], ['L', x + w, y + h - r]);
  11368. // Simple connector
  11369. }
  11370. else {
  11371. path.splice(3, 1, ['L', x + w, h / 2], ['L', anchorX, anchorY], ['L', x + w, h / 2], ['L', x + w, y + h - r]);
  11372. }
  11373. // Anchor on left side
  11374. }
  11375. else if (x + anchorX <= 0) {
  11376. // Chevron
  11377. if (anchorY > y + safeDistance &&
  11378. anchorY < y + h - safeDistance) {
  11379. path.splice(7, 1, ['L', x, anchorY + halfDistance], ['L', x - arrowLength, anchorY], ['L', x, anchorY - halfDistance], ['L', x, y + r]);
  11380. // Simple connector
  11381. }
  11382. else {
  11383. path.splice(7, 1, ['L', x, h / 2], ['L', anchorX, anchorY], ['L', x, h / 2], ['L', x, y + r]);
  11384. }
  11385. }
  11386. else if ( // replace bottom
  11387. anchorY &&
  11388. anchorY > h &&
  11389. anchorX > x + safeDistance &&
  11390. anchorX < x + w - safeDistance) {
  11391. path.splice(5, 1, ['L', anchorX + halfDistance, y + h], ['L', anchorX, y + h + arrowLength], ['L', anchorX - halfDistance, y + h], ['L', x + r, y + h]);
  11392. }
  11393. else if ( // replace top
  11394. anchorY &&
  11395. anchorY < 0 &&
  11396. anchorX > x + safeDistance &&
  11397. anchorX < x + w - safeDistance) {
  11398. path.splice(1, 1, ['L', anchorX - halfDistance, y], ['L', anchorX, y - arrowLength], ['L', anchorX + halfDistance, y], ['L', w - r, y]);
  11399. }
  11400. return path;
  11401. }
  11402. function circle(x, y, w, h) {
  11403. // Return a full arc
  11404. return arc(x + w / 2, y + h / 2, w / 2, h / 2, {
  11405. start: Math.PI * 0.5,
  11406. end: Math.PI * 2.5,
  11407. open: false
  11408. });
  11409. }
  11410. function diamond(x, y, w, h) {
  11411. return [
  11412. ['M', x + w / 2, y],
  11413. ['L', x + w, y + h / 2],
  11414. ['L', x + w / 2, y + h],
  11415. ['L', x, y + h / 2],
  11416. ['Z']
  11417. ];
  11418. }
  11419. // #15291
  11420. function rect(x, y, w, h, options) {
  11421. if (options && options.r) {
  11422. return roundedRect(x, y, w, h, options);
  11423. }
  11424. return [
  11425. ['M', x, y],
  11426. ['L', x + w, y],
  11427. ['L', x + w, y + h],
  11428. ['L', x, y + h],
  11429. ['Z']
  11430. ];
  11431. }
  11432. function roundedRect(x, y, w, h, options) {
  11433. var r = (options && options.r) || 0;
  11434. return [
  11435. ['M', x + r, y],
  11436. ['L', x + w - r, y],
  11437. ['C', x + w, y, x + w, y, x + w, y + r],
  11438. ['L', x + w, y + h - r],
  11439. ['C', x + w, y + h, x + w, y + h, x + w - r, y + h],
  11440. ['L', x + r, y + h],
  11441. ['C', x, y + h, x, y + h, x, y + h - r],
  11442. ['L', x, y + r],
  11443. ['C', x, y, x, y, x + r, y] // top-left corner
  11444. ];
  11445. }
  11446. function triangle(x, y, w, h) {
  11447. return [
  11448. ['M', x + w / 2, y],
  11449. ['L', x + w, y + h],
  11450. ['L', x, y + h],
  11451. ['Z']
  11452. ];
  11453. }
  11454. function triangleDown(x, y, w, h) {
  11455. return [
  11456. ['M', x, y],
  11457. ['L', x + w, y],
  11458. ['L', x + w / 2, y + h],
  11459. ['Z']
  11460. ];
  11461. }
  11462. var Symbols = {
  11463. arc: arc,
  11464. callout: callout,
  11465. circle: circle,
  11466. diamond: diamond,
  11467. rect: rect,
  11468. roundedRect: roundedRect,
  11469. square: rect,
  11470. triangle: triangle,
  11471. 'triangle-down': triangleDown
  11472. };
  11473. /* *
  11474. *
  11475. * Default Export
  11476. *
  11477. * */
  11478. return Symbols;
  11479. });
  11480. _registerModule(_modules, 'Core/Renderer/SVG/TextBuilder.js', [_modules['Core/Renderer/HTML/AST.js'], _modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (AST, H, U) {
  11481. /* *
  11482. *
  11483. * (c) 2010-2020 Torstein Honsi
  11484. *
  11485. * License: www.highcharts.com/license
  11486. *
  11487. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  11488. *
  11489. * */
  11490. var doc = H.doc,
  11491. SVG_NS = H.SVG_NS;
  11492. var attr = U.attr,
  11493. isString = U.isString,
  11494. objectEach = U.objectEach,
  11495. pick = U.pick;
  11496. /* *
  11497. *
  11498. * Class
  11499. *
  11500. * */
  11501. /**
  11502. * SVG Text Builder
  11503. * @private
  11504. * @class
  11505. * @name Highcharts.TextBuilder
  11506. */
  11507. var TextBuilder = /** @class */ (function () {
  11508. function TextBuilder(svgElement) {
  11509. var textStyles = svgElement.styles;
  11510. this.renderer = svgElement.renderer;
  11511. this.svgElement = svgElement;
  11512. this.width = svgElement.textWidth;
  11513. this.textLineHeight = textStyles && textStyles.lineHeight;
  11514. this.textOutline = textStyles && textStyles.textOutline;
  11515. this.ellipsis = Boolean(textStyles && textStyles.textOverflow === 'ellipsis');
  11516. this.noWrap = Boolean(textStyles && textStyles.whiteSpace === 'nowrap');
  11517. this.fontSize = textStyles && textStyles.fontSize;
  11518. }
  11519. /**
  11520. * Build an SVG representation of the pseudo HTML given in the object's
  11521. * svgElement.
  11522. *
  11523. * @private
  11524. *
  11525. * @return {void}.
  11526. */
  11527. TextBuilder.prototype.buildSVG = function () {
  11528. var wrapper = this.svgElement;
  11529. var textNode = wrapper.element, renderer = wrapper.renderer, textStr = pick(wrapper.textStr, '').toString(), hasMarkup = textStr.indexOf('<') !== -1, childNodes = textNode.childNodes, textCache, i = childNodes.length, tempParent = this.width && !wrapper.added && renderer.box;
  11530. var regexMatchBreaks = /<br.*?>/g;
  11531. // The buildText code is quite heavy, so if we're not changing something
  11532. // that affects the text, skip it (#6113).
  11533. textCache = [
  11534. textStr,
  11535. this.ellipsis,
  11536. this.noWrap,
  11537. this.textLineHeight,
  11538. this.textOutline,
  11539. this.fontSize,
  11540. this.width
  11541. ].join(',');
  11542. if (textCache === wrapper.textCache) {
  11543. return;
  11544. }
  11545. wrapper.textCache = textCache;
  11546. delete wrapper.actualWidth;
  11547. // Remove old text
  11548. while (i--) {
  11549. textNode.removeChild(childNodes[i]);
  11550. }
  11551. // Simple strings, add text directly and return
  11552. if (!hasMarkup &&
  11553. !this.ellipsis &&
  11554. !this.width &&
  11555. (textStr.indexOf(' ') === -1 ||
  11556. (this.noWrap && !regexMatchBreaks.test(textStr)))) {
  11557. textNode.appendChild(doc.createTextNode(this.unescapeEntities(textStr)));
  11558. // Complex strings, add more logic
  11559. }
  11560. else if (textStr !== '') {
  11561. if (tempParent) {
  11562. // attach it to the DOM to read offset width
  11563. tempParent.appendChild(textNode);
  11564. }
  11565. // Step 1. Parse the markup safely and directly into a tree
  11566. // structure.
  11567. var ast = new AST(textStr);
  11568. // Step 2. Do as many as we can of the modifications to the tree
  11569. // structure before it is added to the DOM
  11570. this.modifyTree(ast.nodes);
  11571. ast.addToDOM(wrapper.element);
  11572. // Step 3. Some modifications can't be done until the structure is
  11573. // in the DOM, because we need to read computed metrics.
  11574. this.modifyDOM();
  11575. // Add title if an ellipsis was added
  11576. if (this.ellipsis &&
  11577. (textNode.textContent || '').indexOf('\u2026') !== -1) {
  11578. wrapper.attr('title', this.unescapeEntities(wrapper.textStr || '', ['&lt;', '&gt;']) // #7179
  11579. );
  11580. }
  11581. if (tempParent) {
  11582. tempParent.removeChild(textNode);
  11583. }
  11584. }
  11585. // Apply the text outline
  11586. if (isString(this.textOutline) && wrapper.applyTextOutline) {
  11587. wrapper.applyTextOutline(this.textOutline);
  11588. }
  11589. };
  11590. /**
  11591. * Modify the DOM of the generated SVG structure. This function only does
  11592. * operations that cannot be done until the elements are attached to the
  11593. * DOM, like doing layout based on rendered metrics of the added elements.
  11594. *
  11595. * @private
  11596. *
  11597. * @return {void}
  11598. */
  11599. TextBuilder.prototype.modifyDOM = function () {
  11600. var _this = this;
  11601. var wrapper = this.svgElement;
  11602. var x = attr(wrapper.element, 'x');
  11603. wrapper.firstLineMetrics = void 0;
  11604. // Modify hard line breaks by applying the rendered line height
  11605. [].forEach.call(wrapper.element.querySelectorAll('tspan.highcharts-br'), function (br, i) {
  11606. if (br.nextSibling && br.previousSibling) { // #5261
  11607. if (i === 0 && br.previousSibling.nodeType === 1) {
  11608. wrapper.firstLineMetrics = wrapper.renderer
  11609. .fontMetrics(void 0, br.previousSibling);
  11610. }
  11611. attr(br, {
  11612. // Since the break is inserted in front of the next
  11613. // line, we need to use the next sibling for the line
  11614. // height
  11615. dy: _this.getLineHeight(br.nextSibling),
  11616. x: x
  11617. });
  11618. }
  11619. });
  11620. // Constrain the line width, either by ellipsis or wrapping
  11621. var width = this.width || 0;
  11622. if (!width) {
  11623. return;
  11624. }
  11625. // Insert soft line breaks into each text node
  11626. var modifyTextNode = function (textNode,
  11627. parentElement) {
  11628. var text = textNode.textContent || '';
  11629. var words = text
  11630. .replace(/([^\^])-/g, '$1- ') // Split on hyphens
  11631. // .trim()
  11632. .split(' '); // #1273
  11633. var hasWhiteSpace = !_this.noWrap && (words.length > 1 || wrapper.element.childNodes.length > 1);
  11634. var dy = _this.getLineHeight(parentElement);
  11635. var lineNo = 0;
  11636. var startAt = wrapper.actualWidth;
  11637. if (_this.ellipsis) {
  11638. if (text) {
  11639. _this.truncate(textNode, text, void 0, 0,
  11640. // Target width
  11641. Math.max(0,
  11642. // Substract the font face to make room for the
  11643. // ellipsis itself
  11644. width - parseInt(_this.fontSize || 12, 10)),
  11645. // Build the text to test for
  11646. function (text, currentIndex) {
  11647. return text.substring(0, currentIndex) + '\u2026';
  11648. });
  11649. }
  11650. }
  11651. else if (hasWhiteSpace) {
  11652. var lines = [];
  11653. // Remove preceding siblings in order to make the text length
  11654. // calculation correct in the truncate function
  11655. var precedingSiblings = [];
  11656. while (parentElement.firstChild &&
  11657. parentElement.firstChild !== textNode) {
  11658. precedingSiblings.push(parentElement.firstChild);
  11659. parentElement.removeChild(parentElement.firstChild);
  11660. }
  11661. while (words.length) {
  11662. // Apply the previous line
  11663. if (words.length && !_this.noWrap && lineNo > 0) {
  11664. lines.push(textNode.textContent || '');
  11665. textNode.textContent = words.join(' ')
  11666. .replace(/- /g, '-');
  11667. }
  11668. // For each line, truncate the remaining
  11669. // words into the line length.
  11670. _this.truncate(textNode, void 0, words, lineNo === 0 ? (startAt || 0) : 0, width,
  11671. // Build the text to test for
  11672. function (t, currentIndex) {
  11673. return words
  11674. .slice(0, currentIndex)
  11675. .join(' ')
  11676. .replace(/- /g, '-');
  11677. });
  11678. startAt = wrapper.actualWidth;
  11679. lineNo++;
  11680. }
  11681. // Reinsert the preceding child nodes
  11682. precedingSiblings.forEach(function (childNode) {
  11683. parentElement.insertBefore(childNode, textNode);
  11684. });
  11685. // Insert the previous lines before the original text node
  11686. lines.forEach(function (line) {
  11687. // Insert the line
  11688. parentElement.insertBefore(doc.createTextNode(line), textNode);
  11689. // Insert a break
  11690. var br = doc.createElementNS(SVG_NS, 'tspan');
  11691. br.textContent = '\u200B'; // zero-width space
  11692. attr(br, { dy: dy, x: x });
  11693. parentElement.insertBefore(br, textNode);
  11694. });
  11695. }
  11696. };
  11697. // Recurse down the DOM tree and handle line breaks for each text node
  11698. var modifyChildren = (function (node) {
  11699. var childNodes = [].slice.call(node.childNodes);
  11700. childNodes.forEach(function (childNode) {
  11701. if (childNode.nodeType === Node.TEXT_NODE) {
  11702. modifyTextNode(childNode, node);
  11703. }
  11704. else {
  11705. // Reset word-wrap width readings after hard breaks
  11706. if (childNode.className.baseVal
  11707. .indexOf('highcharts-br') !== -1) {
  11708. wrapper.actualWidth = 0;
  11709. }
  11710. // Recurse down to child node
  11711. modifyChildren(childNode);
  11712. }
  11713. });
  11714. });
  11715. modifyChildren(wrapper.element);
  11716. };
  11717. /**
  11718. * Get the rendered line height of a <text>, <tspan> or pure text node.
  11719. *
  11720. * @param {DOMElementType|Text} node The node to check for
  11721. *
  11722. * @return {number} The rendered line height
  11723. */
  11724. TextBuilder.prototype.getLineHeight = function (node) {
  11725. var fontSizeStyle;
  11726. // If the node is a text node, use its parent
  11727. var element = node.nodeType === Node.TEXT_NODE ?
  11728. node.parentElement :
  11729. node;
  11730. if (!this.renderer.styledMode) {
  11731. fontSizeStyle =
  11732. element && /(px|em)$/.test(element.style.fontSize) ?
  11733. element.style.fontSize :
  11734. (this.fontSize || this.renderer.style.fontSize || 12);
  11735. }
  11736. return this.textLineHeight ?
  11737. parseInt(this.textLineHeight.toString(), 10) :
  11738. this.renderer.fontMetrics(fontSizeStyle, element || this.svgElement.element).h;
  11739. };
  11740. /**
  11741. * Transform a pseudo HTML AST node tree into an SVG structure. We do as
  11742. * much heavy lifting as we can here, before doing the final processing in
  11743. * the modifyDOM function. The original data is mutated.
  11744. *
  11745. * @private
  11746. *
  11747. * @param {ASTNode[]} nodes The AST nodes
  11748. *
  11749. * @return {void}
  11750. */
  11751. TextBuilder.prototype.modifyTree = function (nodes) {
  11752. var _this = this;
  11753. var modifyChild = function (node,
  11754. i) {
  11755. var tagName = node.tagName;
  11756. var styledMode = _this.renderer.styledMode;
  11757. var attributes = node.attributes || {};
  11758. // Apply styling to text tags
  11759. if (tagName === 'b' || tagName === 'strong') {
  11760. if (styledMode) {
  11761. attributes['class'] = 'highcharts-strong'; // eslint-disable-line dot-notation
  11762. }
  11763. else {
  11764. attributes.style = 'font-weight:bold;' + (attributes.style || '');
  11765. }
  11766. }
  11767. else if (tagName === 'i' || tagName === 'em') {
  11768. if (styledMode) {
  11769. attributes['class'] = 'highcharts-emphasized'; // eslint-disable-line dot-notation
  11770. }
  11771. else {
  11772. attributes.style = 'font-style:italic;' + (attributes.style || '');
  11773. }
  11774. }
  11775. // Modify attributes
  11776. if (isString(attributes.style)) {
  11777. attributes.style = attributes.style.replace(/(;| |^)color([ :])/, '$1fill$2');
  11778. }
  11779. if (tagName === 'br') {
  11780. attributes['class'] = 'highcharts-br'; // eslint-disable-line dot-notation
  11781. node.textContent = '\u200B'; // zero-width space
  11782. // Trim whitespace off the beginning of new lines
  11783. var nextNode = nodes[i + 1];
  11784. if (nextNode && nextNode.textContent) {
  11785. nextNode.textContent =
  11786. nextNode.textContent.replace(/^ +/gm, '');
  11787. }
  11788. }
  11789. if (tagName !== '#text' && tagName !== 'a') {
  11790. node.tagName = 'tspan';
  11791. }
  11792. node.attributes = attributes;
  11793. // Recurse
  11794. if (node.children) {
  11795. node.children
  11796. .filter(function (c) { return c.tagName !== '#text'; })
  11797. .forEach(modifyChild);
  11798. }
  11799. };
  11800. nodes.forEach(modifyChild);
  11801. // Remove empty spans from the beginning because SVG's getBBox doesn't
  11802. // count empty lines. The use case is tooltip where the header is empty.
  11803. while (nodes[0]) {
  11804. if (nodes[0].tagName === 'tspan' && !nodes[0].children) {
  11805. nodes.splice(0, 1);
  11806. }
  11807. else {
  11808. break;
  11809. }
  11810. }
  11811. };
  11812. /*
  11813. * Truncate the text node contents to a given length. Used when the css
  11814. * width is set. If the `textOverflow` is `ellipsis`, the text is truncated
  11815. * character by character to the given length. If not, the text is
  11816. * word-wrapped line by line.
  11817. */
  11818. TextBuilder.prototype.truncate = function (textNode, text, words, startAt, width, getString) {
  11819. var svgElement = this.svgElement;
  11820. var renderer = svgElement.renderer,
  11821. rotation = svgElement.rotation;
  11822. // Cache the lengths to avoid checking the same twice
  11823. var lengths = [];
  11824. // Word wrap can not be truncated to shorter than one word, ellipsis
  11825. // text can be completely blank.
  11826. var minIndex = words ? 1 : 0;
  11827. var maxIndex = (text || words || '').length;
  11828. var currentIndex = maxIndex;
  11829. var str;
  11830. var actualWidth;
  11831. var getSubStringLength = function (charEnd,
  11832. concatenatedEnd) {
  11833. // charEnd is used when finding the character-by-character
  11834. // break for ellipsis, concatenatedEnd is used for word-by-word
  11835. // break for word wrapping.
  11836. var end = concatenatedEnd || charEnd;
  11837. var parentNode = textNode.parentNode;
  11838. if (parentNode && typeof lengths[end] === 'undefined') {
  11839. // Modern browsers
  11840. if (parentNode.getSubStringLength) {
  11841. // Fails with DOM exception on unit-tests/legend/members
  11842. // of unknown reason. Desired width is 0, text content
  11843. // is "5" and end is 1.
  11844. try {
  11845. lengths[end] = startAt +
  11846. parentNode.getSubStringLength(0, words ? end + 1 : end);
  11847. }
  11848. catch (e) {
  11849. '';
  11850. }
  11851. // Legacy
  11852. }
  11853. else if (renderer.getSpanWidth) { // #9058 jsdom
  11854. textNode.textContent = getString(text || words, charEnd);
  11855. lengths[end] = startAt +
  11856. renderer.getSpanWidth(svgElement, textNode);
  11857. }
  11858. }
  11859. return lengths[end];
  11860. };
  11861. svgElement.rotation = 0; // discard rotation when computing box
  11862. actualWidth = getSubStringLength(textNode.textContent.length);
  11863. if (startAt + actualWidth > width) {
  11864. // Do a binary search for the index where to truncate the text
  11865. while (minIndex <= maxIndex) {
  11866. currentIndex = Math.ceil((minIndex + maxIndex) / 2);
  11867. // When checking words for word-wrap, we need to build the
  11868. // string and measure the subStringLength at the concatenated
  11869. // word length.
  11870. if (words) {
  11871. str = getString(words, currentIndex);
  11872. }
  11873. actualWidth = getSubStringLength(currentIndex, str && str.length - 1);
  11874. if (minIndex === maxIndex) {
  11875. // Complete
  11876. minIndex = maxIndex + 1;
  11877. }
  11878. else if (actualWidth > width) {
  11879. // Too large. Set max index to current.
  11880. maxIndex = currentIndex - 1;
  11881. }
  11882. else {
  11883. // Within width. Set min index to current.
  11884. minIndex = currentIndex;
  11885. }
  11886. }
  11887. // If max index was 0 it means the shortest possible text was also
  11888. // too large. For ellipsis that means only the ellipsis, while for
  11889. // word wrap it means the whole first word.
  11890. if (maxIndex === 0) {
  11891. // Remove ellipsis
  11892. textNode.textContent = '';
  11893. // If the new text length is one less than the original, we don't
  11894. // need the ellipsis
  11895. }
  11896. else if (!(text && maxIndex === text.length - 1)) {
  11897. textNode.textContent = str || getString(text || words, currentIndex);
  11898. }
  11899. }
  11900. // When doing line wrapping, prepare for the next line by removing the
  11901. // items from this line.
  11902. if (words) {
  11903. words.splice(0, currentIndex);
  11904. }
  11905. svgElement.actualWidth = actualWidth;
  11906. svgElement.rotation = rotation; // Apply rotation again.
  11907. };
  11908. /*
  11909. * Un-escape HTML entities based on the public `renderer.escapes` list
  11910. *
  11911. * @private
  11912. *
  11913. * @param {string} inputStr The string to unescape
  11914. * @param {Array<string>} [except] Exceptions
  11915. *
  11916. * @return {string} The processed string
  11917. */
  11918. TextBuilder.prototype.unescapeEntities = function (inputStr, except) {
  11919. objectEach(this.renderer.escapes, function (value, key) {
  11920. if (!except || except.indexOf(value) === -1) {
  11921. inputStr = inputStr.toString().replace(new RegExp(value, 'g'), key);
  11922. }
  11923. });
  11924. return inputStr;
  11925. };
  11926. return TextBuilder;
  11927. }());
  11928. return TextBuilder;
  11929. });
  11930. _registerModule(_modules, 'Core/Renderer/SVG/SVGRenderer.js', [_modules['Core/Renderer/HTML/AST.js'], _modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Core/Color/Palette.js'], _modules['Core/Renderer/RendererRegistry.js'], _modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Renderer/SVG/SVGLabel.js'], _modules['Core/Renderer/SVG/Symbols.js'], _modules['Core/Renderer/SVG/TextBuilder.js'], _modules['Core/Utilities.js']], function (AST, Color, H, Palette, RendererRegistry, SVGElement, SVGLabel, Symbols, TextBuilder, U) {
  11931. /* *
  11932. *
  11933. * (c) 2010-2021 Torstein Honsi
  11934. *
  11935. * License: www.highcharts.com/license
  11936. *
  11937. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  11938. *
  11939. * */
  11940. var charts = H.charts,
  11941. deg2rad = H.deg2rad,
  11942. doc = H.doc,
  11943. isFirefox = H.isFirefox,
  11944. isMS = H.isMS,
  11945. isWebKit = H.isWebKit,
  11946. noop = H.noop,
  11947. SVG_NS = H.SVG_NS,
  11948. symbolSizes = H.symbolSizes,
  11949. win = H.win;
  11950. var addEvent = U.addEvent,
  11951. attr = U.attr,
  11952. createElement = U.createElement,
  11953. css = U.css,
  11954. defined = U.defined,
  11955. destroyObjectProperties = U.destroyObjectProperties,
  11956. extend = U.extend,
  11957. isArray = U.isArray,
  11958. isNumber = U.isNumber,
  11959. isObject = U.isObject,
  11960. isString = U.isString,
  11961. merge = U.merge,
  11962. pick = U.pick,
  11963. pInt = U.pInt,
  11964. uniqueKey = U.uniqueKey;
  11965. /* *
  11966. *
  11967. * Variables
  11968. *
  11969. * */
  11970. var hasInternalReferenceBug;
  11971. /* *
  11972. *
  11973. * Class
  11974. *
  11975. * */
  11976. /* eslint-disable no-invalid-this, valid-jsdoc */
  11977. /**
  11978. * Allows direct access to the Highcharts rendering layer in order to draw
  11979. * primitive shapes like circles, rectangles, paths or text directly on a chart,
  11980. * or independent from any chart. The SVGRenderer represents a wrapper object
  11981. * for SVG in modern browsers. Through the VMLRenderer, part of the `oldie.js`
  11982. * module, it also brings vector graphics to IE <= 8.
  11983. *
  11984. * An existing chart's renderer can be accessed through {@link Chart.renderer}.
  11985. * The renderer can also be used completely decoupled from a chart.
  11986. *
  11987. * @sample highcharts/members/renderer-on-chart
  11988. * Annotating a chart programmatically.
  11989. * @sample highcharts/members/renderer-basic
  11990. * Independent SVG drawing.
  11991. *
  11992. * @example
  11993. * // Use directly without a chart object.
  11994. * let renderer = new Highcharts.Renderer(parentNode, 600, 400);
  11995. *
  11996. * @class
  11997. * @name Highcharts.SVGRenderer
  11998. *
  11999. * @param {Highcharts.HTMLDOMElement} container
  12000. * Where to put the SVG in the web page.
  12001. *
  12002. * @param {number} width
  12003. * The width of the SVG.
  12004. *
  12005. * @param {number} height
  12006. * The height of the SVG.
  12007. *
  12008. * @param {Highcharts.CSSObject} [style]
  12009. * The box style, if not in styleMode
  12010. *
  12011. * @param {boolean} [forExport=false]
  12012. * Whether the rendered content is intended for export.
  12013. *
  12014. * @param {boolean} [allowHTML=true]
  12015. * Whether the renderer is allowed to include HTML text, which will be
  12016. * projected on top of the SVG.
  12017. *
  12018. * @param {boolean} [styledMode=false]
  12019. * Whether the renderer belongs to a chart that is in styled mode.
  12020. * If it does, it will avoid setting presentational attributes in
  12021. * some cases, but not when set explicitly through `.attr` and `.css`
  12022. * etc.
  12023. */
  12024. var SVGRenderer = /** @class */ (function () {
  12025. /* *
  12026. *
  12027. * Constructors
  12028. *
  12029. * */
  12030. function SVGRenderer(container, width, height, style, forExport, allowHTML, styledMode) {
  12031. /* *
  12032. *
  12033. * Properties
  12034. *
  12035. * */
  12036. this.alignedObjects = void 0;
  12037. /**
  12038. * The root `svg` node of the renderer.
  12039. *
  12040. * @name Highcharts.SVGRenderer#box
  12041. * @type {Highcharts.SVGDOMElement}
  12042. */
  12043. this.box = void 0;
  12044. /**
  12045. * The wrapper for the root `svg` node of the renderer.
  12046. *
  12047. * @name Highcharts.SVGRenderer#boxWrapper
  12048. * @type {Highcharts.SVGElement}
  12049. */
  12050. this.boxWrapper = void 0;
  12051. this.cache = void 0;
  12052. this.cacheKeys = void 0;
  12053. this.chartIndex = void 0;
  12054. /**
  12055. * A pointer to the `defs` node of the root SVG.
  12056. *
  12057. * @name Highcharts.SVGRenderer#defs
  12058. * @type {Highcharts.SVGElement}
  12059. */
  12060. this.defs = void 0;
  12061. this.globalAnimation = void 0;
  12062. this.gradients = void 0;
  12063. this.height = void 0;
  12064. this.imgCount = void 0;
  12065. this.isSVG = void 0;
  12066. this.style = void 0;
  12067. /**
  12068. * Page url used for internal references.
  12069. *
  12070. * @private
  12071. * @name Highcharts.SVGRenderer#url
  12072. * @type {string}
  12073. */
  12074. this.url = void 0;
  12075. this.width = void 0;
  12076. this.init(container, width, height, style, forExport, allowHTML, styledMode);
  12077. }
  12078. /* *
  12079. *
  12080. * Functions
  12081. *
  12082. * */
  12083. /**
  12084. * Initialize the SVGRenderer. Overridable initializer function that takes
  12085. * the same parameters as the constructor.
  12086. *
  12087. * @function Highcharts.SVGRenderer#init
  12088. *
  12089. * @param {Highcharts.HTMLDOMElement} container
  12090. * Where to put the SVG in the web page.
  12091. *
  12092. * @param {number} width
  12093. * The width of the SVG.
  12094. *
  12095. * @param {number} height
  12096. * The height of the SVG.
  12097. *
  12098. * @param {Highcharts.CSSObject} [style]
  12099. * The box style, if not in styleMode
  12100. *
  12101. * @param {boolean} [forExport=false]
  12102. * Whether the rendered content is intended for export.
  12103. *
  12104. * @param {boolean} [allowHTML=true]
  12105. * Whether the renderer is allowed to include HTML text, which will be
  12106. * projected on top of the SVG.
  12107. *
  12108. * @param {boolean} [styledMode=false]
  12109. * Whether the renderer belongs to a chart that is in styled mode. If it
  12110. * does, it will avoid setting presentational attributes in some cases, but
  12111. * not when set explicitly through `.attr` and `.css` etc.
  12112. */
  12113. SVGRenderer.prototype.init = function (container, width, height, style, forExport, allowHTML, styledMode) {
  12114. var renderer = this,
  12115. boxWrapper = renderer
  12116. .createElement('svg')
  12117. .attr({
  12118. version: '1.1',
  12119. 'class': 'highcharts-root'
  12120. }),
  12121. element = boxWrapper.element;
  12122. if (!styledMode) {
  12123. boxWrapper.css(this.getStyle(style));
  12124. }
  12125. container.appendChild(element);
  12126. // Always use ltr on the container, otherwise text-anchor will be
  12127. // flipped and text appear outside labels, buttons, tooltip etc (#3482)
  12128. attr(container, 'dir', 'ltr');
  12129. // For browsers other than IE, add the namespace attribute (#1978)
  12130. if (container.innerHTML.indexOf('xmlns') === -1) {
  12131. attr(element, 'xmlns', this.SVG_NS);
  12132. }
  12133. // object properties
  12134. renderer.isSVG = true;
  12135. this.box = element;
  12136. this.boxWrapper = boxWrapper;
  12137. renderer.alignedObjects = [];
  12138. this.url = this.getReferenceURL();
  12139. // Add description
  12140. var desc = this.createElement('desc').add();
  12141. desc.element.appendChild(doc.createTextNode('Created with Highcharts 9.1.1'));
  12142. renderer.defs = this.createElement('defs').add();
  12143. renderer.allowHTML = allowHTML;
  12144. renderer.forExport = forExport;
  12145. renderer.styledMode = styledMode;
  12146. renderer.gradients = {}; // Object where gradient SvgElements are stored
  12147. renderer.cache = {}; // Cache for numerical bounding boxes
  12148. renderer.cacheKeys = [];
  12149. renderer.imgCount = 0;
  12150. renderer.setSize(width, height, false);
  12151. // Issue 110 workaround:
  12152. // In Firefox, if a div is positioned by percentage, its pixel position
  12153. // may land between pixels. The container itself doesn't display this,
  12154. // but an SVG element inside this container will be drawn at subpixel
  12155. // precision. In order to draw sharp lines, this must be compensated
  12156. // for. This doesn't seem to work inside iframes though (like in
  12157. // jsFiddle).
  12158. var subPixelFix,
  12159. rect;
  12160. if (isFirefox && container.getBoundingClientRect) {
  12161. subPixelFix = function () {
  12162. css(container, { left: 0, top: 0 });
  12163. rect = container.getBoundingClientRect();
  12164. css(container, {
  12165. left: (Math.ceil(rect.left) - rect.left) + 'px',
  12166. top: (Math.ceil(rect.top) - rect.top) + 'px'
  12167. });
  12168. };
  12169. // run the fix now
  12170. subPixelFix();
  12171. // run it on resize
  12172. renderer.unSubPixelFix = addEvent(win, 'resize', subPixelFix);
  12173. }
  12174. };
  12175. /**
  12176. * General method for adding a definition to the SVG `defs` tag. Can be used
  12177. * for gradients, fills, filters etc. Styled mode only. A hook for adding
  12178. * general definitions to the SVG's defs tag. Definitions can be referenced
  12179. * from the CSS by its `id`. Read more in
  12180. * [gradients, shadows and patterns](https://www.highcharts.com/docs/chart-design-and-style/gradients-shadows-and-patterns).
  12181. * Styled mode only.
  12182. *
  12183. * @function Highcharts.SVGRenderer#definition
  12184. *
  12185. * @param {Highcharts.ASTNode} def
  12186. * A serialized form of an SVG definition, including children.
  12187. *
  12188. * @return {Highcharts.SVGElement}
  12189. * The inserted node.
  12190. */
  12191. SVGRenderer.prototype.definition = function (def) {
  12192. var ast = new AST([def]);
  12193. return ast.addToDOM(this.defs.element);
  12194. };
  12195. /**
  12196. * Get the prefix needed for internal URL references to work in certain
  12197. * cases. Some older browser versions had a bug where internal url
  12198. * references in SVG attributes, on the form `url(#some-id)`, would fail if
  12199. * a base tag was present in the page. There were also issues with
  12200. * `history.pushState` related to this prefix.
  12201. *
  12202. * Related issues: #24, #672, #1070, #5244.
  12203. *
  12204. * The affected browsers are:
  12205. * - Chrome <= 53 (May 2018)
  12206. * - Firefox <= 51 (January 2017)
  12207. * - Safari/Mac <= 12.1 (2018 or 2019)
  12208. * - Safari/iOS <= 13
  12209. *
  12210. * @todo Remove this hack when time has passed. All the affected browsers
  12211. * are evergreens, so it is increasingly unlikely that users are affected by
  12212. * the bug.
  12213. *
  12214. * @return {string}
  12215. * The prefix to use. An empty string for modern browsers.
  12216. */
  12217. SVGRenderer.prototype.getReferenceURL = function () {
  12218. if ((isFirefox || isWebKit) &&
  12219. doc.getElementsByTagName('base').length) {
  12220. // Detect if a clip path is taking effect by performing a hit test
  12221. // outside the clipped area. If the hit element is the rectangle
  12222. // that was supposed to be clipped, the bug is present. This only
  12223. // has to be performed once per page load, so we store the result
  12224. // locally in the module.
  12225. if (!defined(hasInternalReferenceBug)) {
  12226. var id = uniqueKey();
  12227. var ast = new AST([{
  12228. tagName: 'svg',
  12229. attributes: {
  12230. width: 8,
  12231. height: 8
  12232. },
  12233. children: [{
  12234. tagName: 'defs',
  12235. children: [{
  12236. tagName: 'clipPath',
  12237. attributes: {
  12238. id: id
  12239. },
  12240. children: [{
  12241. tagName: 'rect',
  12242. attributes: {
  12243. width: 4,
  12244. height: 4
  12245. }
  12246. }]
  12247. }]
  12248. }, {
  12249. tagName: 'rect',
  12250. attributes: {
  12251. id: 'hitme',
  12252. width: 8,
  12253. height: 8,
  12254. 'clip-path': "url(#" + id + ")",
  12255. fill: 'rgba(0,0,0,0.001)'
  12256. }
  12257. }]
  12258. }]);
  12259. var svg = ast.addToDOM(doc.body);
  12260. css(svg, {
  12261. position: 'fixed',
  12262. top: 0,
  12263. left: 0,
  12264. zIndex: 9e5
  12265. });
  12266. var hitElement = doc.elementFromPoint(6, 6);
  12267. hasInternalReferenceBug = (hitElement && hitElement.id) === 'hitme';
  12268. doc.body.removeChild(svg);
  12269. }
  12270. if (hasInternalReferenceBug) {
  12271. return win.location.href
  12272. .split('#')[0] // remove the hash
  12273. .replace(/<[^>]*>/g, '') // wing cut HTML
  12274. // escape parantheses and quotes
  12275. .replace(/([\('\)])/g, '\\$1')
  12276. // replace spaces (needed for Safari only)
  12277. .replace(/ /g, '%20');
  12278. }
  12279. }
  12280. return '';
  12281. };
  12282. /**
  12283. * Get the global style setting for the renderer.
  12284. *
  12285. * @private
  12286. * @function Highcharts.SVGRenderer#getStyle
  12287. *
  12288. * @param {Highcharts.CSSObject} style
  12289. * Style settings.
  12290. *
  12291. * @return {Highcharts.CSSObject}
  12292. * The style settings mixed with defaults.
  12293. */
  12294. SVGRenderer.prototype.getStyle = function (style) {
  12295. this.style = extend({
  12296. fontFamily: '"Lucida Grande", "Lucida Sans Unicode", ' +
  12297. 'Arial, Helvetica, sans-serif',
  12298. fontSize: '12px'
  12299. }, style);
  12300. return this.style;
  12301. };
  12302. /**
  12303. * Apply the global style on the renderer, mixed with the default styles.
  12304. *
  12305. * @function Highcharts.SVGRenderer#setStyle
  12306. *
  12307. * @param {Highcharts.CSSObject} style
  12308. * CSS to apply.
  12309. */
  12310. SVGRenderer.prototype.setStyle = function (style) {
  12311. this.boxWrapper.css(this.getStyle(style));
  12312. };
  12313. /**
  12314. * Detect whether the renderer is hidden. This happens when one of the
  12315. * parent elements has `display: none`. Used internally to detect when we
  12316. * needto render preliminarily in another div to get the text bounding boxes
  12317. * right.
  12318. *
  12319. * @function Highcharts.SVGRenderer#isHidden
  12320. *
  12321. * @return {boolean}
  12322. * True if it is hidden.
  12323. */
  12324. SVGRenderer.prototype.isHidden = function () {
  12325. return !this.boxWrapper.getBBox().width;
  12326. };
  12327. /**
  12328. * Destroys the renderer and its allocated members.
  12329. *
  12330. * @function Highcharts.SVGRenderer#destroy
  12331. *
  12332. * @return {null}
  12333. */
  12334. SVGRenderer.prototype.destroy = function () {
  12335. var renderer = this,
  12336. rendererDefs = renderer.defs;
  12337. renderer.box = null;
  12338. renderer.boxWrapper = renderer.boxWrapper.destroy();
  12339. // Call destroy on all gradient elements
  12340. destroyObjectProperties(renderer.gradients || {});
  12341. renderer.gradients = null;
  12342. // Defs are null in VMLRenderer
  12343. // Otherwise, destroy them here.
  12344. if (rendererDefs) {
  12345. renderer.defs = rendererDefs.destroy();
  12346. }
  12347. // Remove sub pixel fix handler (#982)
  12348. if (renderer.unSubPixelFix) {
  12349. renderer.unSubPixelFix();
  12350. }
  12351. renderer.alignedObjects = null;
  12352. return null;
  12353. };
  12354. /**
  12355. * Create a wrapper for an SVG element. Serves as a factory for
  12356. * {@link SVGElement}, but this function is itself mostly called from
  12357. * primitive factories like {@link SVGRenderer#path}, {@link
  12358. * SVGRenderer#rect} or {@link SVGRenderer#text}.
  12359. *
  12360. * @function Highcharts.SVGRenderer#createElement
  12361. *
  12362. * @param {string} nodeName
  12363. * The node name, for example `rect`, `g` etc.
  12364. *
  12365. * @return {Highcharts.SVGElement}
  12366. * The generated SVGElement.
  12367. */
  12368. SVGRenderer.prototype.createElement = function (nodeName) {
  12369. var wrapper = new this.Element();
  12370. wrapper.init(this, nodeName);
  12371. return wrapper;
  12372. };
  12373. /**
  12374. * Get converted radial gradient attributes according to the radial
  12375. * reference. Used internally from the {@link SVGElement#colorGradient}
  12376. * function.
  12377. *
  12378. * @private
  12379. * @function Highcharts.SVGRenderer#getRadialAttr
  12380. */
  12381. SVGRenderer.prototype.getRadialAttr = function (radialReference, gradAttr) {
  12382. return {
  12383. cx: (radialReference[0] - radialReference[2] / 2) +
  12384. (gradAttr.cx || 0) * radialReference[2],
  12385. cy: (radialReference[1] - radialReference[2] / 2) +
  12386. (gradAttr.cy || 0) * radialReference[2],
  12387. r: (gradAttr.r || 0) * radialReference[2]
  12388. };
  12389. };
  12390. /**
  12391. * Parse a simple HTML string into SVG tspans. Called internally when text
  12392. * is set on an SVGElement. The function supports a subset of HTML tags, CSS
  12393. * text features like `width`, `text-overflow`, `white-space`, and also
  12394. * attributes like `href` and `style`.
  12395. *
  12396. * @private
  12397. * @function Highcharts.SVGRenderer#buildText
  12398. *
  12399. * @param {Highcharts.SVGElement} wrapper
  12400. * The parent SVGElement.
  12401. */
  12402. SVGRenderer.prototype.buildText = function (wrapper) {
  12403. new TextBuilder(wrapper).buildSVG();
  12404. };
  12405. /**
  12406. * Returns white for dark colors and black for bright colors.
  12407. *
  12408. * @function Highcharts.SVGRenderer#getContrast
  12409. *
  12410. * @param {Highcharts.ColorString} rgba
  12411. * The color to get the contrast for.
  12412. *
  12413. * @return {Highcharts.ColorString}
  12414. * The contrast color, either `#000000` or `#FFFFFF`.
  12415. */
  12416. SVGRenderer.prototype.getContrast = function (rgba) {
  12417. rgba = Color.parse(rgba).rgba;
  12418. // The threshold may be discussed. Here's a proposal for adding
  12419. // different weight to the color channels (#6216)
  12420. rgba[0] *= 1; // red
  12421. rgba[1] *= 1.2; // green
  12422. rgba[2] *= 0.5; // blue
  12423. return rgba[0] + rgba[1] + rgba[2] >
  12424. 1.8 * 255 ?
  12425. '#000000' :
  12426. '#FFFFFF';
  12427. };
  12428. /**
  12429. * Create a button with preset states.
  12430. *
  12431. * @function Highcharts.SVGRenderer#button
  12432. *
  12433. * @param {string} text
  12434. * The text or HTML to draw.
  12435. *
  12436. * @param {number} x
  12437. * The x position of the button's left side.
  12438. *
  12439. * @param {number} y
  12440. * The y position of the button's top side.
  12441. *
  12442. * @param {Highcharts.EventCallbackFunction<Highcharts.SVGElement>} callback
  12443. * The function to execute on button click or touch.
  12444. *
  12445. * @param {Highcharts.SVGAttributes} [theme]
  12446. * SVG attributes for the normal state.
  12447. *
  12448. * @param {Highcharts.SVGAttributes} [hoverState]
  12449. * SVG attributes for the hover state.
  12450. *
  12451. * @param {Highcharts.SVGAttributes} [pressedState]
  12452. * SVG attributes for the pressed state.
  12453. *
  12454. * @param {Highcharts.SVGAttributes} [disabledState]
  12455. * SVG attributes for the disabled state.
  12456. *
  12457. * @param {Highcharts.SymbolKeyValue} [shape=rect]
  12458. * The shape type.
  12459. *
  12460. * @param {boolean} [useHTML=false]
  12461. * Wether to use HTML to render the label.
  12462. *
  12463. * @return {Highcharts.SVGElement}
  12464. * The button element.
  12465. */
  12466. SVGRenderer.prototype.button = function (text, x, y, callback, theme, hoverState, pressedState, disabledState, shape, useHTML) {
  12467. var label = this.label(text,
  12468. x,
  12469. y,
  12470. shape,
  12471. void 0,
  12472. void 0,
  12473. useHTML,
  12474. void 0, 'button'),
  12475. styledMode = this.styledMode;
  12476. var curState = 0,
  12477. // Make a copy of normalState (#13798)
  12478. // (reference to options.rangeSelector.buttonTheme)
  12479. normalState = theme ? merge(theme) : {};
  12480. var userNormalStyle = normalState && normalState.style || {};
  12481. // Remove stylable attributes
  12482. normalState = AST.filterUserAttributes(normalState);
  12483. // Default, non-stylable attributes
  12484. label.attr(merge({ padding: 8, r: 2 }, normalState));
  12485. // Presentational
  12486. var normalStyle,
  12487. hoverStyle,
  12488. pressedStyle,
  12489. disabledStyle;
  12490. if (!styledMode) {
  12491. // Normal state - prepare the attributes
  12492. normalState = merge({
  12493. fill: Palette.neutralColor3,
  12494. stroke: Palette.neutralColor20,
  12495. 'stroke-width': 1,
  12496. style: {
  12497. color: Palette.neutralColor80,
  12498. cursor: 'pointer',
  12499. fontWeight: 'normal'
  12500. }
  12501. }, {
  12502. style: userNormalStyle
  12503. }, normalState);
  12504. normalStyle = normalState.style;
  12505. delete normalState.style;
  12506. // Hover state
  12507. hoverState = merge(normalState, {
  12508. fill: Palette.neutralColor10
  12509. }, AST.filterUserAttributes(hoverState || {}));
  12510. hoverStyle = hoverState.style;
  12511. delete hoverState.style;
  12512. // Pressed state
  12513. pressedState = merge(normalState, {
  12514. fill: Palette.highlightColor10,
  12515. style: {
  12516. color: Palette.neutralColor100,
  12517. fontWeight: 'bold'
  12518. }
  12519. }, AST.filterUserAttributes(pressedState || {}));
  12520. pressedStyle = pressedState.style;
  12521. delete pressedState.style;
  12522. // Disabled state
  12523. disabledState = merge(normalState, {
  12524. style: {
  12525. color: Palette.neutralColor20
  12526. }
  12527. }, AST.filterUserAttributes(disabledState || {}));
  12528. disabledStyle = disabledState.style;
  12529. delete disabledState.style;
  12530. }
  12531. // Add the events. IE9 and IE10 need mouseover and mouseout to funciton
  12532. // (#667).
  12533. addEvent(label.element, isMS ? 'mouseover' : 'mouseenter', function () {
  12534. if (curState !== 3) {
  12535. label.setState(1);
  12536. }
  12537. });
  12538. addEvent(label.element, isMS ? 'mouseout' : 'mouseleave', function () {
  12539. if (curState !== 3) {
  12540. label.setState(curState);
  12541. }
  12542. });
  12543. label.setState = function (state) {
  12544. // Hover state is temporary, don't record it
  12545. if (state !== 1) {
  12546. label.state = curState = state;
  12547. }
  12548. // Update visuals
  12549. label
  12550. .removeClass(/highcharts-button-(normal|hover|pressed|disabled)/)
  12551. .addClass('highcharts-button-' +
  12552. ['normal', 'hover', 'pressed', 'disabled'][state || 0]);
  12553. if (!styledMode) {
  12554. label
  12555. .attr([
  12556. normalState,
  12557. hoverState,
  12558. pressedState,
  12559. disabledState
  12560. ][state || 0])
  12561. .css([
  12562. normalStyle,
  12563. hoverStyle,
  12564. pressedStyle,
  12565. disabledStyle
  12566. ][state || 0]);
  12567. }
  12568. };
  12569. // Presentational attributes
  12570. if (!styledMode) {
  12571. label
  12572. .attr(normalState)
  12573. .css(extend({ cursor: 'default' }, normalStyle));
  12574. }
  12575. return label
  12576. .on('touchstart', function (e) { return e.stopPropagation(); })
  12577. .on('click', function (e) {
  12578. if (curState !== 3) {
  12579. callback.call(label, e);
  12580. }
  12581. });
  12582. };
  12583. /**
  12584. * Make a straight line crisper by not spilling out to neighbour pixels.
  12585. *
  12586. * @function Highcharts.SVGRenderer#crispLine
  12587. *
  12588. * @param {Highcharts.SVGPathArray} points
  12589. * The original points on the format `[['M', 0, 0], ['L', 100, 0]]`.
  12590. *
  12591. * @param {number} width
  12592. * The width of the line.
  12593. *
  12594. * @param {string} [roundingFunction=round]
  12595. * The rounding function name on the `Math` object, can be one of
  12596. * `round`, `floor` or `ceil`.
  12597. *
  12598. * @return {Highcharts.SVGPathArray}
  12599. * The original points array, but modified to render crisply.
  12600. */
  12601. SVGRenderer.prototype.crispLine = function (points, width, roundingFunction) {
  12602. if (roundingFunction === void 0) { roundingFunction = 'round'; }
  12603. var start = points[0];
  12604. var end = points[1];
  12605. // Normalize to a crisp line
  12606. if (defined(start[1]) && start[1] === end[1]) {
  12607. // Substract due to #1129. Now bottom and left axis gridlines behave
  12608. // the same.
  12609. start[1] = end[1] =
  12610. Math[roundingFunction](start[1]) - (width % 2 / 2);
  12611. }
  12612. if (defined(start[2]) && start[2] === end[2]) {
  12613. start[2] = end[2] =
  12614. Math[roundingFunction](start[2]) + (width % 2 / 2);
  12615. }
  12616. return points;
  12617. };
  12618. /**
  12619. * Draw a path, wraps the SVG `path` element.
  12620. *
  12621. * @sample highcharts/members/renderer-path-on-chart/
  12622. * Draw a path in a chart
  12623. * @sample highcharts/members/renderer-path/
  12624. * Draw a path independent from a chart
  12625. *
  12626. * @example
  12627. * let path = renderer.path(['M', 10, 10, 'L', 30, 30, 'z'])
  12628. * .attr({ stroke: '#ff00ff' })
  12629. * .add();
  12630. *
  12631. * @function Highcharts.SVGRenderer#path
  12632. *
  12633. * @param {Highcharts.SVGPathArray} [path]
  12634. * An SVG path definition in array form.
  12635. *
  12636. * @return {Highcharts.SVGElement}
  12637. * The generated wrapper element.
  12638. *
  12639. */ /**
  12640. * Draw a path, wraps the SVG `path` element.
  12641. *
  12642. * @function Highcharts.SVGRenderer#path
  12643. *
  12644. * @param {Highcharts.SVGAttributes} [attribs]
  12645. * The initial attributes.
  12646. *
  12647. * @return {Highcharts.SVGElement}
  12648. * The generated wrapper element.
  12649. */
  12650. SVGRenderer.prototype.path = function (path) {
  12651. var attribs = (this.styledMode ? {} : {
  12652. fill: 'none'
  12653. });
  12654. if (isArray(path)) {
  12655. attribs.d = path;
  12656. }
  12657. else if (isObject(path)) { // attributes
  12658. extend(attribs, path);
  12659. }
  12660. return this.createElement('path').attr(attribs);
  12661. };
  12662. /**
  12663. * Draw a circle, wraps the SVG `circle` element.
  12664. *
  12665. * @sample highcharts/members/renderer-circle/
  12666. * Drawing a circle
  12667. *
  12668. * @function Highcharts.SVGRenderer#circle
  12669. *
  12670. * @param {number} [x]
  12671. * The center x position.
  12672. *
  12673. * @param {number} [y]
  12674. * The center y position.
  12675. *
  12676. * @param {number} [r]
  12677. * The radius.
  12678. *
  12679. * @return {Highcharts.SVGElement}
  12680. * The generated wrapper element.
  12681. */ /**
  12682. * Draw a circle, wraps the SVG `circle` element.
  12683. *
  12684. * @function Highcharts.SVGRenderer#circle
  12685. *
  12686. * @param {Highcharts.SVGAttributes} [attribs]
  12687. * The initial attributes.
  12688. *
  12689. * @return {Highcharts.SVGElement}
  12690. * The generated wrapper element.
  12691. */
  12692. SVGRenderer.prototype.circle = function (x, y, r) {
  12693. var attribs = (isObject(x) ?
  12694. x :
  12695. typeof x === 'undefined' ? {} : { x: x, y: y, r: r }), wrapper = this.createElement('circle');
  12696. // Setting x or y translates to cx and cy
  12697. wrapper.xSetter = wrapper.ySetter = function (value, key, element) {
  12698. element.setAttribute('c' + key, value);
  12699. };
  12700. return wrapper.attr(attribs);
  12701. };
  12702. /**
  12703. * Draw and return an arc.
  12704. *
  12705. * @sample highcharts/members/renderer-arc/
  12706. * Drawing an arc
  12707. *
  12708. * @function Highcharts.SVGRenderer#arc
  12709. *
  12710. * @param {number} [x=0]
  12711. * Center X position.
  12712. *
  12713. * @param {number} [y=0]
  12714. * Center Y position.
  12715. *
  12716. * @param {number} [r=0]
  12717. * The outer radius' of the arc.
  12718. *
  12719. * @param {number} [innerR=0]
  12720. * Inner radius like used in donut charts.
  12721. *
  12722. * @param {number} [start=0]
  12723. * The starting angle of the arc in radians, where 0 is to the right and
  12724. * `-Math.PI/2` is up.
  12725. *
  12726. * @param {number} [end=0]
  12727. * The ending angle of the arc in radians, where 0 is to the right and
  12728. * `-Math.PI/2` is up.
  12729. *
  12730. * @return {Highcharts.SVGElement}
  12731. * The generated wrapper element.
  12732. */ /**
  12733. * Draw and return an arc. Overloaded function that takes arguments object.
  12734. *
  12735. * @function Highcharts.SVGRenderer#arc
  12736. *
  12737. * @param {Highcharts.SVGAttributes} attribs
  12738. * Initial SVG attributes.
  12739. *
  12740. * @return {Highcharts.SVGElement}
  12741. * The generated wrapper element.
  12742. */
  12743. SVGRenderer.prototype.arc = function (x, y, r, innerR, start, end) {
  12744. var options;
  12745. if (isObject(x)) {
  12746. options = x;
  12747. y = options.y;
  12748. r = options.r;
  12749. innerR = options.innerR;
  12750. start = options.start;
  12751. end = options.end;
  12752. x = options.x;
  12753. }
  12754. else {
  12755. options = { innerR: innerR, start: start, end: end };
  12756. }
  12757. // Arcs are defined as symbols for the ability to set
  12758. // attributes in attr and animate
  12759. var arc = this.symbol('arc',
  12760. x,
  12761. y,
  12762. r,
  12763. r,
  12764. options);
  12765. arc.r = r; // #959
  12766. return arc;
  12767. };
  12768. /**
  12769. * Draw and return a rectangle.
  12770. *
  12771. * @function Highcharts.SVGRenderer#rect
  12772. *
  12773. * @param {number} [x]
  12774. * Left position.
  12775. *
  12776. * @param {number} [y]
  12777. * Top position.
  12778. *
  12779. * @param {number} [width]
  12780. * Width of the rectangle.
  12781. *
  12782. * @param {number} [height]
  12783. * Height of the rectangle.
  12784. *
  12785. * @param {number} [r]
  12786. * Border corner radius.
  12787. *
  12788. * @param {number} [strokeWidth]
  12789. * A stroke width can be supplied to allow crisp drawing.
  12790. *
  12791. * @return {Highcharts.SVGElement}
  12792. * The generated wrapper element.
  12793. */ /**
  12794. * Draw and return a rectangle.
  12795. *
  12796. * @sample highcharts/members/renderer-rect-on-chart/
  12797. * Draw a rectangle in a chart
  12798. * @sample highcharts/members/renderer-rect/
  12799. * Draw a rectangle independent from a chart
  12800. *
  12801. * @function Highcharts.SVGRenderer#rect
  12802. *
  12803. * @param {Highcharts.SVGAttributes} [attributes]
  12804. * General SVG attributes for the rectangle.
  12805. *
  12806. * @return {Highcharts.SVGElement}
  12807. * The generated wrapper element.
  12808. */
  12809. SVGRenderer.prototype.rect = function (x, y, width, height, r, strokeWidth) {
  12810. r = isObject(x) ? x.r : r;
  12811. var wrapper = this.createElement('rect');
  12812. var attribs = (isObject(x) ?
  12813. x :
  12814. typeof x === 'undefined' ?
  12815. {} :
  12816. {
  12817. x: x,
  12818. y: y,
  12819. width: Math.max(width, 0),
  12820. height: Math.max(height, 0)
  12821. });
  12822. if (!this.styledMode) {
  12823. if (typeof strokeWidth !== 'undefined') {
  12824. attribs['stroke-width'] = strokeWidth;
  12825. attribs = wrapper.crisp(attribs);
  12826. }
  12827. attribs.fill = 'none';
  12828. }
  12829. if (r) {
  12830. attribs.r = r;
  12831. }
  12832. wrapper.rSetter = function (value, _key, element) {
  12833. wrapper.r = value;
  12834. attr(element, {
  12835. rx: value,
  12836. ry: value
  12837. });
  12838. };
  12839. wrapper.rGetter = function () {
  12840. return wrapper.r || 0;
  12841. };
  12842. return wrapper.attr(attribs);
  12843. };
  12844. /**
  12845. * Resize the {@link SVGRenderer#box} and re-align all aligned child
  12846. * elements.
  12847. *
  12848. * @sample highcharts/members/renderer-g/
  12849. * Show and hide grouped objects
  12850. *
  12851. * @function Highcharts.SVGRenderer#setSize
  12852. *
  12853. * @param {number} width
  12854. * The new pixel width.
  12855. *
  12856. * @param {number} height
  12857. * The new pixel height.
  12858. *
  12859. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animate=true]
  12860. * Whether and how to animate.
  12861. */
  12862. SVGRenderer.prototype.setSize = function (width, height, animate) {
  12863. var renderer = this;
  12864. renderer.width = width;
  12865. renderer.height = height;
  12866. renderer.boxWrapper.animate({
  12867. width: width,
  12868. height: height
  12869. }, {
  12870. step: function () {
  12871. this.attr({
  12872. viewBox: '0 0 ' + this.attr('width') + ' ' +
  12873. this.attr('height')
  12874. });
  12875. },
  12876. duration: pick(animate, true) ? void 0 : 0
  12877. });
  12878. renderer.alignElements();
  12879. };
  12880. /**
  12881. * Create and return an svg group element. Child
  12882. * {@link Highcharts.SVGElement} objects are added to the group by using the
  12883. * group as the first parameter in {@link Highcharts.SVGElement#add|add()}.
  12884. *
  12885. * @function Highcharts.SVGRenderer#g
  12886. *
  12887. * @param {string} [name]
  12888. * The group will be given a class name of `highcharts-{name}`. This
  12889. * can be used for styling and scripting.
  12890. *
  12891. * @return {Highcharts.SVGElement}
  12892. * The generated wrapper element.
  12893. */
  12894. SVGRenderer.prototype.g = function (name) {
  12895. var elem = this.createElement('g');
  12896. return name ?
  12897. elem.attr({ 'class': 'highcharts-' + name }) :
  12898. elem;
  12899. };
  12900. /**
  12901. * Display an image.
  12902. *
  12903. * @sample highcharts/members/renderer-image-on-chart/
  12904. * Add an image in a chart
  12905. * @sample highcharts/members/renderer-image/
  12906. * Add an image independent of a chart
  12907. *
  12908. * @function Highcharts.SVGRenderer#image
  12909. *
  12910. * @param {string} src
  12911. * The image source.
  12912. *
  12913. * @param {number} [x]
  12914. * The X position.
  12915. *
  12916. * @param {number} [y]
  12917. * The Y position.
  12918. *
  12919. * @param {number} [width]
  12920. * The image width. If omitted, it defaults to the image file width.
  12921. *
  12922. * @param {number} [height]
  12923. * The image height. If omitted it defaults to the image file
  12924. * height.
  12925. *
  12926. * @param {Function} [onload]
  12927. * Event handler for image load.
  12928. *
  12929. * @return {Highcharts.SVGElement}
  12930. * The generated wrapper element.
  12931. */
  12932. SVGRenderer.prototype.image = function (src, x, y, width, height, onload) {
  12933. var attribs = { preserveAspectRatio: 'none' }, setSVGImageSource = function (el, src) {
  12934. // Set the href in the xlink namespace
  12935. if (el.setAttributeNS) {
  12936. el.setAttributeNS('http://www.w3.org/1999/xlink', 'href', src);
  12937. }
  12938. else {
  12939. // could be exporting in IE
  12940. // using href throws "not supported" in ie7 and under,
  12941. // requries regex shim to fix later
  12942. el.setAttribute('hc-svg-href', src);
  12943. }
  12944. };
  12945. // optional properties
  12946. if (arguments.length > 1) {
  12947. extend(attribs, {
  12948. x: x,
  12949. y: y,
  12950. width: width,
  12951. height: height
  12952. });
  12953. }
  12954. var elemWrapper = this.createElement('image').attr(attribs),
  12955. onDummyLoad = function (e) {
  12956. setSVGImageSource(elemWrapper.element,
  12957. src);
  12958. onload.call(elemWrapper, e);
  12959. };
  12960. // Add load event if supplied
  12961. if (onload) {
  12962. // We have to use a dummy HTML image since IE support for SVG image
  12963. // load events is very buggy. First set a transparent src, wait for
  12964. // dummy to load, and then add the real src to the SVG image.
  12965. setSVGImageSource(elemWrapper.element, 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' /* eslint-disable-line */);
  12966. var dummy = new win.Image();
  12967. addEvent(dummy, 'load', onDummyLoad);
  12968. dummy.src = src;
  12969. if (dummy.complete) {
  12970. onDummyLoad({});
  12971. }
  12972. }
  12973. else {
  12974. setSVGImageSource(elemWrapper.element, src);
  12975. }
  12976. return elemWrapper;
  12977. };
  12978. /**
  12979. * Draw a symbol out of pre-defined shape paths from
  12980. * {@link SVGRenderer#symbols}.
  12981. * It is used in Highcharts for point makers, which cake a `symbol` option,
  12982. * and label and button backgrounds like in the tooltip and stock flags.
  12983. *
  12984. * @function Highcharts.SVGRenderer#symbol
  12985. *
  12986. * @param {string} symbol
  12987. * The symbol name.
  12988. *
  12989. * @param {number} [x]
  12990. * The X coordinate for the top left position.
  12991. *
  12992. * @param {number} [y]
  12993. * The Y coordinate for the top left position.
  12994. *
  12995. * @param {number} [width]
  12996. * The pixel width.
  12997. *
  12998. * @param {number} [height]
  12999. * The pixel height.
  13000. *
  13001. * @param {Highcharts.SymbolOptionsObject} [options]
  13002. * Additional options, depending on the actual symbol drawn.
  13003. *
  13004. * @return {Highcharts.SVGElement}
  13005. */
  13006. SVGRenderer.prototype.symbol = function (symbol, x, y, width, height, options) {
  13007. var ren = this,
  13008. imageRegex = /^url\((.*?)\)$/,
  13009. isImage = imageRegex.test(symbol),
  13010. sym = (!isImage && (this.symbols[symbol] ? symbol : 'circle')),
  13011. // get the symbol definition function
  13012. symbolFn = (sym && this.symbols[sym]);
  13013. var obj,
  13014. path,
  13015. imageSrc,
  13016. centerImage;
  13017. if (symbolFn) {
  13018. // Check if there's a path defined for this symbol
  13019. if (typeof x === 'number') {
  13020. path = symbolFn.call(this.symbols, Math.round(x || 0), Math.round(y || 0), width || 0, height || 0, options);
  13021. }
  13022. obj = this.path(path);
  13023. if (!ren.styledMode) {
  13024. obj.attr('fill', 'none');
  13025. }
  13026. // expando properties for use in animate and attr
  13027. extend(obj, {
  13028. symbolName: (sym || void 0),
  13029. x: x,
  13030. y: y,
  13031. width: width,
  13032. height: height
  13033. });
  13034. if (options) {
  13035. extend(obj, options);
  13036. }
  13037. // Image symbols
  13038. }
  13039. else if (isImage) {
  13040. imageSrc = symbol.match(imageRegex)[1];
  13041. // Create the image synchronously, add attribs async
  13042. var img_1 = obj = this.image(imageSrc);
  13043. // The image width is not always the same as the symbol width. The
  13044. // image may be centered within the symbol, as is the case when
  13045. // image shapes are used as label backgrounds, for example in flags.
  13046. img_1.imgwidth = pick(symbolSizes[imageSrc] && symbolSizes[imageSrc].width, options && options.width);
  13047. img_1.imgheight = pick(symbolSizes[imageSrc] && symbolSizes[imageSrc].height, options && options.height);
  13048. /**
  13049. * Set the size and position
  13050. */
  13051. centerImage = function (obj) { return obj.attr({
  13052. width: obj.width,
  13053. height: obj.height
  13054. }); };
  13055. /**
  13056. * Width and height setters that take both the image's physical size
  13057. * and the label size into consideration, and translates the image
  13058. * to center within the label.
  13059. */
  13060. ['width', 'height'].forEach(function (key) {
  13061. img_1[key + 'Setter'] = function (value, key) {
  13062. var imgSize = this['img' + key];
  13063. this[key] = value;
  13064. if (defined(imgSize)) {
  13065. // Scale and center the image within its container.
  13066. // The name `backgroundSize` is taken from the CSS spec,
  13067. // but the value `within` is made up. Other possible
  13068. // values in the spec, `cover` and `contain`, can be
  13069. // implemented if needed.
  13070. if (options &&
  13071. options.backgroundSize === 'within' &&
  13072. this.width &&
  13073. this.height) {
  13074. imgSize = Math.round(imgSize * Math.min(this.width / this.imgwidth, this.height / this.imgheight));
  13075. }
  13076. if (this.element) {
  13077. this.element.setAttribute(key, imgSize);
  13078. }
  13079. if (!this.alignByTranslate) {
  13080. var translate = ((this[key] || 0) - imgSize) / 2;
  13081. var attribs = key === 'width' ?
  13082. { translateX: translate } :
  13083. { translateY: translate };
  13084. this.attr(attribs);
  13085. }
  13086. }
  13087. };
  13088. });
  13089. if (defined(x)) {
  13090. img_1.attr({
  13091. x: x,
  13092. y: y
  13093. });
  13094. }
  13095. img_1.isImg = true;
  13096. if (defined(img_1.imgwidth) && defined(img_1.imgheight)) {
  13097. centerImage(img_1);
  13098. }
  13099. else {
  13100. // Initialize image to be 0 size so export will still function
  13101. // if there's no cached sizes.
  13102. img_1.attr({ width: 0, height: 0 });
  13103. // Create a dummy JavaScript image to get the width and height.
  13104. createElement('img', {
  13105. onload: function () {
  13106. var chart = charts[ren.chartIndex];
  13107. // Special case for SVGs on IE11, the width is not
  13108. // accessible until the image is part of the DOM
  13109. // (#2854).
  13110. if (this.width === 0) {
  13111. css(this, {
  13112. position: 'absolute',
  13113. top: '-999em'
  13114. });
  13115. doc.body.appendChild(this);
  13116. }
  13117. // Center the image
  13118. symbolSizes[imageSrc] = {
  13119. width: this.width,
  13120. height: this.height
  13121. };
  13122. img_1.imgwidth = this.width;
  13123. img_1.imgheight = this.height;
  13124. if (img_1.element) {
  13125. centerImage(img_1);
  13126. }
  13127. // Clean up after #2854 workaround.
  13128. if (this.parentNode) {
  13129. this.parentNode.removeChild(this);
  13130. }
  13131. // Fire the load event when all external images are
  13132. // loaded
  13133. ren.imgCount--;
  13134. if (!ren.imgCount && chart && !chart.hasLoaded) {
  13135. chart.onload();
  13136. }
  13137. },
  13138. src: imageSrc
  13139. });
  13140. this.imgCount++;
  13141. }
  13142. }
  13143. return obj;
  13144. };
  13145. /**
  13146. * Define a clipping rectangle. The clipping rectangle is later applied
  13147. * to {@link SVGElement} objects through the {@link SVGElement#clip}
  13148. * function.
  13149. *
  13150. * @example
  13151. * let circle = renderer.circle(100, 100, 100)
  13152. * .attr({ fill: 'red' })
  13153. * .add();
  13154. * let clipRect = renderer.clipRect(100, 100, 100, 100);
  13155. *
  13156. * // Leave only the lower right quarter visible
  13157. * circle.clip(clipRect);
  13158. *
  13159. * @function Highcharts.SVGRenderer#clipRect
  13160. *
  13161. * @param {number} [x]
  13162. *
  13163. * @param {number} [y]
  13164. *
  13165. * @param {number} [width]
  13166. *
  13167. * @param {number} [height]
  13168. *
  13169. * @return {Highcharts.ClipRectElement}
  13170. * A clipping rectangle.
  13171. */
  13172. SVGRenderer.prototype.clipRect = function (x, y, width, height) {
  13173. var
  13174. // Add a hyphen at the end to avoid confusion in testing indexes
  13175. // -1 and -10, -11 etc (#6550)
  13176. id = uniqueKey() + '-', clipPath = this.createElement('clipPath').attr({
  13177. id: id
  13178. }).add(this.defs), wrapper = this.rect(x, y, width, height, 0).add(clipPath);
  13179. wrapper.id = id;
  13180. wrapper.clipPath = clipPath;
  13181. wrapper.count = 0;
  13182. return wrapper;
  13183. };
  13184. /**
  13185. * Draw text. The text can contain a subset of HTML, like spans and anchors
  13186. * and some basic text styling of these. For more advanced features like
  13187. * border and background, use {@link Highcharts.SVGRenderer#label} instead.
  13188. * To update the text after render, run `text.attr({ text: 'New text' })`.
  13189. *
  13190. * @sample highcharts/members/renderer-text-on-chart/
  13191. * Annotate the chart freely
  13192. * @sample highcharts/members/renderer-on-chart/
  13193. * Annotate with a border and in response to the data
  13194. * @sample highcharts/members/renderer-text/
  13195. * Formatted text
  13196. *
  13197. * @function Highcharts.SVGRenderer#text
  13198. *
  13199. * @param {string} [str]
  13200. * The text of (subset) HTML to draw.
  13201. *
  13202. * @param {number} [x]
  13203. * The x position of the text's lower left corner.
  13204. *
  13205. * @param {number} [y]
  13206. * The y position of the text's lower left corner.
  13207. *
  13208. * @param {boolean} [useHTML=false]
  13209. * Use HTML to render the text.
  13210. *
  13211. * @return {Highcharts.SVGElement}
  13212. * The text object.
  13213. */
  13214. SVGRenderer.prototype.text = function (str, x, y, useHTML) {
  13215. var renderer = this,
  13216. attribs = {};
  13217. if (useHTML && (renderer.allowHTML || !renderer.forExport)) {
  13218. return renderer.html(str, x, y);
  13219. }
  13220. attribs.x = Math.round(x || 0); // X always needed for line-wrap logic
  13221. if (y) {
  13222. attribs.y = Math.round(y);
  13223. }
  13224. if (defined(str)) {
  13225. attribs.text = str;
  13226. }
  13227. var wrapper = renderer.createElement('text').attr(attribs);
  13228. if (!useHTML) {
  13229. wrapper.xSetter = function (value, key, element) {
  13230. var tspans = element.getElementsByTagName('tspan'),
  13231. parentVal = element.getAttribute(key);
  13232. for (var i = 0, tspan = void 0; i < tspans.length; i++) {
  13233. tspan = tspans[i];
  13234. // If the x values are equal, the tspan represents a
  13235. // linebreak
  13236. if (tspan.getAttribute(key) === parentVal) {
  13237. tspan.setAttribute(key, value);
  13238. }
  13239. }
  13240. element.setAttribute(key, value);
  13241. };
  13242. }
  13243. return wrapper;
  13244. };
  13245. /**
  13246. * Utility to return the baseline offset and total line height from the font
  13247. * size.
  13248. *
  13249. * @function Highcharts.SVGRenderer#fontMetrics
  13250. *
  13251. * @param {number|string} [fontSize]
  13252. * The current font size to inspect. If not given, the font size
  13253. * will be found from the DOM element.
  13254. *
  13255. * @param {Highcharts.SVGElement|Highcharts.SVGDOMElement} [elem]
  13256. * The element to inspect for a current font size.
  13257. *
  13258. * @return {Highcharts.FontMetricsObject}
  13259. * The font metrics.
  13260. */
  13261. SVGRenderer.prototype.fontMetrics = function (fontSize, elem) {
  13262. if ((this.styledMode || !/px/.test(fontSize)) &&
  13263. win.getComputedStyle // old IE doesn't support it
  13264. ) {
  13265. fontSize = elem && SVGElement.prototype.getStyle.call(elem, 'font-size');
  13266. }
  13267. else {
  13268. fontSize = fontSize ||
  13269. // When the elem is a DOM element (#5932)
  13270. (elem && elem.style && elem.style.fontSize) ||
  13271. // Fall back on the renderer style default
  13272. (this.style && this.style.fontSize);
  13273. }
  13274. // Handle different units
  13275. if (/px/.test(fontSize)) {
  13276. fontSize = pInt(fontSize);
  13277. }
  13278. else {
  13279. fontSize = 12;
  13280. }
  13281. // Empirical values found by comparing font size and bounding box
  13282. // height. Applies to the default font family.
  13283. // https://jsfiddle.net/highcharts/7xvn7/
  13284. var lineHeight = (fontSize < 24 ?
  13285. fontSize + 3 :
  13286. Math.round(fontSize * 1.2)),
  13287. baseline = Math.round(lineHeight * 0.8);
  13288. return {
  13289. h: lineHeight,
  13290. b: baseline,
  13291. f: fontSize
  13292. };
  13293. };
  13294. /**
  13295. * Correct X and Y positioning of a label for rotation (#1764).
  13296. *
  13297. * @private
  13298. * @function Highcharts.SVGRenderer#rotCorr
  13299. *
  13300. * @param {number} baseline
  13301. *
  13302. * @param {number} rotation
  13303. *
  13304. * @param {boolean} [alterY]
  13305. *
  13306. * @param {Highcharts.PositionObject}
  13307. */
  13308. SVGRenderer.prototype.rotCorr = function (baseline, rotation, alterY) {
  13309. var y = baseline;
  13310. if (rotation && alterY) {
  13311. y = Math.max(y * Math.cos(rotation * deg2rad), 4);
  13312. }
  13313. return {
  13314. x: (-baseline / 3) * Math.sin(rotation * deg2rad),
  13315. y: y
  13316. };
  13317. };
  13318. /**
  13319. * Compatibility function to convert the legacy one-dimensional path array
  13320. * into an array of segments.
  13321. *
  13322. * It is used in maps to parse the `path` option, and in SVGRenderer.dSetter
  13323. * to support legacy paths from demos.
  13324. *
  13325. * @private
  13326. * @function Highcharts.SVGRenderer#pathToSegments
  13327. */
  13328. SVGRenderer.prototype.pathToSegments = function (path) {
  13329. var ret = [];
  13330. var segment = [];
  13331. var commandLength = {
  13332. A: 8,
  13333. C: 7,
  13334. H: 2,
  13335. L: 3,
  13336. M: 3,
  13337. Q: 5,
  13338. S: 5,
  13339. T: 3,
  13340. V: 2
  13341. };
  13342. // Short, non-typesafe parsing of the one-dimensional array. It splits
  13343. // the path on any string. This is not type checked against the tuple
  13344. // types, but is shorter, and doesn't require specific checks for any
  13345. // command type in SVG.
  13346. for (var i = 0; i < path.length; i++) {
  13347. // Command skipped, repeat previous or insert L/l for M/m
  13348. if (isString(segment[0]) &&
  13349. isNumber(path[i]) &&
  13350. segment.length === commandLength[(segment[0].toUpperCase())]) {
  13351. path.splice(i, 0, segment[0].replace('M', 'L').replace('m', 'l'));
  13352. }
  13353. // Split on string
  13354. if (typeof path[i] === 'string') {
  13355. if (segment.length) {
  13356. ret.push(segment.slice(0));
  13357. }
  13358. segment.length = 0;
  13359. }
  13360. segment.push(path[i]);
  13361. }
  13362. ret.push(segment.slice(0));
  13363. return ret;
  13364. /*
  13365. // Fully type-safe version where each tuple type is checked. The
  13366. // downside is filesize and a lack of flexibility for unsupported
  13367. // commands
  13368. const ret: SVGPath = [],
  13369. commands = {
  13370. A: 7,
  13371. C: 6,
  13372. H: 1,
  13373. L: 2,
  13374. M: 2,
  13375. Q: 4,
  13376. S: 4,
  13377. T: 2,
  13378. V: 1,
  13379. Z: 0
  13380. };
  13381. let i = 0,
  13382. lastI = 0,
  13383. lastCommand;
  13384. while (i < path.length) {
  13385. const item = path[i];
  13386. let command;
  13387. if (typeof item === 'string') {
  13388. command = item;
  13389. i += 1;
  13390. } else {
  13391. command = lastCommand || 'M';
  13392. }
  13393. // Upper case
  13394. const commandUC = command.toUpperCase();
  13395. if (commandUC in commands) {
  13396. // No numeric parameters
  13397. if (command === 'Z' || command === 'z') {
  13398. ret.push([command]);
  13399. // One numeric parameter
  13400. } else {
  13401. const val0 = path[i];
  13402. if (typeof val0 === 'number') {
  13403. // Horizontal line to
  13404. if (command === 'H' || command === 'h') {
  13405. ret.push([command, val0]);
  13406. i += 1;
  13407. // Vertical line to
  13408. } else if (command === 'V' || command === 'v') {
  13409. ret.push([command, val0]);
  13410. i += 1;
  13411. // Two numeric parameters
  13412. } else {
  13413. const val1 = path[i + 1];
  13414. if (typeof val1 === 'number') {
  13415. // lineTo
  13416. if (command === 'L' || command === 'l') {
  13417. ret.push([command, val0, val1]);
  13418. i += 2;
  13419. // moveTo
  13420. } else if (command === 'M' || command === 'm') {
  13421. ret.push([command, val0, val1]);
  13422. i += 2;
  13423. // Smooth quadratic bezier
  13424. } else if (command === 'T' || command === 't') {
  13425. ret.push([command, val0, val1]);
  13426. i += 2;
  13427. // Four numeric parameters
  13428. } else {
  13429. const val2 = path[i + 2],
  13430. val3 = path[i + 3];
  13431. if (
  13432. typeof val2 === 'number' &&
  13433. typeof val3 === 'number'
  13434. ) {
  13435. // Quadratic bezier to
  13436. if (
  13437. command === 'Q' ||
  13438. command === 'q'
  13439. ) {
  13440. ret.push([
  13441. command,
  13442. val0,
  13443. val1,
  13444. val2,
  13445. val3
  13446. ]);
  13447. i += 4;
  13448. // Smooth cubic bezier to
  13449. } else if (
  13450. command === 'S' ||
  13451. command === 's'
  13452. ) {
  13453. ret.push([
  13454. command,
  13455. val0,
  13456. val1,
  13457. val2,
  13458. val3
  13459. ]);
  13460. i += 4;
  13461. // Six numeric parameters
  13462. } else {
  13463. const val4 = path[i + 4],
  13464. val5 = path[i + 5];
  13465. if (
  13466. typeof val4 === 'number' &&
  13467. typeof val5 === 'number'
  13468. ) {
  13469. // Curve to
  13470. if (
  13471. command === 'C' ||
  13472. command === 'c'
  13473. ) {
  13474. ret.push([
  13475. command,
  13476. val0,
  13477. val1,
  13478. val2,
  13479. val3,
  13480. val4,
  13481. val5
  13482. ]);
  13483. i += 6;
  13484. // Seven numeric parameters
  13485. } else {
  13486. const val6 = path[i + 6];
  13487. // Arc to
  13488. if (
  13489. typeof val6 ===
  13490. 'number' &&
  13491. (
  13492. command === 'A' ||
  13493. command === 'a'
  13494. )
  13495. ) {
  13496. ret.push([
  13497. command,
  13498. val0,
  13499. val1,
  13500. val2,
  13501. val3,
  13502. val4,
  13503. val5,
  13504. val6
  13505. ]);
  13506. i += 7;
  13507. }
  13508. }
  13509. }
  13510. }
  13511. }
  13512. }
  13513. }
  13514. }
  13515. }
  13516. }
  13517. }
  13518. // An unmarked command following a moveTo is a lineTo
  13519. lastCommand = command === 'M' ? 'L' : command;
  13520. if (i === lastI) {
  13521. break;
  13522. }
  13523. lastI = i;
  13524. }
  13525. return ret;
  13526. */
  13527. };
  13528. /**
  13529. * Draw a label, which is an extended text element with support for border
  13530. * and background. Highcharts creates a `g` element with a text and a `path`
  13531. * or `rect` inside, to make it behave somewhat like a HTML div. Border and
  13532. * background are set through `stroke`, `stroke-width` and `fill` attributes
  13533. * using the {@link Highcharts.SVGElement#attr|attr} method. To update the
  13534. * text after render, run `label.attr({ text: 'New text' })`.
  13535. *
  13536. * @sample highcharts/members/renderer-label-on-chart/
  13537. * A label on the chart
  13538. *
  13539. * @function Highcharts.SVGRenderer#label
  13540. *
  13541. * @param {string} str
  13542. * The initial text string or (subset) HTML to render.
  13543. *
  13544. * @param {number} x
  13545. * The x position of the label's left side.
  13546. *
  13547. * @param {number} [y]
  13548. * The y position of the label's top side or baseline, depending on
  13549. * the `baseline` parameter.
  13550. *
  13551. * @param {string} [shape='rect']
  13552. * The shape of the label's border/background, if any. Defaults to
  13553. * `rect`. Other possible values are `callout` or other shapes
  13554. * defined in {@link Highcharts.SVGRenderer#symbols}.
  13555. *
  13556. * @param {number} [anchorX]
  13557. * In case the `shape` has a pointer, like a flag, this is the
  13558. * coordinates it should be pinned to.
  13559. *
  13560. * @param {number} [anchorY]
  13561. * In case the `shape` has a pointer, like a flag, this is the
  13562. * coordinates it should be pinned to.
  13563. *
  13564. * @param {boolean} [useHTML=false]
  13565. * Wether to use HTML to render the label.
  13566. *
  13567. * @param {boolean} [baseline=false]
  13568. * Whether to position the label relative to the text baseline,
  13569. * like {@link Highcharts.SVGRenderer#text|renderer.text}, or to the
  13570. * upper border of the rectangle.
  13571. *
  13572. * @param {string} [className]
  13573. * Class name for the group.
  13574. *
  13575. * @return {Highcharts.SVGElement}
  13576. * The generated label.
  13577. */
  13578. SVGRenderer.prototype.label = function (str, x, y, shape, anchorX, anchorY, useHTML, baseline, className) {
  13579. return new SVGLabel(this, str, x, y, shape, anchorX, anchorY, useHTML, baseline, className);
  13580. };
  13581. /**
  13582. * Re-align all aligned elements.
  13583. *
  13584. * @private
  13585. * @function Highcharts.SVGRenderer#alignElements
  13586. * @return {void}
  13587. */
  13588. SVGRenderer.prototype.alignElements = function () {
  13589. this.alignedObjects.forEach(function (el) { return el.align(); });
  13590. };
  13591. return SVGRenderer;
  13592. }());
  13593. extend(SVGRenderer.prototype, {
  13594. /**
  13595. * A pointer to the renderer's associated Element class. The VMLRenderer
  13596. * will have a pointer to VMLElement here.
  13597. *
  13598. * @name Highcharts.SVGRenderer#Element
  13599. * @type {Highcharts.SVGElement}
  13600. */
  13601. Element: SVGElement,
  13602. SVG_NS: SVG_NS,
  13603. /**
  13604. * A collection of characters mapped to HTML entities. When `useHTML` on an
  13605. * element is true, these entities will be rendered correctly by HTML. In
  13606. * the SVG pseudo-HTML, they need to be unescaped back to simple characters,
  13607. * so for example `&lt;` will render as `<`.
  13608. *
  13609. * @example
  13610. * // Add support for unescaping quotes
  13611. * Highcharts.SVGRenderer.prototype.escapes['"'] = '&quot;';
  13612. *
  13613. * @name Highcharts.SVGRenderer#escapes
  13614. * @type {Highcharts.Dictionary<string>}
  13615. */
  13616. escapes: {
  13617. '&': '&amp;',
  13618. '<': '&lt;',
  13619. '>': '&gt;',
  13620. "'": '&#39;',
  13621. '"': '&quot;'
  13622. },
  13623. /**
  13624. * An extendable collection of functions for defining symbol paths.
  13625. *
  13626. * @name Highcharts.SVGRenderer#symbols
  13627. * @type {Highcharts.SymbolDictionary}
  13628. */
  13629. symbols: Symbols,
  13630. /**
  13631. * Dummy function for plugins, called every time the renderer is updated.
  13632. * Prior to Highcharts 5, this was used for the canvg renderer.
  13633. *
  13634. * @deprecated
  13635. * @function Highcharts.SVGRenderer#draw
  13636. */
  13637. draw: noop
  13638. });
  13639. /* *
  13640. *
  13641. * Registry
  13642. *
  13643. * */
  13644. RendererRegistry.registerRendererType('svg', SVGRenderer, true);
  13645. /* *
  13646. *
  13647. * Export Default
  13648. *
  13649. * */
  13650. /* *
  13651. *
  13652. * API Declarations
  13653. *
  13654. * */
  13655. /**
  13656. * A clipping rectangle that can be applied to one or more {@link SVGElement}
  13657. * instances. It is instanciated with the {@link SVGRenderer#clipRect} function
  13658. * and applied with the {@link SVGElement#clip} function.
  13659. *
  13660. * @example
  13661. * let circle = renderer.circle(100, 100, 100)
  13662. * .attr({ fill: 'red' })
  13663. * .add();
  13664. * let clipRect = renderer.clipRect(100, 100, 100, 100);
  13665. *
  13666. * // Leave only the lower right quarter visible
  13667. * circle.clip(clipRect);
  13668. *
  13669. * @typedef {Highcharts.SVGElement} Highcharts.ClipRectElement
  13670. */
  13671. /**
  13672. * The font metrics.
  13673. *
  13674. * @interface Highcharts.FontMetricsObject
  13675. */ /**
  13676. * The baseline relative to the top of the box.
  13677. *
  13678. * @name Highcharts.FontMetricsObject#b
  13679. * @type {number}
  13680. */ /**
  13681. * The font size.
  13682. *
  13683. * @name Highcharts.FontMetricsObject#f
  13684. * @type {number}
  13685. */ /**
  13686. * The line height.
  13687. *
  13688. * @name Highcharts.FontMetricsObject#h
  13689. * @type {number}
  13690. */
  13691. /**
  13692. * An object containing `x` and `y` properties for the position of an element.
  13693. *
  13694. * @interface Highcharts.PositionObject
  13695. */ /**
  13696. * X position of the element.
  13697. * @name Highcharts.PositionObject#x
  13698. * @type {number}
  13699. */ /**
  13700. * Y position of the element.
  13701. * @name Highcharts.PositionObject#y
  13702. * @type {number}
  13703. */
  13704. /**
  13705. * A rectangle.
  13706. *
  13707. * @interface Highcharts.RectangleObject
  13708. */ /**
  13709. * Height of the rectangle.
  13710. * @name Highcharts.RectangleObject#height
  13711. * @type {number}
  13712. */ /**
  13713. * Width of the rectangle.
  13714. * @name Highcharts.RectangleObject#width
  13715. * @type {number}
  13716. */ /**
  13717. * Horizontal position of the rectangle.
  13718. * @name Highcharts.RectangleObject#x
  13719. * @type {number}
  13720. */ /**
  13721. * Vertical position of the rectangle.
  13722. * @name Highcharts.RectangleObject#y
  13723. * @type {number}
  13724. */
  13725. /**
  13726. * The shadow options.
  13727. *
  13728. * @interface Highcharts.ShadowOptionsObject
  13729. */ /**
  13730. * The shadow color.
  13731. * @name Highcharts.ShadowOptionsObject#color
  13732. * @type {Highcharts.ColorString|undefined}
  13733. * @default ${palette.neutralColor100}
  13734. */ /**
  13735. * The horizontal offset from the element.
  13736. *
  13737. * @name Highcharts.ShadowOptionsObject#offsetX
  13738. * @type {number|undefined}
  13739. * @default 1
  13740. */ /**
  13741. * The vertical offset from the element.
  13742. * @name Highcharts.ShadowOptionsObject#offsetY
  13743. * @type {number|undefined}
  13744. * @default 1
  13745. */ /**
  13746. * The shadow opacity.
  13747. *
  13748. * @name Highcharts.ShadowOptionsObject#opacity
  13749. * @type {number|undefined}
  13750. * @default 0.15
  13751. */ /**
  13752. * The shadow width or distance from the element.
  13753. * @name Highcharts.ShadowOptionsObject#width
  13754. * @type {number|undefined}
  13755. * @default 3
  13756. */
  13757. /**
  13758. * @interface Highcharts.SizeObject
  13759. */ /**
  13760. * @name Highcharts.SizeObject#height
  13761. * @type {number}
  13762. */ /**
  13763. * @name Highcharts.SizeObject#width
  13764. * @type {number}
  13765. */
  13766. /**
  13767. * Array of path commands, that will go into the `d` attribute of an SVG
  13768. * element.
  13769. *
  13770. * @typedef {Array<(Array<Highcharts.SVGPathCommand>|Array<Highcharts.SVGPathCommand,number>|Array<Highcharts.SVGPathCommand,number,number>|Array<Highcharts.SVGPathCommand,number,number,number,number>|Array<Highcharts.SVGPathCommand,number,number,number,number,number,number>|Array<Highcharts.SVGPathCommand,number,number,number,number,number,number,number>)>} Highcharts.SVGPathArray
  13771. */
  13772. /**
  13773. * Possible path commands in an SVG path array. Valid values are `A`, `C`, `H`,
  13774. * `L`, `M`, `Q`, `S`, `T`, `V`, `Z`.
  13775. *
  13776. * @typedef {string} Highcharts.SVGPathCommand
  13777. * @validvalue ["a","c","h","l","m","q","s","t","v","z","A","C","H","L","M","Q","S","T","V","Z"]
  13778. */
  13779. /**
  13780. * An extendable collection of functions for defining symbol paths. Symbols are
  13781. * used internally for point markers, button and label borders and backgrounds,
  13782. * or custom shapes. Extendable by adding to {@link SVGRenderer#symbols}.
  13783. *
  13784. * @interface Highcharts.SymbolDictionary
  13785. */ /**
  13786. * @name Highcharts.SymbolDictionary#[key:string]
  13787. * @type {Function|undefined}
  13788. */ /**
  13789. * @name Highcharts.SymbolDictionary#arc
  13790. * @type {Function|undefined}
  13791. */ /**
  13792. * @name Highcharts.SymbolDictionary#callout
  13793. * @type {Function|undefined}
  13794. */ /**
  13795. * @name Highcharts.SymbolDictionary#circle
  13796. * @type {Function|undefined}
  13797. */ /**
  13798. * @name Highcharts.SymbolDictionary#diamond
  13799. * @type {Function|undefined}
  13800. */ /**
  13801. * @name Highcharts.SymbolDictionary#square
  13802. * @type {Function|undefined}
  13803. */ /**
  13804. * @name Highcharts.SymbolDictionary#triangle
  13805. * @type {Function|undefined}
  13806. */
  13807. /**
  13808. * Can be one of `arc`, `callout`, `circle`, `diamond`, `square`, `triangle`,
  13809. * and `triangle-down`. Symbols are used internally for point markers, button
  13810. * and label borders and backgrounds, or custom shapes. Extendable by adding to
  13811. * {@link SVGRenderer#symbols}.
  13812. *
  13813. * @typedef {"arc"|"callout"|"circle"|"diamond"|"square"|"triangle"|"triangle-down"} Highcharts.SymbolKeyValue
  13814. */
  13815. /**
  13816. * Additional options, depending on the actual symbol drawn.
  13817. *
  13818. * @interface Highcharts.SymbolOptionsObject
  13819. */ /**
  13820. * The anchor X position for the `callout` symbol. This is where the chevron
  13821. * points to.
  13822. *
  13823. * @name Highcharts.SymbolOptionsObject#anchorX
  13824. * @type {number|undefined}
  13825. */ /**
  13826. * The anchor Y position for the `callout` symbol. This is where the chevron
  13827. * points to.
  13828. *
  13829. * @name Highcharts.SymbolOptionsObject#anchorY
  13830. * @type {number|undefined}
  13831. */ /**
  13832. * The end angle of an `arc` symbol.
  13833. *
  13834. * @name Highcharts.SymbolOptionsObject#end
  13835. * @type {number|undefined}
  13836. */ /**
  13837. * Whether to draw `arc` symbol open or closed.
  13838. *
  13839. * @name Highcharts.SymbolOptionsObject#open
  13840. * @type {boolean|undefined}
  13841. */ /**
  13842. * The radius of an `arc` symbol, or the border radius for the `callout` symbol.
  13843. *
  13844. * @name Highcharts.SymbolOptionsObject#r
  13845. * @type {number|undefined}
  13846. */ /**
  13847. * The start angle of an `arc` symbol.
  13848. *
  13849. * @name Highcharts.SymbolOptionsObject#start
  13850. * @type {number|undefined}
  13851. */
  13852. (''); // keeps doclets above in transpiled file
  13853. return SVGRenderer;
  13854. });
  13855. _registerModule(_modules, 'Core/Renderer/HTML/HTMLElement.js', [_modules['Core/Globals.js'], _modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Utilities.js']], function (H, SVGElement, U) {
  13856. /* *
  13857. *
  13858. * (c) 2010-2021 Torstein Honsi
  13859. *
  13860. * License: www.highcharts.com/license
  13861. *
  13862. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  13863. *
  13864. * */
  13865. var __extends = (this && this.__extends) || (function () {
  13866. var extendStatics = function (d,
  13867. b) {
  13868. extendStatics = Object.setPrototypeOf ||
  13869. ({ __proto__: [] } instanceof Array && function (d,
  13870. b) { d.__proto__ = b; }) ||
  13871. function (d,
  13872. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  13873. return extendStatics(d, b);
  13874. };
  13875. return function (d, b) {
  13876. extendStatics(d, b);
  13877. function __() { this.constructor = d; }
  13878. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  13879. };
  13880. })();
  13881. var isFirefox = H.isFirefox,
  13882. isMS = H.isMS,
  13883. isWebKit = H.isWebKit,
  13884. win = H.win;
  13885. var css = U.css,
  13886. defined = U.defined,
  13887. extend = U.extend,
  13888. pick = U.pick,
  13889. pInt = U.pInt;
  13890. /* *
  13891. *
  13892. * Composition
  13893. *
  13894. * */
  13895. /* eslint-disable valid-jsdoc */
  13896. var HTMLElement = /** @class */ (function (_super) {
  13897. __extends(HTMLElement, _super);
  13898. function HTMLElement() {
  13899. return _super !== null && _super.apply(this, arguments) || this;
  13900. }
  13901. /* *
  13902. *
  13903. * Static Functions
  13904. *
  13905. * */
  13906. /**
  13907. * Modifies SVGElement to support HTML elements.
  13908. * @private
  13909. */
  13910. HTMLElement.compose = function (SVGElementClass) {
  13911. var svgElementProto = SVGElementClass.prototype,
  13912. htmlElementProto = HTMLElement.prototype;
  13913. svgElementProto.getSpanCorrection = htmlElementProto.getSpanCorrection;
  13914. svgElementProto.htmlCss = htmlElementProto.htmlCss;
  13915. svgElementProto.htmlGetBBox = htmlElementProto.htmlGetBBox;
  13916. svgElementProto.htmlUpdateTransform = htmlElementProto.htmlUpdateTransform;
  13917. svgElementProto.setSpanRotation = htmlElementProto.setSpanRotation;
  13918. };
  13919. /* *
  13920. *
  13921. * Functions
  13922. *
  13923. * */
  13924. /**
  13925. * Get the correction in X and Y positioning as the element is rotated.
  13926. * @private
  13927. */
  13928. HTMLElement.prototype.getSpanCorrection = function (width, baseline, alignCorrection) {
  13929. this.xCorr = -width * alignCorrection;
  13930. this.yCorr = -baseline;
  13931. };
  13932. /**
  13933. * Apply CSS to HTML elements. This is used in text within SVG rendering and
  13934. * by the VML renderer
  13935. * @private
  13936. */
  13937. HTMLElement.prototype.htmlCss = function (styles) {
  13938. var wrapper = this,
  13939. element = wrapper.element,
  13940. // When setting or unsetting the width style, we need to update
  13941. // transform (#8809)
  13942. isSettingWidth = (element.tagName === 'SPAN' &&
  13943. styles &&
  13944. 'width' in styles),
  13945. textWidth = pick(isSettingWidth && styles.width,
  13946. void 0);
  13947. var doTransform;
  13948. if (isSettingWidth) {
  13949. delete styles.width;
  13950. wrapper.textWidth = textWidth;
  13951. doTransform = true;
  13952. }
  13953. if (styles && styles.textOverflow === 'ellipsis') {
  13954. styles.whiteSpace = 'nowrap';
  13955. styles.overflow = 'hidden';
  13956. }
  13957. wrapper.styles = extend(wrapper.styles, styles);
  13958. css(wrapper.element, styles);
  13959. // Now that all styles are applied, to the transform
  13960. if (doTransform) {
  13961. wrapper.htmlUpdateTransform();
  13962. }
  13963. return wrapper;
  13964. };
  13965. /**
  13966. * VML and useHTML method for calculating the bounding box based on offsets.
  13967. */
  13968. HTMLElement.prototype.htmlGetBBox = function () {
  13969. var wrapper = this,
  13970. element = wrapper.element;
  13971. return {
  13972. x: element.offsetLeft,
  13973. y: element.offsetTop,
  13974. width: element.offsetWidth,
  13975. height: element.offsetHeight
  13976. };
  13977. };
  13978. /**
  13979. * VML override private method to update elements based on internal
  13980. * properties based on SVG transform.
  13981. * @private
  13982. */
  13983. HTMLElement.prototype.htmlUpdateTransform = function () {
  13984. // aligning non added elements is expensive
  13985. if (!this.added) {
  13986. this.alignOnAdd = true;
  13987. return;
  13988. }
  13989. var wrapper = this,
  13990. renderer = wrapper.renderer,
  13991. elem = wrapper.element,
  13992. translateX = wrapper.translateX || 0,
  13993. translateY = wrapper.translateY || 0,
  13994. x = wrapper.x || 0,
  13995. y = wrapper.y || 0,
  13996. align = wrapper.textAlign || 'left',
  13997. alignCorrection = {
  13998. left: 0,
  13999. center: 0.5,
  14000. right: 1
  14001. }[align],
  14002. styles = wrapper.styles,
  14003. whiteSpace = styles && styles.whiteSpace;
  14004. /** @private */
  14005. function getTextPxLength() {
  14006. // Reset multiline/ellipsis in order to read width (#4928,
  14007. // #5417)
  14008. css(elem, {
  14009. width: '',
  14010. whiteSpace: whiteSpace || 'nowrap'
  14011. });
  14012. return elem.offsetWidth;
  14013. }
  14014. // apply translate
  14015. css(elem, {
  14016. marginLeft: translateX,
  14017. marginTop: translateY
  14018. });
  14019. if (!renderer.styledMode && wrapper.shadows) { // used in labels/tooltip
  14020. wrapper.shadows.forEach(function (shadow) {
  14021. css(shadow, {
  14022. marginLeft: translateX + 1,
  14023. marginTop: translateY + 1
  14024. });
  14025. });
  14026. }
  14027. // apply inversion
  14028. if (wrapper.inverted) { // wrapper is a group
  14029. [].forEach.call(elem.childNodes, function (child) {
  14030. renderer.invertChild(child, elem);
  14031. });
  14032. }
  14033. if (elem.tagName === 'SPAN') {
  14034. var rotation = wrapper.rotation, textWidth = wrapper.textWidth && pInt(wrapper.textWidth), currentTextTransform = [
  14035. rotation,
  14036. align,
  14037. elem.innerHTML,
  14038. wrapper.textWidth,
  14039. wrapper.textAlign
  14040. ].join(',');
  14041. var baseline = void 0;
  14042. // Update textWidth. Use the memoized textPxLength if possible, to
  14043. // avoid the getTextPxLength function using elem.offsetWidth.
  14044. // Calling offsetWidth affects rendering time as it forces layout
  14045. // (#7656).
  14046. if (textWidth !== wrapper.oldTextWidth &&
  14047. ((textWidth > wrapper.oldTextWidth) ||
  14048. (wrapper.textPxLength || getTextPxLength()) > textWidth) && (
  14049. // Only set the width if the text is able to word-wrap, or
  14050. // text-overflow is ellipsis (#9537)
  14051. /[ \-]/.test(elem.textContent || elem.innerText) ||
  14052. elem.style.textOverflow === 'ellipsis')) { // #983, #1254
  14053. css(elem, {
  14054. width: textWidth + 'px',
  14055. display: 'block',
  14056. whiteSpace: whiteSpace || 'normal' // #3331
  14057. });
  14058. wrapper.oldTextWidth = textWidth;
  14059. wrapper.hasBoxWidthChanged = true; // #8159
  14060. }
  14061. else {
  14062. wrapper.hasBoxWidthChanged = false; // #8159
  14063. }
  14064. // Do the calculations and DOM access only if properties changed
  14065. if (currentTextTransform !== wrapper.cTT) {
  14066. baseline = renderer.fontMetrics(elem.style.fontSize, elem).b;
  14067. // Renderer specific handling of span rotation, but only if we
  14068. // have something to update.
  14069. if (defined(rotation) &&
  14070. ((rotation !== (wrapper.oldRotation || 0)) ||
  14071. (align !== wrapper.oldAlign))) {
  14072. wrapper.setSpanRotation(rotation, alignCorrection, baseline);
  14073. }
  14074. wrapper.getSpanCorrection(
  14075. // Avoid elem.offsetWidth if we can, it affects rendering
  14076. // time heavily (#7656)
  14077. ((!defined(rotation) && wrapper.textPxLength) || // #7920
  14078. elem.offsetWidth), baseline, alignCorrection, rotation, align);
  14079. }
  14080. // apply position with correction
  14081. css(elem, {
  14082. left: (x + (wrapper.xCorr || 0)) + 'px',
  14083. top: (y + (wrapper.yCorr || 0)) + 'px'
  14084. });
  14085. // record current text transform
  14086. wrapper.cTT = currentTextTransform;
  14087. wrapper.oldRotation = rotation;
  14088. wrapper.oldAlign = align;
  14089. }
  14090. };
  14091. /**
  14092. * Set the rotation of an individual HTML span.
  14093. * @private
  14094. */
  14095. HTMLElement.prototype.setSpanRotation = function (rotation, alignCorrection, baseline) {
  14096. var getTransformKey = function () { return (isMS &&
  14097. !/Edge/.test(win.navigator.userAgent) ?
  14098. '-ms-transform' :
  14099. isWebKit ?
  14100. '-webkit-transform' :
  14101. isFirefox ?
  14102. 'MozTransform' :
  14103. win.opera ?
  14104. '-o-transform' :
  14105. void 0); };
  14106. var rotationStyle = {},
  14107. cssTransformKey = getTransformKey();
  14108. if (cssTransformKey) {
  14109. rotationStyle[cssTransformKey] = rotationStyle.transform =
  14110. 'rotate(' + rotation + 'deg)';
  14111. rotationStyle[cssTransformKey + (isFirefox ? 'Origin' : '-origin')] = rotationStyle.transformOrigin =
  14112. (alignCorrection * 100) + '% ' + baseline + 'px';
  14113. css(this.element, rotationStyle);
  14114. }
  14115. };
  14116. return HTMLElement;
  14117. }(SVGElement));
  14118. /* *
  14119. *
  14120. * Default Export
  14121. *
  14122. * */
  14123. return HTMLElement;
  14124. });
  14125. _registerModule(_modules, 'Core/Renderer/HTML/HTMLRenderer.js', [_modules['Core/Renderer/HTML/AST.js'], _modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Renderer/SVG/SVGRenderer.js'], _modules['Core/Utilities.js']], function (AST, SVGElement, SVGRenderer, U) {
  14126. /* *
  14127. *
  14128. * (c) 2010-2021 Torstein Honsi
  14129. *
  14130. * License: www.highcharts.com/license
  14131. *
  14132. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  14133. *
  14134. * */
  14135. var __extends = (this && this.__extends) || (function () {
  14136. var extendStatics = function (d,
  14137. b) {
  14138. extendStatics = Object.setPrototypeOf ||
  14139. ({ __proto__: [] } instanceof Array && function (d,
  14140. b) { d.__proto__ = b; }) ||
  14141. function (d,
  14142. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  14143. return extendStatics(d, b);
  14144. };
  14145. return function (d, b) {
  14146. extendStatics(d, b);
  14147. function __() { this.constructor = d; }
  14148. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  14149. };
  14150. })();
  14151. var attr = U.attr,
  14152. createElement = U.createElement,
  14153. extend = U.extend,
  14154. pick = U.pick;
  14155. /* *
  14156. *
  14157. * Composition
  14158. *
  14159. * */
  14160. /* eslint-disable valid-jsdoc */
  14161. // Extend SvgRenderer for useHTML option.
  14162. var HTMLRenderer = /** @class */ (function (_super) {
  14163. __extends(HTMLRenderer, _super);
  14164. function HTMLRenderer() {
  14165. return _super !== null && _super.apply(this, arguments) || this;
  14166. }
  14167. /* *
  14168. *
  14169. * Functions
  14170. *
  14171. * */
  14172. /** @private */
  14173. HTMLRenderer.compose = function (SVGRendererClass) {
  14174. var svgRendererProto = SVGRendererClass.prototype,
  14175. htmlRendererProto = HTMLRenderer.prototype;
  14176. svgRendererProto.html = htmlRendererProto.html;
  14177. };
  14178. /**
  14179. * Create HTML text node. This is used by the VML renderer as well as the
  14180. * SVG renderer through the useHTML option.
  14181. *
  14182. * @private
  14183. * @function Highcharts.SVGRenderer#html
  14184. *
  14185. * @param {string} str
  14186. * The text of (subset) HTML to draw.
  14187. *
  14188. * @param {number} x
  14189. * The x position of the text's lower left corner.
  14190. *
  14191. * @param {number} y
  14192. * The y position of the text's lower left corner.
  14193. *
  14194. * @return {Highcharts.HTMLDOMElement}
  14195. */
  14196. HTMLRenderer.prototype.html = function (str, x, y) {
  14197. var wrapper = this.createElement('span'), element = wrapper.element, renderer = wrapper.renderer, isSVG = renderer.isSVG, addSetters = function (gWrapper, style) {
  14198. // These properties are set as attributes on the SVG group, and
  14199. // as identical CSS properties on the div. (#3542)
  14200. ['opacity', 'visibility'].forEach(function (prop) {
  14201. gWrapper[prop + 'Setter'] = function (value, key, elem) {
  14202. var styleObject = gWrapper.div ?
  14203. gWrapper.div.style :
  14204. style;
  14205. SVGElement.prototype[prop + 'Setter']
  14206. .call(this, value, key, elem);
  14207. if (styleObject) {
  14208. styleObject[key] = value;
  14209. }
  14210. };
  14211. });
  14212. gWrapper.addedSetters = true;
  14213. };
  14214. // Text setter
  14215. wrapper.textSetter = function (value) {
  14216. if (value !== this.textStr) {
  14217. delete this.bBox;
  14218. delete this.oldTextWidth;
  14219. AST.setElementHTML(this.element, pick(value, ''));
  14220. this.textStr = value;
  14221. wrapper.doTransform = true;
  14222. }
  14223. };
  14224. // Add setters for the element itself (#4938)
  14225. if (isSVG) { // #4938, only for HTML within SVG
  14226. addSetters(wrapper, wrapper.element.style);
  14227. }
  14228. // Various setters which rely on update transform
  14229. wrapper.xSetter =
  14230. wrapper.ySetter =
  14231. wrapper.alignSetter =
  14232. wrapper.rotationSetter =
  14233. function (value, key) {
  14234. if (key === 'align') {
  14235. // Do not overwrite the SVGElement.align method. Same as VML.
  14236. wrapper.alignValue = wrapper.textAlign = value;
  14237. }
  14238. else {
  14239. wrapper[key] = value;
  14240. }
  14241. wrapper.doTransform = true;
  14242. };
  14243. // Runs at the end of .attr()
  14244. wrapper.afterSetters = function () {
  14245. // Update transform. Do this outside the loop to prevent redundant
  14246. // updating for batch setting of attributes.
  14247. if (this.doTransform) {
  14248. this.htmlUpdateTransform();
  14249. this.doTransform = false;
  14250. }
  14251. };
  14252. // Set the default attributes
  14253. wrapper
  14254. .attr({
  14255. text: str,
  14256. x: Math.round(x),
  14257. y: Math.round(y)
  14258. })
  14259. .css({
  14260. position: 'absolute'
  14261. });
  14262. if (!renderer.styledMode) {
  14263. wrapper.css({
  14264. fontFamily: this.style.fontFamily,
  14265. fontSize: this.style.fontSize
  14266. });
  14267. }
  14268. // Keep the whiteSpace style outside the wrapper.styles collection
  14269. element.style.whiteSpace = 'nowrap';
  14270. // Use the HTML specific .css method
  14271. wrapper.css = wrapper.htmlCss;
  14272. // This is specific for HTML within SVG
  14273. if (isSVG) {
  14274. wrapper.add = function (svgGroupWrapper) {
  14275. var htmlGroup,
  14276. container = renderer.box.parentNode,
  14277. parentGroup,
  14278. parents = [];
  14279. this.parentGroup = svgGroupWrapper;
  14280. // Create a mock group to hold the HTML elements
  14281. if (svgGroupWrapper) {
  14282. htmlGroup = svgGroupWrapper.div;
  14283. if (!htmlGroup) {
  14284. // Read the parent chain into an array and read from top
  14285. // down
  14286. parentGroup = svgGroupWrapper;
  14287. while (parentGroup) {
  14288. parents.push(parentGroup);
  14289. // Move up to the next parent group
  14290. parentGroup = parentGroup.parentGroup;
  14291. }
  14292. // Ensure dynamically updating position when any parent
  14293. // is translated
  14294. parents.reverse().forEach(function (parentGroup) {
  14295. var htmlGroupStyle,
  14296. cls = attr(parentGroup.element, 'class');
  14297. /**
  14298. * Common translate setter for X and Y on the HTML
  14299. * group. Reverted the fix for #6957 du to
  14300. * positioning problems and offline export (#7254,
  14301. * #7280, #7529)
  14302. * @private
  14303. * @param {*} value
  14304. * @param {string} key
  14305. * @return {void}
  14306. */
  14307. function translateSetter(value, key) {
  14308. parentGroup[key] = value;
  14309. if (key === 'translateX') {
  14310. htmlGroupStyle.left = value + 'px';
  14311. }
  14312. else {
  14313. htmlGroupStyle.top = value + 'px';
  14314. }
  14315. parentGroup.doTransform = true;
  14316. }
  14317. // Create a HTML div and append it to the parent div
  14318. // to emulate the SVG group structure
  14319. var parentGroupStyles = parentGroup.styles || {};
  14320. htmlGroup =
  14321. parentGroup.div =
  14322. parentGroup.div || createElement('div', cls ? { className: cls } : void 0, {
  14323. position: 'absolute',
  14324. left: (parentGroup.translateX || 0) + 'px',
  14325. top: (parentGroup.translateY || 0) + 'px',
  14326. display: parentGroup.display,
  14327. opacity: parentGroup.opacity,
  14328. cursor: parentGroupStyles.cursor,
  14329. pointerEvents: parentGroupStyles.pointerEvents // #5595
  14330. // the top group is appended to container
  14331. }, htmlGroup || container);
  14332. // Shortcut
  14333. htmlGroupStyle = htmlGroup.style;
  14334. // Set listeners to update the HTML div's position
  14335. // whenever the SVG group position is changed.
  14336. extend(parentGroup, {
  14337. // (#7287) Pass htmlGroup to use
  14338. // the related group
  14339. classSetter: (function (htmlGroup) {
  14340. return function (value) {
  14341. this.element.setAttribute('class', value);
  14342. htmlGroup.className = value;
  14343. };
  14344. }(htmlGroup)),
  14345. on: function () {
  14346. if (parents[0].div) { // #6418
  14347. wrapper.on.apply({
  14348. element: parents[0].div,
  14349. onEvents: wrapper.onEvents
  14350. }, arguments);
  14351. }
  14352. return parentGroup;
  14353. },
  14354. translateXSetter: translateSetter,
  14355. translateYSetter: translateSetter
  14356. });
  14357. if (!parentGroup.addedSetters) {
  14358. addSetters(parentGroup);
  14359. }
  14360. });
  14361. }
  14362. }
  14363. else {
  14364. htmlGroup = container;
  14365. }
  14366. htmlGroup.appendChild(element);
  14367. // Shared with VML:
  14368. wrapper.added = true;
  14369. if (wrapper.alignOnAdd) {
  14370. wrapper.htmlUpdateTransform();
  14371. }
  14372. return wrapper;
  14373. };
  14374. }
  14375. return wrapper;
  14376. };
  14377. return HTMLRenderer;
  14378. }(SVGRenderer));
  14379. /* *
  14380. *
  14381. * Default Export
  14382. *
  14383. * */
  14384. return HTMLRenderer;
  14385. });
  14386. _registerModule(_modules, 'Core/Axis/AxisDefaults.js', [_modules['Core/Color/Palette.js']], function (Palette) {
  14387. /* *
  14388. *
  14389. * (c) 2010-2021 Torstein Honsi
  14390. *
  14391. * License: www.highcharts.com/license
  14392. *
  14393. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  14394. *
  14395. * */
  14396. /* *
  14397. *
  14398. * Namespace
  14399. *
  14400. * */
  14401. var AxisDefaults;
  14402. (function (AxisDefaults) {
  14403. /* *
  14404. *
  14405. * Constants
  14406. *
  14407. * */
  14408. /**
  14409. * The X axis or category axis. Normally this is the horizontal axis,
  14410. * though if the chart is inverted this is the vertical axis. In case of
  14411. * multiple axes, the xAxis node is an array of configuration objects.
  14412. *
  14413. * See the [Axis class](/class-reference/Highcharts.Axis) for programmatic
  14414. * access to the axis.
  14415. *
  14416. * @productdesc {highmaps}
  14417. * In Highmaps, the axis is hidden, but it is used behind the scenes to
  14418. * control features like zooming and panning. Zooming is in effect the same
  14419. * as setting the extremes of one of the exes.
  14420. *
  14421. * @type {*|Array<*>}
  14422. * @optionparent xAxis
  14423. */
  14424. AxisDefaults.defaultXAxisOptions = {
  14425. /**
  14426. * When using multiple axis, the ticks of two or more opposite axes
  14427. * will automatically be aligned by adding ticks to the axis or axes
  14428. * with the least ticks, as if `tickAmount` were specified.
  14429. *
  14430. * This can be prevented by setting `alignTicks` to false. If the grid
  14431. * lines look messy, it's a good idea to hide them for the secondary
  14432. * axis by setting `gridLineWidth` to 0.
  14433. *
  14434. * If `startOnTick` or `endOnTick` in an Axis options are set to false,
  14435. * then the `alignTicks ` will be disabled for the Axis.
  14436. *
  14437. * Disabled for logarithmic axes.
  14438. *
  14439. * @product highcharts highstock gantt
  14440. */
  14441. alignTicks: true,
  14442. /**
  14443. * Whether to allow decimals in this axis' ticks. When counting
  14444. * integers, like persons or hits on a web page, decimals should
  14445. * be avoided in the labels. By default, decimals are allowed on small
  14446. * scale axes.
  14447. *
  14448. * @see [minTickInterval](#xAxis.minTickInterval)
  14449. *
  14450. * @sample {highcharts|highstock} highcharts/yaxis/allowdecimals-true/
  14451. * True by default
  14452. * @sample {highcharts|highstock} highcharts/yaxis/allowdecimals-false/
  14453. * False
  14454. *
  14455. * @type {boolean|undefined}
  14456. * @default undefined
  14457. * @since 2.0
  14458. */
  14459. allowDecimals: void 0,
  14460. /**
  14461. * When using an alternate grid color, a band is painted across the
  14462. * plot area between every other grid line.
  14463. *
  14464. * @sample {highcharts} highcharts/yaxis/alternategridcolor/
  14465. * Alternate grid color on the Y axis
  14466. * @sample {highstock} stock/xaxis/alternategridcolor/
  14467. * Alternate grid color on the Y axis
  14468. *
  14469. * @type {Highcharts.ColorType}
  14470. * @apioption xAxis.alternateGridColor
  14471. */
  14472. /**
  14473. * An array defining breaks in the axis, the sections defined will be
  14474. * left out and all the points shifted closer to each other.
  14475. *
  14476. * @productdesc {highcharts}
  14477. * Requires that the broken-axis.js module is loaded.
  14478. *
  14479. * @sample {highcharts} highcharts/axisbreak/break-simple/
  14480. * Simple break
  14481. * @sample {highcharts|highstock} highcharts/axisbreak/break-visualized/
  14482. * Advanced with callback
  14483. * @sample {highstock} stock/demo/intraday-breaks/
  14484. * Break on nights and weekends
  14485. *
  14486. * @type {Array<*>}
  14487. * @since 4.1.0
  14488. * @product highcharts highstock gantt
  14489. * @apioption xAxis.breaks
  14490. */
  14491. /**
  14492. * A number indicating how much space should be left between the start
  14493. * and the end of the break. The break size is given in axis units,
  14494. * so for instance on a `datetime` axis, a break size of 3600000 would
  14495. * indicate the equivalent of an hour.
  14496. *
  14497. * @type {number}
  14498. * @default 0
  14499. * @since 4.1.0
  14500. * @product highcharts highstock gantt
  14501. * @apioption xAxis.breaks.breakSize
  14502. */
  14503. /**
  14504. * The point where the break starts.
  14505. *
  14506. * @type {number}
  14507. * @since 4.1.0
  14508. * @product highcharts highstock gantt
  14509. * @apioption xAxis.breaks.from
  14510. */
  14511. /**
  14512. * Defines an interval after which the break appears again. By default
  14513. * the breaks do not repeat.
  14514. *
  14515. * @type {number}
  14516. * @default 0
  14517. * @since 4.1.0
  14518. * @product highcharts highstock gantt
  14519. * @apioption xAxis.breaks.repeat
  14520. */
  14521. /**
  14522. * The point where the break ends.
  14523. *
  14524. * @type {number}
  14525. * @since 4.1.0
  14526. * @product highcharts highstock gantt
  14527. * @apioption xAxis.breaks.to
  14528. */
  14529. /**
  14530. * If categories are present for the xAxis, names are used instead of
  14531. * numbers for that axis.
  14532. *
  14533. * Since Highcharts 3.0, categories can also
  14534. * be extracted by giving each point a [name](#series.data) and setting
  14535. * axis [type](#xAxis.type) to `category`. However, if you have multiple
  14536. * series, best practice remains defining the `categories` array.
  14537. *
  14538. * Example: `categories: ['Apples', 'Bananas', 'Oranges']`
  14539. *
  14540. * @sample {highcharts} highcharts/demo/line-labels/
  14541. * With
  14542. * @sample {highcharts} highcharts/xaxis/categories/
  14543. * Without
  14544. *
  14545. * @type {Array<string>}
  14546. * @product highcharts gantt
  14547. * @apioption xAxis.categories
  14548. */
  14549. /**
  14550. * The highest allowed value for automatically computed axis extremes.
  14551. *
  14552. * @see [floor](#xAxis.floor)
  14553. *
  14554. * @sample {highcharts|highstock} highcharts/yaxis/floor-ceiling/
  14555. * Floor and ceiling
  14556. *
  14557. * @type {number}
  14558. * @since 4.0
  14559. * @product highcharts highstock gantt
  14560. * @apioption xAxis.ceiling
  14561. */
  14562. /**
  14563. * A class name that opens for styling the axis by CSS, especially in
  14564. * Highcharts styled mode. The class name is applied to group elements
  14565. * for the grid, axis elements and labels.
  14566. *
  14567. * @sample {highcharts|highstock|highmaps} highcharts/css/axis/
  14568. * Multiple axes with separate styling
  14569. *
  14570. * @type {string}
  14571. * @since 5.0.0
  14572. * @apioption xAxis.className
  14573. */
  14574. /**
  14575. * Configure a crosshair that follows either the mouse pointer or the
  14576. * hovered point.
  14577. *
  14578. * In styled mode, the crosshairs are styled in the
  14579. * `.highcharts-crosshair`, `.highcharts-crosshair-thin` or
  14580. * `.highcharts-xaxis-category` classes.
  14581. *
  14582. * @productdesc {highstock}
  14583. * In Highcharts stock, by default, the crosshair is enabled on the
  14584. * X axis and disabled on the Y axis.
  14585. *
  14586. * @sample {highcharts} highcharts/xaxis/crosshair-both/
  14587. * Crosshair on both axes
  14588. * @sample {highstock} stock/xaxis/crosshairs-xy/
  14589. * Crosshair on both axes
  14590. * @sample {highmaps} highcharts/xaxis/crosshair-both/
  14591. * Crosshair on both axes
  14592. *
  14593. * @declare Highcharts.AxisCrosshairOptions
  14594. * @type {boolean|*}
  14595. * @default false
  14596. * @since 4.1
  14597. * @apioption xAxis.crosshair
  14598. */
  14599. /**
  14600. * A class name for the crosshair, especially as a hook for styling.
  14601. *
  14602. * @type {string}
  14603. * @since 5.0.0
  14604. * @apioption xAxis.crosshair.className
  14605. */
  14606. /**
  14607. * The color of the crosshair. Defaults to `#cccccc` for numeric and
  14608. * datetime axes, and `rgba(204,214,235,0.25)` for category axes, where
  14609. * the crosshair by default highlights the whole category.
  14610. *
  14611. * @sample {highcharts|highstock|highmaps} highcharts/xaxis/crosshair-customized/
  14612. * Customized crosshairs
  14613. *
  14614. * @type {Highcharts.ColorType}
  14615. * @default #cccccc
  14616. * @since 4.1
  14617. * @apioption xAxis.crosshair.color
  14618. */
  14619. /**
  14620. * The dash style for the crosshair. See
  14621. * [plotOptions.series.dashStyle](#plotOptions.series.dashStyle)
  14622. * for possible values.
  14623. *
  14624. * @sample {highcharts|highmaps} highcharts/xaxis/crosshair-dotted/
  14625. * Dotted crosshair
  14626. * @sample {highstock} stock/xaxis/crosshair-dashed/
  14627. * Dashed X axis crosshair
  14628. *
  14629. * @type {Highcharts.DashStyleValue}
  14630. * @default Solid
  14631. * @since 4.1
  14632. * @apioption xAxis.crosshair.dashStyle
  14633. */
  14634. /**
  14635. * A label on the axis next to the crosshair.
  14636. *
  14637. * In styled mode, the label is styled with the
  14638. * `.highcharts-crosshair-label` class.
  14639. *
  14640. * @sample {highstock} stock/xaxis/crosshair-label/
  14641. * Crosshair labels
  14642. * @sample {highstock} highcharts/css/crosshair-label/
  14643. * Style mode
  14644. *
  14645. * @declare Highcharts.AxisCrosshairLabelOptions
  14646. * @since 2.1
  14647. * @product highstock
  14648. * @apioption xAxis.crosshair.label
  14649. */
  14650. /**
  14651. * Alignment of the label compared to the axis. Defaults to `"left"` for
  14652. * right-side axes, `"right"` for left-side axes and `"center"` for
  14653. * horizontal axes.
  14654. *
  14655. * @type {Highcharts.AlignValue}
  14656. * @since 2.1
  14657. * @product highstock
  14658. * @apioption xAxis.crosshair.label.align
  14659. */
  14660. /**
  14661. * The background color for the label. Defaults to the related series
  14662. * color, or `#666666` if that is not available.
  14663. *
  14664. * @type {Highcharts.ColorType}
  14665. * @since 2.1
  14666. * @product highstock
  14667. * @apioption xAxis.crosshair.label.backgroundColor
  14668. */
  14669. /**
  14670. * The border color for the crosshair label
  14671. *
  14672. * @type {Highcharts.ColorType}
  14673. * @since 2.1
  14674. * @product highstock
  14675. * @apioption xAxis.crosshair.label.borderColor
  14676. */
  14677. /**
  14678. * The border corner radius of the crosshair label.
  14679. *
  14680. * @type {number}
  14681. * @default 3
  14682. * @since 2.1.10
  14683. * @product highstock
  14684. * @apioption xAxis.crosshair.label.borderRadius
  14685. */
  14686. /**
  14687. * The border width for the crosshair label.
  14688. *
  14689. * @type {number}
  14690. * @default 0
  14691. * @since 2.1
  14692. * @product highstock
  14693. * @apioption xAxis.crosshair.label.borderWidth
  14694. */
  14695. /**
  14696. * Flag to enable crosshair's label.
  14697. *
  14698. * @sample {highstock} stock/xaxis/crosshairs-xy/
  14699. * Enabled label for yAxis' crosshair
  14700. *
  14701. * @type {boolean}
  14702. * @default false
  14703. * @since 2.1
  14704. * @product highstock
  14705. * @apioption xAxis.crosshair.label.enabled
  14706. */
  14707. /**
  14708. * A format string for the crosshair label. Defaults to `{value}` for
  14709. * numeric axes and `{value:%b %d, %Y}` for datetime axes.
  14710. *
  14711. * @type {string}
  14712. * @since 2.1
  14713. * @product highstock
  14714. * @apioption xAxis.crosshair.label.format
  14715. */
  14716. /**
  14717. * Formatter function for the label text.
  14718. *
  14719. * @type {Highcharts.XAxisCrosshairLabelFormatterCallbackFunction}
  14720. * @since 2.1
  14721. * @product highstock
  14722. * @apioption xAxis.crosshair.label.formatter
  14723. */
  14724. /**
  14725. * Padding inside the crosshair label.
  14726. *
  14727. * @type {number}
  14728. * @default 8
  14729. * @since 2.1
  14730. * @product highstock
  14731. * @apioption xAxis.crosshair.label.padding
  14732. */
  14733. /**
  14734. * The shape to use for the label box.
  14735. *
  14736. * @type {string}
  14737. * @default callout
  14738. * @since 2.1
  14739. * @product highstock
  14740. * @apioption xAxis.crosshair.label.shape
  14741. */
  14742. /**
  14743. * Text styles for the crosshair label.
  14744. *
  14745. * @type {Highcharts.CSSObject}
  14746. * @default {"color": "white", "fontWeight": "normal", "fontSize": "11px", "textAlign": "center"}
  14747. * @since 2.1
  14748. * @product highstock
  14749. * @apioption xAxis.crosshair.label.style
  14750. */
  14751. /**
  14752. * Whether the crosshair should snap to the point or follow the pointer
  14753. * independent of points.
  14754. *
  14755. * @sample {highcharts|highstock} highcharts/xaxis/crosshair-snap-false/
  14756. * True by default
  14757. * @sample {highmaps} maps/demo/latlon-advanced/
  14758. * Snap is false
  14759. *
  14760. * @type {boolean}
  14761. * @default true
  14762. * @since 4.1
  14763. * @apioption xAxis.crosshair.snap
  14764. */
  14765. /**
  14766. * The pixel width of the crosshair. Defaults to 1 for numeric or
  14767. * datetime axes, and for one category width for category axes.
  14768. *
  14769. * @sample {highcharts} highcharts/xaxis/crosshair-customized/
  14770. * Customized crosshairs
  14771. * @sample {highstock} highcharts/xaxis/crosshair-customized/
  14772. * Customized crosshairs
  14773. * @sample {highmaps} highcharts/xaxis/crosshair-customized/
  14774. * Customized crosshairs
  14775. *
  14776. * @type {number}
  14777. * @default 1
  14778. * @since 4.1
  14779. * @apioption xAxis.crosshair.width
  14780. */
  14781. /**
  14782. * The Z index of the crosshair. Higher Z indices allow drawing the
  14783. * crosshair on top of the series or behind the grid lines.
  14784. *
  14785. * @type {number}
  14786. * @default 2
  14787. * @since 4.1
  14788. * @apioption xAxis.crosshair.zIndex
  14789. */
  14790. /**
  14791. * Whether to pan axis. If `chart.panning` is enabled, the option
  14792. * allows to disable panning on an individual axis.
  14793. */
  14794. panningEnabled: true,
  14795. /**
  14796. * The Z index for the axis group.
  14797. */
  14798. zIndex: 2,
  14799. /**
  14800. * Whether to zoom axis. If `chart.zoomType` is set, the option allows
  14801. * to disable zooming on an individual axis.
  14802. *
  14803. * @sample {highcharts} highcharts/xaxis/zoomenabled/
  14804. * Zoom enabled is false
  14805. */
  14806. zoomEnabled: true,
  14807. /**
  14808. * For a datetime axis, the scale will automatically adjust to the
  14809. * appropriate unit. This member gives the default string
  14810. * representations used for each unit. For intermediate values,
  14811. * different units may be used, for example the `day` unit can be used
  14812. * on midnight and `hour` unit be used for intermediate values on the
  14813. * same axis.
  14814. *
  14815. * For an overview of the replacement codes, see
  14816. * [dateFormat](/class-reference/Highcharts#.dateFormat).
  14817. *
  14818. * Defaults to:
  14819. * ```js
  14820. * {
  14821. * millisecond: '%H:%M:%S.%L',
  14822. * second: '%H:%M:%S',
  14823. * minute: '%H:%M',
  14824. * hour: '%H:%M',
  14825. * day: '%e. %b',
  14826. * week: '%e. %b',
  14827. * month: '%b \'%y',
  14828. * year: '%Y'
  14829. * }
  14830. * ```
  14831. *
  14832. * @sample {highcharts} highcharts/xaxis/datetimelabelformats/
  14833. * Different day format on X axis
  14834. * @sample {highstock} stock/xaxis/datetimelabelformats/
  14835. * More information in x axis labels
  14836. *
  14837. * @declare Highcharts.AxisDateTimeLabelFormatsOptions
  14838. * @product highcharts highstock gantt
  14839. */
  14840. dateTimeLabelFormats: {
  14841. /**
  14842. * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
  14843. * @type {string|*}
  14844. */
  14845. millisecond: {
  14846. main: '%H:%M:%S.%L',
  14847. range: false
  14848. },
  14849. /**
  14850. * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
  14851. * @type {string|*}
  14852. */
  14853. second: {
  14854. main: '%H:%M:%S',
  14855. range: false
  14856. },
  14857. /**
  14858. * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
  14859. * @type {string|*}
  14860. */
  14861. minute: {
  14862. main: '%H:%M',
  14863. range: false
  14864. },
  14865. /**
  14866. * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
  14867. * @type {string|*}
  14868. */
  14869. hour: {
  14870. main: '%H:%M',
  14871. range: false
  14872. },
  14873. /**
  14874. * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
  14875. * @type {string|*}
  14876. */
  14877. day: {
  14878. main: '%e. %b'
  14879. },
  14880. /**
  14881. * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
  14882. * @type {string|*}
  14883. */
  14884. week: {
  14885. main: '%e. %b'
  14886. },
  14887. /**
  14888. * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
  14889. * @type {string|*}
  14890. */
  14891. month: {
  14892. main: '%b \'%y'
  14893. },
  14894. /**
  14895. * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
  14896. * @type {string|*}
  14897. */
  14898. year: {
  14899. main: '%Y'
  14900. }
  14901. },
  14902. /**
  14903. * Whether to force the axis to end on a tick. Use this option with
  14904. * the `maxPadding` option to control the axis end.
  14905. *
  14906. * @productdesc {highstock}
  14907. * In Highcharts Stock, `endOnTick` is always `false` when the navigator
  14908. * is enabled, to prevent jumpy scrolling.
  14909. *
  14910. * @sample {highcharts} highcharts/chart/reflow-true/
  14911. * True by default
  14912. * @sample {highcharts} highcharts/yaxis/endontick/
  14913. * False
  14914. * @sample {highstock} stock/demo/basic-line/
  14915. * True by default
  14916. * @sample {highstock} stock/xaxis/endontick/
  14917. * False
  14918. *
  14919. * @since 1.2.0
  14920. */
  14921. endOnTick: false,
  14922. /**
  14923. * Event handlers for the axis.
  14924. *
  14925. * @type {*}
  14926. * @apioption xAxis.events
  14927. */
  14928. /**
  14929. * An event fired after the breaks have rendered.
  14930. *
  14931. * @see [breaks](#xAxis.breaks)
  14932. *
  14933. * @sample {highcharts} highcharts/axisbreak/break-event/
  14934. * AfterBreak Event
  14935. *
  14936. * @type {Highcharts.AxisEventCallbackFunction}
  14937. * @since 4.1.0
  14938. * @product highcharts gantt
  14939. * @apioption xAxis.events.afterBreaks
  14940. */
  14941. /**
  14942. * As opposed to the `setExtremes` event, this event fires after the
  14943. * final min and max values are computed and corrected for `minRange`.
  14944. *
  14945. * Fires when the minimum and maximum is set for the axis, either by
  14946. * calling the `.setExtremes()` method or by selecting an area in the
  14947. * chart. One parameter, `event`, is passed to the function, containing
  14948. * common event information.
  14949. *
  14950. * The new user set minimum and maximum values can be found by
  14951. * `event.min` and `event.max`. These reflect the axis minimum and
  14952. * maximum in axis values. The actual data extremes are found in
  14953. * `event.dataMin` and `event.dataMax`.
  14954. *
  14955. * @type {Highcharts.AxisSetExtremesEventCallbackFunction}
  14956. * @since 2.3
  14957. * @context Highcharts.Axis
  14958. * @apioption xAxis.events.afterSetExtremes
  14959. */
  14960. /**
  14961. * An event fired when a break from this axis occurs on a point.
  14962. *
  14963. * @see [breaks](#xAxis.breaks)
  14964. *
  14965. * @sample {highcharts} highcharts/axisbreak/break-visualized/
  14966. * Visualization of a Break
  14967. *
  14968. * @type {Highcharts.AxisPointBreakEventCallbackFunction}
  14969. * @since 4.1.0
  14970. * @product highcharts gantt
  14971. * @context Highcharts.Axis
  14972. * @apioption xAxis.events.pointBreak
  14973. */
  14974. /**
  14975. * An event fired when a point falls inside a break from this axis.
  14976. *
  14977. * @type {Highcharts.AxisPointBreakEventCallbackFunction}
  14978. * @product highcharts highstock gantt
  14979. * @context Highcharts.Axis
  14980. * @apioption xAxis.events.pointInBreak
  14981. */
  14982. /**
  14983. * Fires when the minimum and maximum is set for the axis, either by
  14984. * calling the `.setExtremes()` method or by selecting an area in the
  14985. * chart. One parameter, `event`, is passed to the function,
  14986. * containing common event information.
  14987. *
  14988. * The new user set minimum and maximum values can be found by
  14989. * `event.min` and `event.max`. These reflect the axis minimum and
  14990. * maximum in data values. When an axis is zoomed all the way out from
  14991. * the "Reset zoom" button, `event.min` and `event.max` are null, and
  14992. * the new extremes are set based on `this.dataMin` and `this.dataMax`.
  14993. *
  14994. * @sample {highstock} stock/xaxis/events-setextremes/
  14995. * Log new extremes on x axis
  14996. *
  14997. * @type {Highcharts.AxisSetExtremesEventCallbackFunction}
  14998. * @since 1.2.0
  14999. * @context Highcharts.Axis
  15000. * @apioption xAxis.events.setExtremes
  15001. */
  15002. /**
  15003. * The lowest allowed value for automatically computed axis extremes.
  15004. *
  15005. * @see [ceiling](#yAxis.ceiling)
  15006. *
  15007. * @sample {highcharts} highcharts/yaxis/floor-ceiling/
  15008. * Floor and ceiling
  15009. * @sample {highstock} stock/demo/lazy-loading/
  15010. * Prevent negative stock price on Y axis
  15011. *
  15012. * @type {number}
  15013. * @since 4.0
  15014. * @product highcharts highstock gantt
  15015. * @apioption xAxis.floor
  15016. */
  15017. /**
  15018. * The dash or dot style of the grid lines. For possible values, see
  15019. * [this demonstration](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/series-dashstyle-all/).
  15020. *
  15021. * @sample {highcharts} highcharts/yaxis/gridlinedashstyle/
  15022. * Long dashes
  15023. * @sample {highstock} stock/xaxis/gridlinedashstyle/
  15024. * Long dashes
  15025. *
  15026. * @type {Highcharts.DashStyleValue}
  15027. * @since 1.2
  15028. */
  15029. gridLineDashStyle: 'Solid',
  15030. /**
  15031. * The Z index of the grid lines.
  15032. *
  15033. * @sample {highcharts|highstock} highcharts/xaxis/gridzindex/
  15034. * A Z index of 4 renders the grid above the graph
  15035. *
  15036. * @product highcharts highstock gantt
  15037. */
  15038. gridZIndex: 1,
  15039. /**
  15040. * An id for the axis. This can be used after render time to get
  15041. * a pointer to the axis object through `chart.get()`.
  15042. *
  15043. * @sample {highcharts} highcharts/xaxis/id/
  15044. * Get the object
  15045. * @sample {highstock} stock/xaxis/id/
  15046. * Get the object
  15047. *
  15048. * @type {string}
  15049. * @since 1.2.0
  15050. * @apioption xAxis.id
  15051. */
  15052. /**
  15053. * The axis labels show the number or category for each tick.
  15054. *
  15055. * Since v8.0.0: Labels are animated in categorized x-axis with
  15056. * updating data if `tickInterval` and `step` is set to 1.
  15057. *
  15058. * @productdesc {highmaps}
  15059. * X and Y axis labels are by default disabled in Highmaps, but the
  15060. * functionality is inherited from Highcharts and used on `colorAxis`,
  15061. * and can be enabled on X and Y axes too.
  15062. */
  15063. labels: {
  15064. /**
  15065. * What part of the string the given position is anchored to.
  15066. * If `left`, the left side of the string is at the axis position.
  15067. * Can be one of `"left"`, `"center"` or `"right"`. Defaults to
  15068. * an intelligent guess based on which side of the chart the axis
  15069. * is on and the rotation of the label.
  15070. *
  15071. * @see [reserveSpace](#xAxis.labels.reserveSpace)
  15072. *
  15073. * @sample {highcharts} highcharts/xaxis/labels-align-left/
  15074. * Left
  15075. * @sample {highcharts} highcharts/xaxis/labels-align-right/
  15076. * Right
  15077. * @sample {highcharts} highcharts/xaxis/labels-reservespace-true/
  15078. * Left-aligned labels on a vertical category axis
  15079. *
  15080. * @type {Highcharts.AlignValue}
  15081. * @apioption xAxis.labels.align
  15082. */
  15083. /**
  15084. * Whether to allow the axis labels to overlap.
  15085. * When false, overlapping labels are hidden.
  15086. *
  15087. * @sample {highcharts} highcharts/xaxis/labels-allowoverlap-true/
  15088. * X axis labels overlap enabled
  15089. *
  15090. * @type {boolean}
  15091. * @default false
  15092. * @apioption xAxis.labels.allowOverlap
  15093. *
  15094. */
  15095. /**
  15096. * For horizontal axes, the allowed degrees of label rotation
  15097. * to prevent overlapping labels. If there is enough space,
  15098. * labels are not rotated. As the chart gets narrower, it
  15099. * will start rotating the labels -45 degrees, then remove
  15100. * every second label and try again with rotations 0 and -45 etc.
  15101. * Set it to `undefined` to disable rotation, which will
  15102. * cause the labels to word-wrap if possible. Defaults to `[-45]``
  15103. * on bottom and top axes, `undefined` on left and right axes.
  15104. *
  15105. * @sample {highcharts|highstock} highcharts/xaxis/labels-autorotation-default/
  15106. * Default auto rotation of 0 or -45
  15107. * @sample {highcharts|highstock} highcharts/xaxis/labels-autorotation-0-90/
  15108. * Custom graded auto rotation
  15109. *
  15110. * @type {Array<number>}
  15111. * @default undefined
  15112. * @since 4.1.0
  15113. * @product highcharts highstock gantt
  15114. * @apioption xAxis.labels.autoRotation
  15115. */
  15116. autoRotation: void 0,
  15117. /**
  15118. * When each category width is more than this many pixels, we don't
  15119. * apply auto rotation. Instead, we lay out the axis label with word
  15120. * wrap. A lower limit makes sense when the label contains multiple
  15121. * short words that don't extend the available horizontal space for
  15122. * each label.
  15123. *
  15124. * @sample {highcharts} highcharts/xaxis/labels-autorotationlimit/
  15125. * Lower limit
  15126. *
  15127. * @since 4.1.5
  15128. * @product highcharts gantt
  15129. */
  15130. autoRotationLimit: 80,
  15131. /**
  15132. * Polar charts only. The label's pixel distance from the perimeter
  15133. * of the plot area.
  15134. *
  15135. * @type {number}
  15136. * @default undefined
  15137. * @product highcharts gantt
  15138. */
  15139. distance: void 0,
  15140. /**
  15141. * Enable or disable the axis labels.
  15142. *
  15143. * @sample {highcharts} highcharts/xaxis/labels-enabled/
  15144. * X axis labels disabled
  15145. * @sample {highstock} stock/xaxis/labels-enabled/
  15146. * X axis labels disabled
  15147. *
  15148. * @default {highcharts|highstock|gantt} true
  15149. * @default {highmaps} false
  15150. */
  15151. enabled: true,
  15152. /**
  15153. * A format string for the axis label. The context is available as
  15154. * format string variables. For example, you can use `{text}` to
  15155. * insert the default formatted text. The recommended way of adding
  15156. * units for the label is using `text`, for example `{text} km`.
  15157. *
  15158. * To add custom numeric or datetime formatting, use `{value}` with
  15159. * formatting, for example `{value:.1f}` or `{value:%Y-%m-%d}`.
  15160. *
  15161. * See
  15162. * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
  15163. * for more examples of formatting.
  15164. *
  15165. * The default value is not specified due to the dynamic
  15166. * nature of the default implementation.
  15167. *
  15168. * @sample {highcharts|highstock} highcharts/yaxis/labels-format/
  15169. * Add units to Y axis label
  15170. * @sample {highcharts} highcharts/xaxis/labels-format-linked/
  15171. * Linked category names
  15172. * @sample {highcharts} highcharts/xaxis/labels-format-custom/
  15173. * Custom number format
  15174. *
  15175. * @type {string}
  15176. * @since 3.0
  15177. * @apioption xAxis.labels.format
  15178. */
  15179. /**
  15180. * Callback JavaScript function to format the label. The value
  15181. * is given by `this.value`. Additional properties for `this` are
  15182. * `axis`, `chart`, `isFirst`, `isLast` and `text` which holds the
  15183. * value of the default formatter.
  15184. *
  15185. * Defaults to a built in function returning a formatted string
  15186. * depending on whether the axis is `category`, `datetime`,
  15187. * `numeric` or other.
  15188. *
  15189. * @sample {highcharts} highcharts/xaxis/labels-formatter-linked/
  15190. * Linked category names
  15191. * @sample {highcharts} highcharts/xaxis/labels-formatter-extended/
  15192. * Modified numeric labels
  15193. * @sample {highstock} stock/xaxis/labels-formatter/
  15194. * Added units on Y axis
  15195. *
  15196. * @type {Highcharts.AxisLabelsFormatterCallbackFunction}
  15197. * @apioption xAxis.labels.formatter
  15198. */
  15199. /**
  15200. * The number of pixels to indent the labels per level in a treegrid
  15201. * axis.
  15202. *
  15203. * @sample gantt/treegrid-axis/demo
  15204. * Indentation 10px by default.
  15205. * @sample gantt/treegrid-axis/indentation-0px
  15206. * Indentation set to 0px.
  15207. *
  15208. * @product gantt
  15209. */
  15210. indentation: 10,
  15211. /**
  15212. * Horizontal axis only. When `staggerLines` is not set,
  15213. * `maxStaggerLines` defines how many lines the axis is allowed to
  15214. * add to automatically avoid overlapping X labels. Set to `1` to
  15215. * disable overlap detection.
  15216. *
  15217. * @deprecated
  15218. * @type {number}
  15219. * @default 5
  15220. * @since 1.3.3
  15221. * @apioption xAxis.labels.maxStaggerLines
  15222. */
  15223. /**
  15224. * How to handle overflowing labels on horizontal axis. If set to
  15225. * `"allow"`, it will not be aligned at all. By default it
  15226. * `"justify"` labels inside the chart area. If there is room to
  15227. * move it, it will be aligned to the edge, else it will be removed.
  15228. *
  15229. * @since 2.2.5
  15230. * @validvalue ["allow", "justify"]
  15231. */
  15232. overflow: 'justify',
  15233. /**
  15234. * The pixel padding for axis labels, to ensure white space between
  15235. * them.
  15236. *
  15237. * @product highcharts gantt
  15238. */
  15239. padding: 5,
  15240. /**
  15241. * Whether to reserve space for the labels. By default, space is
  15242. * reserved for the labels in these cases:
  15243. *
  15244. * * On all horizontal axes.
  15245. * * On vertical axes if `label.align` is `right` on a left-side
  15246. * axis or `left` on a right-side axis.
  15247. * * On vertical axes if `label.align` is `center`.
  15248. *
  15249. * This can be turned off when for example the labels are rendered
  15250. * inside the plot area instead of outside.
  15251. *
  15252. * @see [labels.align](#xAxis.labels.align)
  15253. *
  15254. * @sample {highcharts} highcharts/xaxis/labels-reservespace/
  15255. * No reserved space, labels inside plot
  15256. * @sample {highcharts} highcharts/xaxis/labels-reservespace-true/
  15257. * Left-aligned labels on a vertical category axis
  15258. *
  15259. * @type {boolean}
  15260. * @since 4.1.10
  15261. * @product highcharts gantt
  15262. * @apioption xAxis.labels.reserveSpace
  15263. */
  15264. reserveSpace: void 0,
  15265. /**
  15266. * Rotation of the labels in degrees. When `undefined`, the
  15267. * `autoRotation` option takes precedence.
  15268. *
  15269. * @sample {highcharts} highcharts/xaxis/labels-rotation/
  15270. * X axis labels rotated 90°
  15271. *
  15272. * @type {number}
  15273. * @default 0
  15274. * @apioption xAxis.labels.rotation
  15275. */
  15276. rotation: void 0,
  15277. /**
  15278. * Horizontal axes only. The number of lines to spread the labels
  15279. * over to make room or tighter labels. 0 disables staggering.
  15280. *
  15281. * @sample {highcharts} highcharts/xaxis/labels-staggerlines/
  15282. * Show labels over two lines
  15283. * @sample {highstock} stock/xaxis/labels-staggerlines/
  15284. * Show labels over two lines
  15285. *
  15286. * @since 2.1
  15287. * @apioption xAxis.labels.staggerLines
  15288. */
  15289. staggerLines: 0,
  15290. /**
  15291. * To show only every _n_'th label on the axis, set the step to _n_.
  15292. * Setting the step to 2 shows every other label.
  15293. *
  15294. * By default, when 0, the step is calculated automatically to avoid
  15295. * overlap. To prevent this, set it to 1\. This usually only
  15296. * happens on a category axis, and is often a sign that you have
  15297. * chosen the wrong axis type.
  15298. *
  15299. * Read more at
  15300. * [Axis docs](https://www.highcharts.com/docs/chart-concepts/axes)
  15301. * => What axis should I use?
  15302. *
  15303. * @sample {highcharts} highcharts/xaxis/labels-step/
  15304. * Showing only every other axis label on a categorized
  15305. * x-axis
  15306. * @sample {highcharts} highcharts/xaxis/labels-step-auto/
  15307. * Auto steps on a category axis
  15308. *
  15309. * @since 2.1
  15310. */
  15311. step: 0,
  15312. /**
  15313. * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  15314. * to render the labels.
  15315. */
  15316. useHTML: false,
  15317. /**
  15318. * The x position offset of all labels relative to the tick
  15319. * positions on the axis.
  15320. *
  15321. * @sample {highcharts} highcharts/xaxis/labels-x/
  15322. * Y axis labels placed on grid lines
  15323. */
  15324. x: 0,
  15325. /**
  15326. * The y position offset of all labels relative to the tick
  15327. * positions on the axis. The default makes it adapt to the font
  15328. * size of the bottom axis.
  15329. *
  15330. * @sample {highcharts} highcharts/xaxis/labels-x/
  15331. * Y axis labels placed on grid lines
  15332. *
  15333. * @type {number}
  15334. * @apioption xAxis.labels.y
  15335. */
  15336. /**
  15337. * The Z index for the axis labels.
  15338. */
  15339. zIndex: 7,
  15340. /**
  15341. * CSS styles for the label. Use `whiteSpace: 'nowrap'` to prevent
  15342. * wrapping of category labels. Use `textOverflow: 'none'` to
  15343. * prevent ellipsis (dots).
  15344. *
  15345. * In styled mode, the labels are styled with the
  15346. * `.highcharts-axis-labels` class.
  15347. *
  15348. * @sample {highcharts} highcharts/xaxis/labels-style/
  15349. * Red X axis labels
  15350. *
  15351. * @type {Highcharts.CSSObject}
  15352. */
  15353. style: {
  15354. /** @internal */
  15355. color: Palette.neutralColor60,
  15356. /** @internal */
  15357. cursor: 'default',
  15358. /** @internal */
  15359. fontSize: '11px'
  15360. }
  15361. },
  15362. /**
  15363. * The left position as the horizontal axis. If it's a number, it is
  15364. * interpreted as pixel position relative to the chart.
  15365. *
  15366. * Since Highcharts v5.0.13: If it's a percentage string, it is
  15367. * interpreted as percentages of the plot width, offset from plot area
  15368. * left.
  15369. *
  15370. * @type {number|string}
  15371. * @product highcharts highstock
  15372. * @apioption xAxis.left
  15373. */
  15374. /**
  15375. * The top position as the vertical axis. If it's a number, it is
  15376. * interpreted as pixel position relative to the chart.
  15377. *
  15378. * Since Highcharts 2: If it's a percentage string, it is interpreted
  15379. * as percentages of the plot height, offset from plot area top.
  15380. *
  15381. * @type {number|string}
  15382. * @product highcharts highstock
  15383. * @apioption xAxis.top
  15384. */
  15385. /**
  15386. * Index of another axis that this axis is linked to. When an axis is
  15387. * linked to a master axis, it will take the same extremes as
  15388. * the master, but as assigned by min or max or by setExtremes.
  15389. * It can be used to show additional info, or to ease reading the
  15390. * chart by duplicating the scales.
  15391. *
  15392. * @sample {highcharts} highcharts/xaxis/linkedto/
  15393. * Different string formats of the same date
  15394. * @sample {highcharts} highcharts/yaxis/linkedto/
  15395. * Y values on both sides
  15396. *
  15397. * @type {number}
  15398. * @since 2.0.2
  15399. * @product highcharts highstock gantt
  15400. * @apioption xAxis.linkedTo
  15401. */
  15402. /**
  15403. * The maximum value of the axis. If `null`, the max value is
  15404. * automatically calculated.
  15405. *
  15406. * If the [endOnTick](#yAxis.endOnTick) option is true, the `max` value
  15407. * might be rounded up.
  15408. *
  15409. * If a [tickAmount](#yAxis.tickAmount) is set, the axis may be extended
  15410. * beyond the set max in order to reach the given number of ticks. The
  15411. * same may happen in a chart with multiple axes, determined by [chart.
  15412. * alignTicks](#chart), where a `tickAmount` is applied internally.
  15413. *
  15414. * @sample {highcharts} highcharts/yaxis/max-200/
  15415. * Y axis max of 200
  15416. * @sample {highcharts} highcharts/yaxis/max-logarithmic/
  15417. * Y axis max on logarithmic axis
  15418. * @sample {highstock} stock/xaxis/min-max/
  15419. * Fixed min and max on X axis
  15420. * @sample {highmaps} maps/axis/min-max/
  15421. * Pre-zoomed to a specific area
  15422. *
  15423. * @type {number|null}
  15424. * @apioption xAxis.max
  15425. */
  15426. /**
  15427. * Padding of the max value relative to the length of the axis. A
  15428. * padding of 0.05 will make a 100px axis 5px longer. This is useful
  15429. * when you don't want the highest data value to appear on the edge
  15430. * of the plot area. When the axis' `max` option is set or a max extreme
  15431. * is set using `axis.setExtremes()`, the maxPadding will be ignored.
  15432. *
  15433. * @productdesc {highstock}
  15434. * For an [ordinal](#xAxis.ordinal) axis, `minPadding` and `maxPadding`
  15435. * are ignored. Use [overscroll](#xAxis.overscroll) instead.
  15436. *
  15437. * @sample {highcharts} highcharts/yaxis/maxpadding/
  15438. * Max padding of 0.25 on y axis
  15439. * @sample {highstock} stock/xaxis/minpadding-maxpadding/
  15440. * Greater min- and maxPadding
  15441. * @sample {highmaps} maps/chart/plotbackgroundcolor-gradient/
  15442. * Add some padding
  15443. *
  15444. * @default {highcharts} 0.01
  15445. * @default {highstock|highmaps} 0
  15446. * @since 1.2.0
  15447. */
  15448. maxPadding: 0.01,
  15449. /**
  15450. * Deprecated. Use `minRange` instead.
  15451. *
  15452. * @deprecated
  15453. * @type {number}
  15454. * @product highcharts highstock
  15455. * @apioption xAxis.maxZoom
  15456. */
  15457. /**
  15458. * The minimum value of the axis. If `null` the min value is
  15459. * automatically calculated.
  15460. *
  15461. * If the [startOnTick](#yAxis.startOnTick) option is true (default),
  15462. * the `min` value might be rounded down.
  15463. *
  15464. * The automatically calculated minimum value is also affected by
  15465. * [floor](#yAxis.floor), [softMin](#yAxis.softMin),
  15466. * [minPadding](#yAxis.minPadding), [minRange](#yAxis.minRange)
  15467. * as well as [series.threshold](#plotOptions.series.threshold)
  15468. * and [series.softThreshold](#plotOptions.series.softThreshold).
  15469. *
  15470. * @sample {highcharts} highcharts/yaxis/min-startontick-false/
  15471. * -50 with startOnTick to false
  15472. * @sample {highcharts} highcharts/yaxis/min-startontick-true/
  15473. * -50 with startOnTick true by default
  15474. * @sample {highstock} stock/xaxis/min-max/
  15475. * Set min and max on X axis
  15476. * @sample {highmaps} maps/axis/min-max/
  15477. * Pre-zoomed to a specific area
  15478. *
  15479. * @type {number|null}
  15480. * @apioption xAxis.min
  15481. */
  15482. /**
  15483. * The dash or dot style of the minor grid lines. For possible values,
  15484. * see [this demonstration](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/series-dashstyle-all/).
  15485. *
  15486. * @sample {highcharts} highcharts/yaxis/minorgridlinedashstyle/
  15487. * Long dashes on minor grid lines
  15488. * @sample {highstock} stock/xaxis/minorgridlinedashstyle/
  15489. * Long dashes on minor grid lines
  15490. *
  15491. * @type {Highcharts.DashStyleValue}
  15492. * @since 1.2
  15493. */
  15494. minorGridLineDashStyle: 'Solid',
  15495. /**
  15496. * Specific tick interval in axis units for the minor ticks. On a linear
  15497. * axis, if `"auto"`, the minor tick interval is calculated as a fifth
  15498. * of the tickInterval. If `null` or `undefined`, minor ticks are not
  15499. * shown.
  15500. *
  15501. * On logarithmic axes, the unit is the power of the value. For example,
  15502. * setting the minorTickInterval to 1 puts one tick on each of 0.1, 1,
  15503. * 10, 100 etc. Setting the minorTickInterval to 0.1 produces 9 ticks
  15504. * between 1 and 10, 10 and 100 etc.
  15505. *
  15506. * If user settings dictate minor ticks to become too dense, they don't
  15507. * make sense, and will be ignored to prevent performance problems.
  15508. *
  15509. * @sample {highcharts} highcharts/yaxis/minortickinterval-null/
  15510. * Null by default
  15511. * @sample {highcharts} highcharts/yaxis/minortickinterval-5/
  15512. * 5 units
  15513. * @sample {highcharts} highcharts/yaxis/minortickinterval-log-auto/
  15514. * "auto"
  15515. * @sample {highcharts} highcharts/yaxis/minortickinterval-log/
  15516. * 0.1
  15517. * @sample {highstock} stock/demo/basic-line/
  15518. * Null by default
  15519. * @sample {highstock} stock/xaxis/minortickinterval-auto/
  15520. * "auto"
  15521. *
  15522. * @type {number|string|null}
  15523. * @apioption xAxis.minorTickInterval
  15524. */
  15525. /**
  15526. * The pixel length of the minor tick marks.
  15527. *
  15528. * @sample {highcharts} highcharts/yaxis/minorticklength/
  15529. * 10px on Y axis
  15530. * @sample {highstock} stock/xaxis/minorticks/
  15531. * 10px on Y axis
  15532. */
  15533. minorTickLength: 2,
  15534. /**
  15535. * The position of the minor tick marks relative to the axis line.
  15536. * Can be one of `inside` and `outside`.
  15537. *
  15538. * @sample {highcharts} highcharts/yaxis/minortickposition-outside/
  15539. * Outside by default
  15540. * @sample {highcharts} highcharts/yaxis/minortickposition-inside/
  15541. * Inside
  15542. * @sample {highstock} stock/xaxis/minorticks/
  15543. * Inside
  15544. *
  15545. * @validvalue ["inside", "outside"]
  15546. */
  15547. minorTickPosition: 'outside',
  15548. /**
  15549. * Enable or disable minor ticks. Unless
  15550. * [minorTickInterval](#xAxis.minorTickInterval) is set, the tick
  15551. * interval is calculated as a fifth of the `tickInterval`.
  15552. *
  15553. * On a logarithmic axis, minor ticks are laid out based on a best
  15554. * guess, attempting to enter approximately 5 minor ticks between
  15555. * each major tick.
  15556. *
  15557. * Prior to v6.0.0, ticks were unabled in auto layout by setting
  15558. * `minorTickInterval` to `"auto"`.
  15559. *
  15560. * @productdesc {highcharts}
  15561. * On axes using [categories](#xAxis.categories), minor ticks are not
  15562. * supported.
  15563. *
  15564. * @sample {highcharts} highcharts/yaxis/minorticks-true/
  15565. * Enabled on linear Y axis
  15566. *
  15567. * @type {boolean}
  15568. * @default false
  15569. * @since 6.0.0
  15570. * @apioption xAxis.minorTicks
  15571. */
  15572. /**
  15573. * The pixel width of the minor tick mark.
  15574. *
  15575. * @sample {highcharts} highcharts/yaxis/minortickwidth/
  15576. * 3px width
  15577. * @sample {highstock} stock/xaxis/minorticks/
  15578. * 1px width
  15579. *
  15580. * @type {number}
  15581. * @default 0
  15582. * @apioption xAxis.minorTickWidth
  15583. */
  15584. /**
  15585. * Padding of the min value relative to the length of the axis. A
  15586. * padding of 0.05 will make a 100px axis 5px longer. This is useful
  15587. * when you don't want the lowest data value to appear on the edge
  15588. * of the plot area. When the axis' `min` option is set or a min extreme
  15589. * is set using `axis.setExtremes()`, the minPadding will be ignored.
  15590. *
  15591. * @productdesc {highstock}
  15592. * For an [ordinal](#xAxis.ordinal) axis, `minPadding` and `maxPadding`
  15593. * are ignored. Use [overscroll](#xAxis.overscroll) instead.
  15594. *
  15595. * @sample {highcharts} highcharts/yaxis/minpadding/
  15596. * Min padding of 0.2
  15597. * @sample {highstock} stock/xaxis/minpadding-maxpadding/
  15598. * Greater min- and maxPadding
  15599. * @sample {highmaps} maps/chart/plotbackgroundcolor-gradient/
  15600. * Add some padding
  15601. *
  15602. * @default {highcharts} 0.01
  15603. * @default {highstock|highmaps} 0
  15604. * @since 1.2.0
  15605. * @product highcharts highstock gantt
  15606. */
  15607. minPadding: 0.01,
  15608. /**
  15609. * The minimum range to display on this axis. The entire axis will not
  15610. * be allowed to span over a smaller interval than this. For example,
  15611. * for a datetime axis the main unit is milliseconds. If minRange is
  15612. * set to 3600000, you can't zoom in more than to one hour.
  15613. *
  15614. * The default minRange for the x axis is five times the smallest
  15615. * interval between any of the data points.
  15616. *
  15617. * On a logarithmic axis, the unit for the minimum range is the power.
  15618. * So a minRange of 1 means that the axis can be zoomed to 10-100,
  15619. * 100-1000, 1000-10000 etc.
  15620. *
  15621. * **Note**: The `minPadding`, `maxPadding`, `startOnTick` and
  15622. * `endOnTick` settings also affect how the extremes of the axis
  15623. * are computed.
  15624. *
  15625. * @sample {highcharts} highcharts/xaxis/minrange/
  15626. * Minimum range of 5
  15627. * @sample {highstock} stock/xaxis/minrange/
  15628. * Max zoom of 6 months overrides user selections
  15629. * @sample {highmaps} maps/axis/minrange/
  15630. * Minimum range of 1000
  15631. *
  15632. * @type {number}
  15633. * @apioption xAxis.minRange
  15634. */
  15635. /**
  15636. * The minimum tick interval allowed in axis values. For example on
  15637. * zooming in on an axis with daily data, this can be used to prevent
  15638. * the axis from showing hours. Defaults to the closest distance between
  15639. * two points on the axis.
  15640. *
  15641. * @type {number}
  15642. * @since 2.3.0
  15643. * @apioption xAxis.minTickInterval
  15644. */
  15645. /**
  15646. * The distance in pixels from the plot area to the axis line.
  15647. * A positive offset moves the axis with it's line, labels and ticks
  15648. * away from the plot area. This is typically used when two or more
  15649. * axes are displayed on the same side of the plot. With multiple
  15650. * axes the offset is dynamically adjusted to avoid collision, this
  15651. * can be overridden by setting offset explicitly.
  15652. *
  15653. * @sample {highcharts} highcharts/yaxis/offset/
  15654. * Y axis offset of 70
  15655. * @sample {highcharts} highcharts/yaxis/offset-centered/
  15656. * Axes positioned in the center of the plot
  15657. * @sample {highstock} stock/xaxis/offset/
  15658. * Y axis offset by 70 px
  15659. *
  15660. * @type {number}
  15661. */
  15662. offset: void 0,
  15663. /**
  15664. * Whether to display the axis on the opposite side of the normal. The
  15665. * normal is on the left side for vertical axes and bottom for
  15666. * horizontal, so the opposite sides will be right and top respectively.
  15667. * This is typically used with dual or multiple axes.
  15668. *
  15669. * @sample {highcharts} highcharts/yaxis/opposite/
  15670. * Secondary Y axis opposite
  15671. * @sample {highstock} stock/xaxis/opposite/
  15672. * Y axis on left side
  15673. *
  15674. * @default {highcharts|highstock|highmaps} false
  15675. * @default {gantt} true
  15676. */
  15677. opposite: false,
  15678. /**
  15679. * In an ordinal axis, the points are equally spaced in the chart
  15680. * regardless of the actual time or x distance between them. This means
  15681. * that missing data periods (e.g. nights or weekends for a stock chart)
  15682. * will not take up space in the chart.
  15683. * Having `ordinal: false` will show any gaps created by the `gapSize`
  15684. * setting proportionate to their duration.
  15685. *
  15686. * In stock charts the X axis is ordinal by default, unless
  15687. * the boost module is used and at least one of the series' data length
  15688. * exceeds the [boostThreshold](#series.line.boostThreshold).
  15689. *
  15690. * For an ordinal axis, `minPadding` and `maxPadding` are ignored. Use
  15691. * [overscroll](#xAxis.overscroll) instead.
  15692. *
  15693. * @sample {highstock} stock/xaxis/ordinal-true/
  15694. * True by default
  15695. * @sample {highstock} stock/xaxis/ordinal-false/
  15696. * False
  15697. *
  15698. * @see [overscroll](#xAxis.overscroll)
  15699. *
  15700. * @type {boolean}
  15701. * @default true
  15702. * @since 1.1
  15703. * @product highstock
  15704. * @apioption xAxis.ordinal
  15705. */
  15706. /**
  15707. * Additional range on the right side of the xAxis. Works similar to
  15708. * `xAxis.maxPadding`, but value is set in milliseconds. Can be set for
  15709. * both main `xAxis` and the navigator's `xAxis`.
  15710. *
  15711. * @sample {highstock} stock/xaxis/overscroll/
  15712. * One minute overscroll with live data
  15713. *
  15714. * @type {number}
  15715. * @default 0
  15716. * @since 6.0.0
  15717. * @product highstock
  15718. * @apioption xAxis.overscroll
  15719. */
  15720. /**
  15721. * Refers to the index in the [panes](#panes) array. Used for circular
  15722. * gauges and polar charts. When the option is not set then first pane
  15723. * will be used.
  15724. *
  15725. * @sample highcharts/demo/gauge-vu-meter
  15726. * Two gauges with different center
  15727. *
  15728. * @type {number}
  15729. * @product highcharts
  15730. * @apioption xAxis.pane
  15731. */
  15732. /**
  15733. * The zoomed range to display when only defining one or none of `min`
  15734. * or `max`. For example, to show the latest month, a range of one month
  15735. * can be set.
  15736. *
  15737. * @sample {highstock} stock/xaxis/range/
  15738. * Setting a zoomed range when the rangeSelector is disabled
  15739. *
  15740. * @type {number}
  15741. * @product highstock
  15742. * @apioption xAxis.range
  15743. */
  15744. /**
  15745. * Whether to reverse the axis so that the highest number is closest
  15746. * to the origin. If the chart is inverted, the x axis is reversed by
  15747. * default.
  15748. *
  15749. * @sample {highcharts} highcharts/yaxis/reversed/
  15750. * Reversed Y axis
  15751. * @sample {highstock} stock/xaxis/reversed/
  15752. * Reversed Y axis
  15753. *
  15754. * @type {boolean}
  15755. * @default undefined
  15756. * @apioption xAxis.reversed
  15757. */
  15758. reversed: void 0,
  15759. /**
  15760. * This option determines how stacks should be ordered within a group.
  15761. * For example reversed xAxis also reverses stacks, so first series
  15762. * comes last in a group. To keep order like for non-reversed xAxis
  15763. * enable this option.
  15764. *
  15765. * @sample {highcharts} highcharts/xaxis/reversedstacks/
  15766. * Reversed stacks comparison
  15767. * @sample {highstock} highcharts/xaxis/reversedstacks/
  15768. * Reversed stacks comparison
  15769. *
  15770. * @since 6.1.1
  15771. * @product highcharts highstock
  15772. */
  15773. reversedStacks: false,
  15774. /**
  15775. * An optional scrollbar to display on the X axis in response to
  15776. * limiting the minimum and maximum of the axis values.
  15777. *
  15778. * In styled mode, all the presentational options for the scrollbar are
  15779. * replaced by the classes `.highcharts-scrollbar-thumb`,
  15780. * `.highcharts-scrollbar-arrow`, `.highcharts-scrollbar-button`,
  15781. * `.highcharts-scrollbar-rifles` and `.highcharts-scrollbar-track`.
  15782. *
  15783. * @sample {highstock} stock/yaxis/heatmap-scrollbars/
  15784. * Heatmap with both scrollbars
  15785. *
  15786. * @extends scrollbar
  15787. * @since 4.2.6
  15788. * @product highstock
  15789. * @apioption xAxis.scrollbar
  15790. */
  15791. /**
  15792. * Whether to show the axis line and title when the axis has no data.
  15793. *
  15794. * @sample {highcharts} highcharts/yaxis/showempty/
  15795. * When clicking the legend to hide series, one axis preserves
  15796. * line and title, the other doesn't
  15797. * @sample {highstock} highcharts/yaxis/showempty/
  15798. * When clicking the legend to hide series, one axis preserves
  15799. * line and title, the other doesn't
  15800. *
  15801. * @since 1.1
  15802. */
  15803. showEmpty: true,
  15804. /**
  15805. * Whether to show the first tick label.
  15806. *
  15807. * @sample {highcharts} highcharts/xaxis/showfirstlabel-false/
  15808. * Set to false on X axis
  15809. * @sample {highstock} stock/xaxis/showfirstlabel/
  15810. * Labels below plot lines on Y axis
  15811. */
  15812. showFirstLabel: true,
  15813. /**
  15814. * Whether to show the last tick label. Defaults to `true` on cartesian
  15815. * charts, and `false` on polar charts.
  15816. *
  15817. * @sample {highcharts} highcharts/xaxis/showlastlabel-true/
  15818. * Set to true on X axis
  15819. * @sample {highstock} stock/xaxis/showfirstlabel/
  15820. * Labels below plot lines on Y axis
  15821. *
  15822. * @product highcharts highstock gantt
  15823. */
  15824. showLastLabel: true,
  15825. /**
  15826. * A soft maximum for the axis. If the series data maximum is less than
  15827. * this, the axis will stay at this maximum, but if the series data
  15828. * maximum is higher, the axis will flex to show all data.
  15829. *
  15830. * @sample highcharts/yaxis/softmin-softmax/
  15831. * Soft min and max
  15832. *
  15833. * @type {number}
  15834. * @since 5.0.1
  15835. * @product highcharts highstock gantt
  15836. * @apioption xAxis.softMax
  15837. */
  15838. /**
  15839. * A soft minimum for the axis. If the series data minimum is greater
  15840. * than this, the axis will stay at this minimum, but if the series
  15841. * data minimum is lower, the axis will flex to show all data.
  15842. *
  15843. * @sample highcharts/yaxis/softmin-softmax/
  15844. * Soft min and max
  15845. *
  15846. * @type {number}
  15847. * @since 5.0.1
  15848. * @product highcharts highstock gantt
  15849. * @apioption xAxis.softMin
  15850. */
  15851. /**
  15852. * For datetime axes, this decides where to put the tick between weeks.
  15853. * 0 = Sunday, 1 = Monday.
  15854. *
  15855. * @sample {highcharts} highcharts/xaxis/startofweek-monday/
  15856. * Monday by default
  15857. * @sample {highcharts} highcharts/xaxis/startofweek-sunday/
  15858. * Sunday
  15859. * @sample {highstock} stock/xaxis/startofweek-1
  15860. * Monday by default
  15861. * @sample {highstock} stock/xaxis/startofweek-0
  15862. * Sunday
  15863. *
  15864. * @product highcharts highstock gantt
  15865. */
  15866. startOfWeek: 1,
  15867. /**
  15868. * Whether to force the axis to start on a tick. Use this option with
  15869. * the `minPadding` option to control the axis start.
  15870. *
  15871. * @productdesc {highstock}
  15872. * In Highcharts Stock, `startOnTick` is always `false` when
  15873. * the navigator is enabled, to prevent jumpy scrolling.
  15874. *
  15875. * @sample {highcharts} highcharts/xaxis/startontick-false/
  15876. * False by default
  15877. * @sample {highcharts} highcharts/xaxis/startontick-true/
  15878. * True
  15879. *
  15880. * @since 1.2.0
  15881. */
  15882. startOnTick: false,
  15883. /**
  15884. * The amount of ticks to draw on the axis. This opens up for aligning
  15885. * the ticks of multiple charts or panes within a chart. This option
  15886. * overrides the `tickPixelInterval` option.
  15887. *
  15888. * This option only has an effect on linear axes. Datetime, logarithmic
  15889. * or category axes are not affected.
  15890. *
  15891. * @sample {highcharts} highcharts/yaxis/tickamount/
  15892. * 8 ticks on Y axis
  15893. * @sample {highstock} highcharts/yaxis/tickamount/
  15894. * 8 ticks on Y axis
  15895. *
  15896. * @type {number}
  15897. * @since 4.1.0
  15898. * @product highcharts highstock gantt
  15899. * @apioption xAxis.tickAmount
  15900. */
  15901. /**
  15902. * The interval of the tick marks in axis units. When `undefined`, the
  15903. * tick interval is computed to approximately follow the
  15904. * [tickPixelInterval](#xAxis.tickPixelInterval) on linear and datetime
  15905. * axes. On categorized axes, a `undefined` tickInterval will default to
  15906. * 1, one category. Note that datetime axes are based on milliseconds,
  15907. * so for example an interval of one day is expressed as
  15908. * `24 * 3600 * 1000`.
  15909. *
  15910. * On logarithmic axes, the tickInterval is based on powers, so a
  15911. * tickInterval of 1 means one tick on each of 0.1, 1, 10, 100 etc. A
  15912. * tickInterval of 2 means a tick of 0.1, 10, 1000 etc. A tickInterval
  15913. * of 0.2 puts a tick on 0.1, 0.2, 0.4, 0.6, 0.8, 1, 2, 4, 6, 8, 10, 20,
  15914. * 40 etc.
  15915. *
  15916. *
  15917. * If the tickInterval is too dense for labels to be drawn, Highcharts
  15918. * may remove ticks.
  15919. *
  15920. * If the chart has multiple axes, the [alignTicks](#chart.alignTicks)
  15921. * option may interfere with the `tickInterval` setting.
  15922. *
  15923. * @see [tickPixelInterval](#xAxis.tickPixelInterval)
  15924. * @see [tickPositions](#xAxis.tickPositions)
  15925. * @see [tickPositioner](#xAxis.tickPositioner)
  15926. *
  15927. * @sample {highcharts} highcharts/xaxis/tickinterval-5/
  15928. * Tick interval of 5 on a linear axis
  15929. * @sample {highstock} stock/xaxis/tickinterval/
  15930. * Tick interval of 0.01 on Y axis
  15931. *
  15932. * @type {number}
  15933. * @apioption xAxis.tickInterval
  15934. */
  15935. /**
  15936. * The pixel length of the main tick marks.
  15937. *
  15938. * @sample {highcharts} highcharts/xaxis/ticklength/
  15939. * 20 px tick length on the X axis
  15940. * @sample {highstock} stock/xaxis/ticks/
  15941. * Formatted ticks on X axis
  15942. */
  15943. tickLength: 10,
  15944. /**
  15945. * If tickInterval is `null` this option sets the approximate pixel
  15946. * interval of the tick marks. Not applicable to categorized axis.
  15947. *
  15948. * The tick interval is also influenced by the [minTickInterval](
  15949. * #xAxis.minTickInterval) option, that, by default prevents ticks from
  15950. * being denser than the data points.
  15951. *
  15952. * @see [tickInterval](#xAxis.tickInterval)
  15953. * @see [tickPositioner](#xAxis.tickPositioner)
  15954. * @see [tickPositions](#xAxis.tickPositions)
  15955. *
  15956. * @sample {highcharts} highcharts/xaxis/tickpixelinterval-50/
  15957. * 50 px on X axis
  15958. * @sample {highstock} stock/xaxis/tickpixelinterval/
  15959. * 200 px on X axis
  15960. */
  15961. tickPixelInterval: 100,
  15962. /**
  15963. * For categorized axes only. If `on` the tick mark is placed in the
  15964. * center of the category, if `between` the tick mark is placed between
  15965. * categories. The default is `between` if the `tickInterval` is 1, else
  15966. * `on`.
  15967. *
  15968. * @sample {highcharts} highcharts/xaxis/tickmarkplacement-between/
  15969. * "between" by default
  15970. * @sample {highcharts} highcharts/xaxis/tickmarkplacement-on/
  15971. * "on"
  15972. *
  15973. * @product highcharts gantt
  15974. * @validvalue ["on", "between"]
  15975. */
  15976. tickmarkPlacement: 'between',
  15977. /**
  15978. * The position of the major tick marks relative to the axis line.
  15979. * Can be one of `inside` and `outside`.
  15980. *
  15981. * @sample {highcharts} highcharts/xaxis/tickposition-outside/
  15982. * "outside" by default
  15983. * @sample {highcharts} highcharts/xaxis/tickposition-inside/
  15984. * "inside"
  15985. * @sample {highstock} stock/xaxis/ticks/
  15986. * Formatted ticks on X axis
  15987. *
  15988. * @validvalue ["inside", "outside"]
  15989. */
  15990. tickPosition: 'outside',
  15991. /**
  15992. * A callback function returning array defining where the ticks are
  15993. * laid out on the axis. This overrides the default behaviour of
  15994. * [tickPixelInterval](#xAxis.tickPixelInterval) and [tickInterval](
  15995. * #xAxis.tickInterval). The automatic tick positions are accessible
  15996. * through `this.tickPositions` and can be modified by the callback.
  15997. *
  15998. * @see [tickPositions](#xAxis.tickPositions)
  15999. *
  16000. * @sample {highcharts} highcharts/xaxis/tickpositions-tickpositioner/
  16001. * Demo of tickPositions and tickPositioner
  16002. * @sample {highstock} highcharts/xaxis/tickpositions-tickpositioner/
  16003. * Demo of tickPositions and tickPositioner
  16004. *
  16005. * @type {Highcharts.AxisTickPositionerCallbackFunction}
  16006. * @apioption xAxis.tickPositioner
  16007. */
  16008. /**
  16009. * An array defining where the ticks are laid out on the axis. This
  16010. * overrides the default behaviour of [tickPixelInterval](
  16011. * #xAxis.tickPixelInterval) and [tickInterval](#xAxis.tickInterval).
  16012. *
  16013. * @see [tickPositioner](#xAxis.tickPositioner)
  16014. *
  16015. * @sample {highcharts} highcharts/xaxis/tickpositions-tickpositioner/
  16016. * Demo of tickPositions and tickPositioner
  16017. * @sample {highstock} highcharts/xaxis/tickpositions-tickpositioner/
  16018. * Demo of tickPositions and tickPositioner
  16019. *
  16020. * @type {Array<number>}
  16021. * @apioption xAxis.tickPositions
  16022. */
  16023. /**
  16024. * The pixel width of the major tick marks. Defaults to 0 on category
  16025. * axes, otherwise 1.
  16026. *
  16027. * In styled mode, the stroke width is given in the `.highcharts-tick`
  16028. * class, but in order for the element to be generated on category axes,
  16029. * the option must be explicitly set to 1.
  16030. *
  16031. * @sample {highcharts} highcharts/xaxis/tickwidth/
  16032. * 10 px width
  16033. * @sample {highcharts} highcharts/css/axis-grid/
  16034. * Styled mode
  16035. * @sample {highstock} stock/xaxis/ticks/
  16036. * Formatted ticks on X axis
  16037. * @sample {highstock} highcharts/css/axis-grid/
  16038. * Styled mode
  16039. *
  16040. * @type {undefined|number}
  16041. * @default {highstock} 1
  16042. * @default {highmaps} 0
  16043. * @apioption xAxis.tickWidth
  16044. */
  16045. /**
  16046. * The axis title, showing next to the axis line.
  16047. *
  16048. * @productdesc {highmaps}
  16049. * In Highmaps, the axis is hidden by default, but adding an axis title
  16050. * is still possible. X axis and Y axis titles will appear at the bottom
  16051. * and left by default.
  16052. */
  16053. title: {
  16054. /**
  16055. * Alignment of the title relative to the axis values. Possible
  16056. * values are "low", "middle" or "high".
  16057. *
  16058. * @sample {highcharts} highcharts/xaxis/title-align-low/
  16059. * "low"
  16060. * @sample {highcharts} highcharts/xaxis/title-align-center/
  16061. * "middle" by default
  16062. * @sample {highcharts} highcharts/xaxis/title-align-high/
  16063. * "high"
  16064. * @sample {highcharts} highcharts/yaxis/title-offset/
  16065. * Place the Y axis title on top of the axis
  16066. * @sample {highstock} stock/xaxis/title-align/
  16067. * Aligned to "high" value
  16068. *
  16069. * @type {Highcharts.AxisTitleAlignValue}
  16070. */
  16071. align: 'middle',
  16072. /**
  16073. * Deprecated. Set the `text` to `undefined` to disable the title.
  16074. *
  16075. * @deprecated
  16076. * @type {boolean}
  16077. * @product highcharts
  16078. * @apioption xAxis.title.enabled
  16079. */
  16080. /**
  16081. * The pixel distance between the axis labels or line and the title.
  16082. * Defaults to 0 for horizontal axes, 10 for vertical
  16083. *
  16084. * @sample {highcharts} highcharts/xaxis/title-margin/
  16085. * Y axis title margin of 60
  16086. *
  16087. * @type {number}
  16088. * @apioption xAxis.title.margin
  16089. */
  16090. /**
  16091. * The distance of the axis title from the axis line. By default,
  16092. * this distance is computed from the offset width of the labels,
  16093. * the labels' distance from the axis and the title's margin.
  16094. * However when the offset option is set, it overrides all this.
  16095. *
  16096. * @sample {highcharts} highcharts/yaxis/title-offset/
  16097. * Place the axis title on top of the axis
  16098. * @sample {highstock} highcharts/yaxis/title-offset/
  16099. * Place the axis title on top of the Y axis
  16100. *
  16101. * @type {number}
  16102. * @since 2.2.0
  16103. * @apioption xAxis.title.offset
  16104. */
  16105. /**
  16106. * Whether to reserve space for the title when laying out the axis.
  16107. *
  16108. * @type {boolean}
  16109. * @default true
  16110. * @since 5.0.11
  16111. * @product highcharts highstock gantt
  16112. * @apioption xAxis.title.reserveSpace
  16113. */
  16114. /**
  16115. * The rotation of the text in degrees. 0 is horizontal, 270 is
  16116. * vertical reading from bottom to top.
  16117. *
  16118. * @sample {highcharts} highcharts/yaxis/title-offset/
  16119. * Horizontal
  16120. */
  16121. rotation: 0,
  16122. /**
  16123. * The actual text of the axis title. It can contain basic HTML tags
  16124. * like `b`, `i` and `span` with style.
  16125. *
  16126. * @sample {highcharts} highcharts/xaxis/title-text/
  16127. * Custom HTML
  16128. * @sample {highstock} stock/xaxis/title-text/
  16129. * Titles for both axes
  16130. *
  16131. * @type {string|null}
  16132. * @apioption xAxis.title.text
  16133. */
  16134. /**
  16135. * Alignment of the text, can be `"left"`, `"right"` or `"center"`.
  16136. * Default alignment depends on the
  16137. * [title.align](xAxis.title.align):
  16138. *
  16139. * Horizontal axes:
  16140. * - for `align` = `"low"`, `textAlign` is set to `left`
  16141. * - for `align` = `"middle"`, `textAlign` is set to `center`
  16142. * - for `align` = `"high"`, `textAlign` is set to `right`
  16143. *
  16144. * Vertical axes:
  16145. * - for `align` = `"low"` and `opposite` = `true`, `textAlign` is
  16146. * set to `right`
  16147. * - for `align` = `"low"` and `opposite` = `false`, `textAlign` is
  16148. * set to `left`
  16149. * - for `align` = `"middle"`, `textAlign` is set to `center`
  16150. * - for `align` = `"high"` and `opposite` = `true` `textAlign` is
  16151. * set to `left`
  16152. * - for `align` = `"high"` and `opposite` = `false` `textAlign` is
  16153. * set to `right`
  16154. *
  16155. * @type {Highcharts.AlignValue}
  16156. * @apioption xAxis.title.textAlign
  16157. */
  16158. /**
  16159. * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  16160. * to render the axis title.
  16161. *
  16162. * @product highcharts highstock gantt
  16163. */
  16164. useHTML: false,
  16165. /**
  16166. * Horizontal pixel offset of the title position.
  16167. *
  16168. * @since 4.1.6
  16169. * @product highcharts highstock gantt
  16170. */
  16171. x: 0,
  16172. /**
  16173. * Vertical pixel offset of the title position.
  16174. *
  16175. * @product highcharts highstock gantt
  16176. */
  16177. y: 0,
  16178. /**
  16179. * CSS styles for the title. If the title text is longer than the
  16180. * axis length, it will wrap to multiple lines by default. This can
  16181. * be customized by setting `textOverflow: 'ellipsis'`, by
  16182. * setting a specific `width` or by setting `whiteSpace: 'nowrap'`.
  16183. *
  16184. * In styled mode, the stroke width is given in the
  16185. * `.highcharts-axis-title` class.
  16186. *
  16187. * @sample {highcharts} highcharts/xaxis/title-style/
  16188. * Red
  16189. * @sample {highcharts} highcharts/css/axis/
  16190. * Styled mode
  16191. *
  16192. * @type {Highcharts.CSSObject}
  16193. */
  16194. style: {
  16195. /** @internal */
  16196. color: Palette.neutralColor60
  16197. }
  16198. },
  16199. /**
  16200. * The type of axis. Can be one of `linear`, `logarithmic`, `datetime`
  16201. * or `category`. In a datetime axis, the numbers are given in
  16202. * milliseconds, and tick marks are placed on appropriate values like
  16203. * full hours or days. In a category axis, the
  16204. * [point names](#series.line.data.name) of the chart's series are used
  16205. * for categories, if not a [categories](#xAxis.categories) array is
  16206. * defined.
  16207. *
  16208. * @sample {highcharts} highcharts/xaxis/type-linear/
  16209. * Linear
  16210. * @sample {highcharts} highcharts/yaxis/type-log/
  16211. * Logarithmic
  16212. * @sample {highcharts} highcharts/yaxis/type-log-minorgrid/
  16213. * Logarithmic with minor grid lines
  16214. * @sample {highcharts} highcharts/xaxis/type-log-both/
  16215. * Logarithmic on two axes
  16216. * @sample {highcharts} highcharts/yaxis/type-log-negative/
  16217. * Logarithmic with extension to emulate negative values
  16218. *
  16219. * @type {Highcharts.AxisTypeValue}
  16220. * @product highcharts gantt
  16221. */
  16222. type: 'linear',
  16223. /**
  16224. * If there are multiple axes on the same side of the chart, the pixel
  16225. * margin between the axes. Defaults to 0 on vertical axes, 15 on
  16226. * horizontal axes.
  16227. *
  16228. * @type {number}
  16229. * @since 7.0.3
  16230. * @apioption xAxis.margin
  16231. */
  16232. /**
  16233. * Applies only when the axis `type` is `category`. When `uniqueNames`
  16234. * is true, points are placed on the X axis according to their names.
  16235. * If the same point name is repeated in the same or another series,
  16236. * the point is placed on the same X position as other points of the
  16237. * same name. When `uniqueNames` is false, the points are laid out in
  16238. * increasing X positions regardless of their names, and the X axis
  16239. * category will take the name of the last point in each position.
  16240. *
  16241. * @sample {highcharts} highcharts/xaxis/uniquenames-true/
  16242. * True by default
  16243. * @sample {highcharts} highcharts/xaxis/uniquenames-false/
  16244. * False
  16245. *
  16246. * @since 4.2.7
  16247. * @product highcharts gantt
  16248. */
  16249. uniqueNames: true,
  16250. /**
  16251. * Datetime axis only. An array determining what time intervals the
  16252. * ticks are allowed to fall on. Each array item is an array where the
  16253. * first value is the time unit and the second value another array of
  16254. * allowed multiples.
  16255. *
  16256. * Defaults to:
  16257. * ```js
  16258. * units: [[
  16259. * 'millisecond', // unit name
  16260. * [1, 2, 5, 10, 20, 25, 50, 100, 200, 500] // allowed multiples
  16261. * ], [
  16262. * 'second',
  16263. * [1, 2, 5, 10, 15, 30]
  16264. * ], [
  16265. * 'minute',
  16266. * [1, 2, 5, 10, 15, 30]
  16267. * ], [
  16268. * 'hour',
  16269. * [1, 2, 3, 4, 6, 8, 12]
  16270. * ], [
  16271. * 'day',
  16272. * [1, 2]
  16273. * ], [
  16274. * 'week',
  16275. * [1, 2]
  16276. * ], [
  16277. * 'month',
  16278. * [1, 2, 3, 4, 6]
  16279. * ], [
  16280. * 'year',
  16281. * null
  16282. * ]]
  16283. * ```
  16284. *
  16285. * @type {Array<Array<string,(Array<number>|null)>>}
  16286. * @product highcharts highstock gantt
  16287. * @apioption xAxis.units
  16288. */
  16289. /**
  16290. * Whether axis, including axis title, line, ticks and labels, should
  16291. * be visible.
  16292. *
  16293. * @since 4.1.9
  16294. * @product highcharts highstock gantt
  16295. */
  16296. visible: true,
  16297. /**
  16298. * Color of the minor, secondary grid lines.
  16299. *
  16300. * In styled mode, the stroke width is given in the
  16301. * `.highcharts-minor-grid-line` class.
  16302. *
  16303. * @sample {highcharts} highcharts/yaxis/minorgridlinecolor/
  16304. * Bright grey lines from Y axis
  16305. * @sample {highcharts|highstock} highcharts/css/axis-grid/
  16306. * Styled mode
  16307. * @sample {highstock} stock/xaxis/minorgridlinecolor/
  16308. * Bright grey lines from Y axis
  16309. *
  16310. * @type {Highcharts.ColorType}
  16311. * @default #f2f2f2
  16312. */
  16313. minorGridLineColor: Palette.neutralColor5,
  16314. /**
  16315. * Width of the minor, secondary grid lines.
  16316. *
  16317. * In styled mode, the stroke width is given in the
  16318. * `.highcharts-grid-line` class.
  16319. *
  16320. * @sample {highcharts} highcharts/yaxis/minorgridlinewidth/
  16321. * 2px lines from Y axis
  16322. * @sample {highcharts|highstock} highcharts/css/axis-grid/
  16323. * Styled mode
  16324. * @sample {highstock} stock/xaxis/minorgridlinewidth/
  16325. * 2px lines from Y axis
  16326. */
  16327. minorGridLineWidth: 1,
  16328. /**
  16329. * Color for the minor tick marks.
  16330. *
  16331. * @sample {highcharts} highcharts/yaxis/minortickcolor/
  16332. * Black tick marks on Y axis
  16333. * @sample {highstock} stock/xaxis/minorticks/
  16334. * Black tick marks on Y axis
  16335. *
  16336. * @type {Highcharts.ColorType}
  16337. * @default #999999
  16338. */
  16339. minorTickColor: Palette.neutralColor40,
  16340. /**
  16341. * The color of the line marking the axis itself.
  16342. *
  16343. * In styled mode, the line stroke is given in the
  16344. * `.highcharts-axis-line` or `.highcharts-xaxis-line` class.
  16345. *
  16346. * @productdesc {highmaps}
  16347. * In Highmaps, the axis line is hidden by default, because the axis is
  16348. * not visible by default.
  16349. *
  16350. * @sample {highcharts} highcharts/yaxis/linecolor/
  16351. * A red line on Y axis
  16352. * @sample {highcharts|highstock} highcharts/css/axis/
  16353. * Axes in styled mode
  16354. * @sample {highstock} stock/xaxis/linecolor/
  16355. * A red line on X axis
  16356. *
  16357. * @type {Highcharts.ColorType}
  16358. * @default #ccd6eb
  16359. */
  16360. lineColor: Palette.highlightColor20,
  16361. /**
  16362. * The width of the line marking the axis itself.
  16363. *
  16364. * In styled mode, the stroke width is given in the
  16365. * `.highcharts-axis-line` or `.highcharts-xaxis-line` class.
  16366. *
  16367. * @sample {highcharts} highcharts/yaxis/linecolor/
  16368. * A 1px line on Y axis
  16369. * @sample {highcharts|highstock} highcharts/css/axis/
  16370. * Axes in styled mode
  16371. * @sample {highstock} stock/xaxis/linewidth/
  16372. * A 2px line on X axis
  16373. *
  16374. * @default {highcharts|highstock} 1
  16375. * @default {highmaps} 0
  16376. */
  16377. lineWidth: 1,
  16378. /**
  16379. * Color of the grid lines extending the ticks across the plot area.
  16380. *
  16381. * In styled mode, the stroke is given in the `.highcharts-grid-line`
  16382. * class.
  16383. *
  16384. * @productdesc {highmaps}
  16385. * In Highmaps, the grid lines are hidden by default.
  16386. *
  16387. * @sample {highcharts} highcharts/yaxis/gridlinecolor/
  16388. * Green lines
  16389. * @sample {highcharts|highstock} highcharts/css/axis-grid/
  16390. * Styled mode
  16391. * @sample {highstock} stock/xaxis/gridlinecolor/
  16392. * Green lines
  16393. *
  16394. * @type {Highcharts.ColorType}
  16395. * @default #e6e6e6
  16396. */
  16397. gridLineColor: Palette.neutralColor10,
  16398. /**
  16399. * The width of the grid lines extending the ticks across the plot area.
  16400. * Defaults to 1 on the Y axis and 0 on the X axis, except for 3d
  16401. * charts.
  16402. *
  16403. * In styled mode, the stroke width is given in the
  16404. * `.highcharts-grid-line` class.
  16405. *
  16406. * @sample {highcharts} highcharts/yaxis/gridlinewidth/
  16407. * 2px lines
  16408. * @sample {highcharts|highstock} highcharts/css/axis-grid/
  16409. * Styled mode
  16410. * @sample {highstock} stock/xaxis/gridlinewidth/
  16411. * 2px lines
  16412. *
  16413. * @type {number}
  16414. * @apioption xAxis.gridLineWidth
  16415. */
  16416. gridLineWidth: void 0,
  16417. /**
  16418. * The height as the vertical axis. If it's a number, it is
  16419. * interpreted as pixels.
  16420. *
  16421. * Since Highcharts 2: If it's a percentage string, it is interpreted
  16422. * as percentages of the total plot height.
  16423. *
  16424. * @type {number|string}
  16425. * @product highcharts highstock
  16426. * @apioption xAxis.height
  16427. */
  16428. /**
  16429. * The width as the horizontal axis. If it's a number, it is interpreted
  16430. * as pixels.
  16431. *
  16432. * Since Highcharts v5.0.13: If it's a percentage string, it is
  16433. * interpreted as percentages of the total plot width.
  16434. *
  16435. * @type {number|string}
  16436. * @product highcharts highstock
  16437. * @apioption xAxis.width
  16438. */
  16439. /**
  16440. * Color for the main tick marks.
  16441. *
  16442. * In styled mode, the stroke is given in the `.highcharts-tick`
  16443. * class.
  16444. *
  16445. * @sample {highcharts} highcharts/xaxis/tickcolor/
  16446. * Red ticks on X axis
  16447. * @sample {highcharts|highstock} highcharts/css/axis-grid/
  16448. * Styled mode
  16449. * @sample {highstock} stock/xaxis/ticks/
  16450. * Formatted ticks on X axis
  16451. *
  16452. * @type {Highcharts.ColorType}
  16453. * @default #ccd6eb
  16454. */
  16455. tickColor: Palette.highlightColor20
  16456. // tickWidth: 1
  16457. };
  16458. /**
  16459. * The Y axis or value axis. Normally this is the vertical axis,
  16460. * though if the chart is inverted this is the horizontal axis.
  16461. * In case of multiple axes, the yAxis node is an array of
  16462. * configuration objects.
  16463. *
  16464. * See [the Axis object](/class-reference/Highcharts.Axis) for programmatic
  16465. * access to the axis.
  16466. *
  16467. * @type {*|Array<*>}
  16468. * @extends xAxis
  16469. * @excluding currentDateIndicator,ordinal,overscroll
  16470. * @optionparent yAxis
  16471. */
  16472. AxisDefaults.defaultYAxisOptions = {
  16473. /**
  16474. * The type of axis. Can be one of `linear`, `logarithmic`, `datetime`,
  16475. * `category` or `treegrid`. Defaults to `treegrid` for Gantt charts,
  16476. * `linear` for other chart types.
  16477. *
  16478. * In a datetime axis, the numbers are given in milliseconds, and tick
  16479. * marks are placed on appropriate values, like full hours or days. In a
  16480. * category or treegrid axis, the [point names](#series.line.data.name)
  16481. * of the chart's series are used for categories, if a
  16482. * [categories](#xAxis.categories) array is not defined.
  16483. *
  16484. * @sample {highcharts} highcharts/yaxis/type-log-minorgrid/
  16485. * Logarithmic with minor grid lines
  16486. * @sample {highcharts} highcharts/yaxis/type-log-negative/
  16487. * Logarithmic with extension to emulate negative values
  16488. * @sample {gantt} gantt/treegrid-axis/demo
  16489. * Treegrid axis
  16490. *
  16491. * @type {Highcharts.AxisTypeValue}
  16492. * @default {highcharts} linear
  16493. * @default {gantt} treegrid
  16494. * @product highcharts gantt
  16495. * @apioption yAxis.type
  16496. */
  16497. /**
  16498. * The height of the Y axis. If it's a number, it is interpreted as
  16499. * pixels.
  16500. *
  16501. * Since Highcharts 2: If it's a percentage string, it is interpreted as
  16502. * percentages of the total plot height.
  16503. *
  16504. * @see [yAxis.top](#yAxis.top)
  16505. *
  16506. * @sample {highstock} stock/demo/candlestick-and-volume/
  16507. * Percentage height panes
  16508. *
  16509. * @type {number|string}
  16510. * @product highcharts highstock
  16511. * @apioption yAxis.height
  16512. */
  16513. /**
  16514. * Solid gauge only. Unless [stops](#yAxis.stops) are set, the color
  16515. * to represent the maximum value of the Y axis.
  16516. *
  16517. * @sample {highcharts} highcharts/yaxis/mincolor-maxcolor/
  16518. * Min and max colors
  16519. *
  16520. * @type {Highcharts.ColorType}
  16521. * @default #003399
  16522. * @since 4.0
  16523. * @product highcharts
  16524. * @apioption yAxis.maxColor
  16525. */
  16526. /**
  16527. * Solid gauge only. Unless [stops](#yAxis.stops) are set, the color
  16528. * to represent the minimum value of the Y axis.
  16529. *
  16530. * @sample {highcharts} highcharts/yaxis/mincolor-maxcolor/
  16531. * Min and max color
  16532. *
  16533. * @type {Highcharts.ColorType}
  16534. * @default #e6ebf5
  16535. * @since 4.0
  16536. * @product highcharts
  16537. * @apioption yAxis.minColor
  16538. */
  16539. /**
  16540. * Whether to reverse the axis so that the highest number is closest
  16541. * to the origin.
  16542. *
  16543. * @sample {highcharts} highcharts/yaxis/reversed/
  16544. * Reversed Y axis
  16545. * @sample {highstock} stock/xaxis/reversed/
  16546. * Reversed Y axis
  16547. *
  16548. * @type {boolean}
  16549. * @default {highcharts} false
  16550. * @default {highstock} false
  16551. * @default {highmaps} true
  16552. * @default {gantt} true
  16553. * @apioption yAxis.reversed
  16554. */
  16555. /**
  16556. * If `true`, the first series in a stack will be drawn on top in a
  16557. * positive, non-reversed Y axis. If `false`, the first series is in
  16558. * the base of the stack.
  16559. *
  16560. * @sample {highcharts} highcharts/yaxis/reversedstacks-false/
  16561. * Non-reversed stacks
  16562. * @sample {highstock} highcharts/yaxis/reversedstacks-false/
  16563. * Non-reversed stacks
  16564. *
  16565. * @type {boolean}
  16566. * @default true
  16567. * @since 3.0.10
  16568. * @product highcharts highstock
  16569. * @apioption yAxis.reversedStacks
  16570. */
  16571. reversedStacks: true,
  16572. /**
  16573. * Solid gauge series only. Color stops for the solid gauge. Use this
  16574. * in cases where a linear gradient between a `minColor` and `maxColor`
  16575. * is not sufficient. The stops is an array of tuples, where the first
  16576. * item is a float between 0 and 1 assigning the relative position in
  16577. * the gradient, and the second item is the color.
  16578. *
  16579. * For solid gauges, the Y axis also inherits the concept of
  16580. * [data classes](https://api.highcharts.com/highmaps#colorAxis.dataClasses)
  16581. * from the Highmaps color axis.
  16582. *
  16583. * @see [minColor](#yAxis.minColor)
  16584. * @see [maxColor](#yAxis.maxColor)
  16585. *
  16586. * @sample {highcharts} highcharts/demo/gauge-solid/
  16587. * True by default
  16588. *
  16589. * @type {Array<Array<number,Highcharts.ColorType>>}
  16590. * @since 4.0
  16591. * @product highcharts
  16592. * @apioption yAxis.stops
  16593. */
  16594. /**
  16595. * The pixel width of the major tick marks.
  16596. *
  16597. * @sample {highcharts} highcharts/xaxis/tickwidth/ 10 px width
  16598. * @sample {highstock} stock/xaxis/ticks/ Formatted ticks on X axis
  16599. *
  16600. * @type {number}
  16601. * @default 0
  16602. * @product highcharts highstock gantt
  16603. * @apioption yAxis.tickWidth
  16604. */
  16605. /**
  16606. * Whether to force the axis to end on a tick. Use this option with
  16607. * the `maxPadding` option to control the axis end.
  16608. *
  16609. * This option is always disabled, when panning type is
  16610. * either `y` or `xy`.
  16611. *
  16612. * @see [type](#chart.panning.type)
  16613. *
  16614. *
  16615. * @sample {highcharts} highcharts/chart/reflow-true/
  16616. * True by default
  16617. * @sample {highcharts} highcharts/yaxis/endontick/
  16618. * False
  16619. * @sample {highstock} stock/demo/basic-line/
  16620. * True by default
  16621. * @sample {highstock} stock/xaxis/endontick/
  16622. * False for Y axis
  16623. *
  16624. * @since 1.2.0
  16625. */
  16626. endOnTick: true,
  16627. /**
  16628. * Padding of the max value relative to the length of the axis. A
  16629. * padding of 0.05 will make a 100px axis 5px longer. This is useful
  16630. * when you don't want the highest data value to appear on the edge
  16631. * of the plot area. When the axis' `max` option is set or a max extreme
  16632. * is set using `axis.setExtremes()`, the maxPadding will be ignored.
  16633. *
  16634. * Also the `softThreshold` option takes precedence over `maxPadding`,
  16635. * so if the data is tangent to the threshold, `maxPadding` may not
  16636. * apply unless `softThreshold` is set to false.
  16637. *
  16638. * @sample {highcharts} highcharts/yaxis/maxpadding-02/
  16639. * Max padding of 0.2
  16640. * @sample {highstock} stock/xaxis/minpadding-maxpadding/
  16641. * Greater min- and maxPadding
  16642. *
  16643. * @since 1.2.0
  16644. * @product highcharts highstock gantt
  16645. */
  16646. maxPadding: 0.05,
  16647. /**
  16648. * Padding of the min value relative to the length of the axis. A
  16649. * padding of 0.05 will make a 100px axis 5px longer. This is useful
  16650. * when you don't want the lowest data value to appear on the edge
  16651. * of the plot area. When the axis' `min` option is set or a max extreme
  16652. * is set using `axis.setExtremes()`, the maxPadding will be ignored.
  16653. *
  16654. * Also the `softThreshold` option takes precedence over `minPadding`,
  16655. * so if the data is tangent to the threshold, `minPadding` may not
  16656. * apply unless `softThreshold` is set to false.
  16657. *
  16658. * @sample {highcharts} highcharts/yaxis/minpadding/
  16659. * Min padding of 0.2
  16660. * @sample {highstock} stock/xaxis/minpadding-maxpadding/
  16661. * Greater min- and maxPadding
  16662. *
  16663. * @since 1.2.0
  16664. * @product highcharts highstock gantt
  16665. */
  16666. minPadding: 0.05,
  16667. /**
  16668. * @productdesc {highstock}
  16669. * In Highcharts Stock 1.x, the Y axis was placed
  16670. * on the left side by default.
  16671. *
  16672. * @sample {highcharts} highcharts/yaxis/opposite/
  16673. * Secondary Y axis opposite
  16674. * @sample {highstock} stock/xaxis/opposite/
  16675. * Y axis on left side
  16676. *
  16677. * @type {boolean}
  16678. * @default {highstock} true
  16679. * @default {highcharts} false
  16680. * @product highstock highcharts gantt
  16681. * @apioption yAxis.opposite
  16682. */
  16683. /**
  16684. * @see [tickInterval](#xAxis.tickInterval)
  16685. * @see [tickPositioner](#xAxis.tickPositioner)
  16686. * @see [tickPositions](#xAxis.tickPositions)
  16687. */
  16688. tickPixelInterval: 72,
  16689. showLastLabel: true,
  16690. /**
  16691. * @extends xAxis.labels
  16692. */
  16693. labels: {
  16694. /**
  16695. * Angular gauges and solid gauges only.
  16696. * The label's pixel distance from the perimeter of the plot area.
  16697. *
  16698. * Since v7.1.2: If it's a percentage string, it is interpreted the
  16699. * same as [series.radius](#plotOptions.gauge.radius), so label can be
  16700. * aligned under the gauge's shape.
  16701. *
  16702. * @sample {highcharts} highcharts/yaxis/labels-distance/
  16703. * Labels centered under the arc
  16704. *
  16705. * @type {number|string}
  16706. * @default -25
  16707. * @product highcharts
  16708. * @apioption yAxis.labels.distance
  16709. */
  16710. /**
  16711. * The y position offset of all labels relative to the tick
  16712. * positions on the axis. For polar and radial axis consider the use
  16713. * of the [distance](#yAxis.labels.distance) option.
  16714. *
  16715. * @sample {highcharts} highcharts/xaxis/labels-x/
  16716. * Y axis labels placed on grid lines
  16717. *
  16718. * @type {number}
  16719. * @default {highcharts} 3
  16720. * @default {highstock} -2
  16721. * @default {highmaps} 3
  16722. * @apioption yAxis.labels.y
  16723. */
  16724. /**
  16725. * What part of the string the given position is anchored to. Can
  16726. * be one of `"left"`, `"center"` or `"right"`. The exact position
  16727. * also depends on the `labels.x` setting.
  16728. *
  16729. * Angular gauges and solid gauges defaults to `"center"`.
  16730. * Solid gauges with two labels have additional option `"auto"`
  16731. * for automatic horizontal and vertical alignment.
  16732. *
  16733. * @see [yAxis.labels.distance](#yAxis.labels.distance)
  16734. *
  16735. * @sample {highcharts} highcharts/yaxis/labels-align-left/
  16736. * Left
  16737. * @sample {highcharts} highcharts/series-solidgauge/labels-auto-aligned/
  16738. * Solid gauge labels auto aligned
  16739. *
  16740. * @type {Highcharts.AlignValue}
  16741. * @default {highcharts|highmaps} right
  16742. * @default {highstock} left
  16743. * @apioption yAxis.labels.align
  16744. */
  16745. /**
  16746. * The x position offset of all labels relative to the tick
  16747. * positions on the axis. Defaults to -15 for left axis, 15 for
  16748. * right axis.
  16749. *
  16750. * @sample {highcharts} highcharts/xaxis/labels-x/
  16751. * Y axis labels placed on grid lines
  16752. */
  16753. x: -8
  16754. },
  16755. /**
  16756. * @productdesc {highmaps}
  16757. * In Highmaps, the axis line is hidden by default, because the axis is
  16758. * not visible by default.
  16759. *
  16760. * @type {Highcharts.ColorType}
  16761. * @apioption yAxis.lineColor
  16762. */
  16763. /**
  16764. * @sample {highcharts} highcharts/yaxis/max-200/
  16765. * Y axis max of 200
  16766. * @sample {highcharts} highcharts/yaxis/max-logarithmic/
  16767. * Y axis max on logarithmic axis
  16768. * @sample {highstock} stock/yaxis/min-max/
  16769. * Fixed min and max on Y axis
  16770. * @sample {highmaps} maps/axis/min-max/
  16771. * Pre-zoomed to a specific area
  16772. *
  16773. * @apioption yAxis.max
  16774. */
  16775. /**
  16776. * @sample {highcharts} highcharts/yaxis/min-startontick-false/
  16777. * -50 with startOnTick to false
  16778. * @sample {highcharts} highcharts/yaxis/min-startontick-true/
  16779. * -50 with startOnTick true by default
  16780. * @sample {highstock} stock/yaxis/min-max/
  16781. * Fixed min and max on Y axis
  16782. * @sample {highmaps} maps/axis/min-max/
  16783. * Pre-zoomed to a specific area
  16784. *
  16785. * @apioption yAxis.min
  16786. */
  16787. /**
  16788. * An optional scrollbar to display on the Y axis in response to
  16789. * limiting the minimum an maximum of the axis values.
  16790. *
  16791. * In styled mode, all the presentational options for the scrollbar
  16792. * are replaced by the classes `.highcharts-scrollbar-thumb`,
  16793. * `.highcharts-scrollbar-arrow`, `.highcharts-scrollbar-button`,
  16794. * `.highcharts-scrollbar-rifles` and `.highcharts-scrollbar-track`.
  16795. *
  16796. * @sample {highstock} stock/yaxis/scrollbar/
  16797. * Scrollbar on the Y axis
  16798. *
  16799. * @extends scrollbar
  16800. * @since 4.2.6
  16801. * @product highstock
  16802. * @excluding height
  16803. * @apioption yAxis.scrollbar
  16804. */
  16805. /**
  16806. * Enable the scrollbar on the Y axis.
  16807. *
  16808. * @sample {highstock} stock/yaxis/scrollbar/
  16809. * Enabled on Y axis
  16810. *
  16811. * @type {boolean}
  16812. * @default false
  16813. * @since 4.2.6
  16814. * @product highstock
  16815. * @apioption yAxis.scrollbar.enabled
  16816. */
  16817. /**
  16818. * Pixel margin between the scrollbar and the axis elements.
  16819. *
  16820. * @type {number}
  16821. * @default 10
  16822. * @since 4.2.6
  16823. * @product highstock
  16824. * @apioption yAxis.scrollbar.margin
  16825. */
  16826. /**
  16827. * Whether to show the scrollbar when it is fully zoomed out at max
  16828. * range. Setting it to `false` on the Y axis makes the scrollbar stay
  16829. * hidden until the user zooms in, like common in browsers.
  16830. *
  16831. * @type {boolean}
  16832. * @default true
  16833. * @since 4.2.6
  16834. * @product highstock
  16835. * @apioption yAxis.scrollbar.showFull
  16836. */
  16837. /**
  16838. * The width of a vertical scrollbar or height of a horizontal
  16839. * scrollbar. Defaults to 20 on touch devices.
  16840. *
  16841. * @type {number}
  16842. * @default 14
  16843. * @since 4.2.6
  16844. * @product highstock
  16845. * @apioption yAxis.scrollbar.size
  16846. */
  16847. /**
  16848. * Z index of the scrollbar elements.
  16849. *
  16850. * @type {number}
  16851. * @default 3
  16852. * @since 4.2.6
  16853. * @product highstock
  16854. * @apioption yAxis.scrollbar.zIndex
  16855. */
  16856. /**
  16857. * A soft maximum for the axis. If the series data maximum is less
  16858. * than this, the axis will stay at this maximum, but if the series
  16859. * data maximum is higher, the axis will flex to show all data.
  16860. *
  16861. * **Note**: The [series.softThreshold](
  16862. * #plotOptions.series.softThreshold) option takes precedence over this
  16863. * option.
  16864. *
  16865. * @sample highcharts/yaxis/softmin-softmax/
  16866. * Soft min and max
  16867. *
  16868. * @type {number}
  16869. * @since 5.0.1
  16870. * @product highcharts highstock gantt
  16871. * @apioption yAxis.softMax
  16872. */
  16873. /**
  16874. * A soft minimum for the axis. If the series data minimum is greater
  16875. * than this, the axis will stay at this minimum, but if the series
  16876. * data minimum is lower, the axis will flex to show all data.
  16877. *
  16878. * **Note**: The [series.softThreshold](
  16879. * #plotOptions.series.softThreshold) option takes precedence over this
  16880. * option.
  16881. *
  16882. * @sample highcharts/yaxis/softmin-softmax/
  16883. * Soft min and max
  16884. *
  16885. * @type {number}
  16886. * @since 5.0.1
  16887. * @product highcharts highstock gantt
  16888. * @apioption yAxis.softMin
  16889. */
  16890. /**
  16891. * Defines the horizontal alignment of the stack total label. Can be one
  16892. * of `"left"`, `"center"` or `"right"`. The default value is calculated
  16893. * at runtime and depends on orientation and whether the stack is
  16894. * positive or negative.
  16895. *
  16896. * @sample {highcharts} highcharts/yaxis/stacklabels-align-left/
  16897. * Aligned to the left
  16898. * @sample {highcharts} highcharts/yaxis/stacklabels-align-center/
  16899. * Aligned in center
  16900. * @sample {highcharts} highcharts/yaxis/stacklabels-align-right/
  16901. * Aligned to the right
  16902. *
  16903. * @type {Highcharts.AlignValue}
  16904. * @since 2.1.5
  16905. * @product highcharts
  16906. * @apioption yAxis.stackLabels.align
  16907. */
  16908. /**
  16909. * A format string for the data label. Available variables are the same
  16910. * as for `formatter`.
  16911. *
  16912. * @type {string}
  16913. * @default {total}
  16914. * @since 3.0.2
  16915. * @product highcharts highstock
  16916. * @apioption yAxis.stackLabels.format
  16917. */
  16918. /**
  16919. * Rotation of the labels in degrees.
  16920. *
  16921. * @sample {highcharts} highcharts/yaxis/stacklabels-rotation/
  16922. * Labels rotated 45°
  16923. *
  16924. * @type {number}
  16925. * @default 0
  16926. * @since 2.1.5
  16927. * @product highcharts
  16928. * @apioption yAxis.stackLabels.rotation
  16929. */
  16930. /**
  16931. * The text alignment for the label. While `align` determines where the
  16932. * texts anchor point is placed with regards to the stack, `textAlign`
  16933. * determines how the text is aligned against its anchor point. Possible
  16934. * values are `"left"`, `"center"` and `"right"`. The default value is
  16935. * calculated at runtime and depends on orientation and whether the
  16936. * stack is positive or negative.
  16937. *
  16938. * @sample {highcharts} highcharts/yaxis/stacklabels-textalign-left/
  16939. * Label in center position but text-aligned left
  16940. *
  16941. * @type {Highcharts.AlignValue}
  16942. * @since 2.1.5
  16943. * @product highcharts
  16944. * @apioption yAxis.stackLabels.textAlign
  16945. */
  16946. /**
  16947. * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  16948. * to render the labels.
  16949. *
  16950. * @type {boolean}
  16951. * @default false
  16952. * @since 3.0
  16953. * @product highcharts highstock
  16954. * @apioption yAxis.stackLabels.useHTML
  16955. */
  16956. /**
  16957. * Defines the vertical alignment of the stack total label. Can be one
  16958. * of `"top"`, `"middle"` or `"bottom"`. The default value is calculated
  16959. * at runtime and depends on orientation and whether the stack is
  16960. * positive or negative.
  16961. *
  16962. * @sample {highcharts} highcharts/yaxis/stacklabels-verticalalign-top/
  16963. * Vertically aligned top
  16964. * @sample {highcharts} highcharts/yaxis/stacklabels-verticalalign-middle/
  16965. * Vertically aligned middle
  16966. * @sample {highcharts} highcharts/yaxis/stacklabels-verticalalign-bottom/
  16967. * Vertically aligned bottom
  16968. *
  16969. * @type {Highcharts.VerticalAlignValue}
  16970. * @since 2.1.5
  16971. * @product highcharts
  16972. * @apioption yAxis.stackLabels.verticalAlign
  16973. */
  16974. /**
  16975. * The x position offset of the label relative to the left of the
  16976. * stacked bar. The default value is calculated at runtime and depends
  16977. * on orientation and whether the stack is positive or negative.
  16978. *
  16979. * @sample {highcharts} highcharts/yaxis/stacklabels-x/
  16980. * Stack total labels with x offset
  16981. *
  16982. * @type {number}
  16983. * @since 2.1.5
  16984. * @product highcharts
  16985. * @apioption yAxis.stackLabels.x
  16986. */
  16987. /**
  16988. * The y position offset of the label relative to the tick position
  16989. * on the axis. The default value is calculated at runtime and depends
  16990. * on orientation and whether the stack is positive or negative.
  16991. *
  16992. * @sample {highcharts} highcharts/yaxis/stacklabels-y/
  16993. * Stack total labels with y offset
  16994. *
  16995. * @type {number}
  16996. * @since 2.1.5
  16997. * @product highcharts
  16998. * @apioption yAxis.stackLabels.y
  16999. */
  17000. /**
  17001. * Whether to force the axis to start on a tick. Use this option with
  17002. * the `maxPadding` option to control the axis start.
  17003. *
  17004. * This option is always disabled, when panning type is
  17005. * either `y` or `xy`.
  17006. *
  17007. * @see [type](#chart.panning.type)
  17008. *
  17009. * @sample {highcharts} highcharts/xaxis/startontick-false/
  17010. * False by default
  17011. * @sample {highcharts} highcharts/xaxis/startontick-true/
  17012. * True
  17013. * @sample {highstock} stock/xaxis/endontick/
  17014. * False for Y axis
  17015. *
  17016. * @since 1.2.0
  17017. * @product highcharts highstock gantt
  17018. */
  17019. startOnTick: true,
  17020. title: {
  17021. /**
  17022. * The pixel distance between the axis labels and the title.
  17023. * Positive values are outside the axis line, negative are inside.
  17024. *
  17025. * @sample {highcharts} highcharts/xaxis/title-margin/
  17026. * Y axis title margin of 60
  17027. *
  17028. * @type {number}
  17029. * @default 40
  17030. * @apioption yAxis.title.margin
  17031. */
  17032. /**
  17033. * The rotation of the text in degrees. 0 is horizontal, 270 is
  17034. * vertical reading from bottom to top.
  17035. *
  17036. * @sample {highcharts} highcharts/yaxis/title-offset/
  17037. * Horizontal
  17038. */
  17039. rotation: 270,
  17040. /**
  17041. * The actual text of the axis title. Horizontal texts can contain
  17042. * HTML, but rotated texts are painted using vector techniques and
  17043. * must be clean text. The Y axis title is disabled by setting the
  17044. * `text` option to `undefined`.
  17045. *
  17046. * @sample {highcharts} highcharts/xaxis/title-text/
  17047. * Custom HTML
  17048. *
  17049. * @type {string|null}
  17050. * @default {highcharts} Values
  17051. * @default {highstock} undefined
  17052. * @product highcharts highstock gantt
  17053. */
  17054. text: 'Values'
  17055. },
  17056. /**
  17057. * The top position of the Y axis. If it's a number, it is interpreted
  17058. * as pixel position relative to the chart.
  17059. *
  17060. * Since Highcharts 2: If it's a percentage string, it is interpreted as
  17061. * percentages of the plot height, offset from plot area top.
  17062. *
  17063. * @see [yAxis.height](#yAxis.height)
  17064. *
  17065. * @sample {highstock} stock/demo/candlestick-and-volume/
  17066. * Percentage height panes
  17067. *
  17068. * @type {number|string}
  17069. * @product highcharts highstock
  17070. * @apioption yAxis.top
  17071. */
  17072. /**
  17073. * The stack labels show the total value for each bar in a stacked
  17074. * column or bar chart. The label will be placed on top of positive
  17075. * columns and below negative columns. In case of an inverted column
  17076. * chart or a bar chart the label is placed to the right of positive
  17077. * bars and to the left of negative bars.
  17078. *
  17079. * @product highcharts
  17080. */
  17081. stackLabels: {
  17082. /**
  17083. * Enable or disable the initial animation when a series is
  17084. * displayed for the `stackLabels`. The animation can also be set as
  17085. * a configuration object. Please note that this option only
  17086. * applies to the initial animation.
  17087. * For other animations, see [chart.animation](#chart.animation)
  17088. * and the animation parameter under the API methods.
  17089. * The following properties are supported:
  17090. *
  17091. * - `defer`: The animation delay time in milliseconds.
  17092. *
  17093. * @sample {highcharts} highcharts/plotoptions/animation-defer/
  17094. * Animation defer settings
  17095. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  17096. * @since 8.2.0
  17097. * @apioption yAxis.stackLabels.animation
  17098. */
  17099. animation: {},
  17100. /**
  17101. * The animation delay time in milliseconds.
  17102. * Set to `0` renders stackLabel immediately.
  17103. * As `undefined` inherits defer time from the [series.animation.defer](#plotOptions.series.animation.defer).
  17104. *
  17105. * @type {number}
  17106. * @since 8.2.0
  17107. * @apioption yAxis.stackLabels.animation.defer
  17108. */
  17109. /**
  17110. * Allow the stack labels to overlap.
  17111. *
  17112. * @sample {highcharts} highcharts/yaxis/stacklabels-allowoverlap-false/
  17113. * Default false
  17114. *
  17115. * @since 5.0.13
  17116. * @product highcharts
  17117. */
  17118. allowOverlap: false,
  17119. /**
  17120. * The background color or gradient for the stack label.
  17121. *
  17122. * @sample {highcharts} highcharts/yaxis/stacklabels-box/
  17123. * Stack labels box options
  17124. * @type {Highcharts.ColorType}
  17125. * @since 8.1.0
  17126. * @apioption yAxis.stackLabels.backgroundColor
  17127. */
  17128. /**
  17129. * The border color for the stack label. Defaults to `undefined`.
  17130. *
  17131. * @sample {highcharts} highcharts/yaxis/stacklabels-box/
  17132. * Stack labels box options
  17133. * @type {Highcharts.ColorType}
  17134. * @since 8.1.0
  17135. * @apioption yAxis.stackLabels.borderColor
  17136. */
  17137. /**
  17138. * The border radius in pixels for the stack label.
  17139. *
  17140. * @sample {highcharts} highcharts/yaxis/stacklabels-box/
  17141. * Stack labels box options
  17142. * @type {number}
  17143. * @default 0
  17144. * @since 8.1.0
  17145. * @apioption yAxis.stackLabels.borderRadius
  17146. */
  17147. /**
  17148. * The border width in pixels for the stack label.
  17149. *
  17150. * @sample {highcharts} highcharts/yaxis/stacklabels-box/
  17151. * Stack labels box options
  17152. * @type {number}
  17153. * @default 0
  17154. * @since 8.1.0
  17155. * @apioption yAxis.stackLabels.borderWidth
  17156. */
  17157. /**
  17158. * Enable or disable the stack total labels.
  17159. *
  17160. * @sample {highcharts} highcharts/yaxis/stacklabels-enabled/
  17161. * Enabled stack total labels
  17162. * @sample {highcharts} highcharts/yaxis/stacklabels-enabled-waterfall/
  17163. * Enabled stack labels in waterfall chart
  17164. *
  17165. * @since 2.1.5
  17166. * @product highcharts
  17167. */
  17168. enabled: false,
  17169. /**
  17170. * Whether to hide stack labels that are outside the plot area.
  17171. * By default, the stack label is moved
  17172. * inside the plot area according to the
  17173. * [overflow](/highcharts/#yAxis/stackLabels/overflow)
  17174. * option.
  17175. *
  17176. * @type {boolean}
  17177. * @since 7.1.3
  17178. */
  17179. crop: true,
  17180. /**
  17181. * How to handle stack total labels that flow outside the plot area.
  17182. * The default is set to `"justify"`,
  17183. * which aligns them inside the plot area.
  17184. * For columns and bars, this means it will be moved inside the bar.
  17185. * To display stack labels outside the plot area,
  17186. * set `crop` to `false` and `overflow` to `"allow"`.
  17187. *
  17188. * @sample highcharts/yaxis/stacklabels-overflow/
  17189. * Stack labels flows outside the plot area.
  17190. *
  17191. * @type {Highcharts.DataLabelsOverflowValue}
  17192. * @since 7.1.3
  17193. */
  17194. overflow: 'justify',
  17195. /* eslint-disable valid-jsdoc */
  17196. /**
  17197. * Callback JavaScript function to format the label. The value is
  17198. * given by `this.total`.
  17199. *
  17200. * @sample {highcharts} highcharts/yaxis/stacklabels-formatter/
  17201. * Added units to stack total value
  17202. *
  17203. * @type {Highcharts.FormatterCallbackFunction<Highcharts.StackItemObject>}
  17204. * @since 2.1.5
  17205. * @product highcharts
  17206. */
  17207. formatter: function () {
  17208. var numberFormatter = this.axis.chart.numberFormatter;
  17209. /* eslint-enable valid-jsdoc */
  17210. return numberFormatter(this.total, -1);
  17211. },
  17212. /**
  17213. * CSS styles for the label.
  17214. *
  17215. * In styled mode, the styles are set in the
  17216. * `.highcharts-stack-label` class.
  17217. *
  17218. * @sample {highcharts} highcharts/yaxis/stacklabels-style/
  17219. * Red stack total labels
  17220. *
  17221. * @type {Highcharts.CSSObject}
  17222. * @since 2.1.5
  17223. * @product highcharts
  17224. */
  17225. style: {
  17226. /** @internal */
  17227. color: Palette.neutralColor100,
  17228. /** @internal */
  17229. fontSize: '11px',
  17230. /** @internal */
  17231. fontWeight: 'bold',
  17232. /** @internal */
  17233. textOutline: '1px contrast'
  17234. }
  17235. },
  17236. gridLineWidth: 1,
  17237. lineWidth: 0
  17238. // tickWidth: 0
  17239. };
  17240. /**
  17241. * The Z axis or depth axis for 3D plots.
  17242. *
  17243. * See the [Axis class](/class-reference/Highcharts.Axis) for programmatic
  17244. * access to the axis.
  17245. *
  17246. * @sample {highcharts} highcharts/3d/scatter-zaxis-categories/
  17247. * Z-Axis with Categories
  17248. * @sample {highcharts} highcharts/3d/scatter-zaxis-grid/
  17249. * Z-Axis with styling
  17250. *
  17251. * @type {*|Array<*>}
  17252. * @extends xAxis
  17253. * @since 5.0.0
  17254. * @product highcharts
  17255. * @excluding breaks, crosshair, height, left, lineColor, lineWidth,
  17256. * nameToX, showEmpty, top, width
  17257. * @apioption zAxis
  17258. */
  17259. // This variable extends the defaultOptions for left axes.
  17260. AxisDefaults.defaultLeftAxisOptions = {
  17261. labels: {
  17262. x: -15
  17263. },
  17264. title: {
  17265. rotation: 270
  17266. }
  17267. };
  17268. // This variable extends the defaultOptions for right axes.
  17269. AxisDefaults.defaultRightAxisOptions = {
  17270. labels: {
  17271. x: 15
  17272. },
  17273. title: {
  17274. rotation: 90
  17275. }
  17276. };
  17277. // This variable extends the defaultOptions for bottom axes.
  17278. AxisDefaults.defaultBottomAxisOptions = {
  17279. labels: {
  17280. autoRotation: [-45],
  17281. x: 0
  17282. // overflow: undefined,
  17283. // staggerLines: null
  17284. },
  17285. margin: 15,
  17286. title: {
  17287. rotation: 0
  17288. }
  17289. };
  17290. // This variable extends the defaultOptions for top axes.
  17291. AxisDefaults.defaultTopAxisOptions = {
  17292. labels: {
  17293. autoRotation: [-45],
  17294. x: 0
  17295. // overflow: undefined
  17296. // staggerLines: null
  17297. },
  17298. margin: 15,
  17299. title: {
  17300. rotation: 0
  17301. }
  17302. };
  17303. })(AxisDefaults || (AxisDefaults = {}));
  17304. /* *
  17305. *
  17306. * Default Export
  17307. *
  17308. * */
  17309. return AxisDefaults;
  17310. });
  17311. _registerModule(_modules, 'Core/Foundation.js', [_modules['Core/Utilities.js']], function (U) {
  17312. /* *
  17313. *
  17314. * (c) 2010-2021 Torstein Honsi
  17315. *
  17316. * License: www.highcharts.com/license
  17317. *
  17318. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  17319. *
  17320. * */
  17321. var addEvent = U.addEvent,
  17322. isFunction = U.isFunction,
  17323. objectEach = U.objectEach,
  17324. removeEvent = U.removeEvent;
  17325. /* *
  17326. *
  17327. * Functions
  17328. *
  17329. * */
  17330. /*
  17331. * Register event options. If an event handler is set on the options, it should
  17332. * be subject to Chart.update, Axis.update and Series.update. This is contrary
  17333. * to general handlers that are set directly using addEvent either on the class
  17334. * or on the instance. #6538, #6943, #10861.
  17335. */
  17336. var registerEventOptions = function (component,
  17337. options) {
  17338. // A lookup over those events that are added by _options_ (not
  17339. // programmatically). These are updated through .update()
  17340. component.eventOptions = component.eventOptions || {};
  17341. // Register event listeners
  17342. objectEach(options.events, function (event, eventType) {
  17343. if (isFunction(event)) {
  17344. // If event does not exist, or is changed by the .update()
  17345. // function
  17346. if (component.eventOptions[eventType] !== event) {
  17347. // Remove existing if set by option
  17348. if (isFunction(component.eventOptions[eventType])) {
  17349. removeEvent(component, eventType, component.eventOptions[eventType]);
  17350. }
  17351. component.eventOptions[eventType] = event;
  17352. addEvent(component, eventType, event);
  17353. }
  17354. }
  17355. });
  17356. };
  17357. /* *
  17358. *
  17359. * Default Export
  17360. *
  17361. * */
  17362. var exports = {
  17363. registerEventOptions: registerEventOptions
  17364. };
  17365. return exports;
  17366. });
  17367. _registerModule(_modules, 'Core/Axis/Tick.js', [_modules['Core/FormatUtilities.js'], _modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (F, H, U) {
  17368. /* *
  17369. *
  17370. * (c) 2010-2021 Torstein Honsi
  17371. *
  17372. * License: www.highcharts.com/license
  17373. *
  17374. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  17375. *
  17376. * */
  17377. var deg2rad = H.deg2rad;
  17378. var clamp = U.clamp,
  17379. correctFloat = U.correctFloat,
  17380. defined = U.defined,
  17381. destroyObjectProperties = U.destroyObjectProperties,
  17382. extend = U.extend,
  17383. fireEvent = U.fireEvent,
  17384. isNumber = U.isNumber,
  17385. merge = U.merge,
  17386. objectEach = U.objectEach,
  17387. pick = U.pick;
  17388. /* *
  17389. *
  17390. * Class
  17391. *
  17392. * */
  17393. /* eslint-disable no-invalid-this, valid-jsdoc */
  17394. /**
  17395. * The Tick class.
  17396. *
  17397. * @class
  17398. * @name Highcharts.Tick
  17399. *
  17400. * @param {Highcharts.Axis} axis
  17401. * The axis of the tick.
  17402. *
  17403. * @param {number} pos
  17404. * The position of the tick on the axis in terms of axis values.
  17405. *
  17406. * @param {string} [type]
  17407. * The type of tick, either 'minor' or an empty string
  17408. *
  17409. * @param {boolean} [noLabel=false]
  17410. * Whether to disable the label or not. Defaults to false.
  17411. *
  17412. * @param {object} [parameters]
  17413. * Optional parameters for the tick.
  17414. */
  17415. var Tick = /** @class */ (function () {
  17416. /* *
  17417. *
  17418. * Constructors
  17419. *
  17420. * */
  17421. function Tick(axis, pos, type, noLabel, parameters) {
  17422. this.isNew = true;
  17423. this.isNewLabel = true;
  17424. /**
  17425. * The related axis of the tick.
  17426. * @name Highcharts.Tick#axis
  17427. * @type {Highcharts.Axis}
  17428. */
  17429. this.axis = axis;
  17430. /**
  17431. * The logical position of the tick on the axis in terms of axis values.
  17432. * @name Highcharts.Tick#pos
  17433. * @type {number}
  17434. */
  17435. this.pos = pos;
  17436. /**
  17437. * The tick type, which can be `"minor"`, or an empty string.
  17438. * @name Highcharts.Tick#type
  17439. * @type {string}
  17440. */
  17441. this.type = type || '';
  17442. this.parameters = parameters || {};
  17443. /**
  17444. * The mark offset of the tick on the axis. Usually `undefined`, numeric
  17445. * for grid axes.
  17446. * @name Highcharts.Tick#tickmarkOffset
  17447. * @type {number|undefined}
  17448. */
  17449. this.tickmarkOffset = this.parameters.tickmarkOffset;
  17450. this.options = this.parameters.options;
  17451. fireEvent(this, 'init');
  17452. if (!type && !noLabel) {
  17453. this.addLabel();
  17454. }
  17455. }
  17456. /* *
  17457. *
  17458. * Functions
  17459. *
  17460. * */
  17461. /**
  17462. * Write the tick label.
  17463. *
  17464. * @private
  17465. * @function Highcharts.Tick#addLabel
  17466. * @return {void}
  17467. */
  17468. Tick.prototype.addLabel = function () {
  17469. var tick = this,
  17470. axis = tick.axis,
  17471. options = axis.options,
  17472. chart = axis.chart,
  17473. categories = axis.categories,
  17474. log = axis.logarithmic,
  17475. names = axis.names,
  17476. pos = tick.pos,
  17477. labelOptions = pick(tick.options && tick.options.labels,
  17478. options.labels),
  17479. tickPositions = axis.tickPositions,
  17480. isFirst = pos === tickPositions[0],
  17481. isLast = pos === tickPositions[tickPositions.length - 1],
  17482. animateLabels = (!labelOptions.step || labelOptions.step === 1) &&
  17483. axis.tickInterval === 1,
  17484. tickPositionInfo = tickPositions.info;
  17485. var label = tick.label,
  17486. dateTimeLabelFormat,
  17487. dateTimeLabelFormats,
  17488. i;
  17489. // The context value
  17490. var value = this.parameters.category || (categories ?
  17491. pick(categories[pos],
  17492. names[pos],
  17493. pos) :
  17494. pos);
  17495. if (log && isNumber(value)) {
  17496. value = correctFloat(log.lin2log(value));
  17497. }
  17498. // Set the datetime label format. If a higher rank is set for this
  17499. // position, use that. If not, use the general format.
  17500. if (axis.dateTime && tickPositionInfo) {
  17501. dateTimeLabelFormats = chart.time.resolveDTLFormat(options.dateTimeLabelFormats[(!options.grid &&
  17502. tickPositionInfo.higherRanks[pos]) ||
  17503. tickPositionInfo.unitName]);
  17504. dateTimeLabelFormat = dateTimeLabelFormats.main;
  17505. }
  17506. // set properties for access in render method
  17507. /**
  17508. * True if the tick is the first one on the axis.
  17509. * @name Highcharts.Tick#isFirst
  17510. * @readonly
  17511. * @type {boolean|undefined}
  17512. */
  17513. tick.isFirst = isFirst;
  17514. /**
  17515. * True if the tick is the last one on the axis.
  17516. * @name Highcharts.Tick#isLast
  17517. * @readonly
  17518. * @type {boolean|undefined}
  17519. */
  17520. tick.isLast = isLast;
  17521. // Get the string
  17522. var ctx = {
  17523. axis: axis,
  17524. chart: chart,
  17525. dateTimeLabelFormat: dateTimeLabelFormat,
  17526. isFirst: isFirst,
  17527. isLast: isLast,
  17528. pos: pos,
  17529. tick: tick,
  17530. tickPositionInfo: tickPositionInfo,
  17531. value: value
  17532. };
  17533. // Fire an event that allows modifying the context for use in
  17534. // `labels.format` and `labels.formatter`.
  17535. fireEvent(this, 'labelFormat', ctx);
  17536. // Label formatting. When `labels.format` is given, we first run the
  17537. // defaultFormatter and append the result to the context as `text`.
  17538. // Handy for adding prefix or suffix while keeping default number
  17539. // formatting.
  17540. var labelFormatter = function (ctx) {
  17541. if (labelOptions.formatter) {
  17542. return labelOptions.formatter.call(ctx,
  17543. ctx);
  17544. }
  17545. if (labelOptions.format) {
  17546. ctx.text = axis.defaultLabelFormatter.call(ctx);
  17547. return F.format(labelOptions.format, ctx, chart);
  17548. }
  17549. return axis.defaultLabelFormatter.call(ctx, ctx);
  17550. };
  17551. var str = labelFormatter.call(ctx,
  17552. ctx);
  17553. // Set up conditional formatting based on the format list if existing.
  17554. var list = dateTimeLabelFormats && dateTimeLabelFormats.list;
  17555. if (list) {
  17556. tick.shortenLabel = function () {
  17557. for (i = 0; i < list.length; i++) {
  17558. extend(ctx, { dateTimeLabelFormat: list[i] });
  17559. label.attr({
  17560. text: labelFormatter.call(ctx, ctx)
  17561. });
  17562. if (label.getBBox().width <
  17563. axis.getSlotWidth(tick) - 2 *
  17564. labelOptions.padding) {
  17565. return;
  17566. }
  17567. }
  17568. label.attr({
  17569. text: ''
  17570. });
  17571. };
  17572. }
  17573. else {
  17574. // #15692
  17575. tick.shortenLabel = void 0;
  17576. }
  17577. // Call only after first render
  17578. if (animateLabels && axis._addedPlotLB) {
  17579. tick.moveLabel(str, labelOptions);
  17580. }
  17581. // First call
  17582. if (!defined(label) && !tick.movedLabel) {
  17583. /**
  17584. * The rendered text label of the tick.
  17585. * @name Highcharts.Tick#label
  17586. * @type {Highcharts.SVGElement|undefined}
  17587. */
  17588. tick.label = label = tick.createLabel({ x: 0, y: 0 }, str, labelOptions);
  17589. // Base value to detect change for new calls to getBBox
  17590. tick.rotation = 0;
  17591. // update
  17592. }
  17593. else if (label && label.textStr !== str && !animateLabels) {
  17594. // When resetting text, also reset the width if dynamically set
  17595. // (#8809)
  17596. if (label.textWidth &&
  17597. !labelOptions.style.width &&
  17598. !label.styles.width) {
  17599. label.css({ width: null });
  17600. }
  17601. label.attr({ text: str });
  17602. label.textPxLength = label.getBBox().width;
  17603. }
  17604. };
  17605. /**
  17606. * Render and return the label of the tick.
  17607. *
  17608. * @private
  17609. * @function Highcharts.Tick#createLabel
  17610. * @param {Highcharts.PositionObject} xy
  17611. * @param {string} str
  17612. * @param {Highcharts.XAxisLabelsOptions} labelOptions
  17613. * @return {Highcharts.SVGElement|undefined}
  17614. */
  17615. Tick.prototype.createLabel = function (xy, str, labelOptions) {
  17616. var axis = this.axis,
  17617. chart = axis.chart,
  17618. label = defined(str) && labelOptions.enabled ?
  17619. chart.renderer
  17620. .text(str,
  17621. xy.x,
  17622. xy.y,
  17623. labelOptions.useHTML)
  17624. .add(axis.labelGroup) :
  17625. null;
  17626. // Un-rotated length
  17627. if (label) {
  17628. // Without position absolute, IE export sometimes is wrong
  17629. if (!chart.styledMode) {
  17630. label.css(merge(labelOptions.style));
  17631. }
  17632. label.textPxLength = label.getBBox().width;
  17633. }
  17634. return label;
  17635. };
  17636. /**
  17637. * Destructor for the tick prototype
  17638. *
  17639. * @private
  17640. * @function Highcharts.Tick#destroy
  17641. * @return {void}
  17642. */
  17643. Tick.prototype.destroy = function () {
  17644. destroyObjectProperties(this, this.axis);
  17645. };
  17646. /**
  17647. * Gets the x and y positions for ticks in terms of pixels.
  17648. *
  17649. * @private
  17650. * @function Highcharts.Tick#getPosition
  17651. *
  17652. * @param {boolean} horiz
  17653. * Whether the tick is on an horizontal axis or not.
  17654. *
  17655. * @param {number} tickPos
  17656. * Position of the tick.
  17657. *
  17658. * @param {number} tickmarkOffset
  17659. * Tickmark offset for all ticks.
  17660. *
  17661. * @param {boolean} [old]
  17662. * Whether the axis has changed or not.
  17663. *
  17664. * @return {Highcharts.PositionObject}
  17665. * The tick position.
  17666. *
  17667. * @fires Highcharts.Tick#event:afterGetPosition
  17668. */
  17669. Tick.prototype.getPosition = function (horiz, tickPos, tickmarkOffset, old) {
  17670. var axis = this.axis,
  17671. chart = axis.chart,
  17672. cHeight = (old && chart.oldChartHeight) || chart.chartHeight,
  17673. pos = {
  17674. x: horiz ?
  17675. correctFloat(axis.translate(tickPos + tickmarkOffset,
  17676. null,
  17677. null,
  17678. old) +
  17679. axis.transB) :
  17680. (axis.left +
  17681. axis.offset +
  17682. (axis.opposite ?
  17683. (((old && chart.oldChartWidth) ||
  17684. chart.chartWidth) -
  17685. axis.right -
  17686. axis.left) :
  17687. 0)),
  17688. y: horiz ?
  17689. (cHeight -
  17690. axis.bottom +
  17691. axis.offset -
  17692. (axis.opposite ? axis.height : 0)) :
  17693. correctFloat(cHeight -
  17694. axis.translate(tickPos + tickmarkOffset,
  17695. null,
  17696. null,
  17697. old) -
  17698. axis.transB)
  17699. };
  17700. // Chrome workaround for #10516
  17701. pos.y = clamp(pos.y, -1e5, 1e5);
  17702. fireEvent(this, 'afterGetPosition', { pos: pos });
  17703. return pos;
  17704. };
  17705. /**
  17706. * Get the x, y position of the tick label
  17707. *
  17708. * @private
  17709. * @return {Highcharts.PositionObject}
  17710. */
  17711. Tick.prototype.getLabelPosition = function (x, y, label, horiz, labelOptions, tickmarkOffset, index, step) {
  17712. var axis = this.axis,
  17713. transA = axis.transA,
  17714. reversed = ( // #7911
  17715. axis.isLinked && axis.linkedParent ?
  17716. axis.linkedParent.reversed :
  17717. axis.reversed),
  17718. staggerLines = axis.staggerLines,
  17719. rotCorr = axis.tickRotCorr || { x: 0,
  17720. y: 0 },
  17721. // Adjust for label alignment if we use reserveSpace: true (#5286)
  17722. labelOffsetCorrection = (!horiz && !axis.reserveSpaceDefault ?
  17723. -axis.labelOffset * (axis.labelAlign === 'center' ? 0.5 : 1) :
  17724. 0),
  17725. pos = {};
  17726. var yOffset = labelOptions.y,
  17727. line;
  17728. if (!defined(yOffset)) {
  17729. if (axis.side === 0) {
  17730. yOffset = label.rotation ? -8 : -label.getBBox().height;
  17731. }
  17732. else if (axis.side === 2) {
  17733. yOffset = rotCorr.y + 8;
  17734. }
  17735. else {
  17736. // #3140, #3140
  17737. yOffset = Math.cos(label.rotation * deg2rad) *
  17738. (rotCorr.y - label.getBBox(false, 0).height / 2);
  17739. }
  17740. }
  17741. x = x +
  17742. labelOptions.x +
  17743. labelOffsetCorrection +
  17744. rotCorr.x -
  17745. (tickmarkOffset && horiz ?
  17746. tickmarkOffset * transA * (reversed ? -1 : 1) :
  17747. 0);
  17748. y = y + yOffset - (tickmarkOffset && !horiz ?
  17749. tickmarkOffset * transA * (reversed ? 1 : -1) : 0);
  17750. // Correct for staggered labels
  17751. if (staggerLines) {
  17752. line = (index / (step || 1) % staggerLines);
  17753. if (axis.opposite) {
  17754. line = staggerLines - line - 1;
  17755. }
  17756. y += line * (axis.labelOffset / staggerLines);
  17757. }
  17758. pos.x = x;
  17759. pos.y = Math.round(y);
  17760. fireEvent(this, 'afterGetLabelPosition', { pos: pos, tickmarkOffset: tickmarkOffset, index: index });
  17761. return pos;
  17762. };
  17763. /**
  17764. * Get the offset height or width of the label
  17765. *
  17766. * @private
  17767. * @function Highcharts.Tick#getLabelSize
  17768. * @return {number}
  17769. */
  17770. Tick.prototype.getLabelSize = function () {
  17771. return this.label ?
  17772. this.label.getBBox()[this.axis.horiz ? 'height' : 'width'] :
  17773. 0;
  17774. };
  17775. /**
  17776. * Extendible method to return the path of the marker
  17777. *
  17778. * @private
  17779. *
  17780. */
  17781. Tick.prototype.getMarkPath = function (x, y, tickLength, tickWidth, horiz, renderer) {
  17782. return renderer.crispLine([[
  17783. 'M',
  17784. x,
  17785. y
  17786. ], [
  17787. 'L',
  17788. x + (horiz ? 0 : -tickLength),
  17789. y + (horiz ? tickLength : 0)
  17790. ]], tickWidth);
  17791. };
  17792. /**
  17793. * Handle the label overflow by adjusting the labels to the left and right
  17794. * edge, or hide them if they collide into the neighbour label.
  17795. *
  17796. * @private
  17797. * @function Highcharts.Tick#handleOverflow
  17798. * @param {Highcharts.PositionObject} xy
  17799. * @return {void}
  17800. */
  17801. Tick.prototype.handleOverflow = function (xy) {
  17802. var tick = this,
  17803. axis = this.axis,
  17804. labelOptions = axis.options.labels,
  17805. pxPos = xy.x,
  17806. chartWidth = axis.chart.chartWidth,
  17807. spacing = axis.chart.spacing,
  17808. leftBound = pick(axis.labelLeft,
  17809. Math.min(axis.pos,
  17810. spacing[3])),
  17811. rightBound = pick(axis.labelRight,
  17812. Math.max(!axis.isRadial ? axis.pos + axis.len : 0,
  17813. chartWidth - spacing[1])),
  17814. label = this.label,
  17815. rotation = this.rotation,
  17816. factor = {
  17817. left: 0,
  17818. center: 0.5,
  17819. right: 1
  17820. }[axis.labelAlign || label.attr('align')],
  17821. labelWidth = label.getBBox().width,
  17822. slotWidth = axis.getSlotWidth(tick),
  17823. xCorrection = factor,
  17824. css = {};
  17825. var modifiedSlotWidth = slotWidth,
  17826. goRight = 1,
  17827. leftPos,
  17828. rightPos,
  17829. textWidth;
  17830. // Check if the label overshoots the chart spacing box. If it does, move
  17831. // it. If it now overshoots the slotWidth, add ellipsis.
  17832. if (!rotation && labelOptions.overflow === 'justify') {
  17833. leftPos = pxPos - factor * labelWidth;
  17834. rightPos = pxPos + (1 - factor) * labelWidth;
  17835. if (leftPos < leftBound) {
  17836. modifiedSlotWidth =
  17837. xy.x + modifiedSlotWidth * (1 - factor) - leftBound;
  17838. }
  17839. else if (rightPos > rightBound) {
  17840. modifiedSlotWidth =
  17841. rightBound - xy.x + modifiedSlotWidth * factor;
  17842. goRight = -1;
  17843. }
  17844. modifiedSlotWidth = Math.min(slotWidth, modifiedSlotWidth); // #4177
  17845. if (modifiedSlotWidth < slotWidth && axis.labelAlign === 'center') {
  17846. xy.x += (goRight *
  17847. (slotWidth -
  17848. modifiedSlotWidth -
  17849. xCorrection * (slotWidth - Math.min(labelWidth, modifiedSlotWidth))));
  17850. }
  17851. // If the label width exceeds the available space, set a text width
  17852. // to be picked up below. Also, if a width has been set before, we
  17853. // need to set a new one because the reported labelWidth will be
  17854. // limited by the box (#3938).
  17855. if (labelWidth > modifiedSlotWidth ||
  17856. (axis.autoRotation && (label.styles || {}).width)) {
  17857. textWidth = modifiedSlotWidth;
  17858. }
  17859. // Add ellipsis to prevent rotated labels to be clipped against the edge
  17860. // of the chart
  17861. }
  17862. else if (rotation < 0 &&
  17863. pxPos - factor * labelWidth < leftBound) {
  17864. textWidth = Math.round(pxPos / Math.cos(rotation * deg2rad) - leftBound);
  17865. }
  17866. else if (rotation > 0 &&
  17867. pxPos + factor * labelWidth > rightBound) {
  17868. textWidth = Math.round((chartWidth - pxPos) /
  17869. Math.cos(rotation * deg2rad));
  17870. }
  17871. if (textWidth) {
  17872. if (tick.shortenLabel) {
  17873. tick.shortenLabel();
  17874. }
  17875. else {
  17876. css.width = Math.floor(textWidth) + 'px';
  17877. if (!(labelOptions.style || {}).textOverflow) {
  17878. css.textOverflow = 'ellipsis';
  17879. }
  17880. label.css(css);
  17881. }
  17882. }
  17883. };
  17884. /**
  17885. * Try to replace the label if the same one already exists.
  17886. *
  17887. * @private
  17888. * @function Highcharts.Tick#moveLabel
  17889. * @param {string} str
  17890. * @param {Highcharts.XAxisLabelsOptions} labelOptions
  17891. *
  17892. * @return {void}
  17893. */
  17894. Tick.prototype.moveLabel = function (str, labelOptions) {
  17895. var tick = this,
  17896. label = tick.label,
  17897. axis = tick.axis,
  17898. reversed = axis.reversed;
  17899. var moved = false,
  17900. labelPos,
  17901. xPos,
  17902. yPos;
  17903. if (label && label.textStr === str) {
  17904. tick.movedLabel = label;
  17905. moved = true;
  17906. delete tick.label;
  17907. }
  17908. else { // Find a label with the same string
  17909. objectEach(axis.ticks, function (currentTick) {
  17910. if (!moved &&
  17911. !currentTick.isNew &&
  17912. currentTick !== tick &&
  17913. currentTick.label &&
  17914. currentTick.label.textStr === str) {
  17915. tick.movedLabel = currentTick.label;
  17916. moved = true;
  17917. currentTick.labelPos = tick.movedLabel.xy;
  17918. delete currentTick.label;
  17919. }
  17920. });
  17921. }
  17922. // Create new label if the actual one is moved
  17923. if (!moved && (tick.labelPos || label)) {
  17924. labelPos = tick.labelPos || label.xy;
  17925. xPos = axis.horiz ?
  17926. (reversed ? 0 : axis.width + axis.left) : labelPos.x;
  17927. yPos = axis.horiz ?
  17928. labelPos.y : (reversed ? (axis.width + axis.left) : 0);
  17929. tick.movedLabel = tick.createLabel({ x: xPos, y: yPos }, str, labelOptions);
  17930. if (tick.movedLabel) {
  17931. tick.movedLabel.attr({ opacity: 0 });
  17932. }
  17933. }
  17934. };
  17935. /**
  17936. * Put everything in place
  17937. *
  17938. * @private
  17939. * @param {number} index
  17940. * @param {boolean} [old]
  17941. * Use old coordinates to prepare an animation into new position
  17942. * @param {number} [opacity]
  17943. * @return {voids}
  17944. */
  17945. Tick.prototype.render = function (index, old, opacity) {
  17946. var tick = this,
  17947. axis = tick.axis,
  17948. horiz = axis.horiz,
  17949. pos = tick.pos,
  17950. tickmarkOffset = pick(tick.tickmarkOffset,
  17951. axis.tickmarkOffset),
  17952. xy = tick.getPosition(horiz,
  17953. pos,
  17954. tickmarkOffset,
  17955. old),
  17956. x = xy.x,
  17957. y = xy.y,
  17958. reverseCrisp = ((horiz && x === axis.pos + axis.len) ||
  17959. (!horiz && y === axis.pos)) ? -1 : 1; // #1480, #1687
  17960. var labelOpacity = pick(opacity,
  17961. tick.label && tick.label.newOpacity, // #15528
  17962. 1);
  17963. opacity = pick(opacity, 1);
  17964. this.isActive = true;
  17965. // Create the grid line
  17966. this.renderGridLine(old, opacity, reverseCrisp);
  17967. // create the tick mark
  17968. this.renderMark(xy, opacity, reverseCrisp);
  17969. // the label is created on init - now move it into place
  17970. this.renderLabel(xy, old, labelOpacity, index);
  17971. tick.isNew = false;
  17972. fireEvent(this, 'afterRender');
  17973. };
  17974. /**
  17975. * Renders the gridLine.
  17976. *
  17977. * @private
  17978. * @param {boolean} old Whether or not the tick is old
  17979. * @param {number} opacity The opacity of the grid line
  17980. * @param {number} reverseCrisp Modifier for avoiding overlapping 1 or -1
  17981. * @return {void}
  17982. */
  17983. Tick.prototype.renderGridLine = function (old, opacity, reverseCrisp) {
  17984. var tick = this,
  17985. axis = tick.axis,
  17986. options = axis.options,
  17987. attribs = {},
  17988. pos = tick.pos,
  17989. type = tick.type,
  17990. tickmarkOffset = pick(tick.tickmarkOffset,
  17991. axis.tickmarkOffset),
  17992. renderer = axis.chart.renderer;
  17993. var gridLine = tick.gridLine,
  17994. gridLinePath,
  17995. gridLineWidth = options.gridLineWidth,
  17996. gridLineColor = options.gridLineColor,
  17997. dashStyle = options.gridLineDashStyle;
  17998. if (tick.type === 'minor') {
  17999. gridLineWidth = options.minorGridLineWidth;
  18000. gridLineColor = options.minorGridLineColor;
  18001. dashStyle = options.minorGridLineDashStyle;
  18002. }
  18003. if (!gridLine) {
  18004. if (!axis.chart.styledMode) {
  18005. attribs.stroke = gridLineColor;
  18006. attribs['stroke-width'] = gridLineWidth || 0;
  18007. attribs.dashstyle = dashStyle;
  18008. }
  18009. if (!type) {
  18010. attribs.zIndex = 1;
  18011. }
  18012. if (old) {
  18013. opacity = 0;
  18014. }
  18015. /**
  18016. * The rendered grid line of the tick.
  18017. * @name Highcharts.Tick#gridLine
  18018. * @type {Highcharts.SVGElement|undefined}
  18019. */
  18020. tick.gridLine = gridLine = renderer.path()
  18021. .attr(attribs)
  18022. .addClass('highcharts-' + (type ? type + '-' : '') + 'grid-line')
  18023. .add(axis.gridGroup);
  18024. }
  18025. if (gridLine) {
  18026. gridLinePath = axis.getPlotLinePath({
  18027. value: pos + tickmarkOffset,
  18028. lineWidth: gridLine.strokeWidth() * reverseCrisp,
  18029. force: 'pass',
  18030. old: old
  18031. });
  18032. // If the parameter 'old' is set, the current call will be followed
  18033. // by another call, therefore do not do any animations this time
  18034. if (gridLinePath) {
  18035. gridLine[old || tick.isNew ? 'attr' : 'animate']({
  18036. d: gridLinePath,
  18037. opacity: opacity
  18038. });
  18039. }
  18040. }
  18041. };
  18042. /**
  18043. * Renders the tick mark.
  18044. *
  18045. * @private
  18046. * @param {Highcharts.PositionObject} xy The position vector of the mark
  18047. * @param {number} opacity The opacity of the mark
  18048. * @param {number} reverseCrisp Modifier for avoiding overlapping 1 or -1
  18049. * @return {void}
  18050. */
  18051. Tick.prototype.renderMark = function (xy, opacity, reverseCrisp) {
  18052. var tick = this, axis = tick.axis, options = axis.options, renderer = axis.chart.renderer, type = tick.type, tickSize = axis.tickSize(type ? type + 'Tick' : 'tick'), x = xy.x, y = xy.y, tickWidth = pick(options[type !== 'minor' ? 'tickWidth' : 'minorTickWidth'], !type && axis.isXAxis ? 1 : 0), // X axis defaults to 1
  18053. tickColor = options[type !== 'minor' ? 'tickColor' : 'minorTickColor'];
  18054. var mark = tick.mark;
  18055. var isNewMark = !mark;
  18056. if (tickSize) {
  18057. // negate the length
  18058. if (axis.opposite) {
  18059. tickSize[0] = -tickSize[0];
  18060. }
  18061. // First time, create it
  18062. if (!mark) {
  18063. /**
  18064. * The rendered mark of the tick.
  18065. * @name Highcharts.Tick#mark
  18066. * @type {Highcharts.SVGElement|undefined}
  18067. */
  18068. tick.mark = mark = renderer.path()
  18069. .addClass('highcharts-' + (type ? type + '-' : '') + 'tick')
  18070. .add(axis.axisGroup);
  18071. if (!axis.chart.styledMode) {
  18072. mark.attr({
  18073. stroke: tickColor,
  18074. 'stroke-width': tickWidth
  18075. });
  18076. }
  18077. }
  18078. mark[isNewMark ? 'attr' : 'animate']({
  18079. d: tick.getMarkPath(x, y, tickSize[0], mark.strokeWidth() * reverseCrisp, axis.horiz, renderer),
  18080. opacity: opacity
  18081. });
  18082. }
  18083. };
  18084. /**
  18085. * Renders the tick label.
  18086. * Note: The label should already be created in init(), so it should only
  18087. * have to be moved into place.
  18088. *
  18089. * @private
  18090. * @param {Highcharts.PositionObject} xy The position vector of the label
  18091. * @param {boolean} old Whether or not the tick is old
  18092. * @param {number} opacity The opacity of the label
  18093. * @param {number} index The index of the tick
  18094. * @return {void}
  18095. */
  18096. Tick.prototype.renderLabel = function (xy, old, opacity, index) {
  18097. var tick = this,
  18098. axis = tick.axis,
  18099. horiz = axis.horiz,
  18100. options = axis.options,
  18101. label = tick.label,
  18102. labelOptions = options.labels,
  18103. step = labelOptions.step,
  18104. tickmarkOffset = pick(tick.tickmarkOffset,
  18105. axis.tickmarkOffset),
  18106. x = xy.x,
  18107. y = xy.y;
  18108. var show = true;
  18109. if (label && isNumber(x)) {
  18110. label.xy = xy = tick.getLabelPosition(x, y, label, horiz, labelOptions, tickmarkOffset, index, step);
  18111. // Apply show first and show last. If the tick is both first and
  18112. // last, it is a single centered tick, in which case we show the
  18113. // label anyway (#2100).
  18114. if ((tick.isFirst &&
  18115. !tick.isLast &&
  18116. !options.showFirstLabel) ||
  18117. (tick.isLast &&
  18118. !tick.isFirst &&
  18119. !options.showLastLabel)) {
  18120. show = false;
  18121. // Handle label overflow and show or hide accordingly
  18122. }
  18123. else if (horiz &&
  18124. !labelOptions.step &&
  18125. !labelOptions.rotation &&
  18126. !old &&
  18127. opacity !== 0) {
  18128. tick.handleOverflow(xy);
  18129. }
  18130. // apply step
  18131. if (step && index % step) {
  18132. // show those indices dividable by step
  18133. show = false;
  18134. }
  18135. // Set the new position, and show or hide
  18136. if (show && isNumber(xy.y)) {
  18137. xy.opacity = opacity;
  18138. label[tick.isNewLabel ? 'attr' : 'animate'](xy);
  18139. tick.isNewLabel = false;
  18140. }
  18141. else {
  18142. label.attr('y', -9999); // #1338
  18143. tick.isNewLabel = true;
  18144. }
  18145. }
  18146. };
  18147. /**
  18148. * Replace labels with the moved ones to perform animation. Additionally
  18149. * destroy unused labels.
  18150. *
  18151. * @private
  18152. * @function Highcharts.Tick#replaceMovedLabel
  18153. * @return {void}
  18154. */
  18155. Tick.prototype.replaceMovedLabel = function () {
  18156. var tick = this,
  18157. label = tick.label,
  18158. axis = tick.axis,
  18159. reversed = axis.reversed;
  18160. var x,
  18161. y;
  18162. // Animate and destroy
  18163. if (label && !tick.isNew) {
  18164. x = axis.horiz ? (reversed ? axis.left : axis.width + axis.left) : label.xy.x;
  18165. y = axis.horiz ?
  18166. label.xy.y :
  18167. (reversed ? axis.width + axis.top : axis.top);
  18168. label.animate({ x: x, y: y, opacity: 0 }, void 0, label.destroy);
  18169. delete tick.label;
  18170. }
  18171. axis.isDirty = true;
  18172. tick.label = tick.movedLabel;
  18173. delete tick.movedLabel;
  18174. };
  18175. return Tick;
  18176. }());
  18177. /* *
  18178. *
  18179. * Default Export
  18180. *
  18181. * */
  18182. /* *
  18183. *
  18184. * API Declarations
  18185. *
  18186. * */
  18187. /**
  18188. * Optional parameters for the tick.
  18189. * @private
  18190. * @interface Highcharts.TickParametersObject
  18191. */ /**
  18192. * Set category for the tick.
  18193. * @name Highcharts.TickParametersObject#category
  18194. * @type {string|undefined}
  18195. */ /**
  18196. * @name Highcharts.TickParametersObject#options
  18197. * @type {Highcharts.Dictionary<any>|undefined}
  18198. */ /**
  18199. * Set tickmarkOffset for the tick.
  18200. * @name Highcharts.TickParametersObject#tickmarkOffset
  18201. * @type {number|undefined}
  18202. */
  18203. /**
  18204. * Additonal time tick information.
  18205. *
  18206. * @interface Highcharts.TimeTicksInfoObject
  18207. * @extends Highcharts.TimeNormalizedObject
  18208. */ /**
  18209. * @name Highcharts.TimeTicksInfoObject#higherRanks
  18210. * @type {Array<string>}
  18211. */ /**
  18212. * @name Highcharts.TimeTicksInfoObject#totalRange
  18213. * @type {number}
  18214. */
  18215. ''; // detach doclets above
  18216. return Tick;
  18217. });
  18218. _registerModule(_modules, 'Core/Axis/Axis.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Axis/AxisDefaults.js'], _modules['Core/Color/Color.js'], _modules['Core/Foundation.js'], _modules['Core/Globals.js'], _modules['Core/Color/Palette.js'], _modules['Core/DefaultOptions.js'], _modules['Core/Axis/Tick.js'], _modules['Core/Utilities.js']], function (A, AxisDefaults, Color, F, H, Palette, D, Tick, U) {
  18219. /* *
  18220. *
  18221. * (c) 2010-2021 Torstein Honsi
  18222. *
  18223. * License: www.highcharts.com/license
  18224. *
  18225. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  18226. *
  18227. * */
  18228. var animObject = A.animObject;
  18229. var registerEventOptions = F.registerEventOptions;
  18230. var deg2rad = H.deg2rad;
  18231. var defaultOptions = D.defaultOptions;
  18232. var arrayMax = U.arrayMax,
  18233. arrayMin = U.arrayMin,
  18234. clamp = U.clamp,
  18235. correctFloat = U.correctFloat,
  18236. defined = U.defined,
  18237. destroyObjectProperties = U.destroyObjectProperties,
  18238. erase = U.erase,
  18239. error = U.error,
  18240. extend = U.extend,
  18241. fireEvent = U.fireEvent,
  18242. getMagnitude = U.getMagnitude,
  18243. isArray = U.isArray,
  18244. isNumber = U.isNumber,
  18245. isString = U.isString,
  18246. merge = U.merge,
  18247. normalizeTickInterval = U.normalizeTickInterval,
  18248. objectEach = U.objectEach,
  18249. pick = U.pick,
  18250. relativeLength = U.relativeLength,
  18251. removeEvent = U.removeEvent,
  18252. splat = U.splat,
  18253. syncTimeout = U.syncTimeout;
  18254. /* *
  18255. *
  18256. * Class
  18257. *
  18258. * */
  18259. /**
  18260. * Create a new axis object. Called internally when instanciating a new chart or
  18261. * adding axes by {@link Highcharts.Chart#addAxis}.
  18262. *
  18263. * A chart can have from 0 axes (pie chart) to multiples. In a normal, single
  18264. * series cartesian chart, there is one X axis and one Y axis.
  18265. *
  18266. * The X axis or axes are referenced by {@link Highcharts.Chart.xAxis}, which is
  18267. * an array of Axis objects. If there is only one axis, it can be referenced
  18268. * through `chart.xAxis[0]`, and multiple axes have increasing indices. The same
  18269. * pattern goes for Y axes.
  18270. *
  18271. * If you need to get the axes from a series object, use the `series.xAxis` and
  18272. * `series.yAxis` properties. These are not arrays, as one series can only be
  18273. * associated to one X and one Y axis.
  18274. *
  18275. * A third way to reference the axis programmatically is by `id`. Add an `id` in
  18276. * the axis configuration options, and get the axis by
  18277. * {@link Highcharts.Chart#get}.
  18278. *
  18279. * Configuration options for the axes are given in options.xAxis and
  18280. * options.yAxis.
  18281. *
  18282. * @class
  18283. * @name Highcharts.Axis
  18284. *
  18285. * @param {Highcharts.Chart} chart
  18286. * The Chart instance to apply the axis on.
  18287. *
  18288. * @param {Highcharts.AxisOptions} userOptions
  18289. * Axis options.
  18290. */
  18291. var Axis = /** @class */ (function () {
  18292. /* *
  18293. *
  18294. * Constructors
  18295. *
  18296. * */
  18297. function Axis(chart, userOptions) {
  18298. this.alternateBands = void 0;
  18299. this.bottom = void 0;
  18300. this.categories = void 0;
  18301. this.chart = void 0;
  18302. this.closestPointRange = void 0;
  18303. this.coll = void 0;
  18304. this.eventOptions = void 0;
  18305. this.hasNames = void 0;
  18306. this.hasVisibleSeries = void 0;
  18307. this.height = void 0;
  18308. this.isLinked = void 0;
  18309. this.labelEdge = void 0; // @todo
  18310. this.labelFormatter = void 0;
  18311. this.left = void 0;
  18312. this.len = void 0;
  18313. this.max = void 0;
  18314. this.maxLabelLength = void 0;
  18315. this.min = void 0;
  18316. this.minorTickInterval = void 0;
  18317. this.minorTicks = void 0;
  18318. this.minPixelPadding = void 0;
  18319. this.names = void 0;
  18320. this.offset = void 0;
  18321. this.options = void 0;
  18322. this.overlap = void 0;
  18323. this.paddedTicks = void 0;
  18324. this.plotLinesAndBands = void 0;
  18325. this.plotLinesAndBandsGroups = void 0;
  18326. this.pointRange = void 0;
  18327. this.pointRangePadding = void 0;
  18328. this.pos = void 0;
  18329. this.positiveValuesOnly = void 0;
  18330. this.right = void 0;
  18331. this.series = void 0;
  18332. this.side = void 0;
  18333. this.tickAmount = void 0;
  18334. this.tickInterval = void 0;
  18335. this.tickmarkOffset = void 0;
  18336. this.tickPositions = void 0;
  18337. this.tickRotCorr = void 0;
  18338. this.ticks = void 0;
  18339. this.top = void 0;
  18340. this.transA = void 0;
  18341. this.transB = void 0;
  18342. this.translationSlope = void 0;
  18343. this.userOptions = void 0;
  18344. this.visible = void 0;
  18345. this.width = void 0;
  18346. this.zoomEnabled = void 0;
  18347. this.init(chart, userOptions);
  18348. }
  18349. /* *
  18350. *
  18351. * Functions
  18352. *
  18353. * */
  18354. /**
  18355. * Overrideable function to initialize the axis.
  18356. *
  18357. * @see {@link Axis}
  18358. *
  18359. * @function Highcharts.Axis#init
  18360. *
  18361. * @param {Highcharts.Chart} chart
  18362. * The Chart instance to apply the axis on.
  18363. *
  18364. * @param {AxisOptions} userOptions
  18365. * Axis options.
  18366. *
  18367. * @fires Highcharts.Axis#event:afterInit
  18368. * @fires Highcharts.Axis#event:init
  18369. */
  18370. Axis.prototype.init = function (chart, userOptions) {
  18371. var isXAxis = userOptions.isX,
  18372. axis = this;
  18373. /**
  18374. * The Chart that the axis belongs to.
  18375. *
  18376. * @name Highcharts.Axis#chart
  18377. * @type {Highcharts.Chart}
  18378. */
  18379. axis.chart = chart;
  18380. /**
  18381. * Whether the axis is horizontal.
  18382. *
  18383. * @name Highcharts.Axis#horiz
  18384. * @type {boolean|undefined}
  18385. */
  18386. axis.horiz = chart.inverted && !axis.isZAxis ? !isXAxis : isXAxis;
  18387. /**
  18388. * Whether the axis is the x-axis.
  18389. *
  18390. * @name Highcharts.Axis#isXAxis
  18391. * @type {boolean|undefined}
  18392. */
  18393. axis.isXAxis = isXAxis;
  18394. /**
  18395. * The collection where the axis belongs, for example `xAxis`, `yAxis`
  18396. * or `colorAxis`. Corresponds to properties on Chart, for example
  18397. * {@link Chart.xAxis}.
  18398. *
  18399. * @name Highcharts.Axis#coll
  18400. * @type {string}
  18401. */
  18402. axis.coll = axis.coll || (isXAxis ? 'xAxis' : 'yAxis');
  18403. fireEvent(this, 'init', { userOptions: userOptions });
  18404. axis.opposite = pick(userOptions.opposite, axis.opposite); // needed in setOptions
  18405. /**
  18406. * The side on which the axis is rendered. 0 is top, 1 is right, 2
  18407. * is bottom and 3 is left.
  18408. *
  18409. * @name Highcharts.Axis#side
  18410. * @type {number}
  18411. */
  18412. axis.side = pick(userOptions.side, axis.side, (axis.horiz ?
  18413. (axis.opposite ? 0 : 2) : // top : bottom
  18414. (axis.opposite ? 1 : 3)) // right : left
  18415. );
  18416. /**
  18417. * Current options for the axis after merge of defaults and user's
  18418. * options.
  18419. *
  18420. * @name Highcharts.Axis#options
  18421. * @type {Highcharts.AxisOptions}
  18422. */
  18423. axis.setOptions(userOptions);
  18424. var options = this.options,
  18425. labelsOptions = options.labels,
  18426. type = options.type;
  18427. /**
  18428. * User's options for this axis without defaults.
  18429. *
  18430. * @name Highcharts.Axis#userOptions
  18431. * @type {Highcharts.AxisOptions}
  18432. */
  18433. axis.userOptions = userOptions;
  18434. axis.minPixelPadding = 0;
  18435. /**
  18436. * Whether the axis is reversed. Based on the `axis.reversed`,
  18437. * option, but inverted charts have reversed xAxis by default.
  18438. *
  18439. * @name Highcharts.Axis#reversed
  18440. * @type {boolean}
  18441. */
  18442. axis.reversed = pick(options.reversed, axis.reversed);
  18443. axis.visible = options.visible;
  18444. axis.zoomEnabled = options.zoomEnabled;
  18445. // Initial categories
  18446. axis.hasNames =
  18447. type === 'category' || options.categories === true;
  18448. /**
  18449. * If categories are present for the axis, names are used instead of
  18450. * numbers for that axis.
  18451. *
  18452. * Since Highcharts 3.0, categories can also be extracted by giving each
  18453. * point a name and setting axis type to `category`. However, if you
  18454. * have multiple series, best practice remains defining the `categories`
  18455. * array.
  18456. *
  18457. * @see [xAxis.categories](/highcharts/xAxis.categories)
  18458. *
  18459. * @name Highcharts.Axis#categories
  18460. * @type {Array<string>}
  18461. * @readonly
  18462. */
  18463. axis.categories = options.categories || axis.hasNames;
  18464. if (!axis.names) { // Preserve on update (#3830)
  18465. axis.names = [];
  18466. axis.names.keys = {};
  18467. }
  18468. // Placeholder for plotlines and plotbands groups
  18469. axis.plotLinesAndBandsGroups = {};
  18470. // Shorthand types
  18471. axis.positiveValuesOnly = !!axis.logarithmic;
  18472. // Flag, if axis is linked to another axis
  18473. axis.isLinked = defined(options.linkedTo);
  18474. /**
  18475. * List of major ticks mapped by postition on axis.
  18476. *
  18477. * @see {@link Highcharts.Tick}
  18478. *
  18479. * @name Highcharts.Axis#ticks
  18480. * @type {Highcharts.Dictionary<Highcharts.Tick>}
  18481. */
  18482. axis.ticks = {};
  18483. axis.labelEdge = [];
  18484. /**
  18485. * List of minor ticks mapped by position on the axis.
  18486. *
  18487. * @see {@link Highcharts.Tick}
  18488. *
  18489. * @name Highcharts.Axis#minorTicks
  18490. * @type {Highcharts.Dictionary<Highcharts.Tick>}
  18491. */
  18492. axis.minorTicks = {};
  18493. // List of plotLines/Bands
  18494. axis.plotLinesAndBands = [];
  18495. // Alternate bands
  18496. axis.alternateBands = {};
  18497. // Axis metrics
  18498. axis.len = 0;
  18499. axis.minRange = axis.userMinRange = options.minRange || options.maxZoom;
  18500. axis.range = options.range;
  18501. axis.offset = options.offset || 0;
  18502. /**
  18503. * The maximum value of the axis. In a logarithmic axis, this is the
  18504. * logarithm of the real value, and the real value can be obtained from
  18505. * {@link Axis#getExtremes}.
  18506. *
  18507. * @name Highcharts.Axis#max
  18508. * @type {number|null}
  18509. */
  18510. axis.max = null;
  18511. /**
  18512. * The minimum value of the axis. In a logarithmic axis, this is the
  18513. * logarithm of the real value, and the real value can be obtained from
  18514. * {@link Axis#getExtremes}.
  18515. *
  18516. * @name Highcharts.Axis#min
  18517. * @type {number|null}
  18518. */
  18519. axis.min = null;
  18520. /**
  18521. * The processed crosshair options.
  18522. *
  18523. * @name Highcharts.Axis#crosshair
  18524. * @type {boolean|Highcharts.AxisCrosshairOptions}
  18525. */
  18526. var crosshair = pick(options.crosshair,
  18527. splat(chart.options.tooltip.crosshairs)[isXAxis ? 0 : 1]);
  18528. axis.crosshair = crosshair === true ? {} : crosshair;
  18529. // Register. Don't add it again on Axis.update().
  18530. if (chart.axes.indexOf(axis) === -1) { //
  18531. if (isXAxis) { // #2713
  18532. chart.axes.splice(chart.xAxis.length, 0, axis);
  18533. }
  18534. else {
  18535. chart.axes.push(axis);
  18536. }
  18537. chart[axis.coll].push(axis);
  18538. }
  18539. /**
  18540. * All series associated to the axis.
  18541. *
  18542. * @name Highcharts.Axis#series
  18543. * @type {Array<Highcharts.Series>}
  18544. */
  18545. axis.series = axis.series || []; // populated by Series
  18546. // Reversed axis
  18547. if (chart.inverted &&
  18548. !axis.isZAxis &&
  18549. isXAxis &&
  18550. typeof axis.reversed === 'undefined') {
  18551. axis.reversed = true;
  18552. }
  18553. axis.labelRotation = isNumber(labelsOptions.rotation) ?
  18554. labelsOptions.rotation :
  18555. void 0;
  18556. // Register event listeners
  18557. registerEventOptions(axis, options);
  18558. fireEvent(this, 'afterInit');
  18559. };
  18560. /**
  18561. * Merge and set options.
  18562. *
  18563. * @private
  18564. * @function Highcharts.Axis#setOptions
  18565. *
  18566. * @param {Highcharts.AxisOptions} userOptions
  18567. * Axis options.
  18568. *
  18569. * @fires Highcharts.Axis#event:afterSetOptions
  18570. */
  18571. Axis.prototype.setOptions = function (userOptions) {
  18572. this.options = merge(AxisDefaults.defaultXAxisOptions, (this.coll === 'yAxis') && AxisDefaults.defaultYAxisOptions, [
  18573. AxisDefaults.defaultTopAxisOptions,
  18574. AxisDefaults.defaultRightAxisOptions,
  18575. AxisDefaults.defaultBottomAxisOptions,
  18576. AxisDefaults.defaultLeftAxisOptions
  18577. ][this.side], merge(
  18578. // if set in setOptions (#1053):
  18579. defaultOptions[this.coll], userOptions));
  18580. fireEvent(this, 'afterSetOptions', { userOptions: userOptions });
  18581. };
  18582. /**
  18583. * The default label formatter. The context is a special config object for
  18584. * the label. In apps, use the
  18585. * [labels.formatter](https://api.highcharts.com/highcharts/xAxis.labels.formatter)
  18586. * instead, except when a modification is needed.
  18587. *
  18588. * @function Highcharts.Axis#defaultLabelFormatter
  18589. *
  18590. * @param {Highcharts.AxisLabelsFormatterContextObject} this
  18591. * Formatter context of axis label.
  18592. *
  18593. * @param {Highcharts.AxisLabelsFormatterContextObject} [ctx]
  18594. * Formatter context of axis label.
  18595. *
  18596. * @return {string}
  18597. * The formatted label content.
  18598. */
  18599. Axis.prototype.defaultLabelFormatter = function (ctx) {
  18600. var axis = this.axis,
  18601. chart = this.chart,
  18602. numberFormatter = chart.numberFormatter,
  18603. value = isNumber(this.value) ? this.value : NaN,
  18604. time = axis.chart.time,
  18605. categories = axis.categories,
  18606. dateTimeLabelFormat = this.dateTimeLabelFormat,
  18607. lang = defaultOptions.lang,
  18608. numericSymbols = lang.numericSymbols,
  18609. numSymMagnitude = lang.numericSymbolMagnitude || 1000,
  18610. // make sure the same symbol is added for all labels on a linear
  18611. // axis
  18612. numericSymbolDetector = axis.logarithmic ?
  18613. Math.abs(value) :
  18614. axis.tickInterval;
  18615. var i = numericSymbols && numericSymbols.length,
  18616. multi,
  18617. ret;
  18618. if (categories) {
  18619. ret = "" + this.value;
  18620. }
  18621. else if (dateTimeLabelFormat) { // datetime axis
  18622. ret = time.dateFormat(dateTimeLabelFormat, value);
  18623. }
  18624. else if (i && numericSymbolDetector >= 1000) {
  18625. // Decide whether we should add a numeric symbol like k (thousands)
  18626. // or M (millions). If we are to enable this in tooltip or other
  18627. // places as well, we can move this logic to the numberFormatter and
  18628. // enable it by a parameter.
  18629. while (i-- && typeof ret === 'undefined') {
  18630. multi = Math.pow(numSymMagnitude, i + 1);
  18631. if (
  18632. // Only accept a numeric symbol when the distance is more
  18633. // than a full unit. So for example if the symbol is k, we
  18634. // don't accept numbers like 0.5k.
  18635. numericSymbolDetector >= multi &&
  18636. // Accept one decimal before the symbol. Accepts 0.5k but
  18637. // not 0.25k. How does this work with the previous?
  18638. (value * 10) % multi === 0 &&
  18639. numericSymbols[i] !== null &&
  18640. value !== 0) { // #5480
  18641. ret = numberFormatter(value / multi, -1) + numericSymbols[i];
  18642. }
  18643. }
  18644. }
  18645. if (typeof ret === 'undefined') {
  18646. if (Math.abs(value) >= 10000) { // add thousands separators
  18647. ret = numberFormatter(value, -1);
  18648. }
  18649. else { // small numbers
  18650. ret = numberFormatter(value, -1, void 0, ''); // #2466
  18651. }
  18652. }
  18653. return ret;
  18654. };
  18655. /**
  18656. * Get the minimum and maximum for the series of each axis. The function
  18657. * analyzes the axis series and updates `this.dataMin` and `this.dataMax`.
  18658. *
  18659. * @private
  18660. * @function Highcharts.Axis#getSeriesExtremes
  18661. *
  18662. * @fires Highcharts.Axis#event:afterGetSeriesExtremes
  18663. * @fires Highcharts.Axis#event:getSeriesExtremes
  18664. */
  18665. Axis.prototype.getSeriesExtremes = function () {
  18666. var axis = this,
  18667. chart = axis.chart;
  18668. var xExtremes;
  18669. fireEvent(this, 'getSeriesExtremes', null, function () {
  18670. axis.hasVisibleSeries = false;
  18671. // Reset properties in case we're redrawing (#3353)
  18672. axis.dataMin = axis.dataMax = axis.threshold = null;
  18673. axis.softThreshold = !axis.isXAxis;
  18674. if (axis.stacking) {
  18675. axis.stacking.buildStacks();
  18676. }
  18677. // loop through this axis' series
  18678. axis.series.forEach(function (series) {
  18679. if (series.visible ||
  18680. !chart.options.chart.ignoreHiddenSeries) {
  18681. var seriesOptions = series.options;
  18682. var xData = void 0,
  18683. threshold = seriesOptions.threshold,
  18684. seriesDataMin = void 0,
  18685. seriesDataMax = void 0;
  18686. axis.hasVisibleSeries = true;
  18687. // Validate threshold in logarithmic axes
  18688. if (axis.positiveValuesOnly && threshold <= 0) {
  18689. threshold = null;
  18690. }
  18691. // Get dataMin and dataMax for X axes
  18692. if (axis.isXAxis) {
  18693. xData = series.xData;
  18694. if (xData.length) {
  18695. var isPositive = function (number) { return number > 0; };
  18696. xData = axis.logarithmic ?
  18697. xData.filter(axis.validatePositiveValue) :
  18698. xData;
  18699. xExtremes = series.getXExtremes(xData);
  18700. // If xData contains values which is not numbers,
  18701. // then filter them out. To prevent performance hit,
  18702. // we only do this after we have already found
  18703. // seriesDataMin because in most cases all data is
  18704. // valid. #5234.
  18705. seriesDataMin = xExtremes.min;
  18706. seriesDataMax = xExtremes.max;
  18707. if (!isNumber(seriesDataMin) &&
  18708. // #5010:
  18709. !(seriesDataMin instanceof Date)) {
  18710. xData = xData.filter(isNumber);
  18711. xExtremes = series.getXExtremes(xData);
  18712. // Do it again with valid data
  18713. seriesDataMin = xExtremes.min;
  18714. seriesDataMax = xExtremes.max;
  18715. }
  18716. if (xData.length) {
  18717. axis.dataMin = Math.min(pick(axis.dataMin, seriesDataMin), seriesDataMin);
  18718. axis.dataMax = Math.max(pick(axis.dataMax, seriesDataMax), seriesDataMax);
  18719. }
  18720. }
  18721. // Get dataMin and dataMax for Y axes, as well as handle
  18722. // stacking and processed data
  18723. }
  18724. else {
  18725. // Get this particular series extremes
  18726. var dataExtremes = series.applyExtremes();
  18727. // Get the dataMin and dataMax so far. If percentage is
  18728. // used, the min and max are always 0 and 100. If
  18729. // seriesDataMin and seriesDataMax is null, then series
  18730. // doesn't have active y data, we continue with nulls
  18731. if (isNumber(dataExtremes.dataMin)) {
  18732. seriesDataMin = dataExtremes.dataMin;
  18733. axis.dataMin = Math.min(pick(axis.dataMin, seriesDataMin), seriesDataMin);
  18734. }
  18735. if (isNumber(dataExtremes.dataMax)) {
  18736. seriesDataMax = dataExtremes.dataMax;
  18737. axis.dataMax = Math.max(pick(axis.dataMax, seriesDataMax), seriesDataMax);
  18738. }
  18739. // Adjust to threshold
  18740. if (defined(threshold)) {
  18741. axis.threshold = threshold;
  18742. }
  18743. // If any series has a hard threshold, it takes
  18744. // precedence
  18745. if (!seriesOptions.softThreshold ||
  18746. axis.positiveValuesOnly) {
  18747. axis.softThreshold = false;
  18748. }
  18749. }
  18750. }
  18751. });
  18752. });
  18753. fireEvent(this, 'afterGetSeriesExtremes');
  18754. };
  18755. /**
  18756. * Translate from axis value to pixel position on the chart, or back. Use
  18757. * the `toPixels` and `toValue` functions in applications.
  18758. *
  18759. * @private
  18760. * @function Highcharts.Axis#translate
  18761. *
  18762. * @param {number} val
  18763. * TO-DO: parameter description
  18764. *
  18765. * @param {boolean|null} [backwards]
  18766. * TO-DO: parameter description
  18767. *
  18768. * @param {boolean|null} [cvsCoord]
  18769. * TO-DO: parameter description
  18770. *
  18771. * @param {boolean|null} [old]
  18772. * TO-DO: parameter description
  18773. *
  18774. * @param {boolean} [handleLog]
  18775. * TO-DO: parameter description
  18776. *
  18777. * @param {number} [pointPlacement]
  18778. * TO-DO: parameter description
  18779. *
  18780. * @return {number|undefined}
  18781. */
  18782. Axis.prototype.translate = function (val, backwards, cvsCoord, old, handleLog, pointPlacement) {
  18783. var axis = (this.linkedParent || this), // #1417
  18784. localMin = old && axis.old ? axis.old.min : axis.min,
  18785. minPixelPadding = axis.minPixelPadding,
  18786. doPostTranslate = (axis.isOrdinal ||
  18787. axis.brokenAxis && axis.brokenAxis.hasBreaks ||
  18788. (axis.logarithmic && handleLog)) && axis.lin2val;
  18789. var sign = 1,
  18790. cvsOffset = 0,
  18791. localA = old && axis.old ? axis.old.transA : axis.transA,
  18792. returnValue = 0;
  18793. if (!localA) {
  18794. localA = axis.transA;
  18795. }
  18796. // In vertical axes, the canvas coordinates start from 0 at the top like
  18797. // in SVG.
  18798. if (cvsCoord) {
  18799. sign *= -1; // canvas coordinates inverts the value
  18800. cvsOffset = axis.len;
  18801. }
  18802. // Handle reversed axis
  18803. if (axis.reversed) {
  18804. sign *= -1;
  18805. cvsOffset -= sign * (axis.sector || axis.len);
  18806. }
  18807. // From pixels to value
  18808. if (backwards) { // reverse translation
  18809. val = val * sign + cvsOffset;
  18810. val -= minPixelPadding;
  18811. // from chart pixel to value:
  18812. returnValue = val / localA + localMin;
  18813. if (doPostTranslate) { // log and ordinal axes
  18814. returnValue = axis.lin2val(returnValue);
  18815. }
  18816. // From value to pixels
  18817. }
  18818. else {
  18819. if (doPostTranslate) { // log and ordinal axes
  18820. val = axis.val2lin(val);
  18821. }
  18822. returnValue = isNumber(localMin) ?
  18823. (sign * (val - localMin) * localA +
  18824. cvsOffset +
  18825. (sign * minPixelPadding) +
  18826. (isNumber(pointPlacement) ?
  18827. localA * pointPlacement :
  18828. 0)) :
  18829. void 0;
  18830. }
  18831. return returnValue;
  18832. };
  18833. /**
  18834. * Translate a value in terms of axis units into pixels within the chart.
  18835. *
  18836. * @function Highcharts.Axis#toPixels
  18837. *
  18838. * @param {number} value
  18839. * A value in terms of axis units.
  18840. *
  18841. * @param {boolean} paneCoordinates
  18842. * Whether to return the pixel coordinate relative to the chart or just the
  18843. * axis/pane itself.
  18844. *
  18845. * @return {number}
  18846. * Pixel position of the value on the chart or axis.
  18847. */
  18848. Axis.prototype.toPixels = function (value, paneCoordinates) {
  18849. return this.translate(value, false, !this.horiz, null, true) +
  18850. (paneCoordinates ? 0 : this.pos);
  18851. };
  18852. /**
  18853. * Translate a pixel position along the axis to a value in terms of axis
  18854. * units.
  18855. *
  18856. * @function Highcharts.Axis#toValue
  18857. *
  18858. * @param {number} pixel
  18859. * The pixel value coordinate.
  18860. *
  18861. * @param {boolean} [paneCoordinates=false]
  18862. * Whether the input pixel is relative to the chart or just the axis/pane
  18863. * itself.
  18864. *
  18865. * @return {number}
  18866. * The axis value.
  18867. */
  18868. Axis.prototype.toValue = function (pixel, paneCoordinates) {
  18869. return this.translate(pixel - (paneCoordinates ? 0 : this.pos), true, !this.horiz, null, true);
  18870. };
  18871. /**
  18872. * Create the path for a plot line that goes from the given value on
  18873. * this axis, across the plot to the opposite side. Also used internally for
  18874. * grid lines and crosshairs.
  18875. *
  18876. * @function Highcharts.Axis#getPlotLinePath
  18877. *
  18878. * @param {Highcharts.AxisPlotLinePathOptionsObject} options
  18879. * Options for the path.
  18880. *
  18881. * @return {Highcharts.SVGPathArray|null}
  18882. * The SVG path definition for the plot line.
  18883. */
  18884. Axis.prototype.getPlotLinePath = function (options) {
  18885. var axis = this,
  18886. chart = axis.chart,
  18887. axisLeft = axis.left,
  18888. axisTop = axis.top,
  18889. old = options.old,
  18890. value = options.value,
  18891. lineWidth = options.lineWidth,
  18892. cHeight = (old && chart.oldChartHeight) || chart.chartHeight,
  18893. cWidth = (old && chart.oldChartWidth) || chart.chartWidth,
  18894. transB = axis.transB;
  18895. var translatedValue = options.translatedValue,
  18896. force = options.force,
  18897. x1,
  18898. y1,
  18899. x2,
  18900. y2,
  18901. skip;
  18902. // eslint-disable-next-line valid-jsdoc
  18903. /**
  18904. * Check if x is between a and b. If not, either move to a/b
  18905. * or skip, depending on the force parameter.
  18906. * @private
  18907. */
  18908. function between(x, a, b) {
  18909. if (force !== 'pass' && x < a || x > b) {
  18910. if (force) {
  18911. x = clamp(x, a, b);
  18912. }
  18913. else {
  18914. skip = true;
  18915. }
  18916. }
  18917. return x;
  18918. }
  18919. var evt = {
  18920. value: value,
  18921. lineWidth: lineWidth,
  18922. old: old,
  18923. force: force,
  18924. acrossPanes: options.acrossPanes,
  18925. translatedValue: translatedValue
  18926. };
  18927. fireEvent(this, 'getPlotLinePath', evt, function (e) {
  18928. translatedValue = pick(translatedValue, axis.translate(value, null, null, old));
  18929. // Keep the translated value within sane bounds, and avoid Infinity
  18930. // to fail the isNumber test (#7709).
  18931. translatedValue = clamp(translatedValue, -1e5, 1e5);
  18932. x1 = x2 = Math.round(translatedValue + transB);
  18933. y1 = y2 = Math.round(cHeight - translatedValue - transB);
  18934. if (!isNumber(translatedValue)) { // no min or max
  18935. skip = true;
  18936. force = false; // #7175, don't force it when path is invalid
  18937. }
  18938. else if (axis.horiz) {
  18939. y1 = axisTop;
  18940. y2 = cHeight - axis.bottom;
  18941. x1 = x2 = between(x1, axisLeft, axisLeft + axis.width);
  18942. }
  18943. else {
  18944. x1 = axisLeft;
  18945. x2 = cWidth - axis.right;
  18946. y1 = y2 = between(y1, axisTop, axisTop + axis.height);
  18947. }
  18948. e.path = skip && !force ?
  18949. null :
  18950. chart.renderer.crispLine([['M', x1, y1], ['L', x2, y2]], lineWidth || 1);
  18951. });
  18952. return evt.path;
  18953. };
  18954. /**
  18955. * Internal function to get the tick positions of a linear axis to round
  18956. * values like whole tens or every five.
  18957. *
  18958. * @function Highcharts.Axis#getLinearTickPositions
  18959. *
  18960. * @param {number} tickInterval
  18961. * The normalized tick interval.
  18962. *
  18963. * @param {number} min
  18964. * Axis minimum.
  18965. *
  18966. * @param {number} max
  18967. * Axis maximum.
  18968. *
  18969. * @return {Array<number>}
  18970. * An array of axis values where ticks should be placed.
  18971. */
  18972. Axis.prototype.getLinearTickPositions = function (tickInterval, min, max) {
  18973. var roundedMin = correctFloat(Math.floor(min / tickInterval) * tickInterval),
  18974. roundedMax = correctFloat(Math.ceil(max / tickInterval) * tickInterval),
  18975. tickPositions = [];
  18976. var pos,
  18977. lastPos,
  18978. precision;
  18979. // When the precision is higher than what we filter out in
  18980. // correctFloat, skip it (#6183).
  18981. if (correctFloat(roundedMin + tickInterval) === roundedMin) {
  18982. precision = 20;
  18983. }
  18984. // For single points, add a tick regardless of the relative position
  18985. // (#2662, #6274)
  18986. if (this.single) {
  18987. return [min];
  18988. }
  18989. // Populate the intermediate values
  18990. pos = roundedMin;
  18991. while (pos <= roundedMax) {
  18992. // Place the tick on the rounded value
  18993. tickPositions.push(pos);
  18994. // Always add the raw tickInterval, not the corrected one.
  18995. pos = correctFloat(pos + tickInterval, precision);
  18996. // If the interval is not big enough in the current min - max range
  18997. // to actually increase the loop variable, we need to break out to
  18998. // prevent endless loop. Issue #619
  18999. if (pos === lastPos) {
  19000. break;
  19001. }
  19002. // Record the last value
  19003. lastPos = pos;
  19004. }
  19005. return tickPositions;
  19006. };
  19007. /**
  19008. * Resolve the new minorTicks/minorTickInterval options into the legacy
  19009. * loosely typed minorTickInterval option.
  19010. *
  19011. * @function Highcharts.Axis#getMinorTickInterval
  19012. *
  19013. * @return {number|"auto"|null}
  19014. */
  19015. Axis.prototype.getMinorTickInterval = function () {
  19016. var options = this.options;
  19017. if (options.minorTicks === true) {
  19018. return pick(options.minorTickInterval, 'auto');
  19019. }
  19020. if (options.minorTicks === false) {
  19021. return null;
  19022. }
  19023. return options.minorTickInterval;
  19024. };
  19025. /**
  19026. * Internal function to return the minor tick positions. For logarithmic
  19027. * axes, the same logic as for major ticks is reused.
  19028. *
  19029. * @function Highcharts.Axis#getMinorTickPositions
  19030. *
  19031. * @return {Array<number>}
  19032. * An array of axis values where ticks should be placed.
  19033. */
  19034. Axis.prototype.getMinorTickPositions = function () {
  19035. var axis = this,
  19036. options = axis.options,
  19037. tickPositions = axis.tickPositions,
  19038. minorTickInterval = axis.minorTickInterval,
  19039. pointRangePadding = axis.pointRangePadding || 0,
  19040. min = axis.min - pointRangePadding, // #1498
  19041. max = axis.max + pointRangePadding, // #1498
  19042. range = max - min;
  19043. var minorTickPositions = [],
  19044. pos;
  19045. // If minor ticks get too dense, they are hard to read, and may cause
  19046. // long running script. So we don't draw them.
  19047. if (range && range / minorTickInterval < axis.len / 3) { // #3875
  19048. var logarithmic_1 = axis.logarithmic;
  19049. if (logarithmic_1) {
  19050. // For each interval in the major ticks, compute the minor ticks
  19051. // separately.
  19052. this.paddedTicks.forEach(function (_pos, i, paddedTicks) {
  19053. if (i) {
  19054. minorTickPositions.push.apply(minorTickPositions, logarithmic_1.getLogTickPositions(minorTickInterval, paddedTicks[i - 1], paddedTicks[i], true));
  19055. }
  19056. });
  19057. }
  19058. else if (axis.dateTime &&
  19059. this.getMinorTickInterval() === 'auto') { // #1314
  19060. minorTickPositions = minorTickPositions.concat(axis.getTimeTicks(axis.dateTime.normalizeTimeTickInterval(minorTickInterval), min, max, options.startOfWeek));
  19061. }
  19062. else {
  19063. for (pos = min + (tickPositions[0] - min) % minorTickInterval; pos <= max; pos += minorTickInterval) {
  19064. // Very, very, tight grid lines (#5771)
  19065. if (pos === minorTickPositions[0]) {
  19066. break;
  19067. }
  19068. minorTickPositions.push(pos);
  19069. }
  19070. }
  19071. }
  19072. if (minorTickPositions.length !== 0) {
  19073. axis.trimTicks(minorTickPositions); // #3652 #3743 #1498 #6330
  19074. }
  19075. return minorTickPositions;
  19076. };
  19077. /**
  19078. * Adjust the min and max for the minimum range. Keep in mind that the
  19079. * series data is not yet processed, so we don't have information on data
  19080. * cropping and grouping, or updated `axis.pointRange` or
  19081. * `series.pointRange`. The data can't be processed until we have finally
  19082. * established min and max.
  19083. *
  19084. * @private
  19085. * @function Highcharts.Axis#adjustForMinRange
  19086. */
  19087. Axis.prototype.adjustForMinRange = function () {
  19088. var axis = this,
  19089. options = axis.options,
  19090. log = axis.logarithmic;
  19091. var min = axis.min,
  19092. max = axis.max,
  19093. zoomOffset,
  19094. spaceAvailable,
  19095. closestDataRange = 0,
  19096. i,
  19097. distance,
  19098. xData,
  19099. loopLength,
  19100. minArgs,
  19101. maxArgs,
  19102. minRange;
  19103. // Set the automatic minimum range based on the closest point distance
  19104. if (axis.isXAxis &&
  19105. typeof axis.minRange === 'undefined' &&
  19106. !log) {
  19107. if (defined(options.min) || defined(options.max)) {
  19108. axis.minRange = null; // don't do this again
  19109. }
  19110. else {
  19111. // Find the closest distance between raw data points, as opposed
  19112. // to closestPointRange that applies to processed points
  19113. // (cropped and grouped)
  19114. axis.series.forEach(function (series) {
  19115. xData = series.xData;
  19116. loopLength = series.xIncrement ? 1 : xData.length - 1;
  19117. if (xData.length > 1) {
  19118. for (i = loopLength; i > 0; i--) {
  19119. distance = xData[i] - xData[i - 1];
  19120. if (!closestDataRange || distance < closestDataRange) {
  19121. closestDataRange = distance;
  19122. }
  19123. }
  19124. }
  19125. });
  19126. axis.minRange = Math.min(closestDataRange * 5, axis.dataMax - axis.dataMin);
  19127. }
  19128. }
  19129. // if minRange is exceeded, adjust
  19130. if (max - min < axis.minRange) {
  19131. spaceAvailable =
  19132. axis.dataMax - axis.dataMin >=
  19133. axis.minRange;
  19134. minRange = axis.minRange;
  19135. zoomOffset = (minRange - max + min) / 2;
  19136. // if min and max options have been set, don't go beyond it
  19137. minArgs = [
  19138. min - zoomOffset,
  19139. pick(options.min, min - zoomOffset)
  19140. ];
  19141. // If space is available, stay within the data range
  19142. if (spaceAvailable) {
  19143. minArgs[2] = axis.logarithmic ?
  19144. axis.logarithmic.log2lin(axis.dataMin) :
  19145. axis.dataMin;
  19146. }
  19147. min = arrayMax(minArgs);
  19148. maxArgs = [
  19149. min + minRange,
  19150. pick(options.max, min + minRange)
  19151. ];
  19152. // If space is availabe, stay within the data range
  19153. if (spaceAvailable) {
  19154. maxArgs[2] = log ?
  19155. log.log2lin(axis.dataMax) :
  19156. axis.dataMax;
  19157. }
  19158. max = arrayMin(maxArgs);
  19159. // now if the max is adjusted, adjust the min back
  19160. if (max - min < minRange) {
  19161. minArgs[0] = max - minRange;
  19162. minArgs[1] = pick(options.min, max - minRange);
  19163. min = arrayMax(minArgs);
  19164. }
  19165. }
  19166. // Record modified extremes
  19167. axis.min = min;
  19168. axis.max = max;
  19169. };
  19170. /**
  19171. * Find the closestPointRange across all series.
  19172. *
  19173. * @private
  19174. * @function Highcharts.Axis#getClosest
  19175. *
  19176. * @return {number}
  19177. */
  19178. Axis.prototype.getClosest = function () {
  19179. var ret;
  19180. if (this.categories) {
  19181. ret = 1;
  19182. }
  19183. else {
  19184. this.series.forEach(function (series) {
  19185. var seriesClosest = series.closestPointRange,
  19186. visible = series.visible ||
  19187. !series.chart.options.chart.ignoreHiddenSeries;
  19188. if (!series.noSharedTooltip &&
  19189. defined(seriesClosest) &&
  19190. visible) {
  19191. ret = defined(ret) ?
  19192. Math.min(ret, seriesClosest) :
  19193. seriesClosest;
  19194. }
  19195. });
  19196. }
  19197. return ret;
  19198. };
  19199. /**
  19200. * When a point name is given and no x, search for the name in the existing
  19201. * categories, or if categories aren't provided, search names or create a
  19202. * new category (#2522).
  19203. *
  19204. * @private
  19205. * @function Highcharts.Axis#nameToX
  19206. *
  19207. * @param {Highcharts.Point} point
  19208. * The point to inspect.
  19209. *
  19210. * @return {number}
  19211. * The X value that the point is given.
  19212. */
  19213. Axis.prototype.nameToX = function (point) {
  19214. var explicitCategories = isArray(this.categories),
  19215. names = explicitCategories ? this.categories : this.names;
  19216. var nameX = point.options.x,
  19217. x;
  19218. point.series.requireSorting = false;
  19219. if (!defined(nameX)) {
  19220. nameX = this.options.uniqueNames ?
  19221. (explicitCategories ?
  19222. names.indexOf(point.name) :
  19223. pick(names.keys[point.name], -1)) :
  19224. point.series.autoIncrement();
  19225. }
  19226. if (nameX === -1) { // Not found in currenct categories
  19227. if (!explicitCategories) {
  19228. x = names.length;
  19229. }
  19230. }
  19231. else {
  19232. x = nameX;
  19233. }
  19234. // Write the last point's name to the names array
  19235. if (typeof x !== 'undefined') {
  19236. this.names[x] = point.name;
  19237. // Backwards mapping is much faster than array searching (#7725)
  19238. this.names.keys[point.name] = x;
  19239. }
  19240. return x;
  19241. };
  19242. /**
  19243. * When changes have been done to series data, update the axis.names.
  19244. *
  19245. * @private
  19246. * @function Highcharts.Axis#updateNames
  19247. */
  19248. Axis.prototype.updateNames = function () {
  19249. var axis = this,
  19250. names = this.names,
  19251. i = names.length;
  19252. if (i > 0) {
  19253. Object.keys(names.keys).forEach(function (key) {
  19254. delete (names.keys)[key];
  19255. });
  19256. names.length = 0;
  19257. this.minRange = this.userMinRange; // Reset
  19258. (this.series || []).forEach(function (series) {
  19259. // Reset incrementer (#5928)
  19260. series.xIncrement = null;
  19261. // When adding a series, points are not yet generated
  19262. if (!series.points || series.isDirtyData) {
  19263. // When we're updating the series with data that is longer
  19264. // than it was, and cropThreshold is passed, we need to make
  19265. // sure that the axis.max is increased _before_ running the
  19266. // premature processData. Otherwise this early iteration of
  19267. // processData will crop the points to axis.max, and the
  19268. // names array will be too short (#5857).
  19269. axis.max = Math.max(axis.max, series.xData.length - 1);
  19270. series.processData();
  19271. series.generatePoints();
  19272. }
  19273. series.data.forEach(function (point, i) {
  19274. var x;
  19275. if (point &&
  19276. point.options &&
  19277. typeof point.name !== 'undefined' // #9562
  19278. ) {
  19279. x = axis.nameToX(point);
  19280. if (typeof x !== 'undefined' && x !== point.x) {
  19281. point.x = x;
  19282. series.xData[i] = x;
  19283. }
  19284. }
  19285. });
  19286. });
  19287. }
  19288. };
  19289. /**
  19290. * Update translation information.
  19291. *
  19292. * @private
  19293. * @function Highcharts.Axis#setAxisTranslation
  19294. *
  19295. * @fires Highcharts.Axis#event:afterSetAxisTranslation
  19296. */
  19297. Axis.prototype.setAxisTranslation = function () {
  19298. var axis = this,
  19299. range = axis.max - axis.min,
  19300. linkedParent = axis.linkedParent,
  19301. hasCategories = !!axis.categories,
  19302. isXAxis = axis.isXAxis;
  19303. var pointRange = axis.axisPointRange || 0,
  19304. closestPointRange,
  19305. minPointOffset = 0,
  19306. pointRangePadding = 0,
  19307. ordinalCorrection,
  19308. transA = axis.transA;
  19309. // Adjust translation for padding. Y axis with categories need to go
  19310. // through the same (#1784).
  19311. if (isXAxis || hasCategories || pointRange) {
  19312. // Get the closest points
  19313. closestPointRange = axis.getClosest();
  19314. if (linkedParent) {
  19315. minPointOffset = linkedParent.minPointOffset;
  19316. pointRangePadding = linkedParent.pointRangePadding;
  19317. }
  19318. else {
  19319. axis.series.forEach(function (series) {
  19320. var seriesPointRange = hasCategories ?
  19321. 1 :
  19322. (isXAxis ?
  19323. pick(series.options.pointRange,
  19324. closestPointRange, 0) :
  19325. (axis.axisPointRange || 0)), // #2806
  19326. pointPlacement = series.options.pointPlacement;
  19327. pointRange = Math.max(pointRange, seriesPointRange);
  19328. if (!axis.single || hasCategories) {
  19329. // TODO: series should internally set x- and y-
  19330. // pointPlacement to simplify this logic.
  19331. var isPointPlacementAxis = series.is('xrange') ? !isXAxis : isXAxis;
  19332. // minPointOffset is the value padding to the left of
  19333. // the axis in order to make room for points with a
  19334. // pointRange, typically columns. When the
  19335. // pointPlacement option is 'between' or 'on', this
  19336. // padding does not apply.
  19337. minPointOffset = Math.max(minPointOffset, isPointPlacementAxis && isString(pointPlacement) ?
  19338. 0 :
  19339. seriesPointRange / 2);
  19340. // Determine the total padding needed to the length of
  19341. // the axis to make room for the pointRange. If the
  19342. // series' pointPlacement is 'on', no padding is added.
  19343. pointRangePadding = Math.max(pointRangePadding, isPointPlacementAxis && pointPlacement === 'on' ?
  19344. 0 :
  19345. seriesPointRange);
  19346. }
  19347. });
  19348. }
  19349. // Record minPointOffset and pointRangePadding
  19350. ordinalCorrection = axis.ordinal && axis.ordinal.slope && closestPointRange ?
  19351. axis.ordinal.slope / closestPointRange :
  19352. 1; // #988, #1853
  19353. axis.minPointOffset = minPointOffset =
  19354. minPointOffset * ordinalCorrection;
  19355. axis.pointRangePadding =
  19356. pointRangePadding = pointRangePadding * ordinalCorrection;
  19357. // pointRange means the width reserved for each point, like in a
  19358. // column chart
  19359. axis.pointRange = Math.min(pointRange, axis.single && hasCategories ? 1 : range);
  19360. // closestPointRange means the closest distance between points. In
  19361. // columns it is mostly equal to pointRange, but in lines pointRange
  19362. // is 0 while closestPointRange is some other value
  19363. if (isXAxis) {
  19364. axis.closestPointRange = closestPointRange;
  19365. }
  19366. }
  19367. // Secondary values
  19368. axis.translationSlope = axis.transA = transA =
  19369. axis.staticScale ||
  19370. axis.len / ((range + pointRangePadding) || 1);
  19371. // Translation addend
  19372. axis.transB = axis.horiz ? axis.left : axis.bottom;
  19373. axis.minPixelPadding = transA * minPointOffset;
  19374. fireEvent(this, 'afterSetAxisTranslation');
  19375. };
  19376. /**
  19377. * @private
  19378. * @function Highcharts.Axis#minFromRange
  19379. *
  19380. * @return {number|undefined}
  19381. */
  19382. Axis.prototype.minFromRange = function () {
  19383. var axis = this;
  19384. return axis.max - axis.range;
  19385. };
  19386. /**
  19387. * Set the tick positions to round values and optionally extend the extremes
  19388. * to the nearest tick.
  19389. *
  19390. * @private
  19391. * @function Highcharts.Axis#setTickInterval
  19392. *
  19393. * @param {boolean} secondPass
  19394. * TO-DO: parameter description
  19395. *
  19396. * @fires Highcharts.Axis#event:foundExtremes
  19397. */
  19398. Axis.prototype.setTickInterval = function (secondPass) {
  19399. var axis = this,
  19400. chart = axis.chart,
  19401. log = axis.logarithmic,
  19402. options = axis.options,
  19403. isXAxis = axis.isXAxis,
  19404. isLinked = axis.isLinked,
  19405. tickPixelIntervalOption = options.tickPixelInterval,
  19406. categories = axis.categories,
  19407. softThreshold = axis.softThreshold;
  19408. var maxPadding = options.maxPadding,
  19409. minPadding = options.minPadding,
  19410. length,
  19411. linkedParentExtremes,
  19412. tickIntervalOption = options.tickInterval,
  19413. threshold = isNumber(axis.threshold) ? axis.threshold : null,
  19414. thresholdMin,
  19415. thresholdMax,
  19416. hardMin,
  19417. hardMax;
  19418. if (!axis.dateTime && !categories && !isLinked) {
  19419. this.getTickAmount();
  19420. }
  19421. // Min or max set either by zooming/setExtremes or initial options
  19422. hardMin = pick(axis.userMin, options.min);
  19423. hardMax = pick(axis.userMax, options.max);
  19424. // Linked axis gets the extremes from the parent axis
  19425. if (isLinked) {
  19426. axis.linkedParent = chart[axis.coll][options.linkedTo];
  19427. linkedParentExtremes = axis.linkedParent.getExtremes();
  19428. axis.min = pick(linkedParentExtremes.min, linkedParentExtremes.dataMin);
  19429. axis.max = pick(linkedParentExtremes.max, linkedParentExtremes.dataMax);
  19430. if (options.type !== axis.linkedParent.options.type) {
  19431. // Can't link axes of different type
  19432. error(11, 1, chart);
  19433. }
  19434. // Initial min and max from the extreme data values
  19435. }
  19436. else {
  19437. // Adjust to hard threshold
  19438. if (softThreshold && defined(threshold)) {
  19439. if (axis.dataMin >= threshold) {
  19440. thresholdMin = threshold;
  19441. minPadding = 0;
  19442. }
  19443. else if (axis.dataMax <= threshold) {
  19444. thresholdMax = threshold;
  19445. maxPadding = 0;
  19446. }
  19447. }
  19448. axis.min = pick(hardMin, thresholdMin, axis.dataMin);
  19449. axis.max = pick(hardMax, thresholdMax, axis.dataMax);
  19450. }
  19451. if (log) {
  19452. if (axis.positiveValuesOnly &&
  19453. !secondPass &&
  19454. Math.min(axis.min, pick(axis.dataMin, axis.min)) <= 0) { // #978
  19455. // Can't plot negative values on log axis
  19456. error(10, 1, chart);
  19457. }
  19458. // The correctFloat cures #934, float errors on full tens. But it
  19459. // was too aggressive for #4360 because of conversion back to lin,
  19460. // therefore use precision 15.
  19461. axis.min = correctFloat(log.log2lin(axis.min), 16);
  19462. axis.max = correctFloat(log.log2lin(axis.max), 16);
  19463. }
  19464. // handle zoomed range
  19465. if (axis.range && defined(axis.max)) {
  19466. // #618, #6773:
  19467. axis.userMin = axis.min = hardMin =
  19468. Math.max(axis.dataMin, axis.minFromRange());
  19469. axis.userMax = hardMax = axis.max;
  19470. axis.range = null; // don't use it when running setExtremes
  19471. }
  19472. // Hook for Highcharts Stock Scroller.
  19473. // Consider combining with beforePadding.
  19474. fireEvent(axis, 'foundExtremes');
  19475. // Hook for adjusting this.min and this.max. Used by bubble series.
  19476. if (axis.beforePadding) {
  19477. axis.beforePadding();
  19478. }
  19479. // adjust min and max for the minimum range
  19480. axis.adjustForMinRange();
  19481. // Pad the values to get clear of the chart's edges. To avoid
  19482. // tickInterval taking the padding into account, we do this after
  19483. // computing tick interval (#1337).
  19484. if (!categories &&
  19485. !axis.axisPointRange &&
  19486. !(axis.stacking && axis.stacking.usePercentage) &&
  19487. !isLinked &&
  19488. defined(axis.min) &&
  19489. defined(axis.max)) {
  19490. length = axis.max - axis.min;
  19491. if (length) {
  19492. if (!defined(hardMin) && minPadding) {
  19493. axis.min -= length * minPadding;
  19494. }
  19495. if (!defined(hardMax) && maxPadding) {
  19496. axis.max += length * maxPadding;
  19497. }
  19498. }
  19499. }
  19500. // Handle options for floor, ceiling, softMin and softMax (#6359)
  19501. if (!isNumber(axis.userMin)) {
  19502. if (isNumber(options.softMin) && options.softMin < axis.min) {
  19503. axis.min = hardMin = options.softMin; // #6894
  19504. }
  19505. if (isNumber(options.floor)) {
  19506. axis.min = Math.max(axis.min, options.floor);
  19507. }
  19508. }
  19509. if (!isNumber(axis.userMax)) {
  19510. if (isNumber(options.softMax) && options.softMax > axis.max) {
  19511. axis.max = hardMax = options.softMax; // #6894
  19512. }
  19513. if (isNumber(options.ceiling)) {
  19514. axis.max = Math.min(axis.max, options.ceiling);
  19515. }
  19516. }
  19517. // When the threshold is soft, adjust the extreme value only if the data
  19518. // extreme and the padded extreme land on either side of the threshold.
  19519. // For example, a series of [0, 1, 2, 3] would make the yAxis add a tick
  19520. // for -1 because of the default minPadding and startOnTick options.
  19521. // This is prevented by the softThreshold option.
  19522. if (softThreshold && defined(axis.dataMin)) {
  19523. threshold = threshold || 0;
  19524. if (!defined(hardMin) &&
  19525. axis.min < threshold &&
  19526. axis.dataMin >= threshold) {
  19527. axis.min = axis.options.minRange ?
  19528. Math.min(threshold, axis.max -
  19529. axis.minRange) :
  19530. threshold;
  19531. }
  19532. else if (!defined(hardMax) &&
  19533. axis.max > threshold &&
  19534. axis.dataMax <= threshold) {
  19535. axis.max = axis.options.minRange ?
  19536. Math.max(threshold, axis.min +
  19537. axis.minRange) :
  19538. threshold;
  19539. }
  19540. }
  19541. // If min is bigger than highest, or if max less than lowest value, the
  19542. // chart should not render points. (#14417)
  19543. if (isNumber(axis.min) &&
  19544. isNumber(axis.max) &&
  19545. !this.chart.polar &&
  19546. (axis.min > axis.max)) {
  19547. if (defined(axis.options.min)) {
  19548. axis.max = axis.min;
  19549. }
  19550. else if (defined(axis.options.max)) {
  19551. axis.min = axis.max;
  19552. }
  19553. }
  19554. // get tickInterval
  19555. if (axis.min === axis.max ||
  19556. typeof axis.min === 'undefined' ||
  19557. typeof axis.max === 'undefined') {
  19558. axis.tickInterval = 1;
  19559. }
  19560. else if (isLinked &&
  19561. axis.linkedParent &&
  19562. !tickIntervalOption &&
  19563. tickPixelIntervalOption ===
  19564. axis.linkedParent.options.tickPixelInterval) {
  19565. axis.tickInterval = tickIntervalOption =
  19566. axis.linkedParent.tickInterval;
  19567. }
  19568. else {
  19569. axis.tickInterval = pick(tickIntervalOption, this.tickAmount ?
  19570. ((axis.max - axis.min) /
  19571. Math.max(this.tickAmount - 1, 1)) :
  19572. void 0,
  19573. // For categoried axis, 1 is default, for linear axis use
  19574. // tickPix
  19575. categories ?
  19576. 1 :
  19577. // don't let it be more than the data range
  19578. (axis.max - axis.min) *
  19579. tickPixelIntervalOption /
  19580. Math.max(axis.len, tickPixelIntervalOption));
  19581. }
  19582. // Now we're finished detecting min and max, crop and group series data.
  19583. // This is in turn needed in order to find tick positions in ordinal
  19584. // axes.
  19585. if (isXAxis && !secondPass) {
  19586. axis.series.forEach(function (series) {
  19587. series.processData(axis.min !== (axis.old && axis.old.min) ||
  19588. axis.max !== (axis.old && axis.old.max));
  19589. });
  19590. }
  19591. // set the translation factor used in translate function
  19592. axis.setAxisTranslation();
  19593. // hook for ordinal axes and radial axes
  19594. fireEvent(this, 'initialAxisTranslation');
  19595. // In column-like charts, don't cramp in more ticks than there are
  19596. // points (#1943, #4184)
  19597. if (axis.pointRange && !tickIntervalOption) {
  19598. axis.tickInterval = Math.max(axis.pointRange, axis.tickInterval);
  19599. }
  19600. // Before normalizing the tick interval, handle minimum tick interval.
  19601. // This applies only if tickInterval is not defined.
  19602. var minTickInterval = pick(options.minTickInterval,
  19603. // In datetime axes, don't go below the data interval, except when
  19604. // there are scatter-like series involved (#13369).
  19605. axis.dateTime &&
  19606. !axis.series.some(function (s) { return s.noSharedTooltip; }) ?
  19607. axis.closestPointRange : 0);
  19608. if (!tickIntervalOption && axis.tickInterval < minTickInterval) {
  19609. axis.tickInterval = minTickInterval;
  19610. }
  19611. // for linear axes, get magnitude and normalize the interval
  19612. if (!axis.dateTime && !axis.logarithmic && !tickIntervalOption) {
  19613. axis.tickInterval = normalizeTickInterval(axis.tickInterval, void 0, getMagnitude(axis.tickInterval), pick(options.allowDecimals,
  19614. // If the tick interval is greather than 0.5, avoid
  19615. // decimals, as linear axes are often used to render
  19616. // discrete values. #3363. If a tick amount is set, allow
  19617. // decimals by default, as it increases the chances for a
  19618. // good fit.
  19619. axis.tickInterval < 0.5 || this.tickAmount !== void 0), !!this.tickAmount);
  19620. }
  19621. // Prevent ticks from getting so close that we can't draw the labels
  19622. if (!this.tickAmount) {
  19623. axis.tickInterval = axis.unsquish();
  19624. }
  19625. this.setTickPositions();
  19626. };
  19627. /**
  19628. * Now we have computed the normalized tickInterval, get the tick positions.
  19629. *
  19630. * @private
  19631. * @function Highcharts.Axis#setTickPositions
  19632. *
  19633. * @fires Highcharts.Axis#event:afterSetTickPositions
  19634. */
  19635. Axis.prototype.setTickPositions = function () {
  19636. var axis = this,
  19637. options = this.options,
  19638. tickPositionsOption = options.tickPositions,
  19639. minorTickIntervalOption = this.getMinorTickInterval(),
  19640. hasVerticalPanning = this.hasVerticalPanning(),
  19641. isColorAxis = this.coll === 'colorAxis',
  19642. startOnTick = (isColorAxis || !hasVerticalPanning) && options.startOnTick,
  19643. endOnTick = (isColorAxis || !hasVerticalPanning) && options.endOnTick;
  19644. var tickPositions,
  19645. tickPositioner = options.tickPositioner;
  19646. // Set the tickmarkOffset
  19647. this.tickmarkOffset = (this.categories &&
  19648. options.tickmarkPlacement === 'between' &&
  19649. this.tickInterval === 1) ? 0.5 : 0; // #3202
  19650. // get minorTickInterval
  19651. this.minorTickInterval =
  19652. minorTickIntervalOption === 'auto' &&
  19653. this.tickInterval ?
  19654. this.tickInterval / 5 :
  19655. minorTickIntervalOption;
  19656. // When there is only one point, or all points have the same value on
  19657. // this axis, then min and max are equal and tickPositions.length is 0
  19658. // or 1. In this case, add some padding in order to center the point,
  19659. // but leave it with one tick. #1337.
  19660. this.single =
  19661. this.min === this.max &&
  19662. defined(this.min) &&
  19663. !this.tickAmount &&
  19664. (
  19665. // Data is on integer (#6563)
  19666. parseInt(this.min, 10) === this.min ||
  19667. // Between integers and decimals are not allowed (#6274)
  19668. options.allowDecimals !== false);
  19669. /**
  19670. * Contains the current positions that are laid out on the axis. The
  19671. * positions are numbers in terms of axis values. In a category axis
  19672. * they are integers, in a datetime axis they are also integers, but
  19673. * designating milliseconds.
  19674. *
  19675. * This property is read only - for modifying the tick positions, use
  19676. * the `tickPositioner` callback or [axis.tickPositions(
  19677. * https://api.highcharts.com/highcharts/xAxis.tickPositions) option
  19678. * instead.
  19679. *
  19680. * @name Highcharts.Axis#tickPositions
  19681. * @type {Highcharts.AxisTickPositionsArray|undefined}
  19682. */
  19683. this.tickPositions =
  19684. // Find the tick positions. Work on a copy (#1565)
  19685. tickPositions =
  19686. (tickPositionsOption && tickPositionsOption.slice());
  19687. if (!tickPositions) {
  19688. // Too many ticks (#6405). Create a friendly warning and provide two
  19689. // ticks so at least we can show the data series.
  19690. if ((!axis.ordinal || !axis.ordinal.positions) &&
  19691. ((this.max - this.min) /
  19692. this.tickInterval >
  19693. Math.max(2 * this.len, 200))) {
  19694. tickPositions = [this.min, this.max];
  19695. error(19, false, this.chart);
  19696. }
  19697. else if (axis.dateTime) {
  19698. tickPositions = axis.getTimeTicks(axis.dateTime.normalizeTimeTickInterval(this.tickInterval, options.units), this.min, this.max, options.startOfWeek, axis.ordinal && axis.ordinal.positions, this.closestPointRange, true);
  19699. }
  19700. else if (axis.logarithmic) {
  19701. tickPositions = axis.logarithmic.getLogTickPositions(this.tickInterval, this.min, this.max);
  19702. }
  19703. else {
  19704. tickPositions = this.getLinearTickPositions(this.tickInterval, this.min, this.max);
  19705. }
  19706. // Too dense ticks, keep only the first and last (#4477)
  19707. if (tickPositions.length > this.len) {
  19708. tickPositions = [tickPositions[0], tickPositions.pop()];
  19709. // Reduce doubled value (#7339)
  19710. if (tickPositions[0] === tickPositions[1]) {
  19711. tickPositions.length = 1;
  19712. }
  19713. }
  19714. this.tickPositions = tickPositions;
  19715. // Run the tick positioner callback, that allows modifying auto tick
  19716. // positions.
  19717. if (tickPositioner) {
  19718. tickPositioner = tickPositioner.apply(axis, [this.min, this.max]);
  19719. if (tickPositioner) {
  19720. this.tickPositions = tickPositions = tickPositioner;
  19721. }
  19722. }
  19723. }
  19724. // Reset min/max or remove extremes based on start/end on tick
  19725. this.paddedTicks = tickPositions.slice(0); // Used for logarithmic minor
  19726. this.trimTicks(tickPositions, startOnTick, endOnTick);
  19727. if (!this.isLinked) {
  19728. // Substract half a unit (#2619, #2846, #2515, #3390),
  19729. // but not in case of multiple ticks (#6897)
  19730. if (this.single &&
  19731. tickPositions.length < 2 &&
  19732. !this.categories &&
  19733. !this.series.some(function (s) {
  19734. return (s.is('heatmap') && s.options.pointPlacement === 'between');
  19735. })) {
  19736. this.min -= 0.5;
  19737. this.max += 0.5;
  19738. }
  19739. if (!tickPositionsOption && !tickPositioner) {
  19740. this.adjustTickAmount();
  19741. }
  19742. }
  19743. fireEvent(this, 'afterSetTickPositions');
  19744. };
  19745. /**
  19746. * Handle startOnTick and endOnTick by either adapting to padding min/max or
  19747. * rounded min/max. Also handle single data points.
  19748. *
  19749. * @private
  19750. * @function Highcharts.Axis#trimTicks
  19751. *
  19752. * @param {Array<number>} tickPositions
  19753. * TO-DO: parameter description
  19754. *
  19755. * @param {boolean} [startOnTick]
  19756. * TO-DO: parameter description
  19757. *
  19758. * @param {boolean} [endOnTick]
  19759. * TO-DO: parameter description
  19760. */
  19761. Axis.prototype.trimTicks = function (tickPositions, startOnTick, endOnTick) {
  19762. var roundedMin = tickPositions[0],
  19763. roundedMax = tickPositions[tickPositions.length - 1],
  19764. minPointOffset = (!this.isOrdinal && this.minPointOffset) || 0; // (#12716)
  19765. fireEvent(this, 'trimTicks');
  19766. if (!this.isLinked) {
  19767. if (startOnTick && roundedMin !== -Infinity) { // #6502
  19768. this.min = roundedMin;
  19769. }
  19770. else {
  19771. while (this.min - minPointOffset > tickPositions[0]) {
  19772. tickPositions.shift();
  19773. }
  19774. }
  19775. if (endOnTick) {
  19776. this.max = roundedMax;
  19777. }
  19778. else {
  19779. while (this.max + minPointOffset <
  19780. tickPositions[tickPositions.length - 1]) {
  19781. tickPositions.pop();
  19782. }
  19783. }
  19784. // If no tick are left, set one tick in the middle (#3195)
  19785. if (tickPositions.length === 0 &&
  19786. defined(roundedMin) &&
  19787. !this.options.tickPositions) {
  19788. tickPositions.push((roundedMax + roundedMin) / 2);
  19789. }
  19790. }
  19791. };
  19792. /**
  19793. * Check if there are multiple axes in the same pane.
  19794. *
  19795. * @private
  19796. * @function Highcharts.Axis#alignToOthers
  19797. *
  19798. * @return {boolean|undefined}
  19799. * True if there are other axes.
  19800. */
  19801. Axis.prototype.alignToOthers = function () {
  19802. var axis = this,
  19803. others = // Whether there is another axis to pair with this one
  19804. {},
  19805. options = axis.options;
  19806. var hasOther;
  19807. if (
  19808. // Only if alignTicks is true
  19809. this.chart.options.chart.alignTicks !== false &&
  19810. options.alignTicks &&
  19811. // Disabled when startOnTick or endOnTick are false (#7604)
  19812. options.startOnTick !== false &&
  19813. options.endOnTick !== false &&
  19814. // Don't try to align ticks on a log axis, they are not evenly
  19815. // spaced (#6021)
  19816. !axis.logarithmic) {
  19817. this.chart[this.coll].forEach(function (axis) {
  19818. var otherOptions = axis.options, horiz = axis.horiz, key = [
  19819. horiz ? otherOptions.left : otherOptions.top,
  19820. otherOptions.width,
  19821. otherOptions.height,
  19822. otherOptions.pane
  19823. ].join(',');
  19824. if (axis.series.length) { // #4442
  19825. if (others[key]) {
  19826. hasOther = true; // #4201
  19827. }
  19828. else {
  19829. others[key] = 1;
  19830. }
  19831. }
  19832. });
  19833. }
  19834. return hasOther;
  19835. };
  19836. /**
  19837. * Find the max ticks of either the x and y axis collection, and record it
  19838. * in `this.tickAmount`.
  19839. *
  19840. * @private
  19841. * @function Highcharts.Axis#getTickAmount
  19842. */
  19843. Axis.prototype.getTickAmount = function () {
  19844. var axis = this,
  19845. options = this.options,
  19846. tickPixelInterval = options.tickPixelInterval;
  19847. var tickAmount = options.tickAmount;
  19848. if (!defined(options.tickInterval) &&
  19849. !tickAmount &&
  19850. this.len < tickPixelInterval &&
  19851. !this.isRadial &&
  19852. !axis.logarithmic &&
  19853. options.startOnTick &&
  19854. options.endOnTick) {
  19855. tickAmount = 2;
  19856. }
  19857. if (!tickAmount && this.alignToOthers()) {
  19858. // Add 1 because 4 tick intervals require 5 ticks (including first
  19859. // and last)
  19860. tickAmount = Math.ceil(this.len / tickPixelInterval) + 1;
  19861. }
  19862. // For tick amounts of 2 and 3, compute five ticks and remove the
  19863. // intermediate ones. This prevents the axis from adding ticks that are
  19864. // too far away from the data extremes.
  19865. if (tickAmount < 4) {
  19866. this.finalTickAmt = tickAmount;
  19867. tickAmount = 5;
  19868. }
  19869. this.tickAmount = tickAmount;
  19870. };
  19871. /**
  19872. * When using multiple axes, adjust the number of ticks to match the highest
  19873. * number of ticks in that group.
  19874. *
  19875. * @private
  19876. * @function Highcharts.Axis#adjustTickAmount
  19877. */
  19878. Axis.prototype.adjustTickAmount = function () {
  19879. var axis = this,
  19880. axisOptions = axis.options,
  19881. tickInterval = axis.tickInterval,
  19882. tickPositions = axis.tickPositions,
  19883. tickAmount = axis.tickAmount,
  19884. finalTickAmt = axis.finalTickAmt,
  19885. currentTickAmount = tickPositions && tickPositions.length,
  19886. threshold = pick(axis.threshold,
  19887. axis.softThreshold ? 0 : null);
  19888. var len,
  19889. i;
  19890. if (axis.hasData() && isNumber(axis.min) && isNumber(axis.max)) { // #14769
  19891. if (currentTickAmount < tickAmount) {
  19892. while (tickPositions.length < tickAmount) {
  19893. // Extend evenly for both sides unless we're on the
  19894. // threshold (#3965)
  19895. if (tickPositions.length % 2 ||
  19896. axis.min === threshold) {
  19897. // to the end
  19898. tickPositions.push(correctFloat(tickPositions[tickPositions.length - 1] +
  19899. tickInterval));
  19900. }
  19901. else {
  19902. // to the start
  19903. tickPositions.unshift(correctFloat(tickPositions[0] - tickInterval));
  19904. }
  19905. }
  19906. axis.transA *= (currentTickAmount - 1) / (tickAmount - 1);
  19907. // Do not crop when ticks are not extremes (#9841)
  19908. axis.min = axisOptions.startOnTick ?
  19909. tickPositions[0] :
  19910. Math.min(axis.min, tickPositions[0]);
  19911. axis.max = axisOptions.endOnTick ?
  19912. tickPositions[tickPositions.length - 1] :
  19913. Math.max(axis.max, tickPositions[tickPositions.length - 1]);
  19914. // We have too many ticks, run second pass to try to reduce ticks
  19915. }
  19916. else if (currentTickAmount > tickAmount) {
  19917. axis.tickInterval *= 2;
  19918. axis.setTickPositions();
  19919. }
  19920. // The finalTickAmt property is set in getTickAmount
  19921. if (defined(finalTickAmt)) {
  19922. i = len = tickPositions.length;
  19923. while (i--) {
  19924. if (
  19925. // Remove every other tick
  19926. (finalTickAmt === 3 && i % 2 === 1) ||
  19927. // Remove all but first and last
  19928. (finalTickAmt <= 2 && i > 0 && i < len - 1)) {
  19929. tickPositions.splice(i, 1);
  19930. }
  19931. }
  19932. axis.finalTickAmt = void 0;
  19933. }
  19934. }
  19935. };
  19936. /**
  19937. * Set the scale based on data min and max, user set min and max or options.
  19938. *
  19939. * @private
  19940. * @function Highcharts.Axis#setScale
  19941. *
  19942. * @fires Highcharts.Axis#event:afterSetScale
  19943. */
  19944. Axis.prototype.setScale = function () {
  19945. var axis = this;
  19946. var isDirtyData = false,
  19947. isXAxisDirty = false;
  19948. axis.series.forEach(function (series) {
  19949. isDirtyData = isDirtyData || series.isDirtyData || series.isDirty;
  19950. // When x axis is dirty, we need new data extremes for y as
  19951. // well:
  19952. isXAxisDirty = (isXAxisDirty ||
  19953. (series.xAxis && series.xAxis.isDirty) ||
  19954. false);
  19955. });
  19956. // set the new axisLength
  19957. axis.setAxisSize();
  19958. var isDirtyAxisLength = axis.len !== (axis.old && axis.old.len);
  19959. // do we really need to go through all this?
  19960. if (isDirtyAxisLength ||
  19961. isDirtyData ||
  19962. isXAxisDirty ||
  19963. axis.isLinked ||
  19964. axis.forceRedraw ||
  19965. axis.userMin !== (axis.old && axis.old.userMin) ||
  19966. axis.userMax !== (axis.old && axis.old.userMax) ||
  19967. axis.alignToOthers()) {
  19968. if (axis.stacking) {
  19969. axis.stacking.resetStacks();
  19970. }
  19971. axis.forceRedraw = false;
  19972. // get data extremes if needed
  19973. axis.getSeriesExtremes();
  19974. // get fixed positions based on tickInterval
  19975. axis.setTickInterval();
  19976. // Mark as dirty if it is not already set to dirty and extremes have
  19977. // changed. #595.
  19978. if (!axis.isDirty) {
  19979. axis.isDirty =
  19980. isDirtyAxisLength ||
  19981. axis.min !== (axis.old && axis.old.min) ||
  19982. axis.max !== (axis.old && axis.old.max);
  19983. }
  19984. }
  19985. else if (axis.stacking) {
  19986. axis.stacking.cleanStacks();
  19987. }
  19988. // Recalculate panning state object, when the data
  19989. // has changed. It is required when vertical panning is enabled.
  19990. if (isDirtyData && axis.panningState) {
  19991. axis.panningState.isDirty = true;
  19992. }
  19993. fireEvent(this, 'afterSetScale');
  19994. };
  19995. /**
  19996. * Set the minimum and maximum of the axes after render time. If the
  19997. * `startOnTick` and `endOnTick` options are true, the minimum and maximum
  19998. * values are rounded off to the nearest tick. To prevent this, these
  19999. * options can be set to false before calling setExtremes. Also, setExtremes
  20000. * will not allow a range lower than the `minRange` option, which by default
  20001. * is the range of five points.
  20002. *
  20003. * @sample highcharts/members/axis-setextremes/
  20004. * Set extremes from a button
  20005. * @sample highcharts/members/axis-setextremes-datetime/
  20006. * Set extremes on a datetime axis
  20007. * @sample highcharts/members/axis-setextremes-off-ticks/
  20008. * Set extremes off ticks
  20009. * @sample stock/members/axis-setextremes/
  20010. * Set extremes in Highcharts Stock
  20011. * @sample maps/members/axis-setextremes/
  20012. * Set extremes in Highmaps
  20013. *
  20014. * @function Highcharts.Axis#setExtremes
  20015. *
  20016. * @param {number} [newMin]
  20017. * The new minimum value.
  20018. *
  20019. * @param {number} [newMax]
  20020. * The new maximum value.
  20021. *
  20022. * @param {boolean} [redraw=true]
  20023. * Whether to redraw the chart or wait for an explicit call to
  20024. * {@link Highcharts.Chart#redraw}
  20025. *
  20026. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=true]
  20027. * Enable or modify animations.
  20028. *
  20029. * @param {*} [eventArguments]
  20030. * Arguments to be accessed in event handler.
  20031. *
  20032. * @fires Highcharts.Axis#event:setExtremes
  20033. */
  20034. Axis.prototype.setExtremes = function (newMin, newMax, redraw, animation, eventArguments) {
  20035. var axis = this,
  20036. chart = axis.chart;
  20037. redraw = pick(redraw, true); // defaults to true
  20038. axis.series.forEach(function (serie) {
  20039. delete serie.kdTree;
  20040. });
  20041. // Extend the arguments with min and max
  20042. eventArguments = extend(eventArguments, {
  20043. min: newMin,
  20044. max: newMax
  20045. });
  20046. // Fire the event
  20047. fireEvent(axis, 'setExtremes', eventArguments, function () {
  20048. axis.userMin = newMin;
  20049. axis.userMax = newMax;
  20050. axis.eventArgs = eventArguments;
  20051. if (redraw) {
  20052. chart.redraw(animation);
  20053. }
  20054. });
  20055. };
  20056. /**
  20057. * Overridable method for zooming chart. Pulled out in a separate method to
  20058. * allow overriding in stock charts.
  20059. *
  20060. * @private
  20061. * @function Highcharts.Axis#zoom
  20062. *
  20063. * @param {number} newMin
  20064. * TO-DO: parameter description
  20065. *
  20066. * @param {number} newMax
  20067. * TO-DO: parameter description
  20068. *
  20069. * @return {boolean}
  20070. */
  20071. Axis.prototype.zoom = function (newMin, newMax) {
  20072. var axis = this,
  20073. dataMin = this.dataMin,
  20074. dataMax = this.dataMax,
  20075. options = this.options,
  20076. min = Math.min(dataMin,
  20077. pick(options.min,
  20078. dataMin)),
  20079. max = Math.max(dataMax,
  20080. pick(options.max,
  20081. dataMax)),
  20082. evt = {
  20083. newMin: newMin,
  20084. newMax: newMax
  20085. };
  20086. fireEvent(this, 'zoom', evt, function (e) {
  20087. // Use e.newMin and e.newMax - event handlers may have altered them
  20088. var newMin = e.newMin,
  20089. newMax = e.newMax;
  20090. if (newMin !== axis.min || newMax !== axis.max) { // #5790
  20091. // Prevent pinch zooming out of range. Check for defined is for
  20092. // #1946. #1734.
  20093. if (!axis.allowZoomOutside) {
  20094. // #6014, sometimes newMax will be smaller than min (or
  20095. // newMin will be larger than max).
  20096. if (defined(dataMin)) {
  20097. if (newMin < min) {
  20098. newMin = min;
  20099. }
  20100. if (newMin > max) {
  20101. newMin = max;
  20102. }
  20103. }
  20104. if (defined(dataMax)) {
  20105. if (newMax < min) {
  20106. newMax = min;
  20107. }
  20108. if (newMax > max) {
  20109. newMax = max;
  20110. }
  20111. }
  20112. }
  20113. // In full view, displaying the reset zoom button is not
  20114. // required
  20115. axis.displayBtn = (typeof newMin !== 'undefined' ||
  20116. typeof newMax !== 'undefined');
  20117. // Do it
  20118. axis.setExtremes(newMin, newMax, false, void 0, { trigger: 'zoom' });
  20119. }
  20120. e.zoomed = true;
  20121. });
  20122. return evt.zoomed;
  20123. };
  20124. /**
  20125. * Update the axis metrics.
  20126. *
  20127. * @private
  20128. * @function Highcharts.Axis#setAxisSize
  20129. */
  20130. Axis.prototype.setAxisSize = function () {
  20131. var chart = this.chart,
  20132. options = this.options,
  20133. // [top, right, bottom, left]
  20134. offsets = options.offsets || [0, 0, 0, 0],
  20135. horiz = this.horiz,
  20136. // Check for percentage based input values. Rounding fixes problems
  20137. // with column overflow and plot line filtering (#4898, #4899)
  20138. width = this.width = Math.round(relativeLength(pick(options.width,
  20139. chart.plotWidth - offsets[3] + offsets[1]),
  20140. chart.plotWidth)),
  20141. height = this.height = Math.round(relativeLength(pick(options.height,
  20142. chart.plotHeight - offsets[0] + offsets[2]),
  20143. chart.plotHeight)),
  20144. top = this.top = Math.round(relativeLength(pick(options.top,
  20145. chart.plotTop + offsets[0]),
  20146. chart.plotHeight,
  20147. chart.plotTop)),
  20148. left = this.left = Math.round(relativeLength(pick(options.left,
  20149. chart.plotLeft + offsets[3]),
  20150. chart.plotWidth,
  20151. chart.plotLeft));
  20152. // Expose basic values to use in Series object and navigator
  20153. this.bottom = chart.chartHeight - height - top;
  20154. this.right = chart.chartWidth - width - left;
  20155. // Direction agnostic properties
  20156. this.len = Math.max(horiz ? width : height, 0); // Math.max fixes #905
  20157. this.pos = horiz ? left : top; // distance from SVG origin
  20158. };
  20159. /**
  20160. * Get the current extremes for the axis.
  20161. *
  20162. * @sample highcharts/members/axis-getextremes/
  20163. * Report extremes by click on a button
  20164. * @sample maps/members/axis-getextremes/
  20165. * Get extremes in Highmaps
  20166. *
  20167. * @function Highcharts.Axis#getExtremes
  20168. *
  20169. * @return {Highcharts.ExtremesObject}
  20170. * An object containing extremes information.
  20171. */
  20172. Axis.prototype.getExtremes = function () {
  20173. var axis = this,
  20174. log = axis.logarithmic;
  20175. return {
  20176. min: log ?
  20177. correctFloat(log.lin2log(axis.min)) :
  20178. axis.min,
  20179. max: log ?
  20180. correctFloat(log.lin2log(axis.max)) :
  20181. axis.max,
  20182. dataMin: axis.dataMin,
  20183. dataMax: axis.dataMax,
  20184. userMin: axis.userMin,
  20185. userMax: axis.userMax
  20186. };
  20187. };
  20188. /**
  20189. * Get the zero plane either based on zero or on the min or max value.
  20190. * Used in bar and area plots.
  20191. *
  20192. * @function Highcharts.Axis#getThreshold
  20193. *
  20194. * @param {number} threshold
  20195. * The threshold in axis values.
  20196. *
  20197. * @return {number|undefined}
  20198. * The translated threshold position in terms of pixels, and corrected to
  20199. * stay within the axis bounds.
  20200. */
  20201. Axis.prototype.getThreshold = function (threshold) {
  20202. var axis = this,
  20203. log = axis.logarithmic,
  20204. realMin = log ? log.lin2log(axis.min) : axis.min,
  20205. realMax = log ? log.lin2log(axis.max) : axis.max;
  20206. if (threshold === null || threshold === -Infinity) {
  20207. threshold = realMin;
  20208. }
  20209. else if (threshold === Infinity) {
  20210. threshold = realMax;
  20211. }
  20212. else if (realMin > threshold) {
  20213. threshold = realMin;
  20214. }
  20215. else if (realMax < threshold) {
  20216. threshold = realMax;
  20217. }
  20218. return axis.translate(threshold, 0, 1, 0, 1);
  20219. };
  20220. /**
  20221. * Compute auto alignment for the axis label based on which side the axis is
  20222. * on and the given rotation for the label.
  20223. *
  20224. * @private
  20225. * @function Highcharts.Axis#autoLabelAlign
  20226. *
  20227. * @param {number} rotation
  20228. * The rotation in degrees as set by either the `rotation` or `autoRotation`
  20229. * options.
  20230. *
  20231. * @return {Highcharts.AlignValue}
  20232. * Can be `"center"`, `"left"` or `"right"`.
  20233. */
  20234. Axis.prototype.autoLabelAlign = function (rotation) {
  20235. var angle = (pick(rotation, 0) - (this.side * 90) + 720) % 360,
  20236. evt = { align: 'center' };
  20237. fireEvent(this, 'autoLabelAlign', evt, function (e) {
  20238. if (angle > 15 && angle < 165) {
  20239. e.align = 'right';
  20240. }
  20241. else if (angle > 195 && angle < 345) {
  20242. e.align = 'left';
  20243. }
  20244. });
  20245. return evt.align;
  20246. };
  20247. /**
  20248. * Get the tick length and width for the axis based on axis options.
  20249. *
  20250. * @private
  20251. * @function Highcharts.Axis#tickSize
  20252. *
  20253. * @param {string} [prefix]
  20254. * 'tick' or 'minorTick'
  20255. *
  20256. * @return {Array<number,number>|undefined}
  20257. * An array of tickLength and tickWidth
  20258. */
  20259. Axis.prototype.tickSize = function (prefix) {
  20260. var options = this.options,
  20261. tickWidth = pick(options[prefix === 'tick' ? 'tickWidth' : 'minorTickWidth'],
  20262. // Default to 1 on linear and datetime X axes
  20263. prefix === 'tick' && this.isXAxis && !this.categories ? 1 : 0);
  20264. var tickLength = options[prefix === 'tick' ? 'tickLength' : 'minorTickLength'],
  20265. tickSize;
  20266. if (tickWidth && tickLength) {
  20267. // Negate the length
  20268. if (options[prefix + 'Position'] === 'inside') {
  20269. tickLength = -tickLength;
  20270. }
  20271. tickSize = [tickLength, tickWidth];
  20272. }
  20273. var e = { tickSize: tickSize };
  20274. fireEvent(this, 'afterTickSize', e);
  20275. return e.tickSize;
  20276. };
  20277. /**
  20278. * Return the size of the labels.
  20279. *
  20280. * @private
  20281. * @function Highcharts.Axis#labelMetrics
  20282. *
  20283. * @return {Highcharts.FontMetricsObject}
  20284. */
  20285. Axis.prototype.labelMetrics = function () {
  20286. var index = this.tickPositions && this.tickPositions[0] || 0;
  20287. return this.chart.renderer.fontMetrics(this.options.labels.style.fontSize, this.ticks[index] && this.ticks[index].label);
  20288. };
  20289. /**
  20290. * Prevent the ticks from getting so close we can't draw the labels. On a
  20291. * horizontal axis, this is handled by rotating the labels, removing ticks
  20292. * and adding ellipsis. On a vertical axis remove ticks and add ellipsis.
  20293. *
  20294. * @private
  20295. * @function Highcharts.Axis#unsquish
  20296. *
  20297. * @return {number}
  20298. */
  20299. Axis.prototype.unsquish = function () {
  20300. var labelOptions = this.options.labels,
  20301. horiz = this.horiz,
  20302. tickInterval = this.tickInterval,
  20303. slotSize = this.len / (((this.categories ? 1 : 0) +
  20304. this.max -
  20305. this.min) /
  20306. tickInterval),
  20307. rotationOption = labelOptions.rotation,
  20308. labelMetrics = this.labelMetrics(),
  20309. range = Math.max(this.max - this.min, 0),
  20310. // Return the multiple of tickInterval that is needed to avoid
  20311. // collision
  20312. getStep = function (spaceNeeded) {
  20313. var step = spaceNeeded / (slotSize || 1);
  20314. step = step > 1 ? Math.ceil(step) : 1;
  20315. // Guard for very small or negative angles (#9835)
  20316. if (step * tickInterval > range &&
  20317. spaceNeeded !== Infinity &&
  20318. slotSize !== Infinity &&
  20319. range) {
  20320. step = Math.ceil(range / tickInterval);
  20321. }
  20322. return correctFloat(step * tickInterval);
  20323. };
  20324. var newTickInterval = tickInterval,
  20325. rotation,
  20326. step,
  20327. bestScore = Number.MAX_VALUE,
  20328. autoRotation;
  20329. if (horiz) {
  20330. if (!labelOptions.staggerLines && !labelOptions.step) {
  20331. if (isNumber(rotationOption)) {
  20332. autoRotation = [rotationOption];
  20333. }
  20334. else if (slotSize < labelOptions.autoRotationLimit) {
  20335. autoRotation = labelOptions.autoRotation;
  20336. }
  20337. }
  20338. if (autoRotation) {
  20339. // Loop over the given autoRotation options, and determine
  20340. // which gives the best score. The best score is that with
  20341. // the lowest number of steps and a rotation closest
  20342. // to horizontal.
  20343. autoRotation.forEach(function (rot) {
  20344. var score;
  20345. if (rot === rotationOption ||
  20346. (rot && rot >= -90 && rot <= 90)) { // #3891
  20347. step = getStep(Math.abs(labelMetrics.h / Math.sin(deg2rad * rot)));
  20348. score = step + Math.abs(rot / 360);
  20349. if (score < bestScore) {
  20350. bestScore = score;
  20351. rotation = rot;
  20352. newTickInterval = step;
  20353. }
  20354. }
  20355. });
  20356. }
  20357. }
  20358. else if (!labelOptions.step) { // #4411
  20359. newTickInterval = getStep(labelMetrics.h);
  20360. }
  20361. this.autoRotation = autoRotation;
  20362. this.labelRotation = pick(rotation, isNumber(rotationOption) ? rotationOption : 0);
  20363. return newTickInterval;
  20364. };
  20365. /**
  20366. * Get the general slot width for labels/categories on this axis. This may
  20367. * change between the pre-render (from Axis.getOffset) and the final tick
  20368. * rendering and placement.
  20369. *
  20370. * @private
  20371. * @function Highcharts.Axis#getSlotWidth
  20372. *
  20373. * @param {Highcharts.Tick} [tick] Optionally, calculate the slot width
  20374. * basing on tick label. It is used in highcharts-3d module, where the slots
  20375. * has different widths depending on perspective angles.
  20376. *
  20377. * @return {number}
  20378. * The pixel width allocated to each axis label.
  20379. */
  20380. Axis.prototype.getSlotWidth = function (tick) {
  20381. // #5086, #1580, #1931
  20382. var chart = this.chart,
  20383. horiz = this.horiz,
  20384. labelOptions = this.options.labels,
  20385. slotCount = Math.max(this.tickPositions.length - (this.categories ? 0 : 1), 1),
  20386. marginLeft = chart.margin[3];
  20387. // Used by grid axis
  20388. if (tick && isNumber(tick.slotWidth)) { // #13221, can be 0
  20389. return tick.slotWidth;
  20390. }
  20391. if (horiz && labelOptions.step < 2) {
  20392. if (labelOptions.rotation) { // #4415
  20393. return 0;
  20394. }
  20395. return ((this.staggerLines || 1) * this.len) / slotCount;
  20396. }
  20397. if (!horiz) {
  20398. // #7028
  20399. var cssWidth = labelOptions.style.width;
  20400. if (cssWidth !== void 0) {
  20401. return parseInt(String(cssWidth), 10);
  20402. }
  20403. if (marginLeft) {
  20404. return marginLeft - chart.spacing[3];
  20405. }
  20406. }
  20407. // Last resort, a fraction of the available size
  20408. return chart.chartWidth * 0.33;
  20409. };
  20410. /**
  20411. * Render the axis labels and determine whether ellipsis or rotation need to
  20412. * be applied.
  20413. *
  20414. * @private
  20415. * @function Highcharts.Axis#renderUnsquish
  20416. */
  20417. Axis.prototype.renderUnsquish = function () {
  20418. var chart = this.chart,
  20419. renderer = chart.renderer,
  20420. tickPositions = this.tickPositions,
  20421. ticks = this.ticks,
  20422. labelOptions = this.options.labels,
  20423. labelStyleOptions = labelOptions.style,
  20424. horiz = this.horiz,
  20425. slotWidth = this.getSlotWidth(),
  20426. innerWidth = Math.max(1,
  20427. Math.round(slotWidth - 2 * labelOptions.padding)),
  20428. attr = {},
  20429. labelMetrics = this.labelMetrics(),
  20430. textOverflowOption = labelStyleOptions.textOverflow;
  20431. var commonWidth,
  20432. commonTextOverflow,
  20433. maxLabelLength = 0,
  20434. label,
  20435. i,
  20436. pos;
  20437. // Set rotation option unless it is "auto", like in gauges
  20438. if (!isString(labelOptions.rotation)) {
  20439. // #4443
  20440. attr.rotation = labelOptions.rotation || 0;
  20441. }
  20442. // Get the longest label length
  20443. tickPositions.forEach(function (tickPosition) {
  20444. var tick = ticks[tickPosition];
  20445. // Replace label - sorting animation
  20446. if (tick.movedLabel) {
  20447. tick.replaceMovedLabel();
  20448. }
  20449. if (tick &&
  20450. tick.label &&
  20451. tick.label.textPxLength > maxLabelLength) {
  20452. maxLabelLength = tick.label.textPxLength;
  20453. }
  20454. });
  20455. this.maxLabelLength = maxLabelLength;
  20456. // Handle auto rotation on horizontal axis
  20457. if (this.autoRotation) {
  20458. // Apply rotation only if the label is too wide for the slot, and
  20459. // the label is wider than its height.
  20460. if (maxLabelLength > innerWidth &&
  20461. maxLabelLength > labelMetrics.h) {
  20462. attr.rotation = this.labelRotation;
  20463. }
  20464. else {
  20465. this.labelRotation = 0;
  20466. }
  20467. // Handle word-wrap or ellipsis on vertical axis
  20468. }
  20469. else if (slotWidth) {
  20470. // For word-wrap or ellipsis
  20471. commonWidth = innerWidth;
  20472. if (!textOverflowOption) {
  20473. commonTextOverflow = 'clip';
  20474. // On vertical axis, only allow word wrap if there is room
  20475. // for more lines.
  20476. i = tickPositions.length;
  20477. while (!horiz && i--) {
  20478. pos = tickPositions[i];
  20479. label = ticks[pos].label;
  20480. if (label) {
  20481. // Reset ellipsis in order to get the correct
  20482. // bounding box (#4070)
  20483. if (label.styles &&
  20484. label.styles.textOverflow === 'ellipsis') {
  20485. label.css({ textOverflow: 'clip' });
  20486. // Set the correct width in order to read
  20487. // the bounding box height (#4678, #5034)
  20488. }
  20489. else if (label.textPxLength > slotWidth) {
  20490. label.css({ width: slotWidth + 'px' });
  20491. }
  20492. if (label.getBBox().height > (this.len / tickPositions.length -
  20493. (labelMetrics.h - labelMetrics.f))) {
  20494. label.specificTextOverflow = 'ellipsis';
  20495. }
  20496. }
  20497. }
  20498. }
  20499. }
  20500. // Add ellipsis if the label length is significantly longer than ideal
  20501. if (attr.rotation) {
  20502. commonWidth = (maxLabelLength > chart.chartHeight * 0.5 ?
  20503. chart.chartHeight * 0.33 :
  20504. maxLabelLength);
  20505. if (!textOverflowOption) {
  20506. commonTextOverflow = 'ellipsis';
  20507. }
  20508. }
  20509. // Set the explicit or automatic label alignment
  20510. this.labelAlign = labelOptions.align ||
  20511. this.autoLabelAlign(this.labelRotation);
  20512. if (this.labelAlign) {
  20513. attr.align = this.labelAlign;
  20514. }
  20515. // Apply general and specific CSS
  20516. tickPositions.forEach(function (pos) {
  20517. var tick = ticks[pos],
  20518. label = tick && tick.label,
  20519. widthOption = labelStyleOptions.width,
  20520. css = {};
  20521. if (label) {
  20522. // This needs to go before the CSS in old IE (#4502)
  20523. label.attr(attr);
  20524. if (tick.shortenLabel) {
  20525. tick.shortenLabel();
  20526. }
  20527. else if (commonWidth &&
  20528. !widthOption &&
  20529. // Setting width in this case messes with the bounding box
  20530. // (#7975)
  20531. labelStyleOptions.whiteSpace !== 'nowrap' &&
  20532. (
  20533. // Speed optimizing, #7656
  20534. commonWidth < label.textPxLength ||
  20535. // Resetting CSS, #4928
  20536. label.element.tagName === 'SPAN')) {
  20537. css.width = commonWidth + 'px';
  20538. if (!textOverflowOption) {
  20539. css.textOverflow = (label.specificTextOverflow ||
  20540. commonTextOverflow);
  20541. }
  20542. label.css(css);
  20543. // Reset previously shortened label (#8210)
  20544. }
  20545. else if (label.styles &&
  20546. label.styles.width &&
  20547. !css.width &&
  20548. !widthOption) {
  20549. label.css({ width: null });
  20550. }
  20551. delete label.specificTextOverflow;
  20552. tick.rotation = attr.rotation;
  20553. }
  20554. }, this);
  20555. // Note: Why is this not part of getLabelPosition?
  20556. this.tickRotCorr = renderer.rotCorr(labelMetrics.b, this.labelRotation || 0, this.side !== 0);
  20557. };
  20558. /**
  20559. * Return true if the axis has associated data.
  20560. *
  20561. * @function Highcharts.Axis#hasData
  20562. *
  20563. * @return {boolean}
  20564. * True if the axis has associated visible series and those series have
  20565. * either valid data points or explicit `min` and `max` settings.
  20566. */
  20567. Axis.prototype.hasData = function () {
  20568. return this.series.some(function (s) {
  20569. return s.hasData();
  20570. }) ||
  20571. (this.options.showEmpty &&
  20572. defined(this.min) &&
  20573. defined(this.max));
  20574. };
  20575. /**
  20576. * Adds the title defined in axis.options.title.
  20577. *
  20578. * @function Highcharts.Axis#addTitle
  20579. *
  20580. * @param {boolean} [display]
  20581. * Whether or not to display the title.
  20582. */
  20583. Axis.prototype.addTitle = function (display) {
  20584. var axis = this,
  20585. renderer = axis.chart.renderer,
  20586. horiz = axis.horiz,
  20587. opposite = axis.opposite,
  20588. options = axis.options,
  20589. axisTitleOptions = options.title,
  20590. styledMode = axis.chart.styledMode;
  20591. var textAlign;
  20592. if (!axis.axisTitle) {
  20593. textAlign = axisTitleOptions.textAlign;
  20594. if (!textAlign) {
  20595. textAlign = (horiz ? {
  20596. low: 'left',
  20597. middle: 'center',
  20598. high: 'right'
  20599. } : {
  20600. low: opposite ? 'right' : 'left',
  20601. middle: 'center',
  20602. high: opposite ? 'left' : 'right'
  20603. })[axisTitleOptions.align];
  20604. }
  20605. axis.axisTitle = renderer
  20606. .text(axisTitleOptions.text || '', 0, 0, axisTitleOptions.useHTML)
  20607. .attr({
  20608. zIndex: 7,
  20609. rotation: axisTitleOptions.rotation,
  20610. align: textAlign
  20611. })
  20612. .addClass('highcharts-axis-title');
  20613. // #7814, don't mutate style option
  20614. if (!styledMode) {
  20615. axis.axisTitle.css(merge(axisTitleOptions.style));
  20616. }
  20617. axis.axisTitle.add(axis.axisGroup);
  20618. axis.axisTitle.isNew = true;
  20619. }
  20620. // Max width defaults to the length of the axis
  20621. if (!styledMode &&
  20622. !axisTitleOptions.style.width &&
  20623. !axis.isRadial) {
  20624. axis.axisTitle.css({
  20625. width: axis.len + 'px'
  20626. });
  20627. }
  20628. // hide or show the title depending on whether showEmpty is set
  20629. axis.axisTitle[display ? 'show' : 'hide'](display);
  20630. };
  20631. /**
  20632. * Generates a tick for initial positioning.
  20633. *
  20634. * @private
  20635. * @function Highcharts.Axis#generateTick
  20636. *
  20637. * @param {number} pos
  20638. * The tick position in axis values.
  20639. *
  20640. * @param {number} [i]
  20641. * The index of the tick in {@link Axis.tickPositions}.
  20642. */
  20643. Axis.prototype.generateTick = function (pos) {
  20644. var axis = this,
  20645. ticks = axis.ticks;
  20646. if (!ticks[pos]) {
  20647. ticks[pos] = new Tick(axis, pos);
  20648. }
  20649. else {
  20650. ticks[pos].addLabel(); // update labels depending on tick interval
  20651. }
  20652. };
  20653. /**
  20654. * Render the tick labels to a preliminary position to get their sizes
  20655. *
  20656. * @private
  20657. * @function Highcharts.Axis#getOffset
  20658. *
  20659. * @fires Highcharts.Axis#event:afterGetOffset
  20660. */
  20661. Axis.prototype.getOffset = function () {
  20662. var _this = this;
  20663. var axis = this,
  20664. chart = axis.chart,
  20665. renderer = chart.renderer,
  20666. options = axis.options,
  20667. tickPositions = axis.tickPositions,
  20668. ticks = axis.ticks,
  20669. horiz = axis.horiz,
  20670. side = axis.side,
  20671. invertedSide = (chart.inverted && !axis.isZAxis ?
  20672. [1, 0, 3, 2][side] :
  20673. side),
  20674. hasData = axis.hasData(),
  20675. axisTitleOptions = options.title,
  20676. labelOptions = options.labels,
  20677. axisOffset = chart.axisOffset,
  20678. clipOffset = chart.clipOffset,
  20679. directionFactor = [-1, 1, 1, -1][side],
  20680. className = options.className,
  20681. axisParent = axis.axisParent; // Used in color axis
  20682. var showAxis,
  20683. titleOffset = 0,
  20684. titleOffsetOption,
  20685. titleMargin = 0,
  20686. labelOffset = 0, // reset
  20687. labelOffsetPadded,
  20688. lineHeightCorrection;
  20689. // For reuse in Axis.render
  20690. axis.showAxis = showAxis = hasData || options.showEmpty;
  20691. // Set/reset staggerLines
  20692. axis.staggerLines = (axis.horiz && labelOptions.staggerLines) || void 0;
  20693. // Create the axisGroup and gridGroup elements on first iteration
  20694. if (!axis.axisGroup) {
  20695. var createGroup = function (name,
  20696. suffix,
  20697. zIndex) { return renderer.g(name)
  20698. .attr({ zIndex: zIndex })
  20699. .addClass("highcharts-" + _this.coll.toLowerCase() + suffix + " " +
  20700. (_this.isRadial ? "highcharts-radial-axis" + suffix + " " : '') +
  20701. (className || ''))
  20702. .add(axisParent); };
  20703. axis.gridGroup = createGroup('grid', '-grid', options.gridZIndex);
  20704. axis.axisGroup = createGroup('axis', '', options.zIndex);
  20705. axis.labelGroup = createGroup('axis-labels', '-labels', labelOptions.zIndex);
  20706. }
  20707. if (hasData || axis.isLinked) {
  20708. // Generate ticks
  20709. tickPositions.forEach(function (pos) {
  20710. // i is not used here, but may be used in overrides
  20711. axis.generateTick(pos);
  20712. });
  20713. axis.renderUnsquish();
  20714. // Left side must be align: right and right side must
  20715. // have align: left for labels
  20716. axis.reserveSpaceDefault = (side === 0 ||
  20717. side === 2 ||
  20718. { 1: 'left', 3: 'right' }[side] === axis.labelAlign);
  20719. if (pick(labelOptions.reserveSpace, axis.labelAlign === 'center' ? true : null, axis.reserveSpaceDefault)) {
  20720. tickPositions.forEach(function (pos) {
  20721. // get the highest offset
  20722. labelOffset = Math.max(ticks[pos].getLabelSize(), labelOffset);
  20723. });
  20724. }
  20725. if (axis.staggerLines) {
  20726. labelOffset *= axis.staggerLines;
  20727. }
  20728. axis.labelOffset = labelOffset * (axis.opposite ? -1 : 1);
  20729. }
  20730. else { // doesn't have data
  20731. objectEach(ticks, function (tick, n) {
  20732. tick.destroy();
  20733. delete ticks[n];
  20734. });
  20735. }
  20736. if (axisTitleOptions &&
  20737. axisTitleOptions.text &&
  20738. axisTitleOptions.enabled !== false) {
  20739. axis.addTitle(showAxis);
  20740. if (showAxis && axisTitleOptions.reserveSpace !== false) {
  20741. axis.titleOffset = titleOffset =
  20742. axis.axisTitle.getBBox()[horiz ? 'height' : 'width'];
  20743. titleOffsetOption = axisTitleOptions.offset;
  20744. titleMargin = defined(titleOffsetOption) ?
  20745. 0 :
  20746. pick(axisTitleOptions.margin, horiz ? 5 : 10);
  20747. }
  20748. }
  20749. // Render the axis line
  20750. axis.renderLine();
  20751. // handle automatic or user set offset
  20752. axis.offset = directionFactor * pick(options.offset, axisOffset[side] ? axisOffset[side] + (options.margin || 0) : 0);
  20753. axis.tickRotCorr = axis.tickRotCorr || { x: 0, y: 0 }; // polar
  20754. if (side === 0) {
  20755. lineHeightCorrection = -axis.labelMetrics().h;
  20756. }
  20757. else if (side === 2) {
  20758. lineHeightCorrection = axis.tickRotCorr.y;
  20759. }
  20760. else {
  20761. lineHeightCorrection = 0;
  20762. }
  20763. // Find the padded label offset
  20764. labelOffsetPadded = Math.abs(labelOffset) + titleMargin;
  20765. if (labelOffset) {
  20766. labelOffsetPadded -= lineHeightCorrection;
  20767. labelOffsetPadded += directionFactor * (horiz ?
  20768. pick(labelOptions.y, axis.tickRotCorr.y + directionFactor * 8) :
  20769. labelOptions.x);
  20770. }
  20771. axis.axisTitleMargin = pick(titleOffsetOption, labelOffsetPadded);
  20772. if (axis.getMaxLabelDimensions) {
  20773. axis.maxLabelDimensions = axis.getMaxLabelDimensions(ticks, tickPositions);
  20774. }
  20775. // Due to GridAxis.tickSize, tickSize should be calculated after ticks
  20776. // has rendered.
  20777. var tickSize = this.tickSize('tick');
  20778. axisOffset[side] = Math.max(axisOffset[side], (axis.axisTitleMargin || 0) + titleOffset +
  20779. directionFactor * axis.offset, labelOffsetPadded, // #3027
  20780. tickPositions && tickPositions.length && tickSize ?
  20781. tickSize[0] + directionFactor * axis.offset :
  20782. 0 // #4866
  20783. );
  20784. // Decide the clipping needed to keep the graph inside
  20785. // the plot area and axis lines
  20786. var clip = options.offset ?
  20787. 0 :
  20788. // #4308, #4371:
  20789. Math.floor(axis.axisLine.strokeWidth() / 2) * 2;
  20790. clipOffset[invertedSide] =
  20791. Math.max(clipOffset[invertedSide], clip);
  20792. fireEvent(this, 'afterGetOffset');
  20793. };
  20794. /**
  20795. * Internal function to get the path for the axis line. Extended for polar
  20796. * charts.
  20797. *
  20798. * @function Highcharts.Axis#getLinePath
  20799. *
  20800. * @param {number} lineWidth
  20801. * The line width in pixels.
  20802. *
  20803. * @return {Highcharts.SVGPathArray}
  20804. * The SVG path definition in array form.
  20805. */
  20806. Axis.prototype.getLinePath = function (lineWidth) {
  20807. var chart = this.chart,
  20808. opposite = this.opposite,
  20809. offset = this.offset,
  20810. horiz = this.horiz,
  20811. lineLeft = this.left + (opposite ? this.width : 0) + offset,
  20812. lineTop = chart.chartHeight - this.bottom -
  20813. (opposite ? this.height : 0) + offset;
  20814. if (opposite) {
  20815. lineWidth *= -1; // crispify the other way - #1480, #1687
  20816. }
  20817. return chart.renderer
  20818. .crispLine([
  20819. [
  20820. 'M',
  20821. horiz ?
  20822. this.left :
  20823. lineLeft,
  20824. horiz ?
  20825. lineTop :
  20826. this.top
  20827. ],
  20828. [
  20829. 'L',
  20830. horiz ?
  20831. chart.chartWidth - this.right :
  20832. lineLeft,
  20833. horiz ?
  20834. lineTop :
  20835. chart.chartHeight - this.bottom
  20836. ]
  20837. ], lineWidth);
  20838. };
  20839. /**
  20840. * Render the axis line. Called internally when rendering and redrawing the
  20841. * axis.
  20842. *
  20843. * @function Highcharts.Axis#renderLine
  20844. */
  20845. Axis.prototype.renderLine = function () {
  20846. if (!this.axisLine) {
  20847. this.axisLine = this.chart.renderer.path()
  20848. .addClass('highcharts-axis-line')
  20849. .add(this.axisGroup);
  20850. if (!this.chart.styledMode) {
  20851. this.axisLine.attr({
  20852. stroke: this.options.lineColor,
  20853. 'stroke-width': this.options.lineWidth,
  20854. zIndex: 7
  20855. });
  20856. }
  20857. }
  20858. };
  20859. /**
  20860. * Position the axis title.
  20861. *
  20862. * @private
  20863. * @function Highcharts.Axis#getTitlePosition
  20864. *
  20865. * @return {Highcharts.PositionObject}
  20866. * X and Y positions for the title.
  20867. */
  20868. Axis.prototype.getTitlePosition = function () {
  20869. // compute anchor points for each of the title align options
  20870. var horiz = this.horiz,
  20871. axisLeft = this.left,
  20872. axisTop = this.top,
  20873. axisLength = this.len,
  20874. axisTitleOptions = this.options.title,
  20875. margin = horiz ? axisLeft : axisTop,
  20876. opposite = this.opposite,
  20877. offset = this.offset,
  20878. xOption = axisTitleOptions.x,
  20879. yOption = axisTitleOptions.y,
  20880. axisTitle = this.axisTitle,
  20881. fontMetrics = this.chart.renderer.fontMetrics(axisTitleOptions.style.fontSize,
  20882. axisTitle),
  20883. // The part of a multiline text that is below the baseline of the
  20884. // first line. Subtract 1 to preserve pixel-perfectness from the
  20885. // old behaviour (v5.0.12), where only one line was allowed.
  20886. textHeightOvershoot = Math.max(axisTitle.getBBox(null, 0).height - fontMetrics.h - 1, 0),
  20887. // the position in the length direction of the axis
  20888. alongAxis = {
  20889. low: margin + (horiz ? 0 : axisLength),
  20890. middle: margin + axisLength / 2,
  20891. high: margin + (horiz ? axisLength : 0)
  20892. }[axisTitleOptions.align],
  20893. // the position in the perpendicular direction of the axis
  20894. offAxis = (horiz ? axisTop + this.height : axisLeft) +
  20895. (horiz ? 1 : -1) * // horizontal axis reverses the margin
  20896. (opposite ? -1 : 1) * // so does opposite axes
  20897. this.axisTitleMargin +
  20898. [
  20899. -textHeightOvershoot,
  20900. textHeightOvershoot,
  20901. fontMetrics.f,
  20902. -textHeightOvershoot // left
  20903. ][this.side],
  20904. titlePosition = {
  20905. x: horiz ?
  20906. alongAxis + xOption :
  20907. offAxis + (opposite ? this.width : 0) + offset + xOption,
  20908. y: horiz ?
  20909. offAxis + yOption - (opposite ? this.height : 0) + offset :
  20910. alongAxis + yOption
  20911. };
  20912. fireEvent(this, 'afterGetTitlePosition', { titlePosition: titlePosition });
  20913. return titlePosition;
  20914. };
  20915. /**
  20916. * Render a minor tick into the given position. If a minor tick already
  20917. * exists in this position, move it.
  20918. *
  20919. * @function Highcharts.Axis#renderMinorTick
  20920. *
  20921. * @param {number} pos
  20922. * The position in axis values.
  20923. */
  20924. Axis.prototype.renderMinorTick = function (pos) {
  20925. var axis = this;
  20926. var slideInTicks = axis.chart.hasRendered && axis.old;
  20927. var minorTicks = axis.minorTicks;
  20928. if (!minorTicks[pos]) {
  20929. minorTicks[pos] = new Tick(axis, pos, 'minor');
  20930. }
  20931. // Render new ticks in old position
  20932. if (slideInTicks && minorTicks[pos].isNew) {
  20933. minorTicks[pos].render(null, true);
  20934. }
  20935. minorTicks[pos].render(null, false, 1);
  20936. };
  20937. /**
  20938. * Render a major tick into the given position. If a tick already exists
  20939. * in this position, move it.
  20940. *
  20941. * @function Highcharts.Axis#renderTick
  20942. *
  20943. * @param {number} pos
  20944. * The position in axis values.
  20945. *
  20946. * @param {number} i
  20947. * The tick index.
  20948. */
  20949. Axis.prototype.renderTick = function (pos, i) {
  20950. var axis = this,
  20951. isLinked = axis.isLinked,
  20952. ticks = axis.ticks,
  20953. slideInTicks = axis.chart.hasRendered && axis.old;
  20954. // Linked axes need an extra check to find out if
  20955. if (!isLinked ||
  20956. (pos >= axis.min && pos <= axis.max) ||
  20957. (axis.grid && axis.grid.isColumn)) {
  20958. if (!ticks[pos]) {
  20959. ticks[pos] = new Tick(axis, pos);
  20960. }
  20961. // NOTE this seems like overkill. Could be handled in tick.render by
  20962. // setting old position in attr, then set new position in animate.
  20963. // render new ticks in old position
  20964. if (slideInTicks && ticks[pos].isNew) {
  20965. // Start with negative opacity so that it is visible from
  20966. // halfway into the animation
  20967. ticks[pos].render(i, true, -1);
  20968. }
  20969. ticks[pos].render(i);
  20970. }
  20971. };
  20972. /**
  20973. * Render the axis.
  20974. *
  20975. * @private
  20976. * @function Highcharts.Axis#render
  20977. *
  20978. * @fires Highcharts.Axis#event:afterRender
  20979. */
  20980. Axis.prototype.render = function () {
  20981. var axis = this,
  20982. chart = axis.chart,
  20983. log = axis.logarithmic,
  20984. renderer = chart.renderer,
  20985. options = axis.options,
  20986. isLinked = axis.isLinked,
  20987. tickPositions = axis.tickPositions,
  20988. axisTitle = axis.axisTitle,
  20989. ticks = axis.ticks,
  20990. minorTicks = axis.minorTicks,
  20991. alternateBands = axis.alternateBands,
  20992. stackLabelOptions = options.stackLabels,
  20993. alternateGridColor = options.alternateGridColor,
  20994. tickmarkOffset = axis.tickmarkOffset,
  20995. axisLine = axis.axisLine,
  20996. showAxis = axis.showAxis,
  20997. animation = animObject(renderer.globalAnimation);
  20998. var from,
  20999. to;
  21000. // Reset
  21001. axis.labelEdge.length = 0;
  21002. axis.overlap = false;
  21003. // Mark all elements inActive before we go over and mark the active ones
  21004. [ticks, minorTicks, alternateBands].forEach(function (coll) {
  21005. objectEach(coll, function (tick) {
  21006. tick.isActive = false;
  21007. });
  21008. });
  21009. // If the series has data draw the ticks. Else only the line and title
  21010. if (axis.hasData() || isLinked) {
  21011. // minor ticks
  21012. if (axis.minorTickInterval && !axis.categories) {
  21013. axis.getMinorTickPositions().forEach(function (pos) {
  21014. axis.renderMinorTick(pos);
  21015. });
  21016. }
  21017. // Major ticks. Pull out the first item and render it last so that
  21018. // we can get the position of the neighbour label. #808.
  21019. if (tickPositions.length) { // #1300
  21020. tickPositions.forEach(function (pos, i) {
  21021. axis.renderTick(pos, i);
  21022. });
  21023. // In a categorized axis, the tick marks are displayed
  21024. // between labels. So we need to add a tick mark and
  21025. // grid line at the left edge of the X axis.
  21026. if (tickmarkOffset && (axis.min === 0 || axis.single)) {
  21027. if (!ticks[-1]) {
  21028. ticks[-1] = new Tick(axis, -1, null, true);
  21029. }
  21030. ticks[-1].render(-1);
  21031. }
  21032. }
  21033. // alternate grid color
  21034. if (alternateGridColor) {
  21035. tickPositions.forEach(function (pos, i) {
  21036. to = typeof tickPositions[i + 1] !== 'undefined' ?
  21037. tickPositions[i + 1] + tickmarkOffset :
  21038. axis.max - tickmarkOffset;
  21039. if (i % 2 === 0 &&
  21040. pos < axis.max &&
  21041. to <= axis.max + (chart.polar ?
  21042. -tickmarkOffset :
  21043. tickmarkOffset)) { // #2248, #4660
  21044. if (!alternateBands[pos]) {
  21045. // Should be imported from PlotLineOrBand.js, but
  21046. // the dependency cycle with axis is a problem
  21047. alternateBands[pos] = new H.PlotLineOrBand(axis);
  21048. }
  21049. from = pos + tickmarkOffset; // #949
  21050. alternateBands[pos].options = {
  21051. from: log ? log.lin2log(from) : from,
  21052. to: log ? log.lin2log(to) : to,
  21053. color: alternateGridColor,
  21054. className: 'highcharts-alternate-grid'
  21055. };
  21056. alternateBands[pos].render();
  21057. alternateBands[pos].isActive = true;
  21058. }
  21059. });
  21060. }
  21061. // custom plot lines and bands
  21062. if (!axis._addedPlotLB) { // only first time
  21063. axis._addedPlotLB = true;
  21064. (options.plotLines || [])
  21065. .concat(options.plotBands || [])
  21066. .forEach(function (plotLineOptions) {
  21067. axis.addPlotBandOrLine(plotLineOptions);
  21068. });
  21069. }
  21070. } // end if hasData
  21071. // Remove inactive ticks
  21072. [ticks, minorTicks, alternateBands].forEach(function (coll) {
  21073. var forDestruction = [],
  21074. delay = animation.duration,
  21075. destroyInactiveItems = function () {
  21076. var i = forDestruction.length;
  21077. while (i--) {
  21078. // When resizing rapidly, the same items
  21079. // may be destroyed in different timeouts,
  21080. // or the may be reactivated
  21081. if (coll[forDestruction[i]] &&
  21082. !coll[forDestruction[i]].isActive) {
  21083. coll[forDestruction[i]].destroy();
  21084. delete coll[forDestruction[i]];
  21085. }
  21086. }
  21087. };
  21088. objectEach(coll, function (tick, pos) {
  21089. if (!tick.isActive) {
  21090. // Render to zero opacity
  21091. tick.render(pos, false, 0);
  21092. tick.isActive = false;
  21093. forDestruction.push(pos);
  21094. }
  21095. });
  21096. // When the objects are finished fading out, destroy them
  21097. syncTimeout(destroyInactiveItems, coll === alternateBands ||
  21098. !chart.hasRendered ||
  21099. !delay ?
  21100. 0 :
  21101. delay);
  21102. });
  21103. // Set the axis line path
  21104. if (axisLine) {
  21105. axisLine[axisLine.isPlaced ? 'animate' : 'attr']({
  21106. d: this.getLinePath(axisLine.strokeWidth())
  21107. });
  21108. axisLine.isPlaced = true;
  21109. // Show or hide the line depending on options.showEmpty
  21110. axisLine[showAxis ? 'show' : 'hide'](showAxis);
  21111. }
  21112. if (axisTitle && showAxis) {
  21113. var titleXy = axis.getTitlePosition();
  21114. if (isNumber(titleXy.y)) {
  21115. axisTitle[axisTitle.isNew ? 'attr' : 'animate'](titleXy);
  21116. axisTitle.isNew = false;
  21117. }
  21118. else {
  21119. axisTitle.attr('y', -9999);
  21120. axisTitle.isNew = true;
  21121. }
  21122. }
  21123. // Stacked totals:
  21124. if (stackLabelOptions && stackLabelOptions.enabled && axis.stacking) {
  21125. axis.stacking.renderStackTotals();
  21126. }
  21127. // End stacked totals
  21128. // Record old scaling for updating/animation
  21129. axis.old = {
  21130. len: axis.len,
  21131. max: axis.max,
  21132. min: axis.min,
  21133. transA: axis.transA,
  21134. userMax: axis.userMax,
  21135. userMin: axis.userMin
  21136. };
  21137. axis.isDirty = false;
  21138. fireEvent(this, 'afterRender');
  21139. };
  21140. /**
  21141. * Redraw the axis to reflect changes in the data or axis extremes. Called
  21142. * internally from Highcharts.Chart#redraw.
  21143. *
  21144. * @private
  21145. * @function Highcharts.Axis#redraw
  21146. */
  21147. Axis.prototype.redraw = function () {
  21148. if (this.visible) {
  21149. // render the axis
  21150. this.render();
  21151. // move plot lines and bands
  21152. this.plotLinesAndBands.forEach(function (plotLine) {
  21153. plotLine.render();
  21154. });
  21155. }
  21156. // mark associated series as dirty and ready for redraw
  21157. this.series.forEach(function (series) {
  21158. series.isDirty = true;
  21159. });
  21160. };
  21161. /**
  21162. * Returns an array of axis properties, that should be untouched during
  21163. * reinitialization.
  21164. *
  21165. * @private
  21166. * @function Highcharts.Axis#getKeepProps
  21167. *
  21168. * @return {Array<string>}
  21169. */
  21170. Axis.prototype.getKeepProps = function () {
  21171. return (this.keepProps || Axis.keepProps);
  21172. };
  21173. /**
  21174. * Destroys an Axis instance. See {@link Axis#remove} for the API endpoint
  21175. * to fully remove the axis.
  21176. *
  21177. * @private
  21178. * @function Highcharts.Axis#destroy
  21179. *
  21180. * @param {boolean} [keepEvents]
  21181. * Whether to preserve events, used internally in Axis.update.
  21182. */
  21183. Axis.prototype.destroy = function (keepEvents) {
  21184. var axis = this,
  21185. plotLinesAndBands = axis.plotLinesAndBands,
  21186. eventOptions = this.eventOptions;
  21187. fireEvent(this, 'destroy', { keepEvents: keepEvents });
  21188. // Remove the events
  21189. if (!keepEvents) {
  21190. removeEvent(axis);
  21191. }
  21192. // Destroy collections
  21193. [axis.ticks, axis.minorTicks, axis.alternateBands].forEach(function (coll) {
  21194. destroyObjectProperties(coll);
  21195. });
  21196. if (plotLinesAndBands) {
  21197. var i = plotLinesAndBands.length;
  21198. while (i--) { // #1975
  21199. plotLinesAndBands[i].destroy();
  21200. }
  21201. }
  21202. // Destroy elements
  21203. ['axisLine', 'axisTitle', 'axisGroup',
  21204. 'gridGroup', 'labelGroup', 'cross', 'scrollbar'].forEach(function (prop) {
  21205. if (axis[prop]) {
  21206. axis[prop] = axis[prop].destroy();
  21207. }
  21208. });
  21209. // Destroy each generated group for plotlines and plotbands
  21210. for (var plotGroup in axis.plotLinesAndBandsGroups) { // eslint-disable-line guard-for-in
  21211. axis.plotLinesAndBandsGroups[plotGroup] =
  21212. axis.plotLinesAndBandsGroups[plotGroup].destroy();
  21213. }
  21214. // Delete all properties and fall back to the prototype.
  21215. objectEach(axis, function (val, key) {
  21216. if (axis.getKeepProps().indexOf(key) === -1) {
  21217. delete axis[key];
  21218. }
  21219. });
  21220. this.eventOptions = eventOptions;
  21221. };
  21222. /**
  21223. * Internal function to draw a crosshair.
  21224. *
  21225. * @function Highcharts.Axis#drawCrosshair
  21226. *
  21227. * @param {Highcharts.PointerEventObject} [e]
  21228. * The event arguments from the modified pointer event, extended with
  21229. * `chartX` and `chartY`
  21230. *
  21231. * @param {Highcharts.Point} [point]
  21232. * The Point object if the crosshair snaps to points.
  21233. *
  21234. * @fires Highcharts.Axis#event:afterDrawCrosshair
  21235. * @fires Highcharts.Axis#event:drawCrosshair
  21236. */
  21237. Axis.prototype.drawCrosshair = function (e, point) {
  21238. var options = this.crosshair,
  21239. snap = pick(options && options.snap,
  21240. true),
  21241. chart = this.chart;
  21242. var path,
  21243. pos,
  21244. categorized,
  21245. graphic = this.cross,
  21246. crossOptions;
  21247. fireEvent(this, 'drawCrosshair', { e: e, point: point });
  21248. // Use last available event when updating non-snapped crosshairs without
  21249. // mouse interaction (#5287)
  21250. if (!e) {
  21251. e = this.cross && this.cross.e;
  21252. }
  21253. if (
  21254. // Disabled in options
  21255. !options ||
  21256. // Snap
  21257. ((defined(point) || !snap) === false)) {
  21258. this.hideCrosshair();
  21259. }
  21260. else {
  21261. // Get the path
  21262. if (!snap) {
  21263. pos = e &&
  21264. (this.horiz ?
  21265. e.chartX - this.pos :
  21266. this.len - e.chartY + this.pos);
  21267. }
  21268. else if (defined(point)) {
  21269. // #3834
  21270. pos = pick(this.coll !== 'colorAxis' ?
  21271. point.crosshairPos : // 3D axis extension
  21272. null, this.isXAxis ?
  21273. point.plotX :
  21274. this.len - point.plotY);
  21275. }
  21276. if (defined(pos)) {
  21277. crossOptions = {
  21278. // value, only used on radial
  21279. value: point && (this.isXAxis ?
  21280. point.x :
  21281. pick(point.stackY, point.y)),
  21282. translatedValue: pos
  21283. };
  21284. if (chart.polar) {
  21285. // Additional information required for crosshairs in
  21286. // polar chart
  21287. extend(crossOptions, {
  21288. isCrosshair: true,
  21289. chartX: e && e.chartX,
  21290. chartY: e && e.chartY,
  21291. point: point
  21292. });
  21293. }
  21294. path = this.getPlotLinePath(crossOptions) ||
  21295. null; // #3189
  21296. }
  21297. if (!defined(path)) {
  21298. this.hideCrosshair();
  21299. return;
  21300. }
  21301. categorized = this.categories && !this.isRadial;
  21302. // Draw the cross
  21303. if (!graphic) {
  21304. this.cross = graphic = chart.renderer
  21305. .path()
  21306. .addClass('highcharts-crosshair highcharts-crosshair-' +
  21307. (categorized ? 'category ' : 'thin ') +
  21308. (options.className || ''))
  21309. .attr({
  21310. zIndex: pick(options.zIndex, 2)
  21311. })
  21312. .add();
  21313. // Presentational attributes
  21314. if (!chart.styledMode) {
  21315. graphic.attr({
  21316. stroke: options.color ||
  21317. (categorized ?
  21318. Color
  21319. .parse(Palette.highlightColor20)
  21320. .setOpacity(0.25)
  21321. .get() :
  21322. Palette.neutralColor20),
  21323. 'stroke-width': pick(options.width, 1)
  21324. }).css({
  21325. 'pointer-events': 'none'
  21326. });
  21327. if (options.dashStyle) {
  21328. graphic.attr({
  21329. dashstyle: options.dashStyle
  21330. });
  21331. }
  21332. }
  21333. }
  21334. graphic.show().attr({
  21335. d: path
  21336. });
  21337. if (categorized && !options.width) {
  21338. graphic.attr({
  21339. 'stroke-width': this.transA
  21340. });
  21341. }
  21342. this.cross.e = e;
  21343. }
  21344. fireEvent(this, 'afterDrawCrosshair', { e: e, point: point });
  21345. };
  21346. /**
  21347. * Hide the crosshair if visible.
  21348. *
  21349. * @function Highcharts.Axis#hideCrosshair
  21350. */
  21351. Axis.prototype.hideCrosshair = function () {
  21352. if (this.cross) {
  21353. this.cross.hide();
  21354. }
  21355. fireEvent(this, 'afterHideCrosshair');
  21356. };
  21357. /**
  21358. * Check whether the chart has vertical panning ('y' or 'xy' type).
  21359. *
  21360. * @private
  21361. * @function Highcharts.Axis#hasVerticalPanning
  21362. *
  21363. * @return {boolean}
  21364. */
  21365. Axis.prototype.hasVerticalPanning = function () {
  21366. var panningOptions = this.chart.options.chart.panning;
  21367. return Boolean(panningOptions &&
  21368. panningOptions.enabled && // #14624
  21369. /y/.test(panningOptions.type));
  21370. };
  21371. /**
  21372. * Check whether the given value is a positive valid axis value.
  21373. *
  21374. * @private
  21375. * @function Highcharts.Axis#validatePositiveValue
  21376. *
  21377. * @param {unknown} value
  21378. * The axis value
  21379. *
  21380. * @return {boolean}
  21381. */
  21382. Axis.prototype.validatePositiveValue = function (value) {
  21383. return isNumber(value) && value > 0;
  21384. };
  21385. /**
  21386. * Update an axis object with a new set of options. The options are merged
  21387. * with the existing options, so only new or altered options need to be
  21388. * specified.
  21389. *
  21390. * @sample highcharts/members/axis-update/
  21391. * Axis update demo
  21392. *
  21393. * @function Highcharts.Axis#update
  21394. *
  21395. * @param {Highcharts.AxisOptions} options
  21396. * The new options that will be merged in with existing options on the axis.
  21397. *
  21398. * @param {boolean} [redraw=true]
  21399. * Whether to redraw the chart after the axis is altered. If doing more
  21400. * operations on the chart, it is a good idea to set redraw to false and
  21401. * call {@link Chart#redraw} after.
  21402. */
  21403. Axis.prototype.update = function (options, redraw) {
  21404. var chart = this.chart;
  21405. options = merge(this.userOptions, options);
  21406. this.destroy(true);
  21407. this.init(chart, options);
  21408. chart.isDirtyBox = true;
  21409. if (pick(redraw, true)) {
  21410. chart.redraw();
  21411. }
  21412. };
  21413. /**
  21414. * Remove the axis from the chart.
  21415. *
  21416. * @sample highcharts/members/chart-addaxis/
  21417. * Add and remove axes
  21418. *
  21419. * @function Highcharts.Axis#remove
  21420. *
  21421. * @param {boolean} [redraw=true]
  21422. * Whether to redraw the chart following the remove.
  21423. */
  21424. Axis.prototype.remove = function (redraw) {
  21425. var chart = this.chart,
  21426. key = this.coll, // xAxis or yAxis
  21427. axisSeries = this.series;
  21428. var i = axisSeries.length;
  21429. // Remove associated series (#2687)
  21430. while (i--) {
  21431. if (axisSeries[i]) {
  21432. axisSeries[i].remove(false);
  21433. }
  21434. }
  21435. // Remove the axis
  21436. erase(chart.axes, this);
  21437. erase(chart[key], this);
  21438. chart[key].forEach(function (axis, i) {
  21439. // Re-index, #1706, #8075
  21440. axis.options.index = axis.userOptions.index = i;
  21441. });
  21442. this.destroy();
  21443. chart.isDirtyBox = true;
  21444. if (pick(redraw, true)) {
  21445. chart.redraw();
  21446. }
  21447. };
  21448. /**
  21449. * Update the axis title by options after render time.
  21450. *
  21451. * @sample highcharts/members/axis-settitle/
  21452. * Set a new Y axis title
  21453. *
  21454. * @function Highcharts.Axis#setTitle
  21455. *
  21456. * @param {Highcharts.AxisTitleOptions} titleOptions
  21457. * The additional title options.
  21458. *
  21459. * @param {boolean} [redraw=true]
  21460. * Whether to redraw the chart after setting the title.
  21461. */
  21462. Axis.prototype.setTitle = function (titleOptions, redraw) {
  21463. this.update({ title: titleOptions }, redraw);
  21464. };
  21465. /**
  21466. * Set new axis categories and optionally redraw.
  21467. *
  21468. * @sample highcharts/members/axis-setcategories/
  21469. * Set categories by click on a button
  21470. *
  21471. * @function Highcharts.Axis#setCategories
  21472. *
  21473. * @param {Array<string>} categories
  21474. * The new categories.
  21475. *
  21476. * @param {boolean} [redraw=true]
  21477. * Whether to redraw the chart.
  21478. */
  21479. Axis.prototype.setCategories = function (categories, redraw) {
  21480. this.update({ categories: categories }, redraw);
  21481. };
  21482. /* *
  21483. *
  21484. * Static Properties
  21485. *
  21486. * */
  21487. Axis.defaultOptions = AxisDefaults.defaultXAxisOptions;
  21488. // Properties to survive after destroy, needed for Axis.update (#4317,
  21489. // #5773, #5881).
  21490. Axis.keepProps = ['extKey', 'hcEvents', 'names', 'series', 'userMax', 'userMin'];
  21491. return Axis;
  21492. }());
  21493. /* *
  21494. *
  21495. * Default Export
  21496. *
  21497. * */
  21498. /* *
  21499. *
  21500. * API Declarations
  21501. *
  21502. * */
  21503. /**
  21504. * Options for the path on the Axis to be calculated.
  21505. * @interface Highcharts.AxisPlotLinePathOptionsObject
  21506. */ /**
  21507. * Axis value.
  21508. * @name Highcharts.AxisPlotLinePathOptionsObject#value
  21509. * @type {number|undefined}
  21510. */ /**
  21511. * Line width used for calculation crisp line coordinates. Defaults to 1.
  21512. * @name Highcharts.AxisPlotLinePathOptionsObject#lineWidth
  21513. * @type {number|undefined}
  21514. */ /**
  21515. * If `false`, the function will return null when it falls outside the axis
  21516. * bounds. If `true`, the function will return a path aligned to the plot area
  21517. * sides if it falls outside. If `pass`, it will return a path outside.
  21518. * @name Highcharts.AxisPlotLinePathOptionsObject#force
  21519. * @type {string|boolean|undefined}
  21520. */ /**
  21521. * Used in Highcharts Stock. When `true`, plot paths
  21522. * (crosshair, plotLines, gridLines)
  21523. * will be rendered on all axes when defined on the first axis.
  21524. * @name Highcharts.AxisPlotLinePathOptionsObject#acrossPanes
  21525. * @type {boolean|undefined}
  21526. */ /**
  21527. * Use old coordinates (for resizing and rescaling).
  21528. * If not set, defaults to `false`.
  21529. * @name Highcharts.AxisPlotLinePathOptionsObject#old
  21530. * @type {boolean|undefined}
  21531. */ /**
  21532. * If given, return the plot line path of a pixel position on the axis.
  21533. * @name Highcharts.AxisPlotLinePathOptionsObject#translatedValue
  21534. * @type {number|undefined}
  21535. */ /**
  21536. * Used in Polar axes. Reverse the positions for concatenation of polygonal
  21537. * plot bands
  21538. * @name Highcharts.AxisPlotLinePathOptionsObject#reverse
  21539. * @type {boolean|undefined}
  21540. */
  21541. /**
  21542. * Options for crosshairs on axes.
  21543. *
  21544. * @product highstock
  21545. *
  21546. * @typedef {Highcharts.XAxisCrosshairOptions|Highcharts.YAxisCrosshairOptions} Highcharts.AxisCrosshairOptions
  21547. */
  21548. /**
  21549. * @typedef {"navigator"|"pan"|"rangeSelectorButton"|"rangeSelectorInput"|"scrollbar"|"traverseUpButton"|"zoom"} Highcharts.AxisExtremesTriggerValue
  21550. */
  21551. /**
  21552. * @callback Highcharts.AxisEventCallbackFunction
  21553. *
  21554. * @param {Highcharts.Axis} this
  21555. */
  21556. /**
  21557. * @callback Highcharts.AxisLabelsFormatterCallbackFunction
  21558. *
  21559. * @param {Highcharts.AxisLabelsFormatterContextObject} this
  21560. *
  21561. * @param {Highcharts.AxisLabelsFormatterContextObject} ctx
  21562. *
  21563. * @return {string}
  21564. */
  21565. /**
  21566. * @interface Highcharts.AxisLabelsFormatterContextObject
  21567. */ /**
  21568. * The axis item of the label
  21569. * @name Highcharts.AxisLabelsFormatterContextObject#axis
  21570. * @type {Highcharts.Axis}
  21571. */ /**
  21572. * The chart instance.
  21573. * @name Highcharts.AxisLabelsFormatterContextObject#chart
  21574. * @type {Highcharts.Chart}
  21575. */ /**
  21576. * Whether the label belongs to the first tick on the axis.
  21577. * @name Highcharts.AxisLabelsFormatterContextObject#isFirst
  21578. * @type {boolean}
  21579. */ /**
  21580. * Whether the label belongs to the last tick on the axis.
  21581. * @name Highcharts.AxisLabelsFormatterContextObject#isLast
  21582. * @type {boolean}
  21583. */ /**
  21584. * The position on the axis in terms of axis values. For category axes, a
  21585. * zero-based index. For datetime axes, the JavaScript time in milliseconds
  21586. * since 1970.
  21587. * @name Highcharts.AxisLabelsFormatterContextObject#pos
  21588. * @type {number}
  21589. */ /**
  21590. * The preformatted text as the result of the default formatting. For example
  21591. * dates will be formatted as strings, and numbers with language-specific comma
  21592. * separators, thousands separators and numeric symbols like `k` or `M`.
  21593. * @name Highcharts.AxisLabelsFormatterContextObject#text
  21594. * @type {string}
  21595. */ /**
  21596. * The Tick instance.
  21597. * @name Highcharts.AxisLabelsFormatterContextObject#tick
  21598. * @type {Highcharts.Tick}
  21599. */ /**
  21600. * This can be either a numeric value or a category string.
  21601. * @name Highcharts.AxisLabelsFormatterContextObject#value
  21602. * @type {number|string}
  21603. */
  21604. /**
  21605. * Options for axes.
  21606. *
  21607. * @typedef {Highcharts.XAxisOptions|Highcharts.YAxisOptions|Highcharts.ZAxisOptions} Highcharts.AxisOptions
  21608. */
  21609. /**
  21610. * @callback Highcharts.AxisPointBreakEventCallbackFunction
  21611. *
  21612. * @param {Highcharts.Axis} this
  21613. *
  21614. * @param {Highcharts.AxisPointBreakEventObject} evt
  21615. */
  21616. /**
  21617. * @interface Highcharts.AxisPointBreakEventObject
  21618. */ /**
  21619. * @name Highcharts.AxisPointBreakEventObject#brk
  21620. * @type {Highcharts.Dictionary<number>}
  21621. */ /**
  21622. * @name Highcharts.AxisPointBreakEventObject#point
  21623. * @type {Highcharts.Point}
  21624. */ /**
  21625. * @name Highcharts.AxisPointBreakEventObject#preventDefault
  21626. * @type {Function}
  21627. */ /**
  21628. * @name Highcharts.AxisPointBreakEventObject#target
  21629. * @type {Highcharts.SVGElement}
  21630. */ /**
  21631. * @name Highcharts.AxisPointBreakEventObject#type
  21632. * @type {"pointBreak"|"pointInBreak"}
  21633. */
  21634. /**
  21635. * @callback Highcharts.AxisSetExtremesEventCallbackFunction
  21636. *
  21637. * @param {Highcharts.Axis} this
  21638. *
  21639. * @param {Highcharts.AxisSetExtremesEventObject} evt
  21640. */
  21641. /**
  21642. * @interface Highcharts.AxisSetExtremesEventObject
  21643. * @extends Highcharts.ExtremesObject
  21644. */ /**
  21645. * @name Highcharts.AxisSetExtremesEventObject#preventDefault
  21646. * @type {Function}
  21647. */ /**
  21648. * @name Highcharts.AxisSetExtremesEventObject#target
  21649. * @type {Highcharts.SVGElement}
  21650. */ /**
  21651. * @name Highcharts.AxisSetExtremesEventObject#trigger
  21652. * @type {Highcharts.AxisExtremesTriggerValue|string}
  21653. */ /**
  21654. * @name Highcharts.AxisSetExtremesEventObject#type
  21655. * @type {"setExtremes"}
  21656. */
  21657. /**
  21658. * @callback Highcharts.AxisTickPositionerCallbackFunction
  21659. *
  21660. * @param {Highcharts.Axis} this
  21661. *
  21662. * @return {Highcharts.AxisTickPositionsArray}
  21663. */
  21664. /**
  21665. * @interface Highcharts.AxisTickPositionsArray
  21666. * @augments Array<number>
  21667. */
  21668. /**
  21669. * @typedef {"high"|"low"|"middle"} Highcharts.AxisTitleAlignValue
  21670. */
  21671. /**
  21672. * @typedef {Highcharts.XAxisTitleOptions|Highcharts.YAxisTitleOptions|Highcharts.ZAxisTitleOptions} Highcharts.AxisTitleOptions
  21673. */
  21674. /**
  21675. * @typedef {"linear"|"logarithmic"|"datetime"|"category"|"treegrid"} Highcharts.AxisTypeValue
  21676. */
  21677. /**
  21678. * The returned object literal from the {@link Highcharts.Axis#getExtremes}
  21679. * function.
  21680. *
  21681. * @interface Highcharts.ExtremesObject
  21682. */ /**
  21683. * The maximum value of the axis' associated series.
  21684. * @name Highcharts.ExtremesObject#dataMax
  21685. * @type {number}
  21686. */ /**
  21687. * The minimum value of the axis' associated series.
  21688. * @name Highcharts.ExtremesObject#dataMin
  21689. * @type {number}
  21690. */ /**
  21691. * The maximum axis value, either automatic or set manually. If the `max` option
  21692. * is not set, `maxPadding` is 0 and `endOnTick` is false, this value will be
  21693. * the same as `dataMax`.
  21694. * @name Highcharts.ExtremesObject#max
  21695. * @type {number}
  21696. */ /**
  21697. * The minimum axis value, either automatic or set manually. If the `min` option
  21698. * is not set, `minPadding` is 0 and `startOnTick` is false, this value will be
  21699. * the same as `dataMin`.
  21700. * @name Highcharts.ExtremesObject#min
  21701. * @type {number}
  21702. */ /**
  21703. * The user defined maximum, either from the `max` option or from a zoom or
  21704. * `setExtremes` action.
  21705. * @name Highcharts.ExtremesObject#userMax
  21706. * @type {number}
  21707. */ /**
  21708. * The user defined minimum, either from the `min` option or from a zoom or
  21709. * `setExtremes` action.
  21710. * @name Highcharts.ExtremesObject#userMin
  21711. * @type {number}
  21712. */
  21713. /**
  21714. * Formatter function for the text of a crosshair label.
  21715. *
  21716. * @callback Highcharts.XAxisCrosshairLabelFormatterCallbackFunction
  21717. *
  21718. * @param {Highcharts.Axis} this
  21719. * Axis context
  21720. *
  21721. * @param {number} value
  21722. * Y value of the data point
  21723. *
  21724. * @return {string}
  21725. */
  21726. ''; // keeps doclets above in JS file
  21727. return Axis;
  21728. });
  21729. _registerModule(_modules, 'Core/Axis/DateTimeAxis.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Utilities.js']], function (Axis, U) {
  21730. /* *
  21731. *
  21732. * (c) 2010-2021 Torstein Honsi
  21733. *
  21734. * License: www.highcharts.com/license
  21735. *
  21736. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  21737. *
  21738. * */
  21739. var addEvent = U.addEvent,
  21740. getMagnitude = U.getMagnitude,
  21741. normalizeTickInterval = U.normalizeTickInterval,
  21742. timeUnits = U.timeUnits;
  21743. /* eslint-disable valid-jsdoc */
  21744. var DateTimeAxisAdditions = /** @class */ (function () {
  21745. /* *
  21746. *
  21747. * Constructors
  21748. *
  21749. * */
  21750. function DateTimeAxisAdditions(axis) {
  21751. this.axis = axis;
  21752. }
  21753. /* *
  21754. *
  21755. * Functions
  21756. *
  21757. * */
  21758. /**
  21759. * Get a normalized tick interval for dates. Returns a configuration object
  21760. * with unit range (interval), count and name. Used to prepare data for
  21761. * `getTimeTicks`. Previously this logic was part of getTimeTicks, but as
  21762. * `getTimeTicks` now runs of segments in stock charts, the normalizing
  21763. * logic was extracted in order to prevent it for running over again for
  21764. * each segment having the same interval. #662, #697.
  21765. * @private
  21766. */
  21767. /**
  21768. * Get a normalized tick interval for dates. Returns a configuration object
  21769. * with unit range (interval), count and name. Used to prepare data for
  21770. * `getTimeTicks`. Previously this logic was part of getTimeTicks, but as
  21771. * `getTimeTicks` now runs of segments in stock charts, the normalizing
  21772. * logic was extracted in order to prevent it for running over again for
  21773. * each segment having the same interval. #662, #697.
  21774. * @private
  21775. */
  21776. DateTimeAxisAdditions.prototype.normalizeTimeTickInterval = function (tickInterval, unitsOption) {
  21777. var units = unitsOption || [[
  21778. 'millisecond',
  21779. [1, 2, 5, 10, 20, 25, 50, 100, 200, 500] // allowed multiples
  21780. ],
  21781. [
  21782. 'second',
  21783. [1, 2, 5, 10, 15, 30]
  21784. ],
  21785. [
  21786. 'minute',
  21787. [1, 2, 5, 10, 15, 30]
  21788. ],
  21789. [
  21790. 'hour',
  21791. [1, 2, 3, 4, 6, 8, 12]
  21792. ],
  21793. [
  21794. 'day',
  21795. [1, 2]
  21796. ],
  21797. [
  21798. 'week',
  21799. [1, 2]
  21800. ],
  21801. [
  21802. 'month',
  21803. [1, 2, 3, 4, 6]
  21804. ],
  21805. [
  21806. 'year',
  21807. null
  21808. ]],
  21809. unit = units[units.length - 1], // default unit is years
  21810. interval = timeUnits[unit[0]],
  21811. multiples = unit[1],
  21812. count,
  21813. i;
  21814. // loop through the units to find the one that best fits the
  21815. // tickInterval
  21816. for (i = 0; i < units.length; i++) {
  21817. unit = units[i];
  21818. interval = timeUnits[unit[0]];
  21819. multiples = unit[1];
  21820. if (units[i + 1]) {
  21821. // lessThan is in the middle between the highest multiple and
  21822. // the next unit.
  21823. var lessThan = (interval *
  21824. multiples[multiples.length - 1] +
  21825. timeUnits[units[i + 1][0]]) / 2;
  21826. // break and keep the current unit
  21827. if (tickInterval <= lessThan) {
  21828. break;
  21829. }
  21830. }
  21831. }
  21832. // prevent 2.5 years intervals, though 25, 250 etc. are allowed
  21833. if (interval === timeUnits.year && tickInterval < 5 * interval) {
  21834. multiples = [1, 2, 5];
  21835. }
  21836. // get the count
  21837. count = normalizeTickInterval(tickInterval / interval, multiples, unit[0] === 'year' ? // #1913, #2360
  21838. Math.max(getMagnitude(tickInterval / interval), 1) :
  21839. 1);
  21840. return {
  21841. unitRange: interval,
  21842. count: count,
  21843. unitName: unit[0]
  21844. };
  21845. };
  21846. return DateTimeAxisAdditions;
  21847. }());
  21848. /**
  21849. * Date and time support for axes.
  21850. *
  21851. * @private
  21852. * @class
  21853. */
  21854. var DateTimeAxis = /** @class */ (function () {
  21855. function DateTimeAxis() {
  21856. }
  21857. /* *
  21858. *
  21859. * Static Functions
  21860. *
  21861. * */
  21862. /**
  21863. * Extends axis class with date and time support.
  21864. * @private
  21865. */
  21866. DateTimeAxis.compose = function (AxisClass) {
  21867. AxisClass.keepProps.push('dateTime');
  21868. var axisProto = AxisClass.prototype;
  21869. /**
  21870. * Set the tick positions to a time unit that makes sense, for example
  21871. * on the first of each month or on every Monday. Return an array with
  21872. * the time positions. Used in datetime axes as well as for grouping
  21873. * data on a datetime axis.
  21874. *
  21875. * @private
  21876. * @function Highcharts.Axis#getTimeTicks
  21877. *
  21878. * @param {Highcharts.TimeNormalizeObject} normalizedInterval
  21879. * The interval in axis values (ms) and thecount.
  21880. *
  21881. * @param {number} min
  21882. * The minimum in axis values.
  21883. *
  21884. * @param {number} max
  21885. * The maximum in axis values.
  21886. *
  21887. * @param {number} startOfWeek
  21888. *
  21889. * @return {Highcharts.AxisTickPositionsArray}
  21890. */
  21891. axisProto.getTimeTicks = function () {
  21892. return this.chart.time.getTimeTicks.apply(this.chart.time, arguments);
  21893. };
  21894. /* eslint-disable no-invalid-this */
  21895. addEvent(AxisClass, 'init', function (e) {
  21896. var axis = this;
  21897. var options = e.userOptions;
  21898. if (options.type !== 'datetime') {
  21899. axis.dateTime = void 0;
  21900. return;
  21901. }
  21902. if (!axis.dateTime) {
  21903. axis.dateTime = new DateTimeAxisAdditions(axis);
  21904. }
  21905. });
  21906. /* eslint-enable no-invalid-this */
  21907. };
  21908. /* *
  21909. *
  21910. * Static Properties
  21911. *
  21912. * */
  21913. DateTimeAxis.AdditionsClass = DateTimeAxisAdditions;
  21914. return DateTimeAxis;
  21915. }());
  21916. DateTimeAxis.compose(Axis);
  21917. return DateTimeAxis;
  21918. });
  21919. _registerModule(_modules, 'Core/Axis/LogarithmicAxis.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Utilities.js']], function (Axis, U) {
  21920. /* *
  21921. *
  21922. * (c) 2010-2021 Torstein Honsi
  21923. *
  21924. * License: www.highcharts.com/license
  21925. *
  21926. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  21927. *
  21928. * */
  21929. var addEvent = U.addEvent,
  21930. getMagnitude = U.getMagnitude,
  21931. normalizeTickInterval = U.normalizeTickInterval,
  21932. pick = U.pick;
  21933. /* eslint-disable valid-jsdoc */
  21934. /**
  21935. * Provides logarithmic support for axes.
  21936. *
  21937. * @private
  21938. * @class
  21939. */
  21940. var LogarithmicAxisAdditions = /** @class */ (function () {
  21941. /* *
  21942. *
  21943. * Constructors
  21944. *
  21945. * */
  21946. function LogarithmicAxisAdditions(axis) {
  21947. this.axis = axis;
  21948. }
  21949. /* *
  21950. *
  21951. * Functions
  21952. *
  21953. * */
  21954. /**
  21955. * Set the tick positions of a logarithmic axis.
  21956. */
  21957. LogarithmicAxisAdditions.prototype.getLogTickPositions = function (interval, min, max, minor) {
  21958. var log = this;
  21959. var axis = log.axis;
  21960. var axisLength = axis.len;
  21961. var options = axis.options;
  21962. // Since we use this method for both major and minor ticks,
  21963. // use a local variable and return the result
  21964. var positions = [];
  21965. // Reset
  21966. if (!minor) {
  21967. log.minorAutoInterval = void 0;
  21968. }
  21969. // First case: All ticks fall on whole logarithms: 1, 10, 100 etc.
  21970. if (interval >= 0.5) {
  21971. interval = Math.round(interval);
  21972. positions = axis.getLinearTickPositions(interval, min, max);
  21973. // Second case: We need intermediary ticks. For example
  21974. // 1, 2, 4, 6, 8, 10, 20, 40 etc.
  21975. }
  21976. else if (interval >= 0.08) {
  21977. var roundedMin = Math.floor(min),
  21978. intermediate = void 0,
  21979. i = void 0,
  21980. j = void 0,
  21981. len = void 0,
  21982. pos = void 0,
  21983. lastPos = void 0,
  21984. break2 = void 0;
  21985. if (interval > 0.3) {
  21986. intermediate = [1, 2, 4];
  21987. // 0.2 equals five minor ticks per 1, 10, 100 etc
  21988. }
  21989. else if (interval > 0.15) {
  21990. intermediate = [1, 2, 4, 6, 8];
  21991. }
  21992. else { // 0.1 equals ten minor ticks per 1, 10, 100 etc
  21993. intermediate = [1, 2, 3, 4, 5, 6, 7, 8, 9];
  21994. }
  21995. for (i = roundedMin; i < max + 1 && !break2; i++) {
  21996. len = intermediate.length;
  21997. for (j = 0; j < len && !break2; j++) {
  21998. pos = log.log2lin(log.lin2log(i) * intermediate[j]);
  21999. // #1670, lastPos is #3113
  22000. if (pos > min &&
  22001. (!minor || lastPos <= max) &&
  22002. typeof lastPos !== 'undefined') {
  22003. positions.push(lastPos);
  22004. }
  22005. if (lastPos > max) {
  22006. break2 = true;
  22007. }
  22008. lastPos = pos;
  22009. }
  22010. }
  22011. // Third case: We are so deep in between whole logarithmic values that
  22012. // we might as well handle the tick positions like a linear axis. For
  22013. // example 1.01, 1.02, 1.03, 1.04.
  22014. }
  22015. else {
  22016. var realMin = log.lin2log(min),
  22017. realMax = log.lin2log(max),
  22018. tickIntervalOption = minor ?
  22019. axis.getMinorTickInterval() :
  22020. options.tickInterval,
  22021. filteredTickIntervalOption = tickIntervalOption === 'auto' ?
  22022. null :
  22023. tickIntervalOption,
  22024. tickPixelIntervalOption = options.tickPixelInterval / (minor ? 5 : 1),
  22025. totalPixelLength = minor ?
  22026. axisLength / axis.tickPositions.length :
  22027. axisLength;
  22028. interval = pick(filteredTickIntervalOption, log.minorAutoInterval, (realMax - realMin) *
  22029. tickPixelIntervalOption / (totalPixelLength || 1));
  22030. interval = normalizeTickInterval(interval, void 0, getMagnitude(interval));
  22031. positions = axis.getLinearTickPositions(interval, realMin, realMax).map(log.log2lin);
  22032. if (!minor) {
  22033. log.minorAutoInterval = interval / 5;
  22034. }
  22035. }
  22036. // Set the axis-level tickInterval variable
  22037. if (!minor) {
  22038. axis.tickInterval = interval;
  22039. }
  22040. return positions;
  22041. };
  22042. LogarithmicAxisAdditions.prototype.lin2log = function (num) {
  22043. return Math.pow(10, num);
  22044. };
  22045. LogarithmicAxisAdditions.prototype.log2lin = function (num) {
  22046. return Math.log(num) / Math.LN10;
  22047. };
  22048. return LogarithmicAxisAdditions;
  22049. }());
  22050. var LogarithmicAxis = /** @class */ (function () {
  22051. function LogarithmicAxis() {
  22052. }
  22053. /**
  22054. * Provides logarithmic support for axes.
  22055. *
  22056. * @private
  22057. */
  22058. LogarithmicAxis.compose = function (AxisClass) {
  22059. AxisClass.keepProps.push('logarithmic');
  22060. /* eslint-disable no-invalid-this */
  22061. addEvent(AxisClass, 'init', function (e) {
  22062. var axis = this;
  22063. var options = e.userOptions;
  22064. var logarithmic = axis.logarithmic;
  22065. if (options.type !== 'logarithmic') {
  22066. axis.logarithmic = void 0;
  22067. }
  22068. else {
  22069. if (!logarithmic) {
  22070. logarithmic = axis.logarithmic = new LogarithmicAxisAdditions(axis);
  22071. }
  22072. }
  22073. });
  22074. addEvent(AxisClass, 'afterInit', function () {
  22075. var axis = this;
  22076. var log = axis.logarithmic;
  22077. // extend logarithmic axis
  22078. if (log) {
  22079. axis.lin2val = function (num) {
  22080. return log.lin2log(num);
  22081. };
  22082. axis.val2lin = function (num) {
  22083. return log.log2lin(num);
  22084. };
  22085. }
  22086. });
  22087. };
  22088. return LogarithmicAxis;
  22089. }());
  22090. LogarithmicAxis.compose(Axis); // @todo move to factory functions
  22091. return LogarithmicAxis;
  22092. });
  22093. _registerModule(_modules, 'Core/Axis/PlotLineOrBand.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Color/Palette.js'], _modules['Core/Utilities.js']], function (Axis, palette, U) {
  22094. /* *
  22095. *
  22096. * (c) 2010-2021 Torstein Honsi
  22097. *
  22098. * License: www.highcharts.com/license
  22099. *
  22100. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  22101. *
  22102. * */
  22103. /**
  22104. * Options for plot bands on axes.
  22105. *
  22106. * @typedef {Highcharts.XAxisPlotBandsOptions|Highcharts.YAxisPlotBandsOptions|Highcharts.ZAxisPlotBandsOptions} Highcharts.AxisPlotBandsOptions
  22107. */
  22108. /**
  22109. * Options for plot band labels on axes.
  22110. *
  22111. * @typedef {Highcharts.XAxisPlotBandsLabelOptions|Highcharts.YAxisPlotBandsLabelOptions|Highcharts.ZAxisPlotBandsLabelOptions} Highcharts.AxisPlotBandsLabelOptions
  22112. */
  22113. /**
  22114. * Options for plot lines on axes.
  22115. *
  22116. * @typedef {Highcharts.XAxisPlotLinesOptions|Highcharts.YAxisPlotLinesOptions|Highcharts.ZAxisPlotLinesOptions} Highcharts.AxisPlotLinesOptions
  22117. */
  22118. /**
  22119. * Options for plot line labels on axes.
  22120. *
  22121. * @typedef {Highcharts.XAxisPlotLinesLabelOptions|Highcharts.YAxisPlotLinesLabelOptions|Highcharts.ZAxisPlotLinesLabelOptions} Highcharts.AxisPlotLinesLabelOptions
  22122. */
  22123. var arrayMax = U.arrayMax,
  22124. arrayMin = U.arrayMin,
  22125. defined = U.defined,
  22126. destroyObjectProperties = U.destroyObjectProperties,
  22127. erase = U.erase,
  22128. extend = U.extend,
  22129. fireEvent = U.fireEvent,
  22130. isNumber = U.isNumber,
  22131. merge = U.merge,
  22132. objectEach = U.objectEach,
  22133. pick = U.pick;
  22134. /* eslint-disable no-invalid-this, valid-jsdoc */
  22135. /**
  22136. * The object wrapper for plot lines and plot bands
  22137. *
  22138. * @class
  22139. * @name Highcharts.PlotLineOrBand
  22140. *
  22141. * @param {Highcharts.Axis} axis
  22142. *
  22143. * @param {Highcharts.AxisPlotLinesOptions|Highcharts.AxisPlotBandsOptions} [options]
  22144. */
  22145. var PlotLineOrBand = /** @class */ (function () {
  22146. function PlotLineOrBand(axis, options) {
  22147. this.axis = axis;
  22148. if (options) {
  22149. this.options = options;
  22150. this.id = options.id;
  22151. }
  22152. }
  22153. /**
  22154. * Render the plot line or plot band. If it is already existing,
  22155. * move it.
  22156. *
  22157. * @private
  22158. * @function Highcharts.PlotLineOrBand#render
  22159. * @return {Highcharts.PlotLineOrBand|undefined}
  22160. */
  22161. PlotLineOrBand.prototype.render = function () {
  22162. fireEvent(this, 'render');
  22163. var plotLine = this,
  22164. axis = plotLine.axis,
  22165. horiz = axis.horiz,
  22166. log = axis.logarithmic,
  22167. options = plotLine.options,
  22168. optionsLabel = options.label,
  22169. label = plotLine.label,
  22170. to = options.to,
  22171. from = options.from,
  22172. value = options.value,
  22173. isBand = defined(from) && defined(to),
  22174. isLine = defined(value),
  22175. svgElem = plotLine.svgElem,
  22176. isNew = !svgElem,
  22177. path = [],
  22178. color = options.color,
  22179. zIndex = pick(options.zIndex, 0),
  22180. events = options.events,
  22181. attribs = {
  22182. 'class': 'highcharts-plot-' + (isBand ? 'band ' : 'line ') +
  22183. (options.className || '')
  22184. },
  22185. groupAttribs = {},
  22186. renderer = axis.chart.renderer,
  22187. groupName = isBand ? 'bands' : 'lines',
  22188. group;
  22189. // logarithmic conversion
  22190. if (log) {
  22191. from = log.log2lin(from);
  22192. to = log.log2lin(to);
  22193. value = log.log2lin(value);
  22194. }
  22195. // Set the presentational attributes
  22196. if (!axis.chart.styledMode) {
  22197. if (isLine) {
  22198. attribs.stroke = color || palette.neutralColor40;
  22199. attribs['stroke-width'] = pick(options.width, 1);
  22200. if (options.dashStyle) {
  22201. attribs.dashstyle =
  22202. options.dashStyle;
  22203. }
  22204. }
  22205. else if (isBand) { // plot band
  22206. attribs.fill = color || palette.highlightColor10;
  22207. if (options.borderWidth) {
  22208. attribs.stroke = options.borderColor;
  22209. attribs['stroke-width'] = options.borderWidth;
  22210. }
  22211. }
  22212. }
  22213. // Grouping and zIndex
  22214. groupAttribs.zIndex = zIndex;
  22215. groupName += '-' + zIndex;
  22216. group = axis.plotLinesAndBandsGroups[groupName];
  22217. if (!group) {
  22218. axis.plotLinesAndBandsGroups[groupName] = group =
  22219. renderer.g('plot-' + groupName)
  22220. .attr(groupAttribs).add();
  22221. }
  22222. // Create the path
  22223. if (isNew) {
  22224. /**
  22225. * SVG element of the plot line or band.
  22226. *
  22227. * @name Highcharts.PlotLineOrBand#svgElement
  22228. * @type {Highcharts.SVGElement}
  22229. */
  22230. plotLine.svgElem = svgElem = renderer
  22231. .path()
  22232. .attr(attribs)
  22233. .add(group);
  22234. }
  22235. // Set the path or return
  22236. if (isLine) {
  22237. path = axis.getPlotLinePath({
  22238. value: value,
  22239. lineWidth: svgElem.strokeWidth(),
  22240. acrossPanes: options.acrossPanes
  22241. });
  22242. }
  22243. else if (isBand) { // plot band
  22244. path = axis.getPlotBandPath(from, to, options);
  22245. }
  22246. else {
  22247. return;
  22248. }
  22249. // common for lines and bands
  22250. // Add events only if they were not added before.
  22251. if (!plotLine.eventsAdded && events) {
  22252. objectEach(events, function (event, eventType) {
  22253. svgElem.on(eventType, function (e) {
  22254. events[eventType].apply(plotLine, [e]);
  22255. });
  22256. });
  22257. plotLine.eventsAdded = true;
  22258. }
  22259. if ((isNew || !svgElem.d) && path && path.length) {
  22260. svgElem.attr({ d: path });
  22261. }
  22262. else if (svgElem) {
  22263. if (path) {
  22264. svgElem.show(true);
  22265. svgElem.animate({ d: path });
  22266. }
  22267. else if (svgElem.d) {
  22268. svgElem.hide();
  22269. if (label) {
  22270. plotLine.label = label = label.destroy();
  22271. }
  22272. }
  22273. }
  22274. // the plot band/line label
  22275. if (optionsLabel &&
  22276. (defined(optionsLabel.text) || defined(optionsLabel.formatter)) &&
  22277. path &&
  22278. path.length &&
  22279. axis.width > 0 &&
  22280. axis.height > 0 &&
  22281. !path.isFlat) {
  22282. // apply defaults
  22283. optionsLabel = merge({
  22284. align: horiz && isBand && 'center',
  22285. x: horiz ? !isBand && 4 : 10,
  22286. verticalAlign: !horiz && isBand && 'middle',
  22287. y: horiz ? isBand ? 16 : 10 : isBand ? 6 : -4,
  22288. rotation: horiz && !isBand && 90
  22289. }, optionsLabel);
  22290. this.renderLabel(optionsLabel, path, isBand, zIndex);
  22291. }
  22292. else if (label) { // move out of sight
  22293. label.hide();
  22294. }
  22295. // chainable
  22296. return plotLine;
  22297. };
  22298. /**
  22299. * Render and align label for plot line or band.
  22300. *
  22301. * @private
  22302. * @function Highcharts.PlotLineOrBand#renderLabel
  22303. * @param {Highcharts.AxisPlotLinesLabelOptions|Highcharts.AxisPlotBandsLabelOptions} optionsLabel
  22304. * @param {Highcharts.SVGPathArray} path
  22305. * @param {boolean} [isBand]
  22306. * @param {number} [zIndex]
  22307. * @return {void}
  22308. */
  22309. PlotLineOrBand.prototype.renderLabel = function (optionsLabel, path, isBand, zIndex) {
  22310. var plotLine = this,
  22311. label = plotLine.label,
  22312. renderer = plotLine.axis.chart.renderer,
  22313. attribs,
  22314. xBounds,
  22315. yBounds,
  22316. x,
  22317. y,
  22318. labelText;
  22319. // add the SVG element
  22320. if (!label) {
  22321. attribs = {
  22322. align: optionsLabel.textAlign || optionsLabel.align,
  22323. rotation: optionsLabel.rotation,
  22324. 'class': 'highcharts-plot-' + (isBand ? 'band' : 'line') +
  22325. '-label ' + (optionsLabel.className || '')
  22326. };
  22327. attribs.zIndex = zIndex;
  22328. labelText = this.getLabelText(optionsLabel);
  22329. /**
  22330. * SVG element of the label.
  22331. *
  22332. * @name Highcharts.PlotLineOrBand#label
  22333. * @type {Highcharts.SVGElement}
  22334. */
  22335. plotLine.label = label = renderer
  22336. .text(labelText, 0, 0, optionsLabel.useHTML)
  22337. .attr(attribs)
  22338. .add();
  22339. if (!this.axis.chart.styledMode) {
  22340. label.css(optionsLabel.style);
  22341. }
  22342. }
  22343. // get the bounding box and align the label
  22344. // #3000 changed to better handle choice between plotband or plotline
  22345. xBounds = path.xBounds ||
  22346. [path[0][1], path[1][1], (isBand ? path[2][1] : path[0][1])];
  22347. yBounds = path.yBounds ||
  22348. [path[0][2], path[1][2], (isBand ? path[2][2] : path[0][2])];
  22349. x = arrayMin(xBounds);
  22350. y = arrayMin(yBounds);
  22351. label.align(optionsLabel, false, {
  22352. x: x,
  22353. y: y,
  22354. width: arrayMax(xBounds) - x,
  22355. height: arrayMax(yBounds) - y
  22356. });
  22357. label.show(true);
  22358. };
  22359. /**
  22360. * Get label's text content.
  22361. *
  22362. * @private
  22363. * @function Highcharts.PlotLineOrBand#getLabelText
  22364. * @param {Highcharts.AxisPlotLinesLabelOptions|Highcharts.AxisPlotBandsLabelOptions} optionsLabel
  22365. * @return {string}
  22366. */
  22367. PlotLineOrBand.prototype.getLabelText = function (optionsLabel) {
  22368. return defined(optionsLabel.formatter) ?
  22369. optionsLabel.formatter
  22370. .call(this) :
  22371. optionsLabel.text;
  22372. };
  22373. /**
  22374. * Remove the plot line or band.
  22375. *
  22376. * @function Highcharts.PlotLineOrBand#destroy
  22377. * @return {void}
  22378. */
  22379. PlotLineOrBand.prototype.destroy = function () {
  22380. // remove it from the lookup
  22381. erase(this.axis.plotLinesAndBands, this);
  22382. delete this.axis;
  22383. destroyObjectProperties(this);
  22384. };
  22385. return PlotLineOrBand;
  22386. }());
  22387. /* eslint-enable no-invalid-this, valid-jsdoc */
  22388. // Object with members for extending the Axis prototype
  22389. extend(Axis.prototype, /** @lends Highcharts.Axis.prototype */ {
  22390. /**
  22391. * An array of colored bands stretching across the plot area marking an
  22392. * interval on the axis.
  22393. *
  22394. * In styled mode, the plot bands are styled by the `.highcharts-plot-band`
  22395. * class in addition to the `className` option.
  22396. *
  22397. * @productdesc {highcharts}
  22398. * In a gauge, a plot band on the Y axis (value axis) will stretch along the
  22399. * perimeter of the gauge.
  22400. *
  22401. * @type {Array<*>}
  22402. * @product highcharts highstock gantt
  22403. * @apioption xAxis.plotBands
  22404. */
  22405. /**
  22406. * Flag to decide if plotBand should be rendered across all panes.
  22407. *
  22408. * @since 7.1.2
  22409. * @product highstock
  22410. * @type {boolean}
  22411. * @default true
  22412. * @apioption xAxis.plotBands.acrossPanes
  22413. */
  22414. /**
  22415. * Border color for the plot band. Also requires `borderWidth` to be set.
  22416. *
  22417. * @type {Highcharts.ColorString}
  22418. * @apioption xAxis.plotBands.borderColor
  22419. */
  22420. /**
  22421. * Border width for the plot band. Also requires `borderColor` to be set.
  22422. *
  22423. * @type {number}
  22424. * @default 0
  22425. * @apioption xAxis.plotBands.borderWidth
  22426. */
  22427. /**
  22428. * A custom class name, in addition to the default `highcharts-plot-band`,
  22429. * to apply to each individual band.
  22430. *
  22431. * @type {string}
  22432. * @since 5.0.0
  22433. * @apioption xAxis.plotBands.className
  22434. */
  22435. /**
  22436. * The color of the plot band.
  22437. *
  22438. * @sample {highcharts} highcharts/xaxis/plotbands-color/
  22439. * Color band
  22440. * @sample {highstock} stock/xaxis/plotbands/
  22441. * Plot band on Y axis
  22442. *
  22443. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  22444. * @default ${palette.highlightColor10}
  22445. * @apioption xAxis.plotBands.color
  22446. */
  22447. /**
  22448. * An object defining mouse events for the plot band. Supported properties
  22449. * are `click`, `mouseover`, `mouseout`, `mousemove`.
  22450. *
  22451. * @sample {highcharts} highcharts/xaxis/plotbands-events/
  22452. * Mouse events demonstrated
  22453. *
  22454. * @since 1.2
  22455. * @apioption xAxis.plotBands.events
  22456. */
  22457. /**
  22458. * Click event on a plot band.
  22459. *
  22460. * @type {Highcharts.EventCallbackFunction<Highcharts.PlotLineOrBand>}
  22461. * @apioption xAxis.plotBands.events.click
  22462. */
  22463. /**
  22464. * Mouse move event on a plot band.
  22465. *
  22466. * @type {Highcharts.EventCallbackFunction<Highcharts.PlotLineOrBand>}
  22467. * @apioption xAxis.plotBands.events.mousemove
  22468. */
  22469. /**
  22470. * Mouse out event on the corner of a plot band.
  22471. *
  22472. * @type {Highcharts.EventCallbackFunction<Highcharts.PlotLineOrBand>}
  22473. * @apioption xAxis.plotBands.events.mouseout
  22474. */
  22475. /**
  22476. * Mouse over event on a plot band.
  22477. *
  22478. * @type {Highcharts.EventCallbackFunction<Highcharts.PlotLineOrBand>}
  22479. * @apioption xAxis.plotBands.events.mouseover
  22480. */
  22481. /**
  22482. * The start position of the plot band in axis units.
  22483. *
  22484. * @sample {highcharts} highcharts/xaxis/plotbands-color/
  22485. * Datetime axis
  22486. * @sample {highcharts} highcharts/xaxis/plotbands-from/
  22487. * Categorized axis
  22488. * @sample {highstock} stock/xaxis/plotbands/
  22489. * Plot band on Y axis
  22490. *
  22491. * @type {number}
  22492. * @apioption xAxis.plotBands.from
  22493. */
  22494. /**
  22495. * An id used for identifying the plot band in Axis.removePlotBand.
  22496. *
  22497. * @sample {highcharts} highcharts/xaxis/plotbands-id/
  22498. * Remove plot band by id
  22499. * @sample {highstock} highcharts/xaxis/plotbands-id/
  22500. * Remove plot band by id
  22501. *
  22502. * @type {string}
  22503. * @apioption xAxis.plotBands.id
  22504. */
  22505. /**
  22506. * The end position of the plot band in axis units.
  22507. *
  22508. * @sample {highcharts} highcharts/xaxis/plotbands-color/
  22509. * Datetime axis
  22510. * @sample {highcharts} highcharts/xaxis/plotbands-from/
  22511. * Categorized axis
  22512. * @sample {highstock} stock/xaxis/plotbands/
  22513. * Plot band on Y axis
  22514. *
  22515. * @type {number}
  22516. * @apioption xAxis.plotBands.to
  22517. */
  22518. /**
  22519. * The z index of the plot band within the chart, relative to other
  22520. * elements. Using the same z index as another element may give
  22521. * unpredictable results, as the last rendered element will be on top.
  22522. * Values from 0 to 20 make sense.
  22523. *
  22524. * @sample {highcharts} highcharts/xaxis/plotbands-color/
  22525. * Behind plot lines by default
  22526. * @sample {highcharts} highcharts/xaxis/plotbands-zindex/
  22527. * Above plot lines
  22528. * @sample {highcharts} highcharts/xaxis/plotbands-zindex-above-series/
  22529. * Above plot lines and series
  22530. *
  22531. * @type {number}
  22532. * @since 1.2
  22533. * @apioption xAxis.plotBands.zIndex
  22534. */
  22535. /**
  22536. * Text labels for the plot bands
  22537. *
  22538. * @product highcharts highstock gantt
  22539. * @apioption xAxis.plotBands.label
  22540. */
  22541. /**
  22542. * Horizontal alignment of the label. Can be one of "left", "center" or
  22543. * "right".
  22544. *
  22545. * @sample {highcharts} highcharts/xaxis/plotbands-label-align/
  22546. * Aligned to the right
  22547. * @sample {highstock} stock/xaxis/plotbands-label/
  22548. * Plot band with labels
  22549. *
  22550. * @type {Highcharts.AlignValue}
  22551. * @default center
  22552. * @since 2.1
  22553. * @apioption xAxis.plotBands.label.align
  22554. */
  22555. /**
  22556. * Rotation of the text label in degrees .
  22557. *
  22558. * @sample {highcharts} highcharts/xaxis/plotbands-label-rotation/
  22559. * Vertical text
  22560. *
  22561. * @type {number}
  22562. * @default 0
  22563. * @since 2.1
  22564. * @apioption xAxis.plotBands.label.rotation
  22565. */
  22566. /**
  22567. * CSS styles for the text label.
  22568. *
  22569. * In styled mode, the labels are styled by the
  22570. * `.highcharts-plot-band-label` class.
  22571. *
  22572. * @sample {highcharts} highcharts/xaxis/plotbands-label-style/
  22573. * Blue and bold label
  22574. *
  22575. * @type {Highcharts.CSSObject}
  22576. * @since 2.1
  22577. * @apioption xAxis.plotBands.label.style
  22578. */
  22579. /**
  22580. * The string text itself. A subset of HTML is supported.
  22581. *
  22582. * @type {string}
  22583. * @since 2.1
  22584. * @apioption xAxis.plotBands.label.text
  22585. */
  22586. /**
  22587. * The text alignment for the label. While `align` determines where the
  22588. * texts anchor point is placed within the plot band, `textAlign` determines
  22589. * how the text is aligned against its anchor point. Possible values are
  22590. * "left", "center" and "right". Defaults to the same as the `align` option.
  22591. *
  22592. * @sample {highcharts} highcharts/xaxis/plotbands-label-rotation/
  22593. * Vertical text in center position but text-aligned left
  22594. *
  22595. * @type {Highcharts.AlignValue}
  22596. * @since 2.1
  22597. * @apioption xAxis.plotBands.label.textAlign
  22598. */
  22599. /**
  22600. * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  22601. * to render the labels.
  22602. *
  22603. * @type {boolean}
  22604. * @default false
  22605. * @since 3.0.3
  22606. * @apioption xAxis.plotBands.label.useHTML
  22607. */
  22608. /**
  22609. * Vertical alignment of the label relative to the plot band. Can be one of
  22610. * "top", "middle" or "bottom".
  22611. *
  22612. * @sample {highcharts} highcharts/xaxis/plotbands-label-verticalalign/
  22613. * Vertically centered label
  22614. * @sample {highstock} stock/xaxis/plotbands-label/
  22615. * Plot band with labels
  22616. *
  22617. * @type {Highcharts.VerticalAlignValue}
  22618. * @default top
  22619. * @since 2.1
  22620. * @apioption xAxis.plotBands.label.verticalAlign
  22621. */
  22622. /**
  22623. * Horizontal position relative the alignment. Default varies by
  22624. * orientation.
  22625. *
  22626. * @sample {highcharts} highcharts/xaxis/plotbands-label-align/
  22627. * Aligned 10px from the right edge
  22628. * @sample {highstock} stock/xaxis/plotbands-label/
  22629. * Plot band with labels
  22630. *
  22631. * @type {number}
  22632. * @since 2.1
  22633. * @apioption xAxis.plotBands.label.x
  22634. */
  22635. /**
  22636. * Vertical position of the text baseline relative to the alignment. Default
  22637. * varies by orientation.
  22638. *
  22639. * @sample {highcharts} highcharts/xaxis/plotbands-label-y/
  22640. * Label on x axis
  22641. * @sample {highstock} stock/xaxis/plotbands-label/
  22642. * Plot band with labels
  22643. *
  22644. * @type {number}
  22645. * @since 2.1
  22646. * @apioption xAxis.plotBands.label.y
  22647. */
  22648. /**
  22649. * An array of lines stretching across the plot area, marking a specific
  22650. * value on one of the axes.
  22651. *
  22652. * In styled mode, the plot lines are styled by the
  22653. * `.highcharts-plot-line` class in addition to the `className` option.
  22654. *
  22655. * @type {Array<*>}
  22656. * @product highcharts highstock gantt
  22657. * @sample {highcharts} highcharts/xaxis/plotlines-color/
  22658. * Basic plot line
  22659. * @sample {highcharts} highcharts/series-solidgauge/labels-auto-aligned/
  22660. * Solid gauge plot line
  22661. * @apioption xAxis.plotLines
  22662. */
  22663. /**
  22664. * Flag to decide if plotLine should be rendered across all panes.
  22665. *
  22666. * @sample {highstock} stock/xaxis/plotlines-acrosspanes/
  22667. * Plot lines on different panes
  22668. *
  22669. * @since 7.1.2
  22670. * @product highstock
  22671. * @type {boolean}
  22672. * @default true
  22673. * @apioption xAxis.plotLines.acrossPanes
  22674. */
  22675. /**
  22676. * A custom class name, in addition to the default `highcharts-plot-line`,
  22677. * to apply to each individual line.
  22678. *
  22679. * @type {string}
  22680. * @since 5.0.0
  22681. * @apioption xAxis.plotLines.className
  22682. */
  22683. /**
  22684. * The color of the line.
  22685. *
  22686. * @sample {highcharts} highcharts/xaxis/plotlines-color/
  22687. * A red line from X axis
  22688. * @sample {highstock} stock/xaxis/plotlines/
  22689. * Plot line on Y axis
  22690. *
  22691. * @type {Highcharts.ColorString}
  22692. * @default ${palette.neutralColor40}
  22693. * @apioption xAxis.plotLines.color
  22694. */
  22695. /**
  22696. * The dashing or dot style for the plot line. For possible values see
  22697. * [this overview](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/series-dashstyle-all/).
  22698. *
  22699. * @sample {highcharts} highcharts/xaxis/plotlines-dashstyle/
  22700. * Dash and dot pattern
  22701. * @sample {highstock} stock/xaxis/plotlines/
  22702. * Plot line on Y axis
  22703. *
  22704. * @type {Highcharts.DashStyleValue}
  22705. * @default Solid
  22706. * @since 1.2
  22707. * @apioption xAxis.plotLines.dashStyle
  22708. */
  22709. /**
  22710. * An object defining mouse events for the plot line. Supported
  22711. * properties are `click`, `mouseover`, `mouseout`, `mousemove`.
  22712. *
  22713. * @sample {highcharts} highcharts/xaxis/plotlines-events/
  22714. * Mouse events demonstrated
  22715. *
  22716. * @since 1.2
  22717. * @apioption xAxis.plotLines.events
  22718. */
  22719. /**
  22720. * Click event on a plot band.
  22721. *
  22722. * @type {Highcharts.EventCallbackFunction<Highcharts.PlotLineOrBand>}
  22723. * @apioption xAxis.plotLines.events.click
  22724. */
  22725. /**
  22726. * Mouse move event on a plot band.
  22727. *
  22728. * @type {Highcharts.EventCallbackFunction<Highcharts.PlotLineOrBand>}
  22729. * @apioption xAxis.plotLines.events.mousemove
  22730. */
  22731. /**
  22732. * Mouse out event on the corner of a plot band.
  22733. *
  22734. * @type {Highcharts.EventCallbackFunction<Highcharts.PlotLineOrBand>}
  22735. * @apioption xAxis.plotLines.events.mouseout
  22736. */
  22737. /**
  22738. * Mouse over event on a plot band.
  22739. *
  22740. * @type {Highcharts.EventCallbackFunction<Highcharts.PlotLineOrBand>}
  22741. * @apioption xAxis.plotLines.events.mouseover
  22742. */
  22743. /**
  22744. * An id used for identifying the plot line in Axis.removePlotLine.
  22745. *
  22746. * @sample {highcharts} highcharts/xaxis/plotlines-id/
  22747. * Remove plot line by id
  22748. *
  22749. * @type {string}
  22750. * @apioption xAxis.plotLines.id
  22751. */
  22752. /**
  22753. * The position of the line in axis units.
  22754. *
  22755. * @sample {highcharts} highcharts/xaxis/plotlines-color/
  22756. * Between two categories on X axis
  22757. * @sample {highstock} stock/xaxis/plotlines/
  22758. * Plot line on Y axis
  22759. *
  22760. * @type {number}
  22761. * @apioption xAxis.plotLines.value
  22762. */
  22763. /**
  22764. * The width or thickness of the plot line.
  22765. *
  22766. * @sample {highcharts} highcharts/xaxis/plotlines-color/
  22767. * 2px wide line from X axis
  22768. * @sample {highstock} stock/xaxis/plotlines/
  22769. * Plot line on Y axis
  22770. *
  22771. * @type {number}
  22772. * @default 2
  22773. * @apioption xAxis.plotLines.width
  22774. */
  22775. /**
  22776. * The z index of the plot line within the chart.
  22777. *
  22778. * @sample {highcharts} highcharts/xaxis/plotlines-zindex-behind/
  22779. * Behind plot lines by default
  22780. * @sample {highcharts} highcharts/xaxis/plotlines-zindex-above/
  22781. * Above plot lines
  22782. * @sample {highcharts} highcharts/xaxis/plotlines-zindex-above-all/
  22783. * Above plot lines and series
  22784. *
  22785. * @type {number}
  22786. * @since 1.2
  22787. * @apioption xAxis.plotLines.zIndex
  22788. */
  22789. /**
  22790. * Text labels for the plot bands
  22791. *
  22792. * @apioption xAxis.plotLines.label
  22793. */
  22794. /**
  22795. * Horizontal alignment of the label. Can be one of "left", "center" or
  22796. * "right".
  22797. *
  22798. * @sample {highcharts} highcharts/xaxis/plotlines-label-align-right/
  22799. * Aligned to the right
  22800. * @sample {highstock} stock/xaxis/plotlines/
  22801. * Plot line on Y axis
  22802. *
  22803. * @type {Highcharts.AlignValue}
  22804. * @default left
  22805. * @since 2.1
  22806. * @apioption xAxis.plotLines.label.align
  22807. */
  22808. /**
  22809. * Callback JavaScript function to format the label. Useful properties like
  22810. * the value of plot line or the range of plot band (`from` & `to`
  22811. * properties) can be found in `this.options` object.
  22812. *
  22813. * @sample {highcharts} highcharts/xaxis/plotlines-plotbands-label-formatter
  22814. * Label formatters for plot line and plot band.
  22815. * @type {Highcharts.FormatterCallbackFunction<Highcharts.PlotLineOrBand>}
  22816. * @apioption xAxis.plotLines.label.formatter
  22817. */
  22818. /**
  22819. * Rotation of the text label in degrees. Defaults to 0 for horizontal plot
  22820. * lines and 90 for vertical lines.
  22821. *
  22822. * @sample {highcharts} highcharts/xaxis/plotlines-label-verticalalign-middle/
  22823. * Slanted text
  22824. *
  22825. * @type {number}
  22826. * @since 2.1
  22827. * @apioption xAxis.plotLines.label.rotation
  22828. */
  22829. /**
  22830. * CSS styles for the text label.
  22831. *
  22832. * In styled mode, the labels are styled by the
  22833. * `.highcharts-plot-line-label` class.
  22834. *
  22835. * @sample {highcharts} highcharts/xaxis/plotlines-label-style/
  22836. * Blue and bold label
  22837. *
  22838. * @type {Highcharts.CSSObject}
  22839. * @since 2.1
  22840. * @apioption xAxis.plotLines.label.style
  22841. */
  22842. /**
  22843. * The text itself. A subset of HTML is supported.
  22844. *
  22845. * @type {string}
  22846. * @since 2.1
  22847. * @apioption xAxis.plotLines.label.text
  22848. */
  22849. /**
  22850. * The text alignment for the label. While `align` determines where the
  22851. * texts anchor point is placed within the plot band, `textAlign` determines
  22852. * how the text is aligned against its anchor point. Possible values are
  22853. * "left", "center" and "right". Defaults to the same as the `align` option.
  22854. *
  22855. * @sample {highcharts} highcharts/xaxis/plotlines-label-textalign/
  22856. * Text label in bottom position
  22857. *
  22858. * @type {Highcharts.AlignValue}
  22859. * @since 2.1
  22860. * @apioption xAxis.plotLines.label.textAlign
  22861. */
  22862. /**
  22863. * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  22864. * to render the labels.
  22865. *
  22866. * @type {boolean}
  22867. * @default false
  22868. * @since 3.0.3
  22869. * @apioption xAxis.plotLines.label.useHTML
  22870. */
  22871. /**
  22872. * Vertical alignment of the label relative to the plot line. Can be
  22873. * one of "top", "middle" or "bottom".
  22874. *
  22875. * @sample {highcharts} highcharts/xaxis/plotlines-label-verticalalign-middle/
  22876. * Vertically centered label
  22877. *
  22878. * @type {Highcharts.VerticalAlignValue}
  22879. * @default {highcharts} top
  22880. * @default {highstock} top
  22881. * @since 2.1
  22882. * @apioption xAxis.plotLines.label.verticalAlign
  22883. */
  22884. /**
  22885. * Horizontal position relative the alignment. Default varies by
  22886. * orientation.
  22887. *
  22888. * @sample {highcharts} highcharts/xaxis/plotlines-label-align-right/
  22889. * Aligned 10px from the right edge
  22890. * @sample {highstock} stock/xaxis/plotlines/
  22891. * Plot line on Y axis
  22892. *
  22893. * @type {number}
  22894. * @since 2.1
  22895. * @apioption xAxis.plotLines.label.x
  22896. */
  22897. /**
  22898. * Vertical position of the text baseline relative to the alignment. Default
  22899. * varies by orientation.
  22900. *
  22901. * @sample {highcharts} highcharts/xaxis/plotlines-label-y/
  22902. * Label below the plot line
  22903. * @sample {highstock} stock/xaxis/plotlines/
  22904. * Plot line on Y axis
  22905. *
  22906. * @type {number}
  22907. * @since 2.1
  22908. * @apioption xAxis.plotLines.label.y
  22909. */
  22910. /**
  22911. *
  22912. * @type {Array<*>}
  22913. * @extends xAxis.plotBands
  22914. * @apioption yAxis.plotBands
  22915. */
  22916. /**
  22917. * In a gauge chart, this option determines the inner radius of the
  22918. * plot band that stretches along the perimeter. It can be given as
  22919. * a percentage string, like `"100%"`, or as a pixel number, like `100`.
  22920. * By default, the inner radius is controlled by the [thickness](
  22921. * #yAxis.plotBands.thickness) option.
  22922. *
  22923. * @sample {highcharts} highcharts/xaxis/plotbands-gauge
  22924. * Gauge plot band
  22925. *
  22926. * @type {number|string}
  22927. * @since 2.3
  22928. * @product highcharts
  22929. * @apioption yAxis.plotBands.innerRadius
  22930. */
  22931. /**
  22932. * In a gauge chart, this option determines the outer radius of the
  22933. * plot band that stretches along the perimeter. It can be given as
  22934. * a percentage string, like `"100%"`, or as a pixel number, like `100`.
  22935. *
  22936. * @sample {highcharts} highcharts/xaxis/plotbands-gauge
  22937. * Gauge plot band
  22938. *
  22939. * @type {number|string}
  22940. * @default 100%
  22941. * @since 2.3
  22942. * @product highcharts
  22943. * @apioption yAxis.plotBands.outerRadius
  22944. */
  22945. /**
  22946. * In a gauge chart, this option sets the width of the plot band
  22947. * stretching along the perimeter. It can be given as a percentage
  22948. * string, like `"10%"`, or as a pixel number, like `10`. The default
  22949. * value 10 is the same as the default [tickLength](#yAxis.tickLength),
  22950. * thus making the plot band act as a background for the tick markers.
  22951. *
  22952. * @sample {highcharts} highcharts/xaxis/plotbands-gauge
  22953. * Gauge plot band
  22954. *
  22955. * @type {number|string}
  22956. * @default 10
  22957. * @since 2.3
  22958. * @product highcharts
  22959. * @apioption yAxis.plotBands.thickness
  22960. */
  22961. /**
  22962. * @type {Array<*>}
  22963. * @extends xAxis.plotLines
  22964. * @apioption yAxis.plotLines
  22965. */
  22966. /* eslint-disable no-invalid-this, valid-jsdoc */
  22967. /**
  22968. * Internal function to create the SVG path definition for a plot band.
  22969. *
  22970. * @function Highcharts.Axis#getPlotBandPath
  22971. *
  22972. * @param {number} from
  22973. * The axis value to start from.
  22974. *
  22975. * @param {number} to
  22976. * The axis value to end on.
  22977. *
  22978. * @param {Highcharts.AxisPlotBandsOptions|Highcharts.AxisPlotLinesOptions} options
  22979. * The plotBand or plotLine configuration object.
  22980. *
  22981. * @return {Highcharts.SVGPathArray}
  22982. * The SVG path definition in array form.
  22983. */
  22984. getPlotBandPath: function (from, to, options) {
  22985. if (options === void 0) { options = this.options; }
  22986. var toPath = this.getPlotLinePath({
  22987. value: to,
  22988. force: true,
  22989. acrossPanes: options.acrossPanes
  22990. }),
  22991. path = this.getPlotLinePath({
  22992. value: from,
  22993. force: true,
  22994. acrossPanes: options.acrossPanes
  22995. }),
  22996. result = [],
  22997. i,
  22998. // #4964 check if chart is inverted or plotband is on yAxis
  22999. horiz = this.horiz,
  23000. plus = 1,
  23001. isFlat,
  23002. outside = !isNumber(this.min) ||
  23003. !isNumber(this.max) ||
  23004. (from < this.min && to < this.min) ||
  23005. (from > this.max && to > this.max);
  23006. if (path && toPath) {
  23007. // Flat paths don't need labels (#3836)
  23008. if (outside) {
  23009. isFlat = path.toString() === toPath.toString();
  23010. plus = 0;
  23011. }
  23012. // Go over each subpath - for panes in Highcharts Stock
  23013. for (i = 0; i < path.length; i += 2) {
  23014. var pathStart = path[i],
  23015. pathEnd = path[i + 1],
  23016. toPathStart = toPath[i],
  23017. toPathEnd = toPath[i + 1];
  23018. // Type checking all affected path segments. Consider something
  23019. // smarter.
  23020. if ((pathStart[0] === 'M' || pathStart[0] === 'L') &&
  23021. (pathEnd[0] === 'M' || pathEnd[0] === 'L') &&
  23022. (toPathStart[0] === 'M' || toPathStart[0] === 'L') &&
  23023. (toPathEnd[0] === 'M' || toPathEnd[0] === 'L')) {
  23024. // Add 1 pixel when coordinates are the same
  23025. if (horiz && toPathStart[1] === pathStart[1]) {
  23026. toPathStart[1] += plus;
  23027. toPathEnd[1] += plus;
  23028. }
  23029. else if (!horiz && toPathStart[2] === pathStart[2]) {
  23030. toPathStart[2] += plus;
  23031. toPathEnd[2] += plus;
  23032. }
  23033. result.push(['M', pathStart[1], pathStart[2]], ['L', pathEnd[1], pathEnd[2]], ['L', toPathEnd[1], toPathEnd[2]], ['L', toPathStart[1], toPathStart[2]], ['Z']);
  23034. }
  23035. result.isFlat = isFlat;
  23036. }
  23037. }
  23038. else { // outside the axis area
  23039. path = null;
  23040. }
  23041. return result;
  23042. },
  23043. /**
  23044. * Add a plot band after render time.
  23045. *
  23046. * @sample highcharts/members/axis-addplotband/
  23047. * Toggle the plot band from a button
  23048. *
  23049. * @function Highcharts.Axis#addPlotBand
  23050. *
  23051. * @param {Highcharts.AxisPlotBandsOptions} options
  23052. * A configuration object for the plot band, as defined in
  23053. * [xAxis.plotBands](https://api.highcharts.com/highcharts/xAxis.plotBands).
  23054. *
  23055. * @return {Highcharts.PlotLineOrBand|undefined}
  23056. * The added plot band.
  23057. */
  23058. addPlotBand: function (options) {
  23059. return this.addPlotBandOrLine(options, 'plotBands');
  23060. },
  23061. /**
  23062. * Add a plot line after render time.
  23063. *
  23064. * @sample highcharts/members/axis-addplotline/
  23065. * Toggle the plot line from a button
  23066. *
  23067. * @function Highcharts.Axis#addPlotLine
  23068. *
  23069. * @param {Highcharts.AxisPlotLinesOptions} options
  23070. * A configuration object for the plot line, as defined in
  23071. * [xAxis.plotLines](https://api.highcharts.com/highcharts/xAxis.plotLines).
  23072. *
  23073. * @return {Highcharts.PlotLineOrBand|undefined}
  23074. * The added plot line.
  23075. */
  23076. addPlotLine: function (options) {
  23077. return this.addPlotBandOrLine(options, 'plotLines');
  23078. },
  23079. /**
  23080. * Add a plot band or plot line after render time. Called from addPlotBand
  23081. * and addPlotLine internally.
  23082. *
  23083. * @private
  23084. * @function Highcharts.Axis#addPlotBandOrLine
  23085. *
  23086. * @param {Highcharts.AxisPlotBandsOptions|Highcharts.AxisPlotLinesOptions} options
  23087. * The plotBand or plotLine configuration object.
  23088. *
  23089. * @param {"plotBands"|"plotLines"} [coll]
  23090. *
  23091. * @return {Highcharts.PlotLineOrBand|undefined}
  23092. */
  23093. addPlotBandOrLine: function (options, coll) {
  23094. var _this = this;
  23095. var obj = new PlotLineOrBand(this,
  23096. options),
  23097. userOptions = this.userOptions;
  23098. if (this.visible) {
  23099. obj = obj.render();
  23100. }
  23101. if (obj) { // #2189
  23102. if (!this._addedPlotLB) {
  23103. this._addedPlotLB = true;
  23104. (userOptions.plotLines || [])
  23105. .concat(userOptions.plotBands || [])
  23106. .forEach(function (plotLineOptions) {
  23107. _this.addPlotBandOrLine(plotLineOptions);
  23108. });
  23109. }
  23110. // Add it to the user options for exporting and Axis.update
  23111. if (coll) {
  23112. // Workaround Microsoft/TypeScript issue #32693
  23113. var updatedOptions = (userOptions[coll] || []);
  23114. updatedOptions.push(options);
  23115. userOptions[coll] = updatedOptions;
  23116. }
  23117. this.plotLinesAndBands.push(obj);
  23118. }
  23119. return obj;
  23120. },
  23121. /**
  23122. * Remove a plot band or plot line from the chart by id. Called internally
  23123. * from `removePlotBand` and `removePlotLine`.
  23124. *
  23125. * @private
  23126. * @function Highcharts.Axis#removePlotBandOrLine
  23127. * @param {string} id
  23128. * @return {void}
  23129. */
  23130. removePlotBandOrLine: function (id) {
  23131. var plotLinesAndBands = this.plotLinesAndBands,
  23132. options = this.options,
  23133. userOptions = this.userOptions;
  23134. if (plotLinesAndBands) { // #15639
  23135. var i_1 = plotLinesAndBands.length;
  23136. while (i_1--) {
  23137. if (plotLinesAndBands[i_1].id === id) {
  23138. plotLinesAndBands[i_1].destroy();
  23139. }
  23140. }
  23141. ([
  23142. options.plotLines || [],
  23143. userOptions.plotLines || [],
  23144. options.plotBands || [],
  23145. userOptions.plotBands || []
  23146. ]).forEach(function (arr) {
  23147. i_1 = arr.length;
  23148. while (i_1--) {
  23149. if ((arr[i_1] || {}).id === id) {
  23150. erase(arr, arr[i_1]);
  23151. }
  23152. }
  23153. });
  23154. }
  23155. },
  23156. /**
  23157. * Remove a plot band by its id.
  23158. *
  23159. * @sample highcharts/members/axis-removeplotband/
  23160. * Remove plot band by id
  23161. * @sample highcharts/members/axis-addplotband/
  23162. * Toggle the plot band from a button
  23163. *
  23164. * @function Highcharts.Axis#removePlotBand
  23165. *
  23166. * @param {string} id
  23167. * The plot band's `id` as given in the original configuration
  23168. * object or in the `addPlotBand` option.
  23169. *
  23170. * @return {void}
  23171. */
  23172. removePlotBand: function (id) {
  23173. this.removePlotBandOrLine(id);
  23174. },
  23175. /**
  23176. * Remove a plot line by its id.
  23177. *
  23178. * @sample highcharts/xaxis/plotlines-id/
  23179. * Remove plot line by id
  23180. * @sample highcharts/members/axis-addplotline/
  23181. * Toggle the plot line from a button
  23182. *
  23183. * @function Highcharts.Axis#removePlotLine
  23184. *
  23185. * @param {string} id
  23186. * The plot line's `id` as given in the original configuration
  23187. * object or in the `addPlotLine` option.
  23188. */
  23189. removePlotLine: function (id) {
  23190. this.removePlotBandOrLine(id);
  23191. }
  23192. });
  23193. return PlotLineOrBand;
  23194. });
  23195. _registerModule(_modules, 'Core/Tooltip.js', [_modules['Core/FormatUtilities.js'], _modules['Core/Globals.js'], _modules['Core/Color/Palette.js'], _modules['Core/Renderer/RendererRegistry.js'], _modules['Core/Utilities.js']], function (F, H, palette, RendererRegistry, U) {
  23196. /* *
  23197. *
  23198. * (c) 2010-2021 Torstein Honsi
  23199. *
  23200. * License: www.highcharts.com/license
  23201. *
  23202. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  23203. *
  23204. * */
  23205. var format = F.format;
  23206. var doc = H.doc;
  23207. var clamp = U.clamp,
  23208. css = U.css,
  23209. defined = U.defined,
  23210. discardElement = U.discardElement,
  23211. extend = U.extend,
  23212. fireEvent = U.fireEvent,
  23213. isArray = U.isArray,
  23214. isNumber = U.isNumber,
  23215. isString = U.isString,
  23216. merge = U.merge,
  23217. pick = U.pick,
  23218. splat = U.splat,
  23219. syncTimeout = U.syncTimeout,
  23220. timeUnits = U.timeUnits;
  23221. /**
  23222. * Callback function to format the text of the tooltip from scratch.
  23223. *
  23224. * In case of single or shared tooltips, a string should be be returned. In case
  23225. * of splitted tooltips, it should return an array where the first item is the
  23226. * header, and subsequent items are mapped to the points. Return `false` to
  23227. * disable tooltip for a specific point on series.
  23228. *
  23229. * @callback Highcharts.TooltipFormatterCallbackFunction
  23230. *
  23231. * @param {Highcharts.TooltipFormatterContextObject} this
  23232. * Context to format
  23233. *
  23234. * @param {Highcharts.Tooltip} tooltip
  23235. * The tooltip instance
  23236. *
  23237. * @return {false|string|Array<(string|null|undefined)>|null|undefined}
  23238. * Formatted text or false
  23239. */
  23240. /**
  23241. * @interface Highcharts.TooltipFormatterContextObject
  23242. */ /**
  23243. * @name Highcharts.TooltipFormatterContextObject#color
  23244. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  23245. */ /**
  23246. * @name Highcharts.TooltipFormatterContextObject#colorIndex
  23247. * @type {number|undefined}
  23248. */ /**
  23249. * @name Highcharts.TooltipFormatterContextObject#key
  23250. * @type {number}
  23251. */ /**
  23252. * @name Highcharts.TooltipFormatterContextObject#percentage
  23253. * @type {number|undefined}
  23254. */ /**
  23255. * @name Highcharts.TooltipFormatterContextObject#point
  23256. * @type {Highcharts.Point}
  23257. */ /**
  23258. * @name Highcharts.TooltipFormatterContextObject#points
  23259. * @type {Array<Highcharts.TooltipFormatterContextObject>|undefined}
  23260. */ /**
  23261. * @name Highcharts.TooltipFormatterContextObject#series
  23262. * @type {Highcharts.Series}
  23263. */ /**
  23264. * @name Highcharts.TooltipFormatterContextObject#total
  23265. * @type {number|undefined}
  23266. */ /**
  23267. * @name Highcharts.TooltipFormatterContextObject#x
  23268. * @type {number}
  23269. */ /**
  23270. * @name Highcharts.TooltipFormatterContextObject#y
  23271. * @type {number}
  23272. */
  23273. /**
  23274. * A callback function to place the tooltip in a specific position.
  23275. *
  23276. * @callback Highcharts.TooltipPositionerCallbackFunction
  23277. *
  23278. * @param {Highcharts.Tooltip} this
  23279. * Tooltip context of the callback.
  23280. *
  23281. * @param {number} labelWidth
  23282. * Width of the tooltip.
  23283. *
  23284. * @param {number} labelHeight
  23285. * Height of the tooltip.
  23286. *
  23287. * @param {Highcharts.TooltipPositionerPointObject} point
  23288. * Point information for positioning a tooltip.
  23289. *
  23290. * @return {Highcharts.PositionObject}
  23291. * New position for the tooltip.
  23292. */
  23293. /**
  23294. * Point information for positioning a tooltip.
  23295. *
  23296. * @interface Highcharts.TooltipPositionerPointObject
  23297. * @extends Highcharts.Point
  23298. */ /**
  23299. * If `tooltip.split` option is enabled and positioner is called for each of the
  23300. * boxes separately, this property indicates the call on the xAxis header, which
  23301. * is not a point itself.
  23302. * @name Highcharts.TooltipPositionerPointObject#isHeader
  23303. * @type {boolean}
  23304. */ /**
  23305. * The reference point relative to the plot area. Add chart.plotLeft to get the
  23306. * full coordinates.
  23307. * @name Highcharts.TooltipPositionerPointObject#plotX
  23308. * @type {number}
  23309. */ /**
  23310. * The reference point relative to the plot area. Add chart.plotTop to get the
  23311. * full coordinates.
  23312. * @name Highcharts.TooltipPositionerPointObject#plotY
  23313. * @type {number}
  23314. */
  23315. /**
  23316. * @typedef {"callout"|"circle"|"square"} Highcharts.TooltipShapeValue
  23317. */
  23318. ''; // separates doclets above from variables below
  23319. /* eslint-disable no-invalid-this, valid-jsdoc */
  23320. /**
  23321. * Tooltip of a chart.
  23322. *
  23323. * @class
  23324. * @name Highcharts.Tooltip
  23325. *
  23326. * @param {Highcharts.Chart} chart
  23327. * The chart instance.
  23328. *
  23329. * @param {Highcharts.TooltipOptions} options
  23330. * Tooltip options.
  23331. */
  23332. var Tooltip = /** @class */ (function () {
  23333. /* *
  23334. *
  23335. * Constructors
  23336. *
  23337. * */
  23338. function Tooltip(chart, options) {
  23339. this.container = void 0;
  23340. this.crosshairs = [];
  23341. this.distance = 0;
  23342. this.isHidden = true;
  23343. this.isSticky = false;
  23344. this.now = {};
  23345. this.options = {};
  23346. this.outside = false;
  23347. this.chart = chart;
  23348. this.init(chart, options);
  23349. }
  23350. /* *
  23351. *
  23352. * Functions
  23353. *
  23354. * */
  23355. /**
  23356. * In styled mode, apply the default filter for the tooltip drop-shadow. It
  23357. * needs to have an id specific to the chart, otherwise there will be issues
  23358. * when one tooltip adopts the filter of a different chart, specifically one
  23359. * where the container is hidden.
  23360. *
  23361. * @private
  23362. * @function Highcharts.Tooltip#applyFilter
  23363. */
  23364. Tooltip.prototype.applyFilter = function () {
  23365. var chart = this.chart;
  23366. chart.renderer.definition({
  23367. tagName: 'filter',
  23368. attributes: {
  23369. id: 'drop-shadow-' + chart.index,
  23370. opacity: 0.5
  23371. },
  23372. children: [{
  23373. tagName: 'feGaussianBlur',
  23374. attributes: {
  23375. 'in': 'SourceAlpha',
  23376. stdDeviation: 1
  23377. }
  23378. }, {
  23379. tagName: 'feOffset',
  23380. attributes: {
  23381. dx: 1,
  23382. dy: 1
  23383. }
  23384. }, {
  23385. tagName: 'feComponentTransfer',
  23386. children: [{
  23387. tagName: 'feFuncA',
  23388. attributes: {
  23389. type: 'linear',
  23390. slope: 0.3
  23391. }
  23392. }]
  23393. }, {
  23394. tagName: 'feMerge',
  23395. children: [{
  23396. tagName: 'feMergeNode'
  23397. }, {
  23398. tagName: 'feMergeNode',
  23399. attributes: {
  23400. 'in': 'SourceGraphic'
  23401. }
  23402. }]
  23403. }]
  23404. });
  23405. chart.renderer.definition({
  23406. tagName: 'style',
  23407. textContent: '.highcharts-tooltip-' + chart.index + '{' +
  23408. 'filter:url(#drop-shadow-' + chart.index + ')' +
  23409. '}'
  23410. });
  23411. };
  23412. /**
  23413. * Build the body (lines) of the tooltip by iterating over the items and
  23414. * returning one entry for each item, abstracting this functionality allows
  23415. * to easily overwrite and extend it.
  23416. *
  23417. * @private
  23418. * @function Highcharts.Tooltip#bodyFormatter
  23419. * @param {Array<(Highcharts.Point|Highcharts.Series)>} items
  23420. * @return {Array<string>}
  23421. */
  23422. Tooltip.prototype.bodyFormatter = function (items) {
  23423. return items.map(function (item) {
  23424. var tooltipOptions = item.series.tooltipOptions;
  23425. return (tooltipOptions[(item.point.formatPrefix || 'point') + 'Formatter'] ||
  23426. item.point.tooltipFormatter).call(item.point, tooltipOptions[(item.point.formatPrefix || 'point') + 'Format'] || '');
  23427. });
  23428. };
  23429. /**
  23430. * Destroy the single tooltips in a split tooltip.
  23431. * If the tooltip is active then it is not destroyed, unless forced to.
  23432. *
  23433. * @private
  23434. * @function Highcharts.Tooltip#cleanSplit
  23435. *
  23436. * @param {boolean} [force]
  23437. * Force destroy all tooltips.
  23438. */
  23439. Tooltip.prototype.cleanSplit = function (force) {
  23440. this.chart.series.forEach(function (series) {
  23441. var tt = series && series.tt;
  23442. if (tt) {
  23443. if (!tt.isActive || force) {
  23444. series.tt = tt.destroy();
  23445. }
  23446. else {
  23447. tt.isActive = false;
  23448. }
  23449. }
  23450. });
  23451. };
  23452. /**
  23453. * In case no user defined formatter is given, this will be used. Note that
  23454. * the context here is an object holding point, series, x, y etc.
  23455. *
  23456. * @function Highcharts.Tooltip#defaultFormatter
  23457. *
  23458. * @param {Highcharts.Tooltip} tooltip
  23459. *
  23460. * @return {Array<string>}
  23461. */
  23462. Tooltip.prototype.defaultFormatter = function (tooltip) {
  23463. var items = this.points || splat(this),
  23464. s;
  23465. // Build the header
  23466. s = [tooltip.tooltipFooterHeaderFormatter(items[0])];
  23467. // build the values
  23468. s = s.concat(tooltip.bodyFormatter(items));
  23469. // footer
  23470. s.push(tooltip.tooltipFooterHeaderFormatter(items[0], true));
  23471. return s;
  23472. };
  23473. /**
  23474. * Removes and destroys the tooltip and its elements.
  23475. *
  23476. * @function Highcharts.Tooltip#destroy
  23477. */
  23478. Tooltip.prototype.destroy = function () {
  23479. // Destroy and clear local variables
  23480. if (this.label) {
  23481. this.label = this.label.destroy();
  23482. }
  23483. if (this.split && this.tt) {
  23484. this.cleanSplit(this.chart, true);
  23485. this.tt = this.tt.destroy();
  23486. }
  23487. if (this.renderer) {
  23488. this.renderer = this.renderer.destroy();
  23489. discardElement(this.container);
  23490. }
  23491. U.clearTimeout(this.hideTimer);
  23492. U.clearTimeout(this.tooltipTimeout);
  23493. };
  23494. /**
  23495. * Extendable method to get the anchor position of the tooltip
  23496. * from a point or set of points
  23497. *
  23498. * @private
  23499. * @function Highcharts.Tooltip#getAnchor
  23500. *
  23501. * @param {Highcharts.Point|Array<Highcharts.Point>} points
  23502. *
  23503. * @param {Highcharts.PointerEventObject} [mouseEvent]
  23504. *
  23505. * @return {Array<number>}
  23506. */
  23507. Tooltip.prototype.getAnchor = function (points, mouseEvent) {
  23508. var ret,
  23509. chart = this.chart,
  23510. pointer = chart.pointer,
  23511. inverted = chart.inverted,
  23512. plotTop = chart.plotTop,
  23513. plotLeft = chart.plotLeft,
  23514. plotX = 0,
  23515. plotY = 0,
  23516. yAxis,
  23517. xAxis;
  23518. points = splat(points);
  23519. // When tooltip follows mouse, relate the position to the mouse
  23520. if (this.followPointer && mouseEvent) {
  23521. if (typeof mouseEvent.chartX === 'undefined') {
  23522. mouseEvent = pointer.normalize(mouseEvent);
  23523. }
  23524. ret = [
  23525. mouseEvent.chartX - plotLeft,
  23526. mouseEvent.chartY - plotTop
  23527. ];
  23528. // Some series types use a specificly calculated tooltip position for
  23529. // each point
  23530. }
  23531. else if (points[0].tooltipPos) {
  23532. ret = points[0].tooltipPos;
  23533. // Calculate the average position and adjust for axis positions
  23534. }
  23535. else {
  23536. points.forEach(function (point) {
  23537. yAxis = point.series.yAxis;
  23538. xAxis = point.series.xAxis;
  23539. plotX += point.plotX || 0;
  23540. plotY += (point.plotLow ?
  23541. (point.plotLow + (point.plotHigh || 0)) / 2 :
  23542. (point.plotY || 0));
  23543. // Adjust position for positioned axes (top/left settings)
  23544. if (xAxis && yAxis) {
  23545. if (!inverted) { // #1151
  23546. plotX += xAxis.pos - plotLeft;
  23547. plotY += yAxis.pos - plotTop;
  23548. }
  23549. else { // #14771
  23550. plotX += plotTop + chart.plotHeight - xAxis.len - xAxis.pos;
  23551. plotY += plotLeft + chart.plotWidth - yAxis.len - yAxis.pos;
  23552. }
  23553. }
  23554. });
  23555. plotX /= points.length;
  23556. plotY /= points.length;
  23557. // Use the average position for multiple points
  23558. ret = [
  23559. inverted ? chart.plotWidth - plotY : plotX,
  23560. inverted ? chart.plotHeight - plotX : plotY
  23561. ];
  23562. // When shared, place the tooltip next to the mouse (#424)
  23563. if (this.shared && points.length > 1 && mouseEvent) {
  23564. if (inverted) {
  23565. ret[0] = mouseEvent.chartX - plotLeft;
  23566. }
  23567. else {
  23568. ret[1] = mouseEvent.chartY - plotTop;
  23569. }
  23570. }
  23571. }
  23572. return ret.map(Math.round);
  23573. };
  23574. /**
  23575. * Get the optimal date format for a point, based on a range.
  23576. *
  23577. * @private
  23578. * @function Highcharts.Tooltip#getDateFormat
  23579. *
  23580. * @param {number} range
  23581. * The time range
  23582. *
  23583. * @param {number} date
  23584. * The date of the point in question
  23585. *
  23586. * @param {number} startOfWeek
  23587. * An integer representing the first day of the week, where 0 is
  23588. * Sunday.
  23589. *
  23590. * @param {Highcharts.Dictionary<string>} dateTimeLabelFormats
  23591. * A map of time units to formats.
  23592. *
  23593. * @return {string}
  23594. * The optimal date format for a point.
  23595. */
  23596. Tooltip.prototype.getDateFormat = function (range, date, startOfWeek, dateTimeLabelFormats) {
  23597. var time = this.chart.time, dateStr = time.dateFormat('%m-%d %H:%M:%S.%L', date), format, n, blank = '01-01 00:00:00.000', strpos = {
  23598. millisecond: 15,
  23599. second: 12,
  23600. minute: 9,
  23601. hour: 6,
  23602. day: 3
  23603. }, lastN = 'millisecond'; // for sub-millisecond data, #4223
  23604. for (n in timeUnits) { // eslint-disable-line guard-for-in
  23605. // If the range is exactly one week and we're looking at a
  23606. // Sunday/Monday, go for the week format
  23607. if (range === timeUnits.week &&
  23608. +time.dateFormat('%w', date) === startOfWeek &&
  23609. dateStr.substr(6) === blank.substr(6)) {
  23610. n = 'week';
  23611. break;
  23612. }
  23613. // The first format that is too great for the range
  23614. if (timeUnits[n] > range) {
  23615. n = lastN;
  23616. break;
  23617. }
  23618. // If the point is placed every day at 23:59, we need to show
  23619. // the minutes as well. #2637.
  23620. if (strpos[n] &&
  23621. dateStr.substr(strpos[n]) !== blank.substr(strpos[n])) {
  23622. break;
  23623. }
  23624. // Weeks are outside the hierarchy, only apply them on
  23625. // Mondays/Sundays like in the first condition
  23626. if (n !== 'week') {
  23627. lastN = n;
  23628. }
  23629. }
  23630. if (n) {
  23631. format = time.resolveDTLFormat(dateTimeLabelFormats[n]).main;
  23632. }
  23633. return format;
  23634. };
  23635. /**
  23636. * Creates the Tooltip label element if it does not exist, then returns it.
  23637. *
  23638. * @function Highcharts.Tooltip#getLabel
  23639. * @return {Highcharts.SVGElement}
  23640. */
  23641. Tooltip.prototype.getLabel = function () {
  23642. var tooltip = this,
  23643. renderer = this.chart.renderer,
  23644. styledMode = this.chart.styledMode,
  23645. options = this.options,
  23646. className = ('tooltip' + (defined(options.className) ?
  23647. ' ' + options.className :
  23648. '')),
  23649. pointerEvents = ((options.style && options.style.pointerEvents) ||
  23650. (!this.followPointer && options.stickOnContact ? 'auto' : 'none')),
  23651. container,
  23652. onMouseEnter = function () {
  23653. tooltip.inContact = true;
  23654. }, onMouseLeave = function () {
  23655. var series = tooltip.chart.hoverSeries;
  23656. tooltip.inContact = false;
  23657. if (series &&
  23658. series.onMouseOut) {
  23659. series.onMouseOut();
  23660. }
  23661. };
  23662. if (!this.label) {
  23663. if (this.outside) {
  23664. var chartStyle = this.chart.options.chart.style,
  23665. Renderer = RendererRegistry.getRendererType();
  23666. /**
  23667. * Reference to the tooltip's container, when
  23668. * [Highcharts.Tooltip#outside] is set to true, otherwise
  23669. * it's undefined.
  23670. *
  23671. * @name Highcharts.Tooltip#container
  23672. * @type {Highcharts.HTMLDOMElement|undefined}
  23673. */
  23674. this.container = container = H.doc.createElement('div');
  23675. container.className = 'highcharts-tooltip-container';
  23676. css(container, {
  23677. position: 'absolute',
  23678. top: '1px',
  23679. pointerEvents: pointerEvents,
  23680. zIndex: Math.max((this.options.style && this.options.style.zIndex || 0), (chartStyle && chartStyle.zIndex || 0) + 3)
  23681. });
  23682. H.doc.body.appendChild(container);
  23683. /**
  23684. * Reference to the tooltip's renderer, when
  23685. * [Highcharts.Tooltip#outside] is set to true, otherwise
  23686. * it's undefined.
  23687. *
  23688. * @name Highcharts.Tooltip#renderer
  23689. * @type {Highcharts.SVGRenderer|undefined}
  23690. */
  23691. this.renderer = renderer = new Renderer(container, 0, 0, chartStyle, void 0, void 0, renderer.styledMode);
  23692. }
  23693. // Create the label
  23694. if (this.split) {
  23695. this.label = renderer.g(className);
  23696. }
  23697. else {
  23698. this.label = renderer
  23699. .label('', 0, 0, options.shape || 'callout', null, null, options.useHTML, null, className)
  23700. .attr({
  23701. padding: options.padding,
  23702. r: options.borderRadius
  23703. });
  23704. if (!styledMode) {
  23705. this.label
  23706. .attr({
  23707. fill: options.backgroundColor,
  23708. 'stroke-width': options.borderWidth
  23709. })
  23710. // #2301, #2657
  23711. .css(options.style)
  23712. .css({ pointerEvents: pointerEvents })
  23713. .shadow(options.shadow);
  23714. }
  23715. }
  23716. if (styledMode) {
  23717. // Apply the drop-shadow filter
  23718. this.applyFilter();
  23719. this.label.addClass('highcharts-tooltip-' + this.chart.index);
  23720. }
  23721. // Split tooltip use updateTooltipContainer to position the tooltip
  23722. // container.
  23723. if (tooltip.outside && !tooltip.split) {
  23724. var label_1 = this.label;
  23725. var xSetter_1 = label_1.xSetter,
  23726. ySetter_1 = label_1.ySetter;
  23727. label_1.xSetter = function (value) {
  23728. xSetter_1.call(label_1, tooltip.distance);
  23729. container.style.left = value + 'px';
  23730. };
  23731. label_1.ySetter = function (value) {
  23732. ySetter_1.call(label_1, tooltip.distance);
  23733. container.style.top = value + 'px';
  23734. };
  23735. }
  23736. this.label
  23737. .on('mouseenter', onMouseEnter)
  23738. .on('mouseleave', onMouseLeave)
  23739. .attr({ zIndex: 8 })
  23740. .add();
  23741. }
  23742. return this.label;
  23743. };
  23744. /**
  23745. * Place the tooltip in a chart without spilling over
  23746. * and not covering the point it self.
  23747. *
  23748. * @private
  23749. * @function Highcharts.Tooltip#getPosition
  23750. *
  23751. * @param {number} boxWidth
  23752. *
  23753. * @param {number} boxHeight
  23754. *
  23755. * @param {Highcharts.Point} point
  23756. *
  23757. * @return {Highcharts.PositionObject}
  23758. */
  23759. Tooltip.prototype.getPosition = function (boxWidth, boxHeight, point) {
  23760. var chart = this.chart,
  23761. distance = this.distance,
  23762. ret = {},
  23763. // Don't use h if chart isn't inverted (#7242) ???
  23764. h = (chart.inverted && point.h) || 0, // #4117 ???
  23765. swapped,
  23766. outside = this.outside,
  23767. outerWidth = outside ?
  23768. // substract distance to prevent scrollbars
  23769. doc.documentElement.clientWidth - 2 * distance :
  23770. chart.chartWidth,
  23771. outerHeight = outside ?
  23772. Math.max(doc.body.scrollHeight,
  23773. doc.documentElement.scrollHeight,
  23774. doc.body.offsetHeight,
  23775. doc.documentElement.offsetHeight,
  23776. doc.documentElement.clientHeight) :
  23777. chart.chartHeight,
  23778. chartPosition = chart.pointer.getChartPosition(),
  23779. scaleX = function (val) { return ( // eslint-disable-line no-confusing-arrow
  23780. val * chartPosition.scaleX); },
  23781. scaleY = function (val) { return ( // eslint-disable-line no-confusing-arrow
  23782. val * chartPosition.scaleY); },
  23783. // Build parameter arrays for firstDimension()/secondDimension()
  23784. buildDimensionArray = function (dim) {
  23785. var isX = dim === 'x';
  23786. return [
  23787. dim,
  23788. isX ? outerWidth : outerHeight,
  23789. isX ? boxWidth : boxHeight
  23790. ].concat(outside ? [
  23791. // If we are using tooltip.outside, we need to scale the
  23792. // position to match scaling of the container in case there
  23793. // is a transform/zoom on the container. #11329
  23794. isX ? scaleX(boxWidth) : scaleY(boxHeight),
  23795. isX ? chartPosition.left - distance +
  23796. scaleX(point.plotX + chart.plotLeft) :
  23797. chartPosition.top - distance +
  23798. scaleY(point.plotY + chart.plotTop),
  23799. 0,
  23800. isX ? outerWidth : outerHeight
  23801. ] : [
  23802. // Not outside, no scaling is needed
  23803. isX ? boxWidth : boxHeight,
  23804. isX ? point.plotX + chart.plotLeft :
  23805. point.plotY + chart.plotTop,
  23806. isX ? chart.plotLeft : chart.plotTop,
  23807. isX ? chart.plotLeft + chart.plotWidth :
  23808. chart.plotTop + chart.plotHeight
  23809. ]);
  23810. }, first = buildDimensionArray('y'), second = buildDimensionArray('x'),
  23811. // The far side is right or bottom
  23812. preferFarSide = !this.followPointer && pick(point.ttBelow, !chart.inverted === !!point.negative), // #4984
  23813. /*
  23814. * Handle the preferred dimension. When the preferred dimension is
  23815. * tooltip on top or bottom of the point, it will look for space
  23816. * there.
  23817. *
  23818. * @private
  23819. */
  23820. firstDimension = function (dim, outerSize, innerSize, scaledInnerSize, // #11329
  23821. point, min, max) {
  23822. var scaledDist = outside ?
  23823. (dim === 'y' ? scaleY(distance) : scaleX(distance)) :
  23824. distance,
  23825. scaleDiff = (innerSize - scaledInnerSize) / 2,
  23826. roomLeft = scaledInnerSize < point - distance,
  23827. roomRight = point + distance + scaledInnerSize < outerSize,
  23828. alignedLeft = point - scaledDist - innerSize + scaleDiff,
  23829. alignedRight = point + scaledDist - scaleDiff;
  23830. if (preferFarSide && roomRight) {
  23831. ret[dim] = alignedRight;
  23832. }
  23833. else if (!preferFarSide && roomLeft) {
  23834. ret[dim] = alignedLeft;
  23835. }
  23836. else if (roomLeft) {
  23837. ret[dim] = Math.min(max - scaledInnerSize, alignedLeft - h < 0 ? alignedLeft : alignedLeft - h);
  23838. }
  23839. else if (roomRight) {
  23840. ret[dim] = Math.max(min, alignedRight + h + innerSize > outerSize ?
  23841. alignedRight :
  23842. alignedRight + h);
  23843. }
  23844. else {
  23845. return false;
  23846. }
  23847. },
  23848. /*
  23849. * Handle the secondary dimension. If the preferred dimension is
  23850. * tooltip on top or bottom of the point, the second dimension is to
  23851. * align the tooltip above the point, trying to align center but
  23852. * allowing left or right align within the chart box.
  23853. *
  23854. * @private
  23855. */
  23856. secondDimension = function (dim, outerSize, innerSize, scaledInnerSize, // #11329
  23857. point) {
  23858. var retVal;
  23859. // Too close to the edge, return false and swap dimensions
  23860. if (point < distance || point > outerSize - distance) {
  23861. retVal = false;
  23862. // Align left/top
  23863. }
  23864. else if (point < innerSize / 2) {
  23865. ret[dim] = 1;
  23866. // Align right/bottom
  23867. }
  23868. else if (point > outerSize - scaledInnerSize / 2) {
  23869. ret[dim] = outerSize - scaledInnerSize - 2;
  23870. // Align center
  23871. }
  23872. else {
  23873. ret[dim] = point - innerSize / 2;
  23874. }
  23875. return retVal;
  23876. },
  23877. /*
  23878. * Swap the dimensions
  23879. */
  23880. swap = function (count) {
  23881. var temp = first;
  23882. first = second;
  23883. second = temp;
  23884. swapped = count;
  23885. }, run = function () {
  23886. if (firstDimension.apply(0, first) !== false) {
  23887. if (secondDimension.apply(0, second) === false &&
  23888. !swapped) {
  23889. swap(true);
  23890. run();
  23891. }
  23892. }
  23893. else if (!swapped) {
  23894. swap(true);
  23895. run();
  23896. }
  23897. else {
  23898. ret.x = ret.y = 0;
  23899. }
  23900. };
  23901. // Under these conditions, prefer the tooltip on the side of the point
  23902. if (chart.inverted || this.len > 1) {
  23903. swap();
  23904. }
  23905. run();
  23906. return ret;
  23907. };
  23908. /**
  23909. * Get the best X date format based on the closest point range on the axis.
  23910. *
  23911. * @private
  23912. * @function Highcharts.Tooltip#getXDateFormat
  23913. *
  23914. * @param {Highcharts.Point} point
  23915. *
  23916. * @param {Highcharts.TooltipOptions} options
  23917. *
  23918. * @param {Highcharts.Axis} xAxis
  23919. *
  23920. * @return {string}
  23921. */
  23922. Tooltip.prototype.getXDateFormat = function (point, options, xAxis) {
  23923. var xDateFormat,
  23924. dateTimeLabelFormats = options.dateTimeLabelFormats,
  23925. closestPointRange = xAxis && xAxis.closestPointRange;
  23926. if (closestPointRange) {
  23927. xDateFormat = this.getDateFormat(closestPointRange, point.x, xAxis.options.startOfWeek, dateTimeLabelFormats);
  23928. }
  23929. else {
  23930. xDateFormat = dateTimeLabelFormats.day;
  23931. }
  23932. return xDateFormat || dateTimeLabelFormats.year; // #2546, 2581
  23933. };
  23934. /**
  23935. * Hides the tooltip with a fade out animation.
  23936. *
  23937. * @function Highcharts.Tooltip#hide
  23938. *
  23939. * @param {number} [delay]
  23940. * The fade out in milliseconds. If no value is provided the value
  23941. * of the tooltip.hideDelay option is used. A value of 0 disables
  23942. * the fade out animation.
  23943. */
  23944. Tooltip.prototype.hide = function (delay) {
  23945. var tooltip = this;
  23946. // disallow duplicate timers (#1728, #1766)
  23947. U.clearTimeout(this.hideTimer);
  23948. delay = pick(delay, this.options.hideDelay, 500);
  23949. if (!this.isHidden) {
  23950. this.hideTimer = syncTimeout(function () {
  23951. // If there is a delay, do fadeOut with the default duration. If
  23952. // the hideDelay is 0, we assume no animation is wanted, so we
  23953. // pass 0 duration. #12994.
  23954. tooltip.getLabel().fadeOut(delay ? void 0 : delay);
  23955. tooltip.isHidden = true;
  23956. }, delay);
  23957. }
  23958. };
  23959. /**
  23960. * @private
  23961. * @function Highcharts.Tooltip#init
  23962. *
  23963. * @param {Highcharts.Chart} chart
  23964. * The chart instance.
  23965. *
  23966. * @param {Highcharts.TooltipOptions} options
  23967. * Tooltip options.
  23968. */
  23969. Tooltip.prototype.init = function (chart, options) {
  23970. /**
  23971. * Chart of the tooltip.
  23972. *
  23973. * @readonly
  23974. * @name Highcharts.Tooltip#chart
  23975. * @type {Highcharts.Chart}
  23976. */
  23977. this.chart = chart;
  23978. /**
  23979. * Used tooltip options.
  23980. *
  23981. * @readonly
  23982. * @name Highcharts.Tooltip#options
  23983. * @type {Highcharts.TooltipOptions}
  23984. */
  23985. this.options = options;
  23986. /**
  23987. * List of crosshairs.
  23988. *
  23989. * @private
  23990. * @readonly
  23991. * @name Highcharts.Tooltip#crosshairs
  23992. * @type {Array<null>}
  23993. */
  23994. this.crosshairs = [];
  23995. /**
  23996. * Current values of x and y when animating.
  23997. *
  23998. * @private
  23999. * @readonly
  24000. * @name Highcharts.Tooltip#now
  24001. * @type {Highcharts.PositionObject}
  24002. */
  24003. this.now = { x: 0, y: 0 };
  24004. /**
  24005. * Tooltips are initially hidden.
  24006. *
  24007. * @private
  24008. * @readonly
  24009. * @name Highcharts.Tooltip#isHidden
  24010. * @type {boolean}
  24011. */
  24012. this.isHidden = true;
  24013. /**
  24014. * True, if the tooltip is split into one label per series, with the
  24015. * header close to the axis.
  24016. *
  24017. * @readonly
  24018. * @name Highcharts.Tooltip#split
  24019. * @type {boolean|undefined}
  24020. */
  24021. this.split = options.split && !chart.inverted && !chart.polar;
  24022. /**
  24023. * When the tooltip is shared, the entire plot area will capture mouse
  24024. * movement or touch events.
  24025. *
  24026. * @readonly
  24027. * @name Highcharts.Tooltip#shared
  24028. * @type {boolean|undefined}
  24029. */
  24030. this.shared = options.shared || this.split;
  24031. /**
  24032. * Whether to allow the tooltip to render outside the chart's SVG
  24033. * element box. By default (false), the tooltip is rendered within the
  24034. * chart's SVG element, which results in the tooltip being aligned
  24035. * inside the chart area.
  24036. *
  24037. * @readonly
  24038. * @name Highcharts.Tooltip#outside
  24039. * @type {boolean}
  24040. *
  24041. * @todo
  24042. * Split tooltip does not support outside in the first iteration. Should
  24043. * not be too complicated to implement.
  24044. */
  24045. this.outside = pick(options.outside, Boolean(chart.scrollablePixelsX || chart.scrollablePixelsY));
  24046. };
  24047. /**
  24048. * Returns true, if the pointer is in contact with the tooltip tracker.
  24049. */
  24050. Tooltip.prototype.isStickyOnContact = function () {
  24051. return !!(!this.followPointer &&
  24052. this.options.stickOnContact &&
  24053. this.inContact);
  24054. };
  24055. /**
  24056. * Moves the tooltip with a soft animation to a new position.
  24057. *
  24058. * @private
  24059. * @function Highcharts.Tooltip#move
  24060. *
  24061. * @param {number} x
  24062. *
  24063. * @param {number} y
  24064. *
  24065. * @param {number} anchorX
  24066. *
  24067. * @param {number} anchorY
  24068. */
  24069. Tooltip.prototype.move = function (x, y, anchorX, anchorY) {
  24070. var tooltip = this,
  24071. now = tooltip.now,
  24072. animate = tooltip.options.animation !== false &&
  24073. !tooltip.isHidden &&
  24074. // When we get close to the target position, abort animation and
  24075. // land on the right place (#3056)
  24076. (Math.abs(x - now.x) > 1 || Math.abs(y - now.y) > 1),
  24077. skipAnchor = tooltip.followPointer || tooltip.len > 1;
  24078. // Get intermediate values for animation
  24079. extend(now, {
  24080. x: animate ? (2 * now.x + x) / 3 : x,
  24081. y: animate ? (now.y + y) / 2 : y,
  24082. anchorX: skipAnchor ?
  24083. void 0 :
  24084. animate ? (2 * now.anchorX + anchorX) / 3 : anchorX,
  24085. anchorY: skipAnchor ?
  24086. void 0 :
  24087. animate ? (now.anchorY + anchorY) / 2 : anchorY
  24088. });
  24089. // Move to the intermediate value
  24090. tooltip.getLabel().attr(now);
  24091. tooltip.drawTracker();
  24092. // Run on next tick of the mouse tracker
  24093. if (animate) {
  24094. // Never allow two timeouts
  24095. U.clearTimeout(this.tooltipTimeout);
  24096. // Set the fixed interval ticking for the smooth tooltip
  24097. this.tooltipTimeout = setTimeout(function () {
  24098. // The interval function may still be running during destroy,
  24099. // so check that the chart is really there before calling.
  24100. if (tooltip) {
  24101. tooltip.move(x, y, anchorX, anchorY);
  24102. }
  24103. }, 32);
  24104. }
  24105. };
  24106. /**
  24107. * Refresh the tooltip's text and position.
  24108. *
  24109. * @function Highcharts.Tooltip#refresh
  24110. *
  24111. * @param {Highcharts.Point|Array<Highcharts.Point>} pointOrPoints
  24112. * Either a point or an array of points.
  24113. *
  24114. * @param {Highcharts.PointerEventObject} [mouseEvent]
  24115. * Mouse event, that is responsible for the refresh and should be
  24116. * used for the tooltip update.
  24117. */
  24118. Tooltip.prototype.refresh = function (pointOrPoints, mouseEvent) {
  24119. var tooltip = this,
  24120. chart = this.chart,
  24121. options = tooltip.options,
  24122. x,
  24123. y,
  24124. points = splat(pointOrPoints),
  24125. point = points[0],
  24126. anchor,
  24127. textConfig = {},
  24128. text,
  24129. pointConfig = [],
  24130. formatter = options.formatter || tooltip.defaultFormatter,
  24131. shared = tooltip.shared,
  24132. styledMode = chart.styledMode;
  24133. if (!options.enabled) {
  24134. return;
  24135. }
  24136. U.clearTimeout(this.hideTimer);
  24137. // get the reference point coordinates (pie charts use tooltipPos)
  24138. tooltip.followPointer = !tooltip.split && point.series.tooltipOptions.followPointer;
  24139. anchor = tooltip.getAnchor(pointOrPoints, mouseEvent);
  24140. x = anchor[0];
  24141. y = anchor[1];
  24142. // shared tooltip, array is sent over
  24143. if (shared &&
  24144. !(!isArray(pointOrPoints) &&
  24145. pointOrPoints.series &&
  24146. pointOrPoints.series.noSharedTooltip)) {
  24147. chart.pointer.applyInactiveState(points);
  24148. // Now set hover state for the choosen ones:
  24149. points.forEach(function (item) {
  24150. item.setState('hover');
  24151. pointConfig.push(item.getLabelConfig());
  24152. });
  24153. textConfig = {
  24154. x: point.category,
  24155. y: point.y
  24156. };
  24157. textConfig.points = pointConfig;
  24158. // single point tooltip
  24159. }
  24160. else {
  24161. textConfig = point.getLabelConfig();
  24162. }
  24163. this.len = pointConfig.length; // #6128
  24164. text = formatter.call(textConfig, tooltip);
  24165. // register the current series
  24166. var currentSeries = point.series;
  24167. this.distance = pick(currentSeries.tooltipOptions.distance, 16);
  24168. // update the inner HTML
  24169. if (text === false) {
  24170. this.hide();
  24171. }
  24172. else {
  24173. // update text
  24174. if (tooltip.split) {
  24175. this.renderSplit(text, points);
  24176. }
  24177. else {
  24178. var checkX = x;
  24179. var checkY = y;
  24180. if (mouseEvent && chart.pointer.isDirectTouch) {
  24181. checkX = mouseEvent.chartX - chart.plotLeft;
  24182. checkY = mouseEvent.chartY - chart.plotTop;
  24183. }
  24184. // #11493, #13095
  24185. if (chart.polar ||
  24186. currentSeries.options.clip === false ||
  24187. currentSeries.shouldShowTooltip(checkX, checkY)) {
  24188. var label = tooltip.getLabel();
  24189. // Prevent the tooltip from flowing over the chart box
  24190. // (#6659)
  24191. if (!options.style.width || styledMode) {
  24192. label.css({
  24193. width: this.chart.spacingBox.width + 'px'
  24194. });
  24195. }
  24196. label.attr({
  24197. text: text && text.join ?
  24198. text.join('') :
  24199. text
  24200. });
  24201. // Set the stroke color of the box to reflect the point
  24202. label.removeClass(/highcharts-color-[\d]+/g)
  24203. .addClass('highcharts-color-' +
  24204. pick(point.colorIndex, currentSeries.colorIndex));
  24205. if (!styledMode) {
  24206. label.attr({
  24207. stroke: (options.borderColor ||
  24208. point.color ||
  24209. currentSeries.color ||
  24210. palette.neutralColor60)
  24211. });
  24212. }
  24213. tooltip.updatePosition({
  24214. plotX: x,
  24215. plotY: y,
  24216. negative: point.negative,
  24217. ttBelow: point.ttBelow,
  24218. h: anchor[2] || 0
  24219. });
  24220. }
  24221. else {
  24222. tooltip.hide();
  24223. return;
  24224. }
  24225. }
  24226. // show it
  24227. if (tooltip.isHidden && tooltip.label) {
  24228. tooltip.label.attr({
  24229. opacity: 1
  24230. }).show();
  24231. }
  24232. tooltip.isHidden = false;
  24233. }
  24234. fireEvent(this, 'refresh');
  24235. };
  24236. /**
  24237. * Render the split tooltip. Loops over each point's text and adds
  24238. * a label next to the point, then uses the distribute function to
  24239. * find best non-overlapping positions.
  24240. *
  24241. * @private
  24242. * @function Highcharts.Tooltip#renderSplit
  24243. *
  24244. * @param {string|Array<(boolean|string)>} labels
  24245. *
  24246. * @param {Array<Highcharts.Point>} points
  24247. */
  24248. Tooltip.prototype.renderSplit = function (labels, points) {
  24249. var tooltip = this;
  24250. var chart = tooltip.chart,
  24251. _a = tooltip.chart,
  24252. chartWidth = _a.chartWidth,
  24253. chartHeight = _a.chartHeight,
  24254. plotHeight = _a.plotHeight,
  24255. plotLeft = _a.plotLeft,
  24256. plotTop = _a.plotTop,
  24257. pointer = _a.pointer,
  24258. _b = _a.scrollablePixelsY,
  24259. scrollablePixelsY = _b === void 0 ? 0 : _b,
  24260. scrollablePixelsX = _a.scrollablePixelsX,
  24261. _c = _a.scrollingContainer,
  24262. _d = _c === void 0 ? { scrollLeft: 0,
  24263. scrollTop: 0 } : _c,
  24264. scrollLeft = _d.scrollLeft,
  24265. scrollTop = _d.scrollTop,
  24266. styledMode = _a.styledMode,
  24267. distance = tooltip.distance,
  24268. options = tooltip.options,
  24269. positioner = tooltip.options.positioner;
  24270. // The area which the tooltip should be limited to. Limit to scrollable
  24271. // plot area if enabled, otherwise limit to the chart container.
  24272. // If outside is true it should be the whole viewport
  24273. var bounds = tooltip.outside && typeof scrollablePixelsX !== 'number' ?
  24274. doc.documentElement.getBoundingClientRect() : {
  24275. left: scrollLeft,
  24276. right: scrollLeft + chartWidth,
  24277. top: scrollTop,
  24278. bottom: scrollTop + chartHeight
  24279. };
  24280. var tooltipLabel = tooltip.getLabel();
  24281. var ren = this.renderer || chart.renderer;
  24282. var headerTop = Boolean(chart.xAxis[0] && chart.xAxis[0].opposite);
  24283. var _e = pointer.getChartPosition(),
  24284. chartLeft = _e.left,
  24285. chartTop = _e.top;
  24286. var distributionBoxTop = plotTop + scrollTop;
  24287. var headerHeight = 0;
  24288. var adjustedPlotHeight = plotHeight - scrollablePixelsY;
  24289. /**
  24290. * Calculates the anchor position for the partial tooltip
  24291. *
  24292. * @private
  24293. * @param {Highcharts.Point} point The point related to the tooltip
  24294. * @return {object} Returns an object with anchorX and anchorY
  24295. */
  24296. function getAnchor(point) {
  24297. var isHeader = point.isHeader,
  24298. _a = point.plotX,
  24299. plotX = _a === void 0 ? 0 : _a,
  24300. _b = point.plotY,
  24301. plotY = _b === void 0 ? 0 : _b,
  24302. series = point.series;
  24303. var anchorX;
  24304. var anchorY;
  24305. if (isHeader) {
  24306. // Set anchorX to plotX
  24307. anchorX = plotLeft + plotX;
  24308. // Set anchorY to center of visible plot area.
  24309. anchorY = plotTop + plotHeight / 2;
  24310. }
  24311. else {
  24312. var xAxis = series.xAxis,
  24313. yAxis = series.yAxis;
  24314. // Set anchorX to plotX. Limit to within xAxis.
  24315. anchorX = xAxis.pos + clamp(plotX, -distance, xAxis.len + distance);
  24316. // Set anchorY, limit to the scrollable plot area
  24317. if (series.shouldShowTooltip(0, yAxis.pos - plotTop + plotY, {
  24318. ignoreX: true
  24319. })) {
  24320. anchorY = yAxis.pos + plotY;
  24321. }
  24322. }
  24323. // Limit values to plot area
  24324. anchorX = clamp(anchorX, bounds.left - distance, bounds.right + distance);
  24325. return { anchorX: anchorX, anchorY: anchorY };
  24326. }
  24327. /**
  24328. * Calculates the position of the partial tooltip
  24329. *
  24330. * @private
  24331. * @param {number} anchorX The partial tooltip anchor x position
  24332. * @param {number} anchorY The partial tooltip anchor y position
  24333. * @param {boolean} isHeader Whether the partial tooltip is a header
  24334. * @param {number} boxWidth Width of the partial tooltip
  24335. * @return {Highcharts.PositionObject} Returns the partial tooltip x and
  24336. * y position
  24337. */
  24338. function defaultPositioner(anchorX, anchorY, isHeader, boxWidth, alignedLeft) {
  24339. if (alignedLeft === void 0) { alignedLeft = true; }
  24340. var y;
  24341. var x;
  24342. if (isHeader) {
  24343. y = headerTop ? 0 : adjustedPlotHeight;
  24344. x = clamp(anchorX - (boxWidth / 2), bounds.left, bounds.right - boxWidth - (tooltip.outside ? chartLeft : 0));
  24345. }
  24346. else {
  24347. y = anchorY - distributionBoxTop;
  24348. x = alignedLeft ?
  24349. anchorX - boxWidth - distance :
  24350. anchorX + distance;
  24351. x = clamp(x, alignedLeft ? x : bounds.left, bounds.right);
  24352. }
  24353. // NOTE: y is relative to distributionBoxTop
  24354. return { x: x, y: y };
  24355. }
  24356. /**
  24357. * Updates the attributes and styling of the partial tooltip. Creates a
  24358. * new partial tooltip if it does not exists.
  24359. *
  24360. * @private
  24361. * @param {Highcharts.SVGElement|undefined} partialTooltip
  24362. * The partial tooltip to update
  24363. * @param {Highcharts.Point} point
  24364. * The point related to the partial tooltip
  24365. * @param {boolean|string} str The text for the partial tooltip
  24366. * @return {Highcharts.SVGElement} Returns the updated partial tooltip
  24367. */
  24368. function updatePartialTooltip(partialTooltip, point, str) {
  24369. var tt = partialTooltip;
  24370. var isHeader = point.isHeader,
  24371. series = point.series;
  24372. var colorClass = 'highcharts-color-' + pick(point.colorIndex, series.colorIndex, 'none');
  24373. if (!tt) {
  24374. var attribs = {
  24375. padding: options.padding,
  24376. r: options.borderRadius
  24377. };
  24378. if (!styledMode) {
  24379. attribs.fill = options.backgroundColor;
  24380. attribs['stroke-width'] = options.borderWidth;
  24381. }
  24382. tt = ren
  24383. .label('', 0, 0, (options[isHeader ? 'headerShape' : 'shape']) ||
  24384. 'callout', void 0, void 0, options.useHTML)
  24385. .addClass((isHeader ? 'highcharts-tooltip-header ' : '') +
  24386. 'highcharts-tooltip-box ' +
  24387. colorClass)
  24388. .attr(attribs)
  24389. .add(tooltipLabel);
  24390. }
  24391. tt.isActive = true;
  24392. tt.attr({
  24393. text: str
  24394. });
  24395. if (!styledMode) {
  24396. tt.css(options.style)
  24397. .shadow(options.shadow)
  24398. .attr({
  24399. stroke: (options.borderColor ||
  24400. point.color ||
  24401. series.color ||
  24402. palette.neutralColor80)
  24403. });
  24404. }
  24405. return tt;
  24406. }
  24407. // Graceful degradation for legacy formatters
  24408. if (isString(labels)) {
  24409. labels = [false, labels];
  24410. }
  24411. // Create the individual labels for header and points, ignore footer
  24412. var boxes = labels.slice(0,
  24413. points.length + 1).reduce(function (boxes,
  24414. str,
  24415. i) {
  24416. if (str !== false && str !== '') {
  24417. var point = (points[i - 1] ||
  24418. {
  24419. // Item 0 is the header. Instead of this, we could also
  24420. // use the crosshair label
  24421. isHeader: true,
  24422. plotX: points[0].plotX,
  24423. plotY: plotHeight,
  24424. series: {}
  24425. });
  24426. var isHeader = point.isHeader;
  24427. // Store the tooltip label referance on the series
  24428. var owner = isHeader ? tooltip : point.series;
  24429. var tt = owner.tt = updatePartialTooltip(owner.tt,
  24430. point,
  24431. str.toString());
  24432. // Get X position now, so we can move all to the other side in
  24433. // case of overflow
  24434. var bBox = tt.getBBox();
  24435. var boxWidth = bBox.width + tt.strokeWidth();
  24436. if (isHeader) {
  24437. headerHeight = bBox.height;
  24438. adjustedPlotHeight += headerHeight;
  24439. if (headerTop) {
  24440. distributionBoxTop -= headerHeight;
  24441. }
  24442. }
  24443. var _a = getAnchor(point),
  24444. anchorX = _a.anchorX,
  24445. anchorY = _a.anchorY;
  24446. if (typeof anchorY === 'number') {
  24447. var size = bBox.height + 1;
  24448. var boxPosition = (positioner ?
  24449. positioner.call(tooltip,
  24450. boxWidth,
  24451. size,
  24452. point) :
  24453. defaultPositioner(anchorX,
  24454. anchorY,
  24455. isHeader,
  24456. boxWidth));
  24457. boxes.push({
  24458. // 0-align to the top, 1-align to the bottom
  24459. align: positioner ? 0 : void 0,
  24460. anchorX: anchorX,
  24461. anchorY: anchorY,
  24462. boxWidth: boxWidth,
  24463. point: point,
  24464. rank: pick(boxPosition.rank, isHeader ? 1 : 0),
  24465. size: size,
  24466. target: boxPosition.y,
  24467. tt: tt,
  24468. x: boxPosition.x
  24469. });
  24470. }
  24471. else {
  24472. // Hide tooltips which anchorY is outside the visible plot
  24473. // area
  24474. tt.isActive = false;
  24475. }
  24476. }
  24477. return boxes;
  24478. }, []);
  24479. // Realign the tooltips towards the right if there is not enough
  24480. // space to the left and there is space to to the right
  24481. if (!positioner && boxes.some(function (box) {
  24482. // Always realign if the beginning of a label is outside bounds
  24483. var outside = tooltip.outside;
  24484. var boxStart = (outside ? chartLeft : 0) + box.anchorX;
  24485. if (boxStart < bounds.left && boxStart + box.boxWidth < bounds.right) {
  24486. return true;
  24487. }
  24488. // Otherwise, check if there is more space available to the right
  24489. return boxStart < (chartLeft - bounds.left) + box.boxWidth &&
  24490. bounds.right - boxStart > boxStart;
  24491. })) {
  24492. boxes = boxes.map(function (box) {
  24493. var _a = defaultPositioner(box.anchorX,
  24494. box.anchorY,
  24495. box.point.isHeader,
  24496. box.boxWidth,
  24497. false),
  24498. x = _a.x,
  24499. y = _a.y;
  24500. return extend(box, {
  24501. target: y,
  24502. x: x
  24503. });
  24504. });
  24505. }
  24506. // Clean previous run (for missing points)
  24507. tooltip.cleanSplit();
  24508. // Distribute and put in place
  24509. H.distribute(boxes, adjustedPlotHeight);
  24510. var boxExtremes = {
  24511. left: chartLeft,
  24512. right: chartLeft
  24513. };
  24514. // Get the extremes from series tooltips
  24515. boxes.forEach(function (box) {
  24516. var x = box.x,
  24517. boxWidth = box.boxWidth,
  24518. isHeader = box.isHeader;
  24519. if (!isHeader) {
  24520. if (tooltip.outside && chartLeft + x < boxExtremes.left) {
  24521. boxExtremes.left = chartLeft + x;
  24522. }
  24523. if (!isHeader && tooltip.outside && boxExtremes.left + boxWidth > boxExtremes.right) {
  24524. boxExtremes.right = chartLeft + x;
  24525. }
  24526. }
  24527. });
  24528. boxes.forEach(function (box) {
  24529. var x = box.x,
  24530. anchorX = box.anchorX,
  24531. anchorY = box.anchorY,
  24532. pos = box.pos,
  24533. isHeader = box.point.isHeader;
  24534. var attributes = {
  24535. visibility: typeof pos === 'undefined' ? 'hidden' : 'inherit',
  24536. x: x,
  24537. /* NOTE: y should equal pos to be consistent with !split
  24538. * tooltip,
  24539. but is currently relative to plotTop. Is left as is
  24540. * to avoid breaking change. Remove distributionBoxTop to make
  24541. * it consistent.
  24542. */
  24543. y: pos + distributionBoxTop,
  24544. anchorX: anchorX,
  24545. anchorY: anchorY
  24546. };
  24547. // Handle left-aligned tooltips overflowing the chart area
  24548. if (tooltip.outside && x < anchorX) {
  24549. var offset = chartLeft - boxExtremes.left;
  24550. // Skip this if there is no overflow
  24551. if (offset > 0) {
  24552. if (!isHeader) {
  24553. attributes.x = x + offset;
  24554. attributes.anchorX = anchorX + offset;
  24555. }
  24556. if (isHeader) {
  24557. attributes.x = (boxExtremes.right - boxExtremes.left) / 2;
  24558. attributes.anchorX = anchorX + offset;
  24559. }
  24560. }
  24561. }
  24562. // Put the label in place
  24563. box.tt.attr(attributes);
  24564. });
  24565. /* If we have a seperate tooltip container, then update the necessary
  24566. * container properties.
  24567. * Test that tooltip has its own container and renderer before executing
  24568. * the operation.
  24569. */
  24570. var container = tooltip.container,
  24571. outside = tooltip.outside,
  24572. renderer = tooltip.renderer;
  24573. if (outside && container && renderer) {
  24574. // Set container size to fit the bounds
  24575. var _f = tooltipLabel.getBBox(),
  24576. width = _f.width,
  24577. height = _f.height,
  24578. x = _f.x,
  24579. y = _f.y;
  24580. renderer.setSize(width + x, height + y, false);
  24581. // Position the tooltip container to the chart container
  24582. container.style.left = boxExtremes.left + 'px';
  24583. container.style.top = chartTop + 'px';
  24584. }
  24585. };
  24586. /**
  24587. * If the `stickOnContact` option is active, this will add a tracker shape.
  24588. *
  24589. * @private
  24590. * @function Highcharts.Tooltip#drawTracker
  24591. */
  24592. Tooltip.prototype.drawTracker = function () {
  24593. var tooltip = this;
  24594. if (tooltip.followPointer ||
  24595. !tooltip.options.stickOnContact) {
  24596. if (tooltip.tracker) {
  24597. tooltip.tracker.destroy();
  24598. }
  24599. return;
  24600. }
  24601. var chart = tooltip.chart;
  24602. var label = tooltip.label;
  24603. var point = chart.hoverPoint;
  24604. if (!label || !point) {
  24605. return;
  24606. }
  24607. var box = {
  24608. x: 0,
  24609. y: 0,
  24610. width: 0,
  24611. height: 0
  24612. };
  24613. // Combine anchor and tooltip
  24614. var anchorPos = this.getAnchor(point);
  24615. var labelBBox = label.getBBox();
  24616. anchorPos[0] += chart.plotLeft - label.translateX;
  24617. anchorPos[1] += chart.plotTop - label.translateY;
  24618. // When the mouse pointer is between the anchor point and the label,
  24619. // the label should stick.
  24620. box.x = Math.min(0, anchorPos[0]);
  24621. box.y = Math.min(0, anchorPos[1]);
  24622. box.width = (anchorPos[0] < 0 ?
  24623. Math.max(Math.abs(anchorPos[0]), (labelBBox.width - anchorPos[0])) :
  24624. Math.max(Math.abs(anchorPos[0]), labelBBox.width));
  24625. box.height = (anchorPos[1] < 0 ?
  24626. Math.max(Math.abs(anchorPos[1]), (labelBBox.height - Math.abs(anchorPos[1]))) :
  24627. Math.max(Math.abs(anchorPos[1]), labelBBox.height));
  24628. if (tooltip.tracker) {
  24629. tooltip.tracker.attr(box);
  24630. }
  24631. else {
  24632. tooltip.tracker = label.renderer
  24633. .rect(box)
  24634. .addClass('highcharts-tracker')
  24635. .add(label);
  24636. if (!chart.styledMode) {
  24637. tooltip.tracker.attr({
  24638. fill: 'rgba(0,0,0,0)'
  24639. });
  24640. }
  24641. }
  24642. };
  24643. /**
  24644. * @private
  24645. */
  24646. Tooltip.prototype.styledModeFormat = function (formatString) {
  24647. return formatString
  24648. .replace('style="font-size: 10px"', 'class="highcharts-header"')
  24649. .replace(/style="color:{(point|series)\.color}"/g, 'class="highcharts-color-{$1.colorIndex}"');
  24650. };
  24651. /**
  24652. * Format the footer/header of the tooltip
  24653. * #3397: abstraction to enable formatting of footer and header
  24654. *
  24655. * @private
  24656. * @function Highcharts.Tooltip#tooltipFooterHeaderFormatter
  24657. * @param {Highcharts.PointLabelObject} labelConfig
  24658. * @param {boolean} [isFooter]
  24659. * @return {string}
  24660. */
  24661. Tooltip.prototype.tooltipFooterHeaderFormatter = function (labelConfig, isFooter) {
  24662. var footOrHead = isFooter ? 'footer' : 'header',
  24663. series = labelConfig.series,
  24664. tooltipOptions = series.tooltipOptions,
  24665. xDateFormat = tooltipOptions.xDateFormat,
  24666. xAxis = series.xAxis,
  24667. isDateTime = (xAxis &&
  24668. xAxis.options.type === 'datetime' &&
  24669. isNumber(labelConfig.key)),
  24670. formatString = tooltipOptions[footOrHead + 'Format'],
  24671. e = {
  24672. isFooter: isFooter,
  24673. labelConfig: labelConfig
  24674. };
  24675. fireEvent(this, 'headerFormatter', e, function (e) {
  24676. // Guess the best date format based on the closest point distance
  24677. // (#568, #3418)
  24678. if (isDateTime && !xDateFormat) {
  24679. xDateFormat = this.getXDateFormat(labelConfig, tooltipOptions, xAxis);
  24680. }
  24681. // Insert the footer date format if any
  24682. if (isDateTime && xDateFormat) {
  24683. ((labelConfig.point && labelConfig.point.tooltipDateKeys) ||
  24684. ['key']).forEach(function (key) {
  24685. formatString = formatString.replace('{point.' + key + '}', '{point.' + key + ':' + xDateFormat + '}');
  24686. });
  24687. }
  24688. // Replace default header style with class name
  24689. if (series.chart.styledMode) {
  24690. formatString = this.styledModeFormat(formatString);
  24691. }
  24692. e.text = format(formatString, {
  24693. point: labelConfig,
  24694. series: series
  24695. }, this.chart);
  24696. });
  24697. return e.text;
  24698. };
  24699. /**
  24700. * Updates the tooltip with the provided tooltip options.
  24701. *
  24702. * @function Highcharts.Tooltip#update
  24703. *
  24704. * @param {Highcharts.TooltipOptions} options
  24705. * The tooltip options to update.
  24706. */
  24707. Tooltip.prototype.update = function (options) {
  24708. this.destroy();
  24709. // Update user options (#6218)
  24710. merge(true, this.chart.options.tooltip.userOptions, options);
  24711. this.init(this.chart, merge(true, this.options, options));
  24712. };
  24713. /**
  24714. * Find the new position and perform the move
  24715. *
  24716. * @private
  24717. * @function Highcharts.Tooltip#updatePosition
  24718. *
  24719. * @param {Highcharts.Point} point
  24720. */
  24721. Tooltip.prototype.updatePosition = function (point) {
  24722. var chart = this.chart,
  24723. pointer = chart.pointer,
  24724. label = this.getLabel(),
  24725. pos,
  24726. anchorX = point.plotX + chart.plotLeft,
  24727. anchorY = point.plotY + chart.plotTop,
  24728. pad;
  24729. // Needed for outside: true (#11688)
  24730. var chartPosition = pointer.getChartPosition();
  24731. pos = (this.options.positioner || this.getPosition).call(this, label.width, label.height, point);
  24732. // Set the renderer size dynamically to prevent document size to change
  24733. if (this.outside) {
  24734. pad = (this.options.borderWidth || 0) + 2 * this.distance;
  24735. this.renderer.setSize(label.width + pad, label.height + pad, false);
  24736. // Anchor and tooltip container need scaling if chart container has
  24737. // scale transform/css zoom. #11329.
  24738. if (chartPosition.scaleX !== 1 || chartPosition.scaleY !== 1) {
  24739. css(this.container, {
  24740. transform: "scale(" + chartPosition.scaleX + ", " + chartPosition.scaleY + ")"
  24741. });
  24742. anchorX *= chartPosition.scaleX;
  24743. anchorY *= chartPosition.scaleY;
  24744. }
  24745. anchorX += chartPosition.left - pos.x;
  24746. anchorY += chartPosition.top - pos.y;
  24747. }
  24748. // do the move
  24749. this.move(Math.round(pos.x), Math.round(pos.y || 0), // can be undefined (#3977)
  24750. anchorX, anchorY);
  24751. };
  24752. return Tooltip;
  24753. }());
  24754. H.Tooltip = Tooltip;
  24755. return H.Tooltip;
  24756. });
  24757. _registerModule(_modules, 'Core/Pointer.js', [_modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Core/Color/Palette.js'], _modules['Core/Tooltip.js'], _modules['Core/Utilities.js']], function (Color, H, Palette, Tooltip, U) {
  24758. /* *
  24759. *
  24760. * (c) 2010-2021 Torstein Honsi
  24761. *
  24762. * License: www.highcharts.com/license
  24763. *
  24764. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  24765. *
  24766. * */
  24767. var color = Color.parse;
  24768. var charts = H.charts,
  24769. noop = H.noop;
  24770. var addEvent = U.addEvent,
  24771. attr = U.attr,
  24772. css = U.css,
  24773. defined = U.defined,
  24774. extend = U.extend,
  24775. find = U.find,
  24776. fireEvent = U.fireEvent,
  24777. isNumber = U.isNumber,
  24778. isObject = U.isObject,
  24779. objectEach = U.objectEach,
  24780. offset = U.offset,
  24781. pick = U.pick,
  24782. splat = U.splat;
  24783. /* *
  24784. *
  24785. * Class
  24786. *
  24787. * */
  24788. /* eslint-disable no-invalid-this, valid-jsdoc */
  24789. /**
  24790. * The mouse and touch tracker object. Each {@link Chart} item has one
  24791. * assosiated Pointer item that can be accessed from the {@link Chart.pointer}
  24792. * property.
  24793. *
  24794. * @class
  24795. * @name Highcharts.Pointer
  24796. *
  24797. * @param {Highcharts.Chart} chart
  24798. * The chart instance.
  24799. *
  24800. * @param {Highcharts.Options} options
  24801. * The root options object. The pointer uses options from the chart and tooltip
  24802. * structures.
  24803. */
  24804. var Pointer = /** @class */ (function () {
  24805. /* *
  24806. *
  24807. * Constructors
  24808. *
  24809. * */
  24810. function Pointer(chart, options) {
  24811. this.lastValidTouch = {};
  24812. this.pinchDown = [];
  24813. this.runChartClick = false;
  24814. this.eventsToUnbind = [];
  24815. this.chart = chart;
  24816. this.hasDragged = false;
  24817. this.options = options;
  24818. this.init(chart, options);
  24819. }
  24820. /* *
  24821. *
  24822. * Functions
  24823. *
  24824. * */
  24825. /**
  24826. * Set inactive state to all series that are not currently hovered,
  24827. * or, if `inactiveOtherPoints` is set to true, set inactive state to
  24828. * all points within that series.
  24829. *
  24830. * @private
  24831. * @function Highcharts.Pointer#applyInactiveState
  24832. *
  24833. * @param {Array<Highcharts.Point>} points
  24834. * Currently hovered points
  24835. */
  24836. Pointer.prototype.applyInactiveState = function (points) {
  24837. var activeSeries = [],
  24838. series;
  24839. // Get all active series from the hovered points
  24840. (points || []).forEach(function (item) {
  24841. series = item.series;
  24842. // Include itself
  24843. activeSeries.push(series);
  24844. // Include parent series
  24845. if (series.linkedParent) {
  24846. activeSeries.push(series.linkedParent);
  24847. }
  24848. // Include all child series
  24849. if (series.linkedSeries) {
  24850. activeSeries = activeSeries.concat(series.linkedSeries);
  24851. }
  24852. // Include navigator series
  24853. if (series.navigatorSeries) {
  24854. activeSeries.push(series.navigatorSeries);
  24855. }
  24856. });
  24857. // Now loop over all series, filtering out active series
  24858. this.chart.series.forEach(function (inactiveSeries) {
  24859. if (activeSeries.indexOf(inactiveSeries) === -1) {
  24860. // Inactive series
  24861. inactiveSeries.setState('inactive', true);
  24862. }
  24863. else if (inactiveSeries.options.inactiveOtherPoints) {
  24864. // Active series, but other points should be inactivated
  24865. inactiveSeries.setAllPointsToState('inactive');
  24866. }
  24867. });
  24868. };
  24869. /**
  24870. * Destroys the Pointer object and disconnects DOM events.
  24871. *
  24872. * @function Highcharts.Pointer#destroy
  24873. */
  24874. Pointer.prototype.destroy = function () {
  24875. var pointer = this;
  24876. this.eventsToUnbind.forEach(function (unbind) { return unbind(); });
  24877. this.eventsToUnbind = [];
  24878. if (!H.chartCount) {
  24879. if (Pointer.unbindDocumentMouseUp) {
  24880. Pointer.unbindDocumentMouseUp = Pointer.unbindDocumentMouseUp();
  24881. }
  24882. if (Pointer.unbindDocumentTouchEnd) {
  24883. Pointer.unbindDocumentTouchEnd = Pointer.unbindDocumentTouchEnd();
  24884. }
  24885. }
  24886. // memory and CPU leak
  24887. clearInterval(pointer.tooltipTimeout);
  24888. objectEach(pointer, function (_val, prop) {
  24889. pointer[prop] = void 0;
  24890. });
  24891. };
  24892. /**
  24893. * Perform a drag operation in response to a mousemove event while the mouse
  24894. * is down.
  24895. * @private
  24896. * @function Highcharts.Pointer#drag
  24897. */
  24898. Pointer.prototype.drag = function (e) {
  24899. var chart = this.chart,
  24900. chartOptions = chart.options.chart,
  24901. zoomHor = this.zoomHor,
  24902. zoomVert = this.zoomVert,
  24903. plotLeft = chart.plotLeft,
  24904. plotTop = chart.plotTop,
  24905. plotWidth = chart.plotWidth,
  24906. plotHeight = chart.plotHeight,
  24907. mouseDownX = (this.mouseDownX || 0),
  24908. mouseDownY = (this.mouseDownY || 0),
  24909. panningEnabled = isObject(chartOptions.panning) ?
  24910. chartOptions.panning && chartOptions.panning.enabled :
  24911. chartOptions.panning,
  24912. panKey = (chartOptions.panKey && e[chartOptions.panKey + 'Key']);
  24913. var chartX = e.chartX,
  24914. chartY = e.chartY,
  24915. clickedInside,
  24916. size,
  24917. selectionMarker = this.selectionMarker;
  24918. // If the device supports both touch and mouse (like IE11), and we are
  24919. // touch-dragging inside the plot area, don't handle the mouse event.
  24920. // #4339.
  24921. if (selectionMarker && selectionMarker.touch) {
  24922. return;
  24923. }
  24924. // If the mouse is outside the plot area, adjust to cooordinates
  24925. // inside to prevent the selection marker from going outside
  24926. if (chartX < plotLeft) {
  24927. chartX = plotLeft;
  24928. }
  24929. else if (chartX > plotLeft + plotWidth) {
  24930. chartX = plotLeft + plotWidth;
  24931. }
  24932. if (chartY < plotTop) {
  24933. chartY = plotTop;
  24934. }
  24935. else if (chartY > plotTop + plotHeight) {
  24936. chartY = plotTop + plotHeight;
  24937. }
  24938. // determine if the mouse has moved more than 10px
  24939. this.hasDragged = Math.sqrt(Math.pow(mouseDownX - chartX, 2) +
  24940. Math.pow(mouseDownY - chartY, 2));
  24941. if (this.hasDragged > 10) {
  24942. clickedInside = chart.isInsidePlot(mouseDownX - plotLeft, mouseDownY - plotTop, {
  24943. visiblePlotOnly: true
  24944. });
  24945. // make a selection
  24946. if (chart.hasCartesianSeries &&
  24947. (this.zoomX || this.zoomY) &&
  24948. clickedInside &&
  24949. !panKey) {
  24950. if (!selectionMarker) {
  24951. this.selectionMarker = selectionMarker =
  24952. chart.renderer.rect(plotLeft, plotTop, zoomHor ? 1 : plotWidth, zoomVert ? 1 : plotHeight, 0)
  24953. .attr({
  24954. 'class': 'highcharts-selection-marker',
  24955. zIndex: 7
  24956. })
  24957. .add();
  24958. if (!chart.styledMode) {
  24959. selectionMarker.attr({
  24960. fill: (chartOptions.selectionMarkerFill ||
  24961. color(Palette.highlightColor80)
  24962. .setOpacity(0.25).get())
  24963. });
  24964. }
  24965. }
  24966. }
  24967. // adjust the width of the selection marker
  24968. if (selectionMarker && zoomHor) {
  24969. size = chartX - mouseDownX;
  24970. selectionMarker.attr({
  24971. width: Math.abs(size),
  24972. x: (size > 0 ? 0 : size) + mouseDownX
  24973. });
  24974. }
  24975. // adjust the height of the selection marker
  24976. if (selectionMarker && zoomVert) {
  24977. size = chartY - mouseDownY;
  24978. selectionMarker.attr({
  24979. height: Math.abs(size),
  24980. y: (size > 0 ? 0 : size) + mouseDownY
  24981. });
  24982. }
  24983. // panning
  24984. if (clickedInside &&
  24985. !selectionMarker &&
  24986. panningEnabled) {
  24987. chart.pan(e, chartOptions.panning);
  24988. }
  24989. }
  24990. };
  24991. /**
  24992. * Start a drag operation.
  24993. * @private
  24994. * @function Highcharts.Pointer#dragStart
  24995. */
  24996. Pointer.prototype.dragStart = function (e) {
  24997. var chart = this.chart;
  24998. // Record the start position
  24999. chart.mouseIsDown = e.type;
  25000. chart.cancelClick = false;
  25001. chart.mouseDownX = this.mouseDownX = e.chartX;
  25002. chart.mouseDownY = this.mouseDownY = e.chartY;
  25003. };
  25004. /**
  25005. * On mouse up or touch end across the entire document, drop the selection.
  25006. * @private
  25007. * @function Highcharts.Pointer#drop
  25008. */
  25009. Pointer.prototype.drop = function (e) {
  25010. var pointer = this,
  25011. chart = this.chart,
  25012. hasPinched = this.hasPinched;
  25013. if (this.selectionMarker) {
  25014. var selectionData_1 = {
  25015. originalEvent: e,
  25016. xAxis: [],
  25017. yAxis: []
  25018. },
  25019. selectionBox = this.selectionMarker,
  25020. selectionLeft_1 = selectionBox.attr ?
  25021. selectionBox.attr('x') :
  25022. selectionBox.x,
  25023. selectionTop_1 = selectionBox.attr ?
  25024. selectionBox.attr('y') :
  25025. selectionBox.y,
  25026. selectionWidth_1 = selectionBox.attr ?
  25027. selectionBox.attr('width') :
  25028. selectionBox.width,
  25029. selectionHeight_1 = selectionBox.attr ?
  25030. selectionBox.attr('height') :
  25031. selectionBox.height;
  25032. var runZoom_1;
  25033. // a selection has been made
  25034. if (this.hasDragged || hasPinched) {
  25035. // record each axis' min and max
  25036. chart.axes.forEach(function (axis) {
  25037. if (axis.zoomEnabled &&
  25038. defined(axis.min) &&
  25039. (hasPinched ||
  25040. pointer[{
  25041. xAxis: 'zoomX',
  25042. yAxis: 'zoomY'
  25043. }[axis.coll]]) &&
  25044. isNumber(selectionLeft_1) &&
  25045. isNumber(selectionTop_1)) { // #859, #3569
  25046. var horiz = axis.horiz,
  25047. minPixelPadding = e.type === 'touchend' ?
  25048. axis.minPixelPadding :
  25049. 0, // #1207, #3075
  25050. selectionMin = axis.toValue((horiz ? selectionLeft_1 : selectionTop_1) +
  25051. minPixelPadding),
  25052. selectionMax = axis.toValue((horiz ?
  25053. selectionLeft_1 + selectionWidth_1 :
  25054. selectionTop_1 + selectionHeight_1) - minPixelPadding);
  25055. selectionData_1[axis.coll].push({
  25056. axis: axis,
  25057. // Min/max for reversed axes
  25058. min: Math.min(selectionMin, selectionMax),
  25059. max: Math.max(selectionMin, selectionMax)
  25060. });
  25061. runZoom_1 = true;
  25062. }
  25063. });
  25064. if (runZoom_1) {
  25065. fireEvent(chart, 'selection', selectionData_1, function (args) {
  25066. chart.zoom(extend(args, hasPinched ?
  25067. { animation: false } :
  25068. null));
  25069. });
  25070. }
  25071. }
  25072. if (isNumber(chart.index)) {
  25073. this.selectionMarker = this.selectionMarker.destroy();
  25074. }
  25075. // Reset scaling preview
  25076. if (hasPinched) {
  25077. this.scaleGroups();
  25078. }
  25079. }
  25080. // Reset all. Check isNumber because it may be destroyed on mouse up
  25081. // (#877)
  25082. if (chart && isNumber(chart.index)) {
  25083. css(chart.container, { cursor: chart._cursor });
  25084. chart.cancelClick = this.hasDragged > 10; // #370
  25085. chart.mouseIsDown = this.hasDragged = this.hasPinched = false;
  25086. this.pinchDown = [];
  25087. }
  25088. };
  25089. /**
  25090. * Finds the closest point to a set of coordinates, using the k-d-tree
  25091. * algorithm.
  25092. *
  25093. * @function Highcharts.Pointer#findNearestKDPoint
  25094. *
  25095. * @param {Array<Highcharts.Series>} series
  25096. * All the series to search in.
  25097. *
  25098. * @param {boolean|undefined} shared
  25099. * Whether it is a shared tooltip or not.
  25100. *
  25101. * @param {Highcharts.PointerEventObject} e
  25102. * The pointer event object, containing chart coordinates of the pointer.
  25103. *
  25104. * @return {Highcharts.Point|undefined}
  25105. * The point closest to given coordinates.
  25106. */
  25107. Pointer.prototype.findNearestKDPoint = function (series, shared, e) {
  25108. var chart = this.chart;
  25109. var hoverPoint = chart.hoverPoint;
  25110. var tooltip = chart.tooltip;
  25111. if (hoverPoint &&
  25112. tooltip &&
  25113. tooltip.isStickyOnContact()) {
  25114. return hoverPoint;
  25115. }
  25116. var closest;
  25117. /** @private */
  25118. function sort(p1, p2) {
  25119. var isCloserX = p1.distX - p2.distX,
  25120. isCloser = p1.dist - p2.dist,
  25121. isAbove = ((p2.series.group && p2.series.group.zIndex) -
  25122. (p1.series.group && p1.series.group.zIndex));
  25123. var result;
  25124. // We have two points which are not in the same place on xAxis
  25125. // and shared tooltip:
  25126. if (isCloserX !== 0 && shared) { // #5721
  25127. result = isCloserX;
  25128. // Points are not exactly in the same place on x/yAxis:
  25129. }
  25130. else if (isCloser !== 0) {
  25131. result = isCloser;
  25132. // The same xAxis and yAxis position, sort by z-index:
  25133. }
  25134. else if (isAbove !== 0) {
  25135. result = isAbove;
  25136. // The same zIndex, sort by array index:
  25137. }
  25138. else {
  25139. result =
  25140. p1.series.index > p2.series.index ?
  25141. -1 :
  25142. 1;
  25143. }
  25144. return result;
  25145. }
  25146. series.forEach(function (s) {
  25147. var noSharedTooltip = s.noSharedTooltip && shared,
  25148. compareX = (!noSharedTooltip &&
  25149. s.options.findNearestPointBy.indexOf('y') < 0),
  25150. point = s.searchPoint(e,
  25151. compareX);
  25152. if ( // Check that we actually found a point on the series.
  25153. isObject(point, true) && point.series &&
  25154. // Use the new point if it is closer.
  25155. (!isObject(closest, true) ||
  25156. (sort(closest, point) > 0))) {
  25157. closest = point;
  25158. }
  25159. });
  25160. return closest;
  25161. };
  25162. /**
  25163. * @private
  25164. * @function Highcharts.Pointer#getChartCoordinatesFromPoint
  25165. */
  25166. Pointer.prototype.getChartCoordinatesFromPoint = function (point, inverted) {
  25167. var series = point.series,
  25168. xAxis = series.xAxis,
  25169. yAxis = series.yAxis,
  25170. shapeArgs = point.shapeArgs;
  25171. if (xAxis && yAxis) {
  25172. var x = pick(point.clientX,
  25173. point.plotX);
  25174. var y = point.plotY || 0;
  25175. if (point.isNode &&
  25176. shapeArgs &&
  25177. isNumber(shapeArgs.x) &&
  25178. isNumber(shapeArgs.y)) {
  25179. x = shapeArgs.x;
  25180. y = shapeArgs.y;
  25181. }
  25182. return inverted ? {
  25183. chartX: yAxis.len + yAxis.pos - y,
  25184. chartY: xAxis.len + xAxis.pos - x
  25185. } : {
  25186. chartX: x + xAxis.pos,
  25187. chartY: y + yAxis.pos
  25188. };
  25189. }
  25190. if (shapeArgs && shapeArgs.x && shapeArgs.y) {
  25191. // E.g. pies do not have axes
  25192. return {
  25193. chartX: shapeArgs.x,
  25194. chartY: shapeArgs.y
  25195. };
  25196. }
  25197. };
  25198. /**
  25199. * Return the cached chartPosition if it is available on the Pointer,
  25200. * otherwise find it. Running offset is quite expensive, so it should be
  25201. * avoided when we know the chart hasn't moved.
  25202. *
  25203. * @function Highcharts.Pointer#getChartPosition
  25204. *
  25205. * @return {Highcharts.ChartPositionObject}
  25206. * The offset of the chart container within the page
  25207. */
  25208. Pointer.prototype.getChartPosition = function () {
  25209. if (this.chartPosition) {
  25210. return this.chartPosition;
  25211. }
  25212. var container = this.chart.container;
  25213. var pos = offset(container);
  25214. this.chartPosition = {
  25215. left: pos.left,
  25216. top: pos.top,
  25217. scaleX: 1,
  25218. scaleY: 1
  25219. };
  25220. var offsetWidth = container.offsetWidth;
  25221. var offsetHeight = container.offsetHeight;
  25222. // #13342 - tooltip was not visible in Chrome, when chart
  25223. // updates height.
  25224. if (offsetWidth > 2 && // #13342
  25225. offsetHeight > 2 // #13342
  25226. ) {
  25227. this.chartPosition.scaleX = pos.width / offsetWidth;
  25228. this.chartPosition.scaleY = pos.height / offsetHeight;
  25229. }
  25230. return this.chartPosition;
  25231. };
  25232. /**
  25233. * Get the click position in terms of axis values.
  25234. *
  25235. * @function Highcharts.Pointer#getCoordinates
  25236. *
  25237. * @param {Highcharts.PointerEventObject} e
  25238. * Pointer event, extended with `chartX` and `chartY` properties.
  25239. *
  25240. * @return {Highcharts.PointerAxisCoordinatesObject}
  25241. */
  25242. Pointer.prototype.getCoordinates = function (e) {
  25243. var coordinates = {
  25244. xAxis: [],
  25245. yAxis: []
  25246. };
  25247. this.chart.axes.forEach(function (axis) {
  25248. coordinates[axis.isXAxis ? 'xAxis' : 'yAxis'].push({
  25249. axis: axis,
  25250. value: axis.toValue(e[axis.horiz ? 'chartX' : 'chartY'])
  25251. });
  25252. });
  25253. return coordinates;
  25254. };
  25255. /**
  25256. * Calculates what is the current hovered point/points and series.
  25257. *
  25258. * @private
  25259. * @function Highcharts.Pointer#getHoverData
  25260. *
  25261. * @param {Highcharts.Point|undefined} existingHoverPoint
  25262. * The point currrently beeing hovered.
  25263. *
  25264. * @param {Highcharts.Series|undefined} existingHoverSeries
  25265. * The series currently beeing hovered.
  25266. *
  25267. * @param {Array<Highcharts.Series>} series
  25268. * All the series in the chart.
  25269. *
  25270. * @param {boolean} isDirectTouch
  25271. * Is the pointer directly hovering the point.
  25272. *
  25273. * @param {boolean|undefined} shared
  25274. * Whether it is a shared tooltip or not.
  25275. *
  25276. * @param {Highcharts.PointerEventObject} [e]
  25277. * The triggering event, containing chart coordinates of the pointer.
  25278. *
  25279. * @return {object}
  25280. * Object containing resulting hover data: hoverPoint, hoverSeries, and
  25281. * hoverPoints.
  25282. */
  25283. Pointer.prototype.getHoverData = function (existingHoverPoint, existingHoverSeries, series, isDirectTouch, shared, e) {
  25284. var hoverPoints = [],
  25285. useExisting = !!(isDirectTouch && existingHoverPoint),
  25286. filter = function (s) {
  25287. return (s.visible &&
  25288. !(!shared && s.directTouch) && // #3821
  25289. pick(s.options.enableMouseTracking,
  25290. true));
  25291. };
  25292. var hoverSeries = existingHoverSeries,
  25293. // Which series to look in for the hover point
  25294. searchSeries,
  25295. // Parameters needed for beforeGetHoverData event.
  25296. eventArgs = {
  25297. chartX: e ? e.chartX : void 0,
  25298. chartY: e ? e.chartY : void 0,
  25299. shared: shared
  25300. };
  25301. // Find chart.hoverPane and update filter method in polar.
  25302. fireEvent(this, 'beforeGetHoverData', eventArgs);
  25303. var notSticky = hoverSeries && !hoverSeries.stickyTracking;
  25304. searchSeries = notSticky ?
  25305. // Only search on hovered series if it has stickyTracking false
  25306. [hoverSeries] :
  25307. // Filter what series to look in.
  25308. series.filter(function (s) {
  25309. return eventArgs.filter ? eventArgs.filter(s) : filter(s) &&
  25310. s.stickyTracking;
  25311. });
  25312. // Use existing hovered point or find the one closest to coordinates.
  25313. var hoverPoint = useExisting || !e ?
  25314. existingHoverPoint :
  25315. this.findNearestKDPoint(searchSeries,
  25316. shared,
  25317. e);
  25318. // Assign hover series
  25319. hoverSeries = hoverPoint && hoverPoint.series;
  25320. // If we have a hoverPoint, assign hoverPoints.
  25321. if (hoverPoint) {
  25322. // When tooltip is shared, it displays more than one point
  25323. if (shared && !hoverSeries.noSharedTooltip) {
  25324. searchSeries = series.filter(function (s) {
  25325. return eventArgs.filter ?
  25326. eventArgs.filter(s) : filter(s) && !s.noSharedTooltip;
  25327. });
  25328. // Get all points with the same x value as the hoverPoint
  25329. searchSeries.forEach(function (s) {
  25330. var point = find(s.points,
  25331. function (p) {
  25332. return p.x === hoverPoint.x && !p.isNull;
  25333. });
  25334. if (isObject(point)) {
  25335. /*
  25336. * Boost returns a minimal point. Convert it to a usable
  25337. * point for tooltip and states.
  25338. */
  25339. if (s.chart.isBoosting) {
  25340. point = s.getPoint(point);
  25341. }
  25342. hoverPoints.push(point);
  25343. }
  25344. });
  25345. }
  25346. else {
  25347. hoverPoints.push(hoverPoint);
  25348. }
  25349. }
  25350. // Check whether the hoverPoint is inside pane we are hovering over.
  25351. eventArgs = { hoverPoint: hoverPoint };
  25352. fireEvent(this, 'afterGetHoverData', eventArgs);
  25353. return {
  25354. hoverPoint: eventArgs.hoverPoint,
  25355. hoverSeries: hoverSeries,
  25356. hoverPoints: hoverPoints
  25357. };
  25358. };
  25359. /**
  25360. * @private
  25361. * @function Highcharts.Pointer#getPointFromEvent
  25362. */
  25363. Pointer.prototype.getPointFromEvent = function (e) {
  25364. var target = e.target,
  25365. point;
  25366. while (target && !point) {
  25367. point = target.point;
  25368. target = target.parentNode;
  25369. }
  25370. return point;
  25371. };
  25372. /**
  25373. * @private
  25374. * @function Highcharts.Pointer#onTrackerMouseOut
  25375. */
  25376. Pointer.prototype.onTrackerMouseOut = function (e) {
  25377. var chart = this.chart;
  25378. var relatedTarget = e.relatedTarget || e.toElement;
  25379. var series = chart.hoverSeries;
  25380. this.isDirectTouch = false;
  25381. if (series &&
  25382. relatedTarget &&
  25383. !series.stickyTracking &&
  25384. !this.inClass(relatedTarget, 'highcharts-tooltip') &&
  25385. (!this.inClass(relatedTarget, 'highcharts-series-' + series.index) || // #2499, #4465, #5553
  25386. !this.inClass(relatedTarget, 'highcharts-tracker'))) {
  25387. series.onMouseOut();
  25388. }
  25389. };
  25390. /**
  25391. * Utility to detect whether an element has, or has a parent with, a
  25392. * specificclass name. Used on detection of tracker objects and on deciding
  25393. * whether hovering the tooltip should cause the active series to mouse out.
  25394. *
  25395. * @function Highcharts.Pointer#inClass
  25396. *
  25397. * @param {Highcharts.SVGDOMElement|Highcharts.HTMLDOMElement} element
  25398. * The element to investigate.
  25399. *
  25400. * @param {string} className
  25401. * The class name to look for.
  25402. *
  25403. * @return {boolean|undefined}
  25404. * True if either the element or one of its parents has the given class
  25405. * name.
  25406. */
  25407. Pointer.prototype.inClass = function (element, className) {
  25408. var elemClassName;
  25409. while (element) {
  25410. elemClassName = attr(element, 'class');
  25411. if (elemClassName) {
  25412. if (elemClassName.indexOf(className) !== -1) {
  25413. return true;
  25414. }
  25415. if (elemClassName.indexOf('highcharts-container') !== -1) {
  25416. return false;
  25417. }
  25418. }
  25419. element = element.parentNode;
  25420. }
  25421. };
  25422. /**
  25423. * Initialize the Pointer.
  25424. *
  25425. * @private
  25426. * @function Highcharts.Pointer#init
  25427. *
  25428. * @param {Highcharts.Chart} chart
  25429. * The Chart instance.
  25430. *
  25431. * @param {Highcharts.Options} options
  25432. * The root options object. The pointer uses options from the chart and
  25433. * tooltip structures.
  25434. */
  25435. Pointer.prototype.init = function (chart, options) {
  25436. // Store references
  25437. this.options = options;
  25438. this.chart = chart;
  25439. // Do we need to handle click on a touch device?
  25440. this.runChartClick = Boolean(options.chart.events && options.chart.events.click);
  25441. this.pinchDown = [];
  25442. this.lastValidTouch = {};
  25443. if (Tooltip) {
  25444. /**
  25445. * Tooltip object for points of series.
  25446. *
  25447. * @name Highcharts.Chart#tooltip
  25448. * @type {Highcharts.Tooltip}
  25449. */
  25450. chart.tooltip = new Tooltip(chart, options.tooltip);
  25451. this.followTouchMove = pick(options.tooltip.followTouchMove, true);
  25452. }
  25453. this.setDOMEvents();
  25454. };
  25455. /**
  25456. * Takes a browser event object and extends it with custom Highcharts
  25457. * properties `chartX` and `chartY` in order to work on the internal
  25458. * coordinate system.
  25459. *
  25460. * @function Highcharts.Pointer#normalize
  25461. *
  25462. * @param {global.MouseEvent|global.PointerEvent|global.TouchEvent} e
  25463. * Event object in standard browsers.
  25464. *
  25465. * @param {Highcharts.OffsetObject} [chartPosition]
  25466. * Additional chart offset.
  25467. *
  25468. * @return {Highcharts.PointerEventObject}
  25469. * A browser event with extended properties `chartX` and `chartY`.
  25470. */
  25471. Pointer.prototype.normalize = function (e, chartPosition) {
  25472. var touches = e.touches;
  25473. // iOS (#2757)
  25474. var ePos = (touches ?
  25475. touches.length ?
  25476. touches.item(0) :
  25477. (pick(// #13534
  25478. touches.changedTouches,
  25479. e.changedTouches))[0] :
  25480. e);
  25481. // Get mouse position
  25482. if (!chartPosition) {
  25483. chartPosition = this.getChartPosition();
  25484. }
  25485. var chartX = ePos.pageX - chartPosition.left,
  25486. chartY = ePos.pageY - chartPosition.top;
  25487. // #11329 - when there is scaling on a parent element, we need to take
  25488. // this into account
  25489. chartX /= chartPosition.scaleX;
  25490. chartY /= chartPosition.scaleY;
  25491. return extend(e, {
  25492. chartX: Math.round(chartX),
  25493. chartY: Math.round(chartY)
  25494. });
  25495. };
  25496. /**
  25497. * @private
  25498. * @function Highcharts.Pointer#onContainerClick
  25499. */
  25500. Pointer.prototype.onContainerClick = function (e) {
  25501. var chart = this.chart;
  25502. var hoverPoint = chart.hoverPoint;
  25503. var pEvt = this.normalize(e);
  25504. var plotLeft = chart.plotLeft;
  25505. var plotTop = chart.plotTop;
  25506. if (!chart.cancelClick) {
  25507. // On tracker click, fire the series and point events. #783, #1583
  25508. if (hoverPoint &&
  25509. this.inClass(pEvt.target, 'highcharts-tracker')) {
  25510. // the series click event
  25511. fireEvent(hoverPoint.series, 'click', extend(pEvt, {
  25512. point: hoverPoint
  25513. }));
  25514. // the point click event
  25515. if (chart.hoverPoint) { // it may be destroyed (#1844)
  25516. hoverPoint.firePointEvent('click', pEvt);
  25517. }
  25518. // When clicking outside a tracker, fire a chart event
  25519. }
  25520. else {
  25521. extend(pEvt, this.getCoordinates(pEvt));
  25522. // fire a click event in the chart
  25523. if (chart.isInsidePlot(pEvt.chartX - plotLeft, pEvt.chartY - plotTop, {
  25524. visiblePlotOnly: true
  25525. })) {
  25526. fireEvent(chart, 'click', pEvt);
  25527. }
  25528. }
  25529. }
  25530. };
  25531. /**
  25532. * @private
  25533. * @function Highcharts.Pointer#onContainerMouseDown
  25534. */
  25535. Pointer.prototype.onContainerMouseDown = function (e) {
  25536. var isPrimaryButton = ((e.buttons || e.button) & 1) === 1;
  25537. // Normalize before the 'if' for the legacy IE (#7850)
  25538. e = this.normalize(e);
  25539. // #11635, Firefox does not reliable fire move event after click scroll
  25540. if (H.isFirefox &&
  25541. e.button !== 0) {
  25542. this.onContainerMouseMove(e);
  25543. }
  25544. // #11635, limiting to primary button (incl. IE 8 support)
  25545. if (typeof e.button === 'undefined' ||
  25546. isPrimaryButton) {
  25547. this.zoomOption(e);
  25548. // #295, #13737 solve conflict between container drag and chart zoom
  25549. if (isPrimaryButton &&
  25550. e.preventDefault) {
  25551. e.preventDefault();
  25552. }
  25553. this.dragStart(e);
  25554. }
  25555. };
  25556. /**
  25557. * When mouse leaves the container, hide the tooltip.
  25558. * @private
  25559. * @function Highcharts.Pointer#onContainerMouseLeave
  25560. */
  25561. Pointer.prototype.onContainerMouseLeave = function (e) {
  25562. var chart = charts[pick(Pointer.hoverChartIndex, -1)];
  25563. var tooltip = this.chart.tooltip;
  25564. e = this.normalize(e);
  25565. // #4886, MS Touch end fires mouseleave but with no related target
  25566. if (chart &&
  25567. (e.relatedTarget || e.toElement)) {
  25568. chart.pointer.reset();
  25569. // Also reset the chart position, used in #149 fix
  25570. chart.pointer.chartPosition = void 0;
  25571. }
  25572. if ( // #11635, Firefox wheel scroll does not fire out events consistently
  25573. tooltip &&
  25574. !tooltip.isHidden) {
  25575. this.reset();
  25576. }
  25577. };
  25578. /**
  25579. * When mouse enters the container, delete pointer's chartPosition.
  25580. * @private
  25581. * @function Highcharts.Pointer#onContainerMouseEnter
  25582. */
  25583. Pointer.prototype.onContainerMouseEnter = function (e) {
  25584. delete this.chartPosition;
  25585. };
  25586. /**
  25587. * The mousemove, touchmove and touchstart event handler
  25588. * @private
  25589. * @function Highcharts.Pointer#onContainerMouseMove
  25590. */
  25591. Pointer.prototype.onContainerMouseMove = function (e) {
  25592. var chart = this.chart;
  25593. var pEvt = this.normalize(e);
  25594. this.setHoverChartIndex();
  25595. // In IE8 we apparently need this returnValue set to false in order to
  25596. // avoid text being selected. But in Chrome, e.returnValue is prevented,
  25597. // plus we don't need to run e.preventDefault to prevent selected text
  25598. // in modern browsers. So we set it conditionally. Remove it when IE8 is
  25599. // no longer needed. #2251, #3224.
  25600. if (!pEvt.preventDefault) {
  25601. pEvt.returnValue = false;
  25602. }
  25603. if (chart.mouseIsDown === 'mousedown' || this.touchSelect(pEvt)) {
  25604. this.drag(pEvt);
  25605. }
  25606. // Show the tooltip and run mouse over events (#977)
  25607. if (!chart.openMenu &&
  25608. (this.inClass(pEvt.target, 'highcharts-tracker') ||
  25609. chart.isInsidePlot(pEvt.chartX - chart.plotLeft, pEvt.chartY - chart.plotTop, {
  25610. visiblePlotOnly: true
  25611. }))) {
  25612. if (this.inClass(pEvt.target, 'highcharts-no-tooltip')) {
  25613. this.reset(false, 0);
  25614. }
  25615. else {
  25616. this.runPointActions(pEvt);
  25617. }
  25618. }
  25619. };
  25620. /**
  25621. * @private
  25622. * @function Highcharts.Pointer#onDocumentTouchEnd
  25623. */
  25624. Pointer.prototype.onDocumentTouchEnd = function (e) {
  25625. var hoverChart = charts[pick(Pointer.hoverChartIndex, -1)];
  25626. if (hoverChart) {
  25627. hoverChart.pointer.drop(e);
  25628. }
  25629. };
  25630. /**
  25631. * @private
  25632. * @function Highcharts.Pointer#onContainerTouchMove
  25633. */
  25634. Pointer.prototype.onContainerTouchMove = function (e) {
  25635. if (this.touchSelect(e)) {
  25636. this.onContainerMouseMove(e);
  25637. }
  25638. else {
  25639. this.touch(e);
  25640. }
  25641. };
  25642. /**
  25643. * @private
  25644. * @function Highcharts.Pointer#onContainerTouchStart
  25645. */
  25646. Pointer.prototype.onContainerTouchStart = function (e) {
  25647. if (this.touchSelect(e)) {
  25648. this.onContainerMouseDown(e);
  25649. }
  25650. else {
  25651. this.zoomOption(e);
  25652. this.touch(e, true);
  25653. }
  25654. };
  25655. /**
  25656. * Special handler for mouse move that will hide the tooltip when the mouse
  25657. * leaves the plotarea. Issue #149 workaround. The mouseleave event does not
  25658. * always fire.
  25659. * @private
  25660. * @function Highcharts.Pointer#onDocumentMouseMove
  25661. */
  25662. Pointer.prototype.onDocumentMouseMove = function (e) {
  25663. var chart = this.chart;
  25664. var chartPosition = this.chartPosition;
  25665. var pEvt = this.normalize(e,
  25666. chartPosition);
  25667. var tooltip = chart.tooltip;
  25668. // If we're outside, hide the tooltip
  25669. if (chartPosition &&
  25670. (!tooltip ||
  25671. !tooltip.isStickyOnContact()) &&
  25672. !chart.isInsidePlot(pEvt.chartX - chart.plotLeft, pEvt.chartY - chart.plotTop, {
  25673. visiblePlotOnly: true
  25674. }) &&
  25675. !this.inClass(pEvt.target, 'highcharts-tracker')) {
  25676. this.reset();
  25677. }
  25678. };
  25679. /**
  25680. * @private
  25681. * @function Highcharts.Pointer#onDocumentMouseUp
  25682. */
  25683. Pointer.prototype.onDocumentMouseUp = function (e) {
  25684. var chart = charts[pick(Pointer.hoverChartIndex, -1)];
  25685. if (chart) {
  25686. chart.pointer.drop(e);
  25687. }
  25688. };
  25689. /**
  25690. * Handle touch events with two touches
  25691. * @private
  25692. * @function Highcharts.Pointer#pinch
  25693. */
  25694. Pointer.prototype.pinch = function (e) {
  25695. var self = this,
  25696. chart = self.chart,
  25697. pinchDown = self.pinchDown,
  25698. touches = (e.touches || []),
  25699. touchesLength = touches.length,
  25700. lastValidTouch = self.lastValidTouch,
  25701. hasZoom = self.hasZoom,
  25702. transform = {},
  25703. fireClickEvent = touchesLength === 1 && ((self.inClass(e.target, 'highcharts-tracker') &&
  25704. chart.runTrackerClick) ||
  25705. self.runChartClick),
  25706. clip = {};
  25707. var selectionMarker = self.selectionMarker;
  25708. // Don't initiate panning until the user has pinched. This prevents us
  25709. // from blocking page scrolling as users scroll down a long page
  25710. // (#4210).
  25711. if (touchesLength > 1) {
  25712. self.initiated = true;
  25713. }
  25714. // On touch devices, only proceed to trigger click if a handler is
  25715. // defined
  25716. if (hasZoom && self.initiated && !fireClickEvent && e.cancelable !== false) {
  25717. e.preventDefault();
  25718. }
  25719. // Normalize each touch
  25720. [].map.call(touches, function (e) {
  25721. return self.normalize(e);
  25722. });
  25723. // Register the touch start position
  25724. if (e.type === 'touchstart') {
  25725. [].forEach.call(touches, function (e, i) {
  25726. pinchDown[i] = { chartX: e.chartX, chartY: e.chartY };
  25727. });
  25728. lastValidTouch.x = [pinchDown[0].chartX, pinchDown[1] &&
  25729. pinchDown[1].chartX];
  25730. lastValidTouch.y = [pinchDown[0].chartY, pinchDown[1] &&
  25731. pinchDown[1].chartY];
  25732. // Identify the data bounds in pixels
  25733. chart.axes.forEach(function (axis) {
  25734. if (axis.zoomEnabled) {
  25735. var bounds = chart.bounds[axis.horiz ? 'h' : 'v'],
  25736. minPixelPadding = axis.minPixelPadding,
  25737. min = axis.toPixels(Math.min(pick(axis.options.min,
  25738. axis.dataMin),
  25739. axis.dataMin)),
  25740. max = axis.toPixels(Math.max(pick(axis.options.max,
  25741. axis.dataMax),
  25742. axis.dataMax)),
  25743. absMin = Math.min(min,
  25744. max),
  25745. absMax = Math.max(min,
  25746. max);
  25747. // Store the bounds for use in the touchmove handler
  25748. bounds.min = Math.min(axis.pos, absMin - minPixelPadding);
  25749. bounds.max = Math.max(axis.pos + axis.len, absMax + minPixelPadding);
  25750. }
  25751. });
  25752. self.res = true; // reset on next move
  25753. // Optionally move the tooltip on touchmove
  25754. }
  25755. else if (self.followTouchMove && touchesLength === 1) {
  25756. this.runPointActions(self.normalize(e));
  25757. // Event type is touchmove, handle panning and pinching
  25758. }
  25759. else if (pinchDown.length) { // can be 0 when releasing, if touchend
  25760. // fires first
  25761. // Set the marker
  25762. if (!selectionMarker) {
  25763. // @todo It's a mock object, so maybe we need a separate
  25764. // interface
  25765. self.selectionMarker = selectionMarker = extend({
  25766. destroy: noop,
  25767. touch: true
  25768. }, chart.plotBox);
  25769. }
  25770. self.pinchTranslate(pinchDown, touches, transform, selectionMarker, clip, lastValidTouch);
  25771. self.hasPinched = hasZoom;
  25772. // Scale and translate the groups to provide visual feedback during
  25773. // pinching
  25774. self.scaleGroups(transform, clip);
  25775. if (self.res) {
  25776. self.res = false;
  25777. this.reset(false, 0);
  25778. }
  25779. }
  25780. };
  25781. /**
  25782. * Run translation operations
  25783. * @private
  25784. * @function Highcharts.Pointer#pinchTranslate
  25785. */
  25786. Pointer.prototype.pinchTranslate = function (pinchDown, touches, transform, selectionMarker, clip, lastValidTouch) {
  25787. if (this.zoomHor) {
  25788. this.pinchTranslateDirection(true, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch);
  25789. }
  25790. if (this.zoomVert) {
  25791. this.pinchTranslateDirection(false, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch);
  25792. }
  25793. };
  25794. /**
  25795. * Run translation operations for each direction (horizontal and vertical)
  25796. * independently.
  25797. * @private
  25798. * @function Highcharts.Pointer#pinchTranslateDirection
  25799. */
  25800. Pointer.prototype.pinchTranslateDirection = function (horiz, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch, forcedScale) {
  25801. var chart = this.chart, xy = horiz ? 'x' : 'y', XY = horiz ? 'X' : 'Y', sChartXY = ('chart' + XY), wh = horiz ? 'width' : 'height', plotLeftTop = chart['plot' + (horiz ? 'Left' : 'Top')], inverted = chart.inverted, bounds = chart.bounds[horiz ? 'h' : 'v'], singleTouch = pinchDown.length === 1, touch0Start = pinchDown[0][sChartXY], touch1Start = !singleTouch && pinchDown[1][sChartXY], setScale = function () {
  25802. // Don't zoom if fingers are too close on this axis
  25803. if (typeof touch1Now === 'number' &&
  25804. Math.abs(touch0Start - touch1Start) > 20) {
  25805. scale = forcedScale ||
  25806. Math.abs(touch0Now - touch1Now) /
  25807. Math.abs(touch0Start - touch1Start);
  25808. }
  25809. clipXY = ((plotLeftTop - touch0Now) / scale) + touch0Start;
  25810. selectionWH = chart['plot' + (horiz ? 'Width' : 'Height')] / scale;
  25811. };
  25812. var selectionWH,
  25813. selectionXY,
  25814. clipXY,
  25815. scale = forcedScale || 1,
  25816. touch0Now = touches[0][sChartXY],
  25817. touch1Now = !singleTouch && touches[1][sChartXY],
  25818. outOfBounds;
  25819. // Set the scale, first pass
  25820. setScale();
  25821. // The clip position (x or y) is altered if out of bounds, the selection
  25822. // position is not
  25823. selectionXY = clipXY;
  25824. // Out of bounds
  25825. if (selectionXY < bounds.min) {
  25826. selectionXY = bounds.min;
  25827. outOfBounds = true;
  25828. }
  25829. else if (selectionXY + selectionWH > bounds.max) {
  25830. selectionXY = bounds.max - selectionWH;
  25831. outOfBounds = true;
  25832. }
  25833. // Is the chart dragged off its bounds, determined by dataMin and
  25834. // dataMax?
  25835. if (outOfBounds) {
  25836. // Modify the touchNow position in order to create an elastic drag
  25837. // movement. This indicates to the user that the chart is responsive
  25838. // but can't be dragged further.
  25839. touch0Now -= 0.8 * (touch0Now - lastValidTouch[xy][0]);
  25840. if (typeof touch1Now === 'number') {
  25841. touch1Now -= 0.8 * (touch1Now - lastValidTouch[xy][1]);
  25842. }
  25843. // Set the scale, second pass to adapt to the modified touchNow
  25844. // positions
  25845. setScale();
  25846. }
  25847. else {
  25848. lastValidTouch[xy] = [touch0Now, touch1Now];
  25849. }
  25850. // Set geometry for clipping, selection and transformation
  25851. if (!inverted) {
  25852. clip[xy] = clipXY - plotLeftTop;
  25853. clip[wh] = selectionWH;
  25854. }
  25855. var scaleKey = inverted ? (horiz ? 'scaleY' : 'scaleX') : 'scale' + XY;
  25856. var transformScale = inverted ? 1 / scale : scale;
  25857. selectionMarker[wh] = selectionWH;
  25858. selectionMarker[xy] = selectionXY;
  25859. transform[scaleKey] = scale;
  25860. transform['translate' + XY] = (transformScale * plotLeftTop) +
  25861. (touch0Now - (transformScale * touch0Start));
  25862. };
  25863. /**
  25864. * Reset the tracking by hiding the tooltip, the hover series state and the
  25865. * hover point
  25866. *
  25867. * @function Highcharts.Pointer#reset
  25868. *
  25869. * @param {boolean} [allowMove]
  25870. * Instead of destroying the tooltip altogether, allow moving it if
  25871. * possible.
  25872. *
  25873. * @param {number} [delay]
  25874. */
  25875. Pointer.prototype.reset = function (allowMove, delay) {
  25876. var pointer = this,
  25877. chart = pointer.chart,
  25878. hoverSeries = chart.hoverSeries,
  25879. hoverPoint = chart.hoverPoint,
  25880. hoverPoints = chart.hoverPoints,
  25881. tooltip = chart.tooltip,
  25882. tooltipPoints = tooltip && tooltip.shared ?
  25883. hoverPoints :
  25884. hoverPoint;
  25885. // Check if the points have moved outside the plot area (#1003, #4736,
  25886. // #5101)
  25887. if (allowMove && tooltipPoints) {
  25888. splat(tooltipPoints).forEach(function (point) {
  25889. if (point.series.isCartesian &&
  25890. typeof point.plotX === 'undefined') {
  25891. allowMove = false;
  25892. }
  25893. });
  25894. }
  25895. // Just move the tooltip, #349
  25896. if (allowMove) {
  25897. if (tooltip && tooltipPoints && splat(tooltipPoints).length) {
  25898. tooltip.refresh(tooltipPoints);
  25899. if (tooltip.shared && hoverPoints) { // #8284
  25900. hoverPoints.forEach(function (point) {
  25901. point.setState(point.state, true);
  25902. if (point.series.isCartesian) {
  25903. if (point.series.xAxis.crosshair) {
  25904. point.series.xAxis
  25905. .drawCrosshair(null, point);
  25906. }
  25907. if (point.series.yAxis.crosshair) {
  25908. point.series.yAxis
  25909. .drawCrosshair(null, point);
  25910. }
  25911. }
  25912. });
  25913. }
  25914. else if (hoverPoint) { // #2500
  25915. hoverPoint.setState(hoverPoint.state, true);
  25916. chart.axes.forEach(function (axis) {
  25917. if (axis.crosshair &&
  25918. hoverPoint.series[axis.coll] === axis) {
  25919. axis.drawCrosshair(null, hoverPoint);
  25920. }
  25921. });
  25922. }
  25923. }
  25924. // Full reset
  25925. }
  25926. else {
  25927. if (hoverPoint) {
  25928. hoverPoint.onMouseOut();
  25929. }
  25930. if (hoverPoints) {
  25931. hoverPoints.forEach(function (point) {
  25932. point.setState();
  25933. });
  25934. }
  25935. if (hoverSeries) {
  25936. hoverSeries.onMouseOut();
  25937. }
  25938. if (tooltip) {
  25939. tooltip.hide(delay);
  25940. }
  25941. if (pointer.unDocMouseMove) {
  25942. pointer.unDocMouseMove = pointer.unDocMouseMove();
  25943. }
  25944. // Remove crosshairs
  25945. chart.axes.forEach(function (axis) {
  25946. axis.hideCrosshair();
  25947. });
  25948. pointer.hoverX = chart.hoverPoints = chart.hoverPoint = null;
  25949. }
  25950. };
  25951. /**
  25952. * With line type charts with a single tracker, get the point closest to the
  25953. * mouse. Run Point.onMouseOver and display tooltip for the point or points.
  25954. *
  25955. * @private
  25956. * @function Highcharts.Pointer#runPointActions
  25957. *
  25958. * @fires Highcharts.Point#event:mouseOut
  25959. * @fires Highcharts.Point#event:mouseOver
  25960. */
  25961. Pointer.prototype.runPointActions = function (e, p) {
  25962. var pointer = this,
  25963. chart = pointer.chart,
  25964. series = chart.series,
  25965. tooltip = (chart.tooltip && chart.tooltip.options.enabled ?
  25966. chart.tooltip :
  25967. void 0),
  25968. shared = (tooltip ?
  25969. tooltip.shared :
  25970. false);
  25971. var hoverPoint = p || chart.hoverPoint,
  25972. hoverSeries = hoverPoint && hoverPoint.series || chart.hoverSeries;
  25973. var // onMouseOver or already hovering a series with directTouch
  25974. isDirectTouch = (!e || e.type !== 'touchmove') && (!!p || ((hoverSeries && hoverSeries.directTouch) &&
  25975. pointer.isDirectTouch)),
  25976. hoverData = this.getHoverData(hoverPoint,
  25977. hoverSeries,
  25978. series,
  25979. isDirectTouch,
  25980. shared,
  25981. e);
  25982. // Update variables from hoverData.
  25983. hoverPoint = hoverData.hoverPoint;
  25984. hoverSeries = hoverData.hoverSeries;
  25985. var points = hoverData.hoverPoints,
  25986. followPointer = hoverSeries &&
  25987. hoverSeries.tooltipOptions.followPointer &&
  25988. !hoverSeries.tooltipOptions.split,
  25989. useSharedTooltip = (shared &&
  25990. hoverSeries &&
  25991. !hoverSeries.noSharedTooltip);
  25992. // Refresh tooltip for kdpoint if new hover point or tooltip was hidden
  25993. // #3926, #4200
  25994. if (hoverPoint &&
  25995. // !(hoverSeries && hoverSeries.directTouch) &&
  25996. (hoverPoint !== chart.hoverPoint || (tooltip && tooltip.isHidden))) {
  25997. (chart.hoverPoints || []).forEach(function (p) {
  25998. if (points.indexOf(p) === -1) {
  25999. p.setState();
  26000. }
  26001. });
  26002. // Set normal state to previous series
  26003. if (chart.hoverSeries !== hoverSeries) {
  26004. hoverSeries.onMouseOver();
  26005. }
  26006. pointer.applyInactiveState(points);
  26007. // Do mouseover on all points (#3919, #3985, #4410, #5622)
  26008. (points || []).forEach(function (p) {
  26009. p.setState('hover');
  26010. });
  26011. // If tracking is on series in stead of on each point,
  26012. // fire mouseOver on hover point. // #4448
  26013. if (chart.hoverPoint) {
  26014. chart.hoverPoint.firePointEvent('mouseOut');
  26015. }
  26016. // Hover point may have been destroyed in the event handlers (#7127)
  26017. if (!hoverPoint.series) {
  26018. return;
  26019. }
  26020. /**
  26021. * Contains all hovered points.
  26022. *
  26023. * @name Highcharts.Chart#hoverPoints
  26024. * @type {Array<Highcharts.Point>|null}
  26025. */
  26026. chart.hoverPoints = points;
  26027. /**
  26028. * Contains the original hovered point.
  26029. *
  26030. * @name Highcharts.Chart#hoverPoint
  26031. * @type {Highcharts.Point|null}
  26032. */
  26033. chart.hoverPoint = hoverPoint;
  26034. /**
  26035. * Hover state should not be lost when axis is updated (#12569)
  26036. * Axis.update runs pointer.reset which uses chart.hoverPoint.state
  26037. * to apply state which does not exist in hoverPoint yet.
  26038. * The mouseOver event should be triggered when hoverPoint
  26039. * is correct.
  26040. */
  26041. hoverPoint.firePointEvent('mouseOver');
  26042. // Draw tooltip if necessary
  26043. if (tooltip) {
  26044. tooltip.refresh(useSharedTooltip ? points : hoverPoint, e);
  26045. }
  26046. // Update positions (regardless of kdpoint or hoverPoint)
  26047. }
  26048. else if (followPointer && tooltip && !tooltip.isHidden) {
  26049. var anchor = tooltip.getAnchor([{}],
  26050. e);
  26051. if (chart.isInsidePlot(anchor[0], anchor[1], {
  26052. visiblePlotOnly: true
  26053. })) {
  26054. tooltip.updatePosition({ plotX: anchor[0], plotY: anchor[1] });
  26055. }
  26056. }
  26057. // Start the event listener to pick up the tooltip and crosshairs
  26058. if (!pointer.unDocMouseMove) {
  26059. pointer.unDocMouseMove = addEvent(chart.container.ownerDocument, 'mousemove', function (e) {
  26060. var chart = charts[Pointer.hoverChartIndex];
  26061. if (chart) {
  26062. chart.pointer.onDocumentMouseMove(e);
  26063. }
  26064. });
  26065. pointer.eventsToUnbind.push(pointer.unDocMouseMove);
  26066. }
  26067. // Issues related to crosshair #4927, #5269 #5066, #5658
  26068. chart.axes.forEach(function drawAxisCrosshair(axis) {
  26069. var snap = pick((axis.crosshair || {}).snap,
  26070. true);
  26071. var point;
  26072. if (snap) {
  26073. point = chart.hoverPoint; // #13002
  26074. if (!point || point.series[axis.coll] !== axis) {
  26075. point = find(points, function (p) {
  26076. return p.series[axis.coll] === axis;
  26077. });
  26078. }
  26079. }
  26080. // Axis has snapping crosshairs, and one of the hover points belongs
  26081. // to axis. Always call drawCrosshair when it is not snap.
  26082. if (point || !snap) {
  26083. axis.drawCrosshair(e, point);
  26084. // Axis has snapping crosshairs, but no hover point belongs to axis
  26085. }
  26086. else {
  26087. axis.hideCrosshair();
  26088. }
  26089. });
  26090. };
  26091. /**
  26092. * Scale series groups to a certain scale and translation.
  26093. * @private
  26094. * @function Highcharts.Pointer#scaleGroups
  26095. */
  26096. Pointer.prototype.scaleGroups = function (attribs, clip) {
  26097. var chart = this.chart;
  26098. // Scale each series
  26099. chart.series.forEach(function (series) {
  26100. var seriesAttribs = attribs || series.getPlotBox(); // #1701
  26101. if (series.xAxis && series.xAxis.zoomEnabled && series.group) {
  26102. series.group.attr(seriesAttribs);
  26103. if (series.markerGroup) {
  26104. series.markerGroup.attr(seriesAttribs);
  26105. series.markerGroup.clip(clip ? chart.clipRect : null);
  26106. }
  26107. if (series.dataLabelsGroup) {
  26108. series.dataLabelsGroup.attr(seriesAttribs);
  26109. }
  26110. }
  26111. });
  26112. // Clip
  26113. chart.clipRect.attr(clip || chart.clipBox);
  26114. };
  26115. /**
  26116. * Set the JS DOM events on the container and document. This method should
  26117. * contain a one-to-one assignment between methods and their handlers. Any
  26118. * advanced logic should be moved to the handler reflecting the event's
  26119. * name.
  26120. * @private
  26121. * @function Highcharts.Pointer#setDOMEvents
  26122. */
  26123. Pointer.prototype.setDOMEvents = function () {
  26124. var _this = this;
  26125. var container = this.chart.container,
  26126. ownerDoc = container.ownerDocument;
  26127. container.onmousedown = this.onContainerMouseDown.bind(this);
  26128. container.onmousemove = this.onContainerMouseMove.bind(this);
  26129. container.onclick = this.onContainerClick.bind(this);
  26130. this.eventsToUnbind.push(addEvent(container, 'mouseenter', this.onContainerMouseEnter.bind(this)));
  26131. this.eventsToUnbind.push(addEvent(container, 'mouseleave', this.onContainerMouseLeave.bind(this)));
  26132. if (!Pointer.unbindDocumentMouseUp) {
  26133. Pointer.unbindDocumentMouseUp = addEvent(ownerDoc, 'mouseup', this.onDocumentMouseUp.bind(this));
  26134. }
  26135. // In case we are dealing with overflow, reset the chart position when
  26136. // scrolling parent elements
  26137. var parent = this.chart.renderTo.parentElement;
  26138. while (parent && parent.tagName !== 'BODY') {
  26139. this.eventsToUnbind.push(addEvent(parent, 'scroll', function () {
  26140. delete _this.chartPosition;
  26141. }));
  26142. parent = parent.parentElement;
  26143. }
  26144. if (H.hasTouch) {
  26145. this.eventsToUnbind.push(addEvent(container, 'touchstart', this.onContainerTouchStart.bind(this), { passive: false }));
  26146. this.eventsToUnbind.push(addEvent(container, 'touchmove', this.onContainerTouchMove.bind(this), { passive: false }));
  26147. if (!Pointer.unbindDocumentTouchEnd) {
  26148. Pointer.unbindDocumentTouchEnd = addEvent(ownerDoc, 'touchend', this.onDocumentTouchEnd.bind(this), { passive: false });
  26149. }
  26150. }
  26151. };
  26152. /**
  26153. * Sets the index of the hovered chart and leaves the previous hovered
  26154. * chart, to reset states like tooltip.
  26155. * @private
  26156. * @function Highcharts.Pointer#setHoverChartIndex
  26157. */
  26158. Pointer.prototype.setHoverChartIndex = function () {
  26159. var chart = this.chart;
  26160. var hoverChart = H.charts[pick(Pointer.hoverChartIndex, -1)];
  26161. if (hoverChart &&
  26162. hoverChart !== chart) {
  26163. hoverChart.pointer.onContainerMouseLeave({ relatedTarget: true });
  26164. }
  26165. if (!hoverChart ||
  26166. !hoverChart.mouseIsDown) {
  26167. Pointer.hoverChartIndex = chart.index;
  26168. }
  26169. };
  26170. /**
  26171. * General touch handler shared by touchstart and touchmove.
  26172. * @private
  26173. * @function Highcharts.Pointer#touch
  26174. */
  26175. Pointer.prototype.touch = function (e, start) {
  26176. var chart = this.chart;
  26177. var hasMoved,
  26178. pinchDown,
  26179. isInside;
  26180. this.setHoverChartIndex();
  26181. if (e.touches.length === 1) {
  26182. e = this.normalize(e);
  26183. isInside = chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop, {
  26184. visiblePlotOnly: true
  26185. });
  26186. if (isInside && !chart.openMenu) {
  26187. // Run mouse events and display tooltip etc
  26188. if (start) {
  26189. this.runPointActions(e);
  26190. }
  26191. // Android fires touchmove events after the touchstart even if
  26192. // the finger hasn't moved, or moved only a pixel or two. In iOS
  26193. // however, the touchmove doesn't fire unless the finger moves
  26194. // more than ~4px. So we emulate this behaviour in Android by
  26195. // checking how much it moved, and cancelling on small
  26196. // distances. #3450.
  26197. if (e.type === 'touchmove') {
  26198. pinchDown = this.pinchDown;
  26199. hasMoved = pinchDown[0] ? Math.sqrt(// #5266
  26200. Math.pow(pinchDown[0].chartX - e.chartX, 2) +
  26201. Math.pow(pinchDown[0].chartY - e.chartY, 2)) >= 4 : false;
  26202. }
  26203. if (pick(hasMoved, true)) {
  26204. this.pinch(e);
  26205. }
  26206. }
  26207. else if (start) {
  26208. // Hide the tooltip on touching outside the plot area (#1203)
  26209. this.reset();
  26210. }
  26211. }
  26212. else if (e.touches.length === 2) {
  26213. this.pinch(e);
  26214. }
  26215. };
  26216. /**
  26217. * Returns true if the chart is set up for zooming by single touch and the
  26218. * event is capable
  26219. * @private
  26220. * @function Highcharts.Pointer#touchSelect
  26221. */
  26222. Pointer.prototype.touchSelect = function (e) {
  26223. return Boolean(this.chart.options.chart.zoomBySingleTouch &&
  26224. e.touches &&
  26225. e.touches.length === 1);
  26226. };
  26227. /**
  26228. * Resolve the zoomType option, this is reset on all touch start and mouse
  26229. * down events.
  26230. * @private
  26231. * @function Highcharts.Pointer#zoomOption
  26232. */
  26233. Pointer.prototype.zoomOption = function (e) {
  26234. var chart = this.chart,
  26235. options = chart.options.chart,
  26236. inverted = chart.inverted;
  26237. var zoomType = options.zoomType || '',
  26238. zoomX,
  26239. zoomY;
  26240. // Look for the pinchType option
  26241. if (/touch/.test(e.type)) {
  26242. zoomType = pick(options.pinchType, zoomType);
  26243. }
  26244. this.zoomX = zoomX = /x/.test(zoomType);
  26245. this.zoomY = zoomY = /y/.test(zoomType);
  26246. this.zoomHor = (zoomX && !inverted) || (zoomY && inverted);
  26247. this.zoomVert = (zoomY && !inverted) || (zoomX && inverted);
  26248. this.hasZoom = zoomX || zoomY;
  26249. };
  26250. return Pointer;
  26251. }());
  26252. /* *
  26253. *
  26254. * Default Export
  26255. *
  26256. * */
  26257. /* *
  26258. *
  26259. * API Declarations
  26260. *
  26261. * */
  26262. /**
  26263. * One position in relation to an axis.
  26264. *
  26265. * @interface Highcharts.PointerAxisCoordinateObject
  26266. */ /**
  26267. * Related axis.
  26268. *
  26269. * @name Highcharts.PointerAxisCoordinateObject#axis
  26270. * @type {Highcharts.Axis}
  26271. */ /**
  26272. * Axis value.
  26273. *
  26274. * @name Highcharts.PointerAxisCoordinateObject#value
  26275. * @type {number}
  26276. */
  26277. /**
  26278. * Positions in terms of axis values.
  26279. *
  26280. * @interface Highcharts.PointerAxisCoordinatesObject
  26281. */ /**
  26282. * Positions on the x-axis.
  26283. * @name Highcharts.PointerAxisCoordinatesObject#xAxis
  26284. * @type {Array<Highcharts.PointerAxisCoordinateObject>}
  26285. */ /**
  26286. * Positions on the y-axis.
  26287. * @name Highcharts.PointerAxisCoordinatesObject#yAxis
  26288. * @type {Array<Highcharts.PointerAxisCoordinateObject>}
  26289. */
  26290. /**
  26291. * Pointer coordinates.
  26292. *
  26293. * @interface Highcharts.PointerCoordinatesObject
  26294. */ /**
  26295. * @name Highcharts.PointerCoordinatesObject#chartX
  26296. * @type {number}
  26297. */ /**
  26298. * @name Highcharts.PointerCoordinatesObject#chartY
  26299. * @type {number}
  26300. */
  26301. /**
  26302. * A native browser mouse or touch event, extended with position information
  26303. * relative to the {@link Chart.container}.
  26304. *
  26305. * @interface Highcharts.PointerEventObject
  26306. * @extends global.PointerEvent
  26307. */ /**
  26308. * The X coordinate of the pointer interaction relative to the chart.
  26309. *
  26310. * @name Highcharts.PointerEventObject#chartX
  26311. * @type {number}
  26312. */ /**
  26313. * The Y coordinate of the pointer interaction relative to the chart.
  26314. *
  26315. * @name Highcharts.PointerEventObject#chartY
  26316. * @type {number}
  26317. */
  26318. /**
  26319. * Axis-specific data of a selection.
  26320. *
  26321. * @interface Highcharts.SelectDataObject
  26322. */ /**
  26323. * @name Highcharts.SelectDataObject#axis
  26324. * @type {Highcharts.Axis}
  26325. */ /**
  26326. * @name Highcharts.SelectDataObject#max
  26327. * @type {number}
  26328. */ /**
  26329. * @name Highcharts.SelectDataObject#min
  26330. * @type {number}
  26331. */
  26332. /**
  26333. * Object for select events.
  26334. *
  26335. * @interface Highcharts.SelectEventObject
  26336. */ /**
  26337. * @name Highcharts.SelectEventObject#originalEvent
  26338. * @type {global.Event}
  26339. */ /**
  26340. * @name Highcharts.SelectEventObject#xAxis
  26341. * @type {Array<Highcharts.SelectDataObject>}
  26342. */ /**
  26343. * @name Highcharts.SelectEventObject#yAxis
  26344. * @type {Array<Highcharts.SelectDataObject>}
  26345. */
  26346. /**
  26347. * Chart position and scale.
  26348. *
  26349. * @interface Highcharts.ChartPositionObject
  26350. */ /**
  26351. * @name Highcharts.ChartPositionObject#left
  26352. * @type {number}
  26353. */ /**
  26354. * @name Highcharts.ChartPositionObject#scaleX
  26355. * @type {number}
  26356. */ /**
  26357. * @name Highcharts.ChartPositionObject#scaleY
  26358. * @type {number}
  26359. */ /**
  26360. * @name Highcharts.ChartPositionObject#top
  26361. * @type {number}
  26362. */
  26363. ''; // keeps doclets above in JS file
  26364. return Pointer;
  26365. });
  26366. _registerModule(_modules, 'Core/MSPointer.js', [_modules['Core/Globals.js'], _modules['Core/Pointer.js'], _modules['Core/Utilities.js']], function (H, Pointer, U) {
  26367. /* *
  26368. *
  26369. * (c) 2010-2021 Torstein Honsi
  26370. *
  26371. * License: www.highcharts.com/license
  26372. *
  26373. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  26374. *
  26375. * */
  26376. var __extends = (this && this.__extends) || (function () {
  26377. var extendStatics = function (d,
  26378. b) {
  26379. extendStatics = Object.setPrototypeOf ||
  26380. ({ __proto__: [] } instanceof Array && function (d,
  26381. b) { d.__proto__ = b; }) ||
  26382. function (d,
  26383. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  26384. return extendStatics(d, b);
  26385. };
  26386. return function (d, b) {
  26387. extendStatics(d, b);
  26388. function __() { this.constructor = d; }
  26389. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  26390. };
  26391. })();
  26392. var charts = H.charts,
  26393. doc = H.doc,
  26394. noop = H.noop,
  26395. win = H.win;
  26396. var addEvent = U.addEvent,
  26397. css = U.css,
  26398. objectEach = U.objectEach,
  26399. removeEvent = U.removeEvent;
  26400. /* *
  26401. *
  26402. * Constants
  26403. *
  26404. * */
  26405. // The touches object keeps track of the points being touched at all times
  26406. var touches = {};
  26407. var hasPointerEvent = !!win.PointerEvent;
  26408. /* *
  26409. *
  26410. * Functions
  26411. *
  26412. * */
  26413. /* eslint-disable valid-jsdoc */
  26414. /** @private */
  26415. function getWebkitTouches() {
  26416. var fake = [];
  26417. fake.item = function (i) {
  26418. return this[i];
  26419. };
  26420. objectEach(touches, function (touch) {
  26421. fake.push({
  26422. pageX: touch.pageX,
  26423. pageY: touch.pageY,
  26424. target: touch.target
  26425. });
  26426. });
  26427. return fake;
  26428. }
  26429. /** @private */
  26430. function translateMSPointer(e, method, wktype, func) {
  26431. var chart = charts[Pointer.hoverChartIndex || NaN];
  26432. if ((e.pointerType === 'touch' ||
  26433. e.pointerType === e.MSPOINTER_TYPE_TOUCH) && chart) {
  26434. var p = chart.pointer;
  26435. func(e);
  26436. p[method]({
  26437. type: wktype,
  26438. target: e.currentTarget,
  26439. preventDefault: noop,
  26440. touches: getWebkitTouches()
  26441. });
  26442. }
  26443. }
  26444. /* *
  26445. *
  26446. * Class
  26447. *
  26448. * */
  26449. /** @private */
  26450. var MSPointer = /** @class */ (function (_super) {
  26451. __extends(MSPointer, _super);
  26452. function MSPointer() {
  26453. return _super !== null && _super.apply(this, arguments) || this;
  26454. }
  26455. /* *
  26456. *
  26457. * Static Functions
  26458. *
  26459. * */
  26460. MSPointer.isRequired = function () {
  26461. return !!(!H.hasTouch && (win.PointerEvent || win.MSPointerEvent));
  26462. };
  26463. /* *
  26464. *
  26465. * Functions
  26466. *
  26467. * */
  26468. /**
  26469. * Add or remove the MS Pointer specific events
  26470. * @private
  26471. * @function Highcharts.Pointer#batchMSEvents
  26472. */
  26473. MSPointer.prototype.batchMSEvents = function (fn) {
  26474. fn(this.chart.container, hasPointerEvent ? 'pointerdown' : 'MSPointerDown', this.onContainerPointerDown);
  26475. fn(this.chart.container, hasPointerEvent ? 'pointermove' : 'MSPointerMove', this.onContainerPointerMove);
  26476. fn(doc, hasPointerEvent ? 'pointerup' : 'MSPointerUp', this.onDocumentPointerUp);
  26477. };
  26478. // Destroy MS events also
  26479. MSPointer.prototype.destroy = function () {
  26480. this.batchMSEvents(removeEvent);
  26481. _super.prototype.destroy.call(this);
  26482. };
  26483. // Disable default IE actions for pinch and such on chart element
  26484. MSPointer.prototype.init = function (chart, options) {
  26485. _super.prototype.init.call(this, chart, options);
  26486. if (this.hasZoom) { // #4014
  26487. css(chart.container, {
  26488. '-ms-touch-action': 'none',
  26489. 'touch-action': 'none'
  26490. });
  26491. }
  26492. };
  26493. /**
  26494. * @private
  26495. * @function Highcharts.Pointer#onContainerPointerDown
  26496. */
  26497. MSPointer.prototype.onContainerPointerDown = function (e) {
  26498. translateMSPointer(e, 'onContainerTouchStart', 'touchstart', function (e) {
  26499. touches[e.pointerId] = {
  26500. pageX: e.pageX,
  26501. pageY: e.pageY,
  26502. target: e.currentTarget
  26503. };
  26504. });
  26505. };
  26506. /**
  26507. * @private
  26508. * @function Highcharts.Pointer#onContainerPointerMove
  26509. */
  26510. MSPointer.prototype.onContainerPointerMove = function (e) {
  26511. translateMSPointer(e, 'onContainerTouchMove', 'touchmove', function (e) {
  26512. touches[e.pointerId] = ({ pageX: e.pageX, pageY: e.pageY });
  26513. if (!touches[e.pointerId].target) {
  26514. touches[e.pointerId].target = e.currentTarget;
  26515. }
  26516. });
  26517. };
  26518. /**
  26519. * @private
  26520. * @function Highcharts.Pointer#onDocumentPointerUp
  26521. */
  26522. MSPointer.prototype.onDocumentPointerUp = function (e) {
  26523. translateMSPointer(e, 'onDocumentTouchEnd', 'touchend', function (e) {
  26524. delete touches[e.pointerId];
  26525. });
  26526. };
  26527. // Add IE specific touch events to chart
  26528. MSPointer.prototype.setDOMEvents = function () {
  26529. _super.prototype.setDOMEvents.call(this);
  26530. if (this.hasZoom || this.followTouchMove) {
  26531. this.batchMSEvents(addEvent);
  26532. }
  26533. };
  26534. return MSPointer;
  26535. }(Pointer));
  26536. /* *
  26537. *
  26538. * Default Export
  26539. *
  26540. * */
  26541. return MSPointer;
  26542. });
  26543. _registerModule(_modules, 'Core/Series/Point.js', [_modules['Core/Renderer/HTML/AST.js'], _modules['Core/Animation/AnimationUtilities.js'], _modules['Core/FormatUtilities.js'], _modules['Core/Globals.js'], _modules['Core/DefaultOptions.js'], _modules['Core/Utilities.js']], function (AST, A, F, H, D, U) {
  26544. /* *
  26545. *
  26546. * (c) 2010-2021 Torstein Honsi
  26547. *
  26548. * License: www.highcharts.com/license
  26549. *
  26550. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  26551. *
  26552. * */
  26553. var animObject = A.animObject;
  26554. var format = F.format;
  26555. var defaultOptions = D.defaultOptions;
  26556. var addEvent = U.addEvent,
  26557. defined = U.defined,
  26558. erase = U.erase,
  26559. extend = U.extend,
  26560. fireEvent = U.fireEvent,
  26561. getNestedProperty = U.getNestedProperty,
  26562. isArray = U.isArray,
  26563. isFunction = U.isFunction,
  26564. isNumber = U.isNumber,
  26565. isObject = U.isObject,
  26566. merge = U.merge,
  26567. objectEach = U.objectEach,
  26568. pick = U.pick,
  26569. syncTimeout = U.syncTimeout,
  26570. removeEvent = U.removeEvent,
  26571. uniqueKey = U.uniqueKey;
  26572. /**
  26573. * Function callback when a series point is clicked. Return false to cancel the
  26574. * action.
  26575. *
  26576. * @callback Highcharts.PointClickCallbackFunction
  26577. *
  26578. * @param {Highcharts.Point} this
  26579. * The point where the event occured.
  26580. *
  26581. * @param {Highcharts.PointClickEventObject} event
  26582. * Event arguments.
  26583. */
  26584. /**
  26585. * Common information for a click event on a series point.
  26586. *
  26587. * @interface Highcharts.PointClickEventObject
  26588. * @extends Highcharts.PointerEventObject
  26589. */ /**
  26590. * Clicked point.
  26591. * @name Highcharts.PointClickEventObject#point
  26592. * @type {Highcharts.Point}
  26593. */
  26594. /**
  26595. * Configuration hash for the data label and tooltip formatters.
  26596. *
  26597. * @interface Highcharts.PointLabelObject
  26598. */ /**
  26599. * The point's current color.
  26600. * @name Highcharts.PointLabelObject#color
  26601. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject|undefined}
  26602. */ /**
  26603. * The point's current color index, used in styled mode instead of `color`. The
  26604. * color index is inserted in class names used for styling.
  26605. * @name Highcharts.PointLabelObject#colorIndex
  26606. * @type {number}
  26607. */ /**
  26608. * The name of the related point.
  26609. * @name Highcharts.PointLabelObject#key
  26610. * @type {string|undefined}
  26611. */ /**
  26612. * The percentage for related points in a stacked series or pies.
  26613. * @name Highcharts.PointLabelObject#percentage
  26614. * @type {number}
  26615. */ /**
  26616. * The related point. The point name, if defined, is available through
  26617. * `this.point.name`.
  26618. * @name Highcharts.PointLabelObject#point
  26619. * @type {Highcharts.Point}
  26620. */ /**
  26621. * The related series. The series name is available through `this.series.name`.
  26622. * @name Highcharts.PointLabelObject#series
  26623. * @type {Highcharts.Series}
  26624. */ /**
  26625. * The total of values in either a stack for stacked series, or a pie in a pie
  26626. * series.
  26627. * @name Highcharts.PointLabelObject#total
  26628. * @type {number|undefined}
  26629. */ /**
  26630. * For categorized axes this property holds the category name for the point. For
  26631. * other axes it holds the X value.
  26632. * @name Highcharts.PointLabelObject#x
  26633. * @type {number|string|undefined}
  26634. */ /**
  26635. * The y value of the point.
  26636. * @name Highcharts.PointLabelObject#y
  26637. * @type {number|undefined}
  26638. */
  26639. /**
  26640. * Gets fired when the mouse leaves the area close to the point.
  26641. *
  26642. * @callback Highcharts.PointMouseOutCallbackFunction
  26643. *
  26644. * @param {Highcharts.Point} this
  26645. * Point where the event occured.
  26646. *
  26647. * @param {global.PointerEvent} event
  26648. * Event that occured.
  26649. */
  26650. /**
  26651. * Gets fired when the mouse enters the area close to the point.
  26652. *
  26653. * @callback Highcharts.PointMouseOverCallbackFunction
  26654. *
  26655. * @param {Highcharts.Point} this
  26656. * Point where the event occured.
  26657. *
  26658. * @param {global.Event} event
  26659. * Event that occured.
  26660. */
  26661. /**
  26662. * The generic point options for all series.
  26663. *
  26664. * In TypeScript you have to extend `PointOptionsObject` with an additional
  26665. * declaration to allow custom data options:
  26666. *
  26667. * ```
  26668. * declare interface PointOptionsObject {
  26669. * customProperty: string;
  26670. * }
  26671. * ```
  26672. *
  26673. * @interface Highcharts.PointOptionsObject
  26674. */
  26675. /**
  26676. * Possible option types for a data point. Use `null` to indicate a gap.
  26677. *
  26678. * @typedef {number|string|Highcharts.PointOptionsObject|Array<(number|string|null)>|null} Highcharts.PointOptionsType
  26679. */
  26680. /**
  26681. * Gets fired when the point is removed using the `.remove()` method.
  26682. *
  26683. * @callback Highcharts.PointRemoveCallbackFunction
  26684. *
  26685. * @param {Highcharts.Point} this
  26686. * Point where the event occured.
  26687. *
  26688. * @param {global.Event} event
  26689. * Event that occured.
  26690. */
  26691. /**
  26692. * Possible key values for the point state options.
  26693. *
  26694. * @typedef {"hover"|"inactive"|"normal"|"select"} Highcharts.PointStateValue
  26695. */
  26696. /**
  26697. * Gets fired when the point is updated programmatically through the `.update()`
  26698. * method.
  26699. *
  26700. * @callback Highcharts.PointUpdateCallbackFunction
  26701. *
  26702. * @param {Highcharts.Point} this
  26703. * Point where the event occured.
  26704. *
  26705. * @param {Highcharts.PointUpdateEventObject} event
  26706. * Event that occured.
  26707. */
  26708. /**
  26709. * Information about the update event.
  26710. *
  26711. * @interface Highcharts.PointUpdateEventObject
  26712. * @extends global.Event
  26713. */ /**
  26714. * Options data of the update event.
  26715. * @name Highcharts.PointUpdateEventObject#options
  26716. * @type {Highcharts.PointOptionsType}
  26717. */
  26718. /**
  26719. * @interface Highcharts.PointEventsOptionsObject
  26720. */ /**
  26721. * Fires when the point is selected either programmatically or following a click
  26722. * on the point. One parameter, `event`, is passed to the function. Returning
  26723. * `false` cancels the operation.
  26724. * @name Highcharts.PointEventsOptionsObject#select
  26725. * @type {Highcharts.PointSelectCallbackFunction|undefined}
  26726. */ /**
  26727. * Fires when the point is unselected either programmatically or following a
  26728. * click on the point. One parameter, `event`, is passed to the function.
  26729. * Returning `false` cancels the operation.
  26730. * @name Highcharts.PointEventsOptionsObject#unselect
  26731. * @type {Highcharts.PointUnselectCallbackFunction|undefined}
  26732. */
  26733. /**
  26734. * Information about the select/unselect event.
  26735. *
  26736. * @interface Highcharts.PointInteractionEventObject
  26737. * @extends global.Event
  26738. */ /**
  26739. * @name Highcharts.PointInteractionEventObject#accumulate
  26740. * @type {boolean}
  26741. */
  26742. /**
  26743. * Gets fired when the point is selected either programmatically or following a
  26744. * click on the point.
  26745. *
  26746. * @callback Highcharts.PointSelectCallbackFunction
  26747. *
  26748. * @param {Highcharts.Point} this
  26749. * Point where the event occured.
  26750. *
  26751. * @param {Highcharts.PointInteractionEventObject} event
  26752. * Event that occured.
  26753. */
  26754. /**
  26755. * Fires when the point is unselected either programmatically or following a
  26756. * click on the point.
  26757. *
  26758. * @callback Highcharts.PointUnselectCallbackFunction
  26759. *
  26760. * @param {Highcharts.Point} this
  26761. * Point where the event occured.
  26762. *
  26763. * @param {Highcharts.PointInteractionEventObject} event
  26764. * Event that occured.
  26765. */
  26766. ''; // detach doclet above
  26767. /* eslint-disable no-invalid-this, valid-jsdoc */
  26768. /**
  26769. * The Point object. The point objects are generated from the `series.data`
  26770. * configuration objects or raw numbers. They can be accessed from the
  26771. * `Series.points` array. Other ways to instantiate points are through {@link
  26772. * Highcharts.Series#addPoint} or {@link Highcharts.Series#setData}.
  26773. *
  26774. * @class
  26775. * @name Highcharts.Point
  26776. */
  26777. var Point = /** @class */ (function () {
  26778. function Point() {
  26779. /* *
  26780. *
  26781. * Properties
  26782. *
  26783. * */
  26784. /**
  26785. * For categorized axes this property holds the category name for the
  26786. * point. For other axes it holds the X value.
  26787. *
  26788. * @name Highcharts.Point#category
  26789. * @type {string}
  26790. */
  26791. this.category = void 0;
  26792. /**
  26793. * The point's current color index, used in styled mode instead of
  26794. * `color`. The color index is inserted in class names used for styling.
  26795. *
  26796. * @name Highcharts.Point#colorIndex
  26797. * @type {number}
  26798. */
  26799. this.colorIndex = void 0;
  26800. this.formatPrefix = 'point';
  26801. this.id = void 0;
  26802. this.isNull = false;
  26803. /**
  26804. * The name of the point. The name can be given as the first position of the
  26805. * point configuration array, or as a `name` property in the configuration:
  26806. *
  26807. * @example
  26808. * // Array config
  26809. * data: [
  26810. * ['John', 1],
  26811. * ['Jane', 2]
  26812. * ]
  26813. *
  26814. * // Object config
  26815. * data: [{
  26816. * name: 'John',
  26817. * y: 1
  26818. * }, {
  26819. * name: 'Jane',
  26820. * y: 2
  26821. * }]
  26822. *
  26823. * @name Highcharts.Point#name
  26824. * @type {string}
  26825. */
  26826. this.name = void 0;
  26827. /**
  26828. * The point's options as applied in the initial configuration, or
  26829. * extended through `Point.update`.
  26830. *
  26831. * In TypeScript you have to extend `PointOptionsObject` via an
  26832. * additional interface to allow custom data options:
  26833. *
  26834. * ```
  26835. * declare interface PointOptionsObject {
  26836. * customProperty: string;
  26837. * }
  26838. * ```
  26839. *
  26840. * @name Highcharts.Point#options
  26841. * @type {Highcharts.PointOptionsObject}
  26842. */
  26843. this.options = void 0;
  26844. /**
  26845. * The percentage for points in a stacked series or pies.
  26846. *
  26847. * @name Highcharts.Point#percentage
  26848. * @type {number|undefined}
  26849. */
  26850. this.percentage = void 0;
  26851. this.selected = false;
  26852. /**
  26853. * The series object associated with the point.
  26854. *
  26855. * @name Highcharts.Point#series
  26856. * @type {Highcharts.Series}
  26857. */
  26858. this.series = void 0;
  26859. /**
  26860. * The total of values in either a stack for stacked series, or a pie in a
  26861. * pie series.
  26862. *
  26863. * @name Highcharts.Point#total
  26864. * @type {number|undefined}
  26865. */
  26866. this.total = void 0;
  26867. /**
  26868. * For certain series types, like pie charts, where individual points can
  26869. * be shown or hidden.
  26870. *
  26871. * @name Highcharts.Point#visible
  26872. * @type {boolean}
  26873. * @default true
  26874. */
  26875. this.visible = true;
  26876. this.x = void 0;
  26877. }
  26878. /* *
  26879. *
  26880. * Functions
  26881. *
  26882. * */
  26883. /**
  26884. * Animate SVG elements associated with the point.
  26885. *
  26886. * @private
  26887. * @function Highcharts.Point#animateBeforeDestroy
  26888. */
  26889. Point.prototype.animateBeforeDestroy = function () {
  26890. var point = this,
  26891. animateParams = { x: point.startXPos,
  26892. opacity: 0 },
  26893. isDataLabel,
  26894. graphicalProps = point.getGraphicalProps();
  26895. graphicalProps.singular.forEach(function (prop) {
  26896. isDataLabel = prop === 'dataLabel';
  26897. point[prop] = point[prop].animate(isDataLabel ? {
  26898. x: point[prop].startXPos,
  26899. y: point[prop].startYPos,
  26900. opacity: 0
  26901. } : animateParams);
  26902. });
  26903. graphicalProps.plural.forEach(function (plural) {
  26904. point[plural].forEach(function (item) {
  26905. if (item.element) {
  26906. item.animate(extend({ x: point.startXPos }, (item.startYPos ? {
  26907. x: item.startXPos,
  26908. y: item.startYPos
  26909. } : {})));
  26910. }
  26911. });
  26912. });
  26913. };
  26914. /**
  26915. * Apply the options containing the x and y data and possible some extra
  26916. * properties. Called on point init or from point.update.
  26917. *
  26918. * @private
  26919. * @function Highcharts.Point#applyOptions
  26920. *
  26921. * @param {Highcharts.PointOptionsType} options
  26922. * The point options as defined in series.data.
  26923. *
  26924. * @param {number} [x]
  26925. * Optionally, the x value.
  26926. *
  26927. * @return {Highcharts.Point}
  26928. * The Point instance.
  26929. */
  26930. Point.prototype.applyOptions = function (options, x) {
  26931. var point = this,
  26932. series = point.series,
  26933. pointValKey = series.options.pointValKey || series.pointValKey;
  26934. options = Point.prototype.optionsToObject.call(this, options);
  26935. // copy options directly to point
  26936. extend(point, options);
  26937. point.options = point.options ? extend(point.options, options) : options;
  26938. // Since options are copied into the Point instance, some accidental
  26939. // options must be shielded (#5681)
  26940. if (options.group) {
  26941. delete point.group;
  26942. }
  26943. if (options.dataLabels) {
  26944. delete point.dataLabels;
  26945. }
  26946. /**
  26947. * The y value of the point.
  26948. * @name Highcharts.Point#y
  26949. * @type {number|undefined}
  26950. */
  26951. // For higher dimension series types. For instance, for ranges, point.y
  26952. // is mapped to point.low.
  26953. if (pointValKey) {
  26954. point.y = Point.prototype.getNestedProperty.call(point, pointValKey);
  26955. }
  26956. point.isNull = pick(point.isValid && !point.isValid(), point.x === null || !isNumber(point.y)); // #3571, check for NaN
  26957. point.formatPrefix = point.isNull ? 'null' : 'point'; // #9233, #10874
  26958. // The point is initially selected by options (#5777)
  26959. if (point.selected) {
  26960. point.state = 'select';
  26961. }
  26962. /**
  26963. * The x value of the point.
  26964. * @name Highcharts.Point#x
  26965. * @type {number}
  26966. */
  26967. // If no x is set by now, get auto incremented value. All points must
  26968. // have an x value, however the y value can be null to create a gap in
  26969. // the series
  26970. if ('name' in point &&
  26971. typeof x === 'undefined' &&
  26972. series.xAxis &&
  26973. series.xAxis.hasNames) {
  26974. point.x = series.xAxis.nameToX(point);
  26975. }
  26976. if (typeof point.x === 'undefined' && series) {
  26977. if (typeof x === 'undefined') {
  26978. point.x = series.autoIncrement(point);
  26979. }
  26980. else {
  26981. point.x = x;
  26982. }
  26983. }
  26984. return point;
  26985. };
  26986. /**
  26987. * Destroy a point to clear memory. Its reference still stays in
  26988. * `series.data`.
  26989. *
  26990. * @private
  26991. * @function Highcharts.Point#destroy
  26992. */
  26993. Point.prototype.destroy = function () {
  26994. var point = this,
  26995. series = point.series,
  26996. chart = series.chart,
  26997. dataSorting = series.options.dataSorting,
  26998. hoverPoints = chart.hoverPoints,
  26999. globalAnimation = point.series.chart.renderer.globalAnimation,
  27000. animation = animObject(globalAnimation),
  27001. prop;
  27002. /**
  27003. * Allow to call after animation.
  27004. * @private
  27005. */
  27006. function destroyPoint() {
  27007. // Remove all events and elements
  27008. if (point.graphic || point.dataLabel || point.dataLabels) {
  27009. removeEvent(point);
  27010. point.destroyElements();
  27011. }
  27012. for (prop in point) { // eslint-disable-line guard-for-in
  27013. point[prop] = null;
  27014. }
  27015. }
  27016. if (point.legendItem) { // pies have legend items
  27017. chart.legend.destroyItem(point);
  27018. }
  27019. if (hoverPoints) {
  27020. point.setState();
  27021. erase(hoverPoints, point);
  27022. if (!hoverPoints.length) {
  27023. chart.hoverPoints = null;
  27024. }
  27025. }
  27026. if (point === chart.hoverPoint) {
  27027. point.onMouseOut();
  27028. }
  27029. // Remove properties after animation
  27030. if (!dataSorting || !dataSorting.enabled) {
  27031. destroyPoint();
  27032. }
  27033. else {
  27034. this.animateBeforeDestroy();
  27035. syncTimeout(destroyPoint, animation.duration);
  27036. }
  27037. chart.pointCount--;
  27038. };
  27039. /**
  27040. * Destroy SVG elements associated with the point.
  27041. *
  27042. * @private
  27043. * @function Highcharts.Point#destroyElements
  27044. * @param {Highcharts.Dictionary<number>} [kinds]
  27045. */
  27046. Point.prototype.destroyElements = function (kinds) {
  27047. var point = this,
  27048. props = point.getGraphicalProps(kinds);
  27049. props.singular.forEach(function (prop) {
  27050. point[prop] = point[prop].destroy();
  27051. });
  27052. props.plural.forEach(function (plural) {
  27053. point[plural].forEach(function (item) {
  27054. if (item.element) {
  27055. item.destroy();
  27056. }
  27057. });
  27058. delete point[plural];
  27059. });
  27060. };
  27061. /**
  27062. * Fire an event on the Point object.
  27063. *
  27064. * @private
  27065. * @function Highcharts.Point#firePointEvent
  27066. *
  27067. * @param {string} eventType
  27068. * Type of the event.
  27069. *
  27070. * @param {Highcharts.Dictionary<any>|Event} [eventArgs]
  27071. * Additional event arguments.
  27072. *
  27073. * @param {Highcharts.EventCallbackFunction<Highcharts.Point>|Function} [defaultFunction]
  27074. * Default event handler.
  27075. *
  27076. * @fires Highcharts.Point#event:*
  27077. */
  27078. Point.prototype.firePointEvent = function (eventType, eventArgs, defaultFunction) {
  27079. var point = this,
  27080. series = this.series,
  27081. seriesOptions = series.options;
  27082. // load event handlers on demand to save time on mouseover/out
  27083. if (seriesOptions.point.events[eventType] ||
  27084. (point.options &&
  27085. point.options.events &&
  27086. point.options.events[eventType])) {
  27087. point.importEvents();
  27088. }
  27089. // add default handler if in selection mode
  27090. if (eventType === 'click' && seriesOptions.allowPointSelect) {
  27091. defaultFunction = function (event) {
  27092. // Control key is for Windows, meta (= Cmd key) for Mac, Shift
  27093. // for Opera.
  27094. if (point.select) { // #2911
  27095. point.select(null, event.ctrlKey || event.metaKey || event.shiftKey);
  27096. }
  27097. };
  27098. }
  27099. fireEvent(point, eventType, eventArgs, defaultFunction);
  27100. };
  27101. /**
  27102. * Get the CSS class names for individual points. Used internally where the
  27103. * returned value is set on every point.
  27104. *
  27105. * @function Highcharts.Point#getClassName
  27106. *
  27107. * @return {string}
  27108. * The class names.
  27109. */
  27110. Point.prototype.getClassName = function () {
  27111. var point = this;
  27112. return 'highcharts-point' +
  27113. (point.selected ? ' highcharts-point-select' : '') +
  27114. (point.negative ? ' highcharts-negative' : '') +
  27115. (point.isNull ? ' highcharts-null-point' : '') +
  27116. (typeof point.colorIndex !== 'undefined' ?
  27117. ' highcharts-color-' + point.colorIndex : '') +
  27118. (point.options.className ? ' ' + point.options.className : '') +
  27119. (point.zone && point.zone.className ? ' ' +
  27120. point.zone.className.replace('highcharts-negative', '') : '');
  27121. };
  27122. /**
  27123. * Get props of all existing graphical point elements.
  27124. *
  27125. * @private
  27126. * @function Highcharts.Point#getGraphicalProps
  27127. * @param {Highcharts.Dictionary<number>} [kinds]
  27128. * @return {Highcharts.PointGraphicalProps}
  27129. */
  27130. Point.prototype.getGraphicalProps = function (kinds) {
  27131. var point = this,
  27132. props = [],
  27133. prop,
  27134. i,
  27135. graphicalProps = { singular: [],
  27136. plural: [] };
  27137. kinds = kinds || { graphic: 1, dataLabel: 1 };
  27138. if (kinds.graphic) {
  27139. props.push('graphic', 'upperGraphic', 'shadowGroup');
  27140. }
  27141. if (kinds.dataLabel) {
  27142. props.push('dataLabel', 'dataLabelUpper', 'connector');
  27143. }
  27144. i = props.length;
  27145. while (i--) {
  27146. prop = props[i];
  27147. if (point[prop]) {
  27148. graphicalProps.singular.push(prop);
  27149. }
  27150. }
  27151. ['dataLabel', 'connector'].forEach(function (prop) {
  27152. var plural = prop + 's';
  27153. if (kinds[prop] && point[plural]) {
  27154. graphicalProps.plural.push(plural);
  27155. }
  27156. });
  27157. return graphicalProps;
  27158. };
  27159. /**
  27160. * Return the configuration hash needed for the data label and tooltip
  27161. * formatters.
  27162. *
  27163. * @function Highcharts.Point#getLabelConfig
  27164. *
  27165. * @return {Highcharts.PointLabelObject}
  27166. * Abstract object used in formatters and formats.
  27167. */
  27168. Point.prototype.getLabelConfig = function () {
  27169. return {
  27170. x: this.category,
  27171. y: this.y,
  27172. color: this.color,
  27173. colorIndex: this.colorIndex,
  27174. key: this.name || this.category,
  27175. series: this.series,
  27176. point: this,
  27177. percentage: this.percentage,
  27178. total: this.total || this.stackTotal
  27179. };
  27180. };
  27181. /**
  27182. * Returns the value of the point property for a given value.
  27183. * @private
  27184. */
  27185. Point.prototype.getNestedProperty = function (key) {
  27186. if (!key) {
  27187. return;
  27188. }
  27189. if (key.indexOf('custom.') === 0) {
  27190. return getNestedProperty(key, this.options);
  27191. }
  27192. return this[key];
  27193. };
  27194. /**
  27195. * In a series with `zones`, return the zone that the point belongs to.
  27196. *
  27197. * @function Highcharts.Point#getZone
  27198. *
  27199. * @return {Highcharts.SeriesZonesOptionsObject}
  27200. * The zone item.
  27201. */
  27202. Point.prototype.getZone = function () {
  27203. var series = this.series,
  27204. zones = series.zones,
  27205. zoneAxis = series.zoneAxis || 'y',
  27206. i = 0,
  27207. zone;
  27208. zone = zones[i];
  27209. while (this[zoneAxis] >= zone.value) {
  27210. zone = zones[++i];
  27211. }
  27212. // For resetting or reusing the point (#8100)
  27213. if (!this.nonZonedColor) {
  27214. this.nonZonedColor = this.color;
  27215. }
  27216. if (zone && zone.color && !this.options.color) {
  27217. this.color = zone.color;
  27218. }
  27219. else {
  27220. this.color = this.nonZonedColor;
  27221. }
  27222. return zone;
  27223. };
  27224. /**
  27225. * Utility to check if point has new shape type. Used in column series and
  27226. * all others that are based on column series.
  27227. *
  27228. * @return boolean|undefined
  27229. */
  27230. Point.prototype.hasNewShapeType = function () {
  27231. var point = this;
  27232. var oldShapeType = point.graphic &&
  27233. (point.graphic.symbolName || point.graphic.element.nodeName);
  27234. return oldShapeType !== this.shapeType;
  27235. };
  27236. /**
  27237. * Initialize the point. Called internally based on the `series.data`
  27238. * option.
  27239. *
  27240. * @function Highcharts.Point#init
  27241. *
  27242. * @param {Highcharts.Series} series
  27243. * The series object containing this point.
  27244. *
  27245. * @param {Highcharts.PointOptionsType} options
  27246. * The data in either number, array or object format.
  27247. *
  27248. * @param {number} [x]
  27249. * Optionally, the X value of the point.
  27250. *
  27251. * @return {Highcharts.Point}
  27252. * The Point instance.
  27253. *
  27254. * @fires Highcharts.Point#event:afterInit
  27255. */
  27256. Point.prototype.init = function (series, options, x) {
  27257. this.series = series;
  27258. this.applyOptions(options, x);
  27259. // Add a unique ID to the point if none is assigned
  27260. this.id = defined(this.id) ? this.id : uniqueKey();
  27261. this.resolveColor();
  27262. series.chart.pointCount++;
  27263. fireEvent(this, 'afterInit');
  27264. return this;
  27265. };
  27266. /**
  27267. * Transform number or array configs into objects. Also called for object
  27268. * configs. Used internally to unify the different configuration formats for
  27269. * points. For example, a simple number `10` in a line series will be
  27270. * transformed to `{ y: 10 }`, and an array config like `[1, 10]` in a
  27271. * scatter series will be transformed to `{ x: 1, y: 10 }`.
  27272. *
  27273. * @function Highcharts.Point#optionsToObject
  27274. *
  27275. * @param {Highcharts.PointOptionsType} options
  27276. * The input option.
  27277. *
  27278. * @return {Highcharts.Dictionary<*>}
  27279. * Transformed options.
  27280. */
  27281. Point.prototype.optionsToObject = function (options) {
  27282. var ret = {},
  27283. series = this.series,
  27284. keys = series.options.keys,
  27285. pointArrayMap = keys || series.pointArrayMap || ['y'],
  27286. valueCount = pointArrayMap.length,
  27287. firstItemType,
  27288. i = 0,
  27289. j = 0;
  27290. if (isNumber(options) || options === null) {
  27291. ret[pointArrayMap[0]] = options;
  27292. }
  27293. else if (isArray(options)) {
  27294. // with leading x value
  27295. if (!keys && options.length > valueCount) {
  27296. firstItemType = typeof options[0];
  27297. if (firstItemType === 'string') {
  27298. ret.name = options[0];
  27299. }
  27300. else if (firstItemType === 'number') {
  27301. ret.x = options[0];
  27302. }
  27303. i++;
  27304. }
  27305. while (j < valueCount) {
  27306. // Skip undefined positions for keys
  27307. if (!keys || typeof options[i] !== 'undefined') {
  27308. if (pointArrayMap[j].indexOf('.') > 0) {
  27309. // Handle nested keys, e.g. ['color.pattern.image']
  27310. // Avoid function call unless necessary.
  27311. Point.prototype.setNestedProperty(ret, options[i], pointArrayMap[j]);
  27312. }
  27313. else {
  27314. ret[pointArrayMap[j]] = options[i];
  27315. }
  27316. }
  27317. i++;
  27318. j++;
  27319. }
  27320. }
  27321. else if (typeof options === 'object') {
  27322. ret = options;
  27323. // This is the fastest way to detect if there are individual point
  27324. // dataLabels that need to be considered in drawDataLabels. These
  27325. // can only occur in object configs.
  27326. if (options.dataLabels) {
  27327. series._hasPointLabels = true;
  27328. }
  27329. // Same approach as above for markers
  27330. if (options.marker) {
  27331. series._hasPointMarkers = true;
  27332. }
  27333. }
  27334. return ret;
  27335. };
  27336. /**
  27337. * @private
  27338. * @function Highcharts.Point#resolveColor
  27339. * @return {void}
  27340. */
  27341. Point.prototype.resolveColor = function () {
  27342. var series = this.series,
  27343. colors,
  27344. optionsChart = series.chart.options.chart,
  27345. colorCount = optionsChart.colorCount,
  27346. styledMode = series.chart.styledMode,
  27347. colorIndex,
  27348. color;
  27349. // remove points nonZonedColor for later recalculation
  27350. delete this.nonZonedColor;
  27351. if (series.options.colorByPoint) {
  27352. if (!styledMode) {
  27353. colors = series.options.colors || series.chart.options.colors;
  27354. color = colors[series.colorCounter];
  27355. colorCount = colors.length;
  27356. }
  27357. colorIndex = series.colorCounter;
  27358. series.colorCounter++;
  27359. // loop back to zero
  27360. if (series.colorCounter === colorCount) {
  27361. series.colorCounter = 0;
  27362. }
  27363. }
  27364. else {
  27365. if (!styledMode) {
  27366. color = series.color;
  27367. }
  27368. colorIndex = series.colorIndex;
  27369. }
  27370. this.colorIndex = pick(this.options.colorIndex, colorIndex);
  27371. /**
  27372. * The point's current color.
  27373. *
  27374. * @name Highcharts.Point#color
  27375. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject|undefined}
  27376. */
  27377. this.color = pick(this.options.color, color);
  27378. };
  27379. /**
  27380. * Set a value in an object, on the property defined by key. The key
  27381. * supports nested properties using dot notation. The function modifies the
  27382. * input object and does not make a copy.
  27383. *
  27384. * @function Highcharts.Point#setNestedProperty<T>
  27385. *
  27386. * @param {T} object
  27387. * The object to set the value on.
  27388. *
  27389. * @param {*} value
  27390. * The value to set.
  27391. *
  27392. * @param {string} key
  27393. * Key to the property to set.
  27394. *
  27395. * @return {T}
  27396. * The modified object.
  27397. */
  27398. Point.prototype.setNestedProperty = function (object, value, key) {
  27399. var nestedKeys = key.split('.');
  27400. nestedKeys.reduce(function (result, key, i, arr) {
  27401. var isLastKey = arr.length - 1 === i;
  27402. result[key] = (isLastKey ?
  27403. value :
  27404. isObject(result[key], true) ?
  27405. result[key] :
  27406. {});
  27407. return result[key];
  27408. }, object);
  27409. return object;
  27410. };
  27411. /**
  27412. * Extendable method for formatting each point's tooltip line.
  27413. *
  27414. * @function Highcharts.Point#tooltipFormatter
  27415. *
  27416. * @param {string} pointFormat
  27417. * The point format.
  27418. *
  27419. * @return {string}
  27420. * A string to be concatenated in to the common tooltip text.
  27421. */
  27422. Point.prototype.tooltipFormatter = function (pointFormat) {
  27423. // Insert options for valueDecimals, valuePrefix, and valueSuffix
  27424. var series = this.series, seriesTooltipOptions = series.tooltipOptions, valueDecimals = pick(seriesTooltipOptions.valueDecimals, ''), valuePrefix = seriesTooltipOptions.valuePrefix || '', valueSuffix = seriesTooltipOptions.valueSuffix || '';
  27425. // Replace default point style with class name
  27426. if (series.chart.styledMode) {
  27427. pointFormat =
  27428. series.chart.tooltip.styledModeFormat(pointFormat);
  27429. }
  27430. // Loop over the point array map and replace unformatted values with
  27431. // sprintf formatting markup
  27432. (series.pointArrayMap || ['y']).forEach(function (key) {
  27433. key = '{point.' + key; // without the closing bracket
  27434. if (valuePrefix || valueSuffix) {
  27435. pointFormat = pointFormat.replace(RegExp(key + '}', 'g'), valuePrefix + key + '}' + valueSuffix);
  27436. }
  27437. pointFormat = pointFormat.replace(RegExp(key + '}', 'g'), key + ':,.' + valueDecimals + 'f}');
  27438. });
  27439. return format(pointFormat, {
  27440. point: this,
  27441. series: this.series
  27442. }, series.chart);
  27443. };
  27444. /**
  27445. * Update point with new options (typically x/y data) and optionally redraw
  27446. * the series.
  27447. *
  27448. * @sample highcharts/members/point-update-column/
  27449. * Update column value
  27450. * @sample highcharts/members/point-update-pie/
  27451. * Update pie slice
  27452. * @sample maps/members/point-update/
  27453. * Update map area value in Highmaps
  27454. *
  27455. * @function Highcharts.Point#update
  27456. *
  27457. * @param {Highcharts.PointOptionsType} options
  27458. * The point options. Point options are handled as described under
  27459. * the `series.type.data` item for each series type. For example
  27460. * for a line series, if options is a single number, the point will
  27461. * be given that number as the marin y value. If it is an array, it
  27462. * will be interpreted as x and y values respectively. If it is an
  27463. * object, advanced options are applied.
  27464. *
  27465. * @param {boolean} [redraw=true]
  27466. * Whether to redraw the chart after the point is updated. If doing
  27467. * more operations on the chart, it is best practice to set
  27468. * `redraw` to false and call `chart.redraw()` after.
  27469. *
  27470. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=true]
  27471. * Whether to apply animation, and optionally animation
  27472. * configuration.
  27473. *
  27474. * @fires Highcharts.Point#event:update
  27475. */
  27476. Point.prototype.update = function (options, redraw, animation, runEvent) {
  27477. var point = this,
  27478. series = point.series,
  27479. graphic = point.graphic,
  27480. i,
  27481. chart = series.chart,
  27482. seriesOptions = series.options;
  27483. redraw = pick(redraw, true);
  27484. /**
  27485. * @private
  27486. */
  27487. function update() {
  27488. point.applyOptions(options);
  27489. // Update visuals, #4146
  27490. // Handle dummy graphic elements for a11y, #12718
  27491. var hasDummyGraphic = graphic && point.hasDummyGraphic;
  27492. var shouldDestroyGraphic = point.y === null ? !hasDummyGraphic : hasDummyGraphic;
  27493. if (graphic && shouldDestroyGraphic) {
  27494. point.graphic = graphic.destroy();
  27495. delete point.hasDummyGraphic;
  27496. }
  27497. if (isObject(options, true)) {
  27498. // Destroy so we can get new elements
  27499. if (graphic && graphic.element) {
  27500. // "null" is also a valid symbol
  27501. if (options &&
  27502. options.marker &&
  27503. typeof options.marker.symbol !== 'undefined') {
  27504. point.graphic = graphic.destroy();
  27505. }
  27506. }
  27507. if (options && options.dataLabels && point.dataLabel) {
  27508. point.dataLabel = point.dataLabel.destroy(); // #2468
  27509. }
  27510. if (point.connector) {
  27511. point.connector = point.connector.destroy(); // #7243
  27512. }
  27513. }
  27514. // record changes in the parallel arrays
  27515. i = point.index;
  27516. series.updateParallelArrays(point, i);
  27517. // Record the options to options.data. If the old or the new config
  27518. // is an object, use point options, otherwise use raw options
  27519. // (#4701, #4916).
  27520. seriesOptions.data[i] = (isObject(seriesOptions.data[i], true) ||
  27521. isObject(options, true)) ?
  27522. point.options :
  27523. pick(options, seriesOptions.data[i]);
  27524. // redraw
  27525. series.isDirty = series.isDirtyData = true;
  27526. if (!series.fixedBox && series.hasCartesianSeries) { // #1906, #2320
  27527. chart.isDirtyBox = true;
  27528. }
  27529. if (seriesOptions.legendType === 'point') { // #1831, #1885
  27530. chart.isDirtyLegend = true;
  27531. }
  27532. if (redraw) {
  27533. chart.redraw(animation);
  27534. }
  27535. }
  27536. // Fire the event with a default handler of doing the update
  27537. if (runEvent === false) { // When called from setData
  27538. update();
  27539. }
  27540. else {
  27541. point.firePointEvent('update', { options: options }, update);
  27542. }
  27543. };
  27544. /**
  27545. * Remove a point and optionally redraw the series and if necessary the axes
  27546. *
  27547. * @sample highcharts/plotoptions/series-point-events-remove/
  27548. * Remove point and confirm
  27549. * @sample highcharts/members/point-remove/
  27550. * Remove pie slice
  27551. * @sample maps/members/point-remove/
  27552. * Remove selected points in Highmaps
  27553. *
  27554. * @function Highcharts.Point#remove
  27555. *
  27556. * @param {boolean} [redraw=true]
  27557. * Whether to redraw the chart or wait for an explicit call. When
  27558. * doing more operations on the chart, for example running
  27559. * `point.remove()` in a loop, it is best practice to set `redraw`
  27560. * to false and call `chart.redraw()` after.
  27561. *
  27562. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=false]
  27563. * Whether to apply animation, and optionally animation
  27564. * configuration.
  27565. */
  27566. Point.prototype.remove = function (redraw, animation) {
  27567. this.series.removePoint(this.series.data.indexOf(this), redraw, animation);
  27568. };
  27569. /**
  27570. * Toggle the selection status of a point.
  27571. *
  27572. * @see Highcharts.Chart#getSelectedPoints
  27573. *
  27574. * @sample highcharts/members/point-select/
  27575. * Select a point from a button
  27576. * @sample highcharts/chart/events-selection-points/
  27577. * Select a range of points through a drag selection
  27578. * @sample maps/series/data-id/
  27579. * Select a point in Highmaps
  27580. *
  27581. * @function Highcharts.Point#select
  27582. *
  27583. * @param {boolean} [selected]
  27584. * When `true`, the point is selected. When `false`, the point is
  27585. * unselected. When `null` or `undefined`, the selection state is toggled.
  27586. *
  27587. * @param {boolean} [accumulate=false]
  27588. * When `true`, the selection is added to other selected points.
  27589. * When `false`, other selected points are deselected. Internally in
  27590. * Highcharts, when
  27591. * [allowPointSelect](https://api.highcharts.com/highcharts/plotOptions.series.allowPointSelect)
  27592. * is `true`, selected points are accumulated on Control, Shift or Cmd
  27593. * clicking the point.
  27594. *
  27595. * @fires Highcharts.Point#event:select
  27596. * @fires Highcharts.Point#event:unselect
  27597. */
  27598. Point.prototype.select = function (selected, accumulate) {
  27599. var point = this,
  27600. series = point.series,
  27601. chart = series.chart;
  27602. selected = pick(selected, !point.selected);
  27603. this.selectedStaging = selected;
  27604. // fire the event with the default handler
  27605. point.firePointEvent(selected ? 'select' : 'unselect', { accumulate: accumulate }, function () {
  27606. /**
  27607. * Whether the point is selected or not.
  27608. *
  27609. * @see Point#select
  27610. * @see Chart#getSelectedPoints
  27611. *
  27612. * @name Highcharts.Point#selected
  27613. * @type {boolean}
  27614. */
  27615. point.selected = point.options.selected = selected;
  27616. series.options.data[series.data.indexOf(point)] =
  27617. point.options;
  27618. point.setState(selected && 'select');
  27619. // unselect all other points unless Ctrl or Cmd + click
  27620. if (!accumulate) {
  27621. chart.getSelectedPoints().forEach(function (loopPoint) {
  27622. var loopSeries = loopPoint.series;
  27623. if (loopPoint.selected && loopPoint !== point) {
  27624. loopPoint.selected = loopPoint.options.selected =
  27625. false;
  27626. loopSeries.options.data[loopSeries.data.indexOf(loopPoint)] = loopPoint.options;
  27627. // Programatically selecting a point should restore
  27628. // normal state, but when click happened on other
  27629. // point, set inactive state to match other points
  27630. loopPoint.setState(chart.hoverPoints &&
  27631. loopSeries.options.inactiveOtherPoints ?
  27632. 'inactive' : '');
  27633. loopPoint.firePointEvent('unselect');
  27634. }
  27635. });
  27636. }
  27637. });
  27638. delete this.selectedStaging;
  27639. };
  27640. /**
  27641. * Runs on mouse over the point. Called internally from mouse and touch
  27642. * events.
  27643. *
  27644. * @function Highcharts.Point#onMouseOver
  27645. *
  27646. * @param {Highcharts.PointerEventObject} [e]
  27647. * The event arguments.
  27648. */
  27649. Point.prototype.onMouseOver = function (e) {
  27650. var point = this,
  27651. series = point.series,
  27652. chart = series.chart,
  27653. pointer = chart.pointer;
  27654. e = e ?
  27655. pointer.normalize(e) :
  27656. // In cases where onMouseOver is called directly without an event
  27657. pointer.getChartCoordinatesFromPoint(point, chart.inverted);
  27658. pointer.runPointActions(e, point);
  27659. };
  27660. /**
  27661. * Runs on mouse out from the point. Called internally from mouse and touch
  27662. * events.
  27663. *
  27664. * @function Highcharts.Point#onMouseOut
  27665. * @fires Highcharts.Point#event:mouseOut
  27666. */
  27667. Point.prototype.onMouseOut = function () {
  27668. var point = this,
  27669. chart = point.series.chart;
  27670. point.firePointEvent('mouseOut');
  27671. if (!point.series.options.inactiveOtherPoints) {
  27672. (chart.hoverPoints || []).forEach(function (p) {
  27673. p.setState();
  27674. });
  27675. }
  27676. chart.hoverPoints = chart.hoverPoint = null;
  27677. };
  27678. /**
  27679. * Import events from the series' and point's options. Only do it on
  27680. * demand, to save processing time on hovering.
  27681. *
  27682. * @private
  27683. * @function Highcharts.Point#importEvents
  27684. */
  27685. Point.prototype.importEvents = function () {
  27686. if (!this.hasImportedEvents) {
  27687. var point_1 = this,
  27688. options = merge(point_1.series.options.point,
  27689. point_1.options),
  27690. events = options.events;
  27691. point_1.events = events;
  27692. objectEach(events, function (event, eventType) {
  27693. if (isFunction(event)) {
  27694. addEvent(point_1, eventType, event);
  27695. }
  27696. });
  27697. this.hasImportedEvents = true;
  27698. }
  27699. };
  27700. /**
  27701. * Set the point's state.
  27702. *
  27703. * @function Highcharts.Point#setState
  27704. *
  27705. * @param {Highcharts.PointStateValue|""} [state]
  27706. * The new state, can be one of `'hover'`, `'select'`, `'inactive'`,
  27707. * or `''` (an empty string), `'normal'` or `undefined` to set to
  27708. * normal state.
  27709. * @param {boolean} [move]
  27710. * State for animation.
  27711. *
  27712. * @fires Highcharts.Point#event:afterSetState
  27713. */
  27714. Point.prototype.setState = function (state, move) {
  27715. var point = this,
  27716. series = point.series,
  27717. previousState = point.state,
  27718. stateOptions = (series.options.states[state || 'normal'] ||
  27719. {}),
  27720. markerOptions = (defaultOptions.plotOptions[series.type].marker &&
  27721. series.options.marker),
  27722. normalDisabled = (markerOptions && markerOptions.enabled === false),
  27723. markerStateOptions = ((markerOptions &&
  27724. markerOptions.states &&
  27725. markerOptions.states[state || 'normal']) || {}),
  27726. stateDisabled = markerStateOptions.enabled === false,
  27727. stateMarkerGraphic = series.stateMarkerGraphic,
  27728. pointMarker = point.marker || {},
  27729. chart = series.chart,
  27730. halo = series.halo,
  27731. haloOptions,
  27732. markerAttribs,
  27733. pointAttribs,
  27734. pointAttribsAnimation,
  27735. hasMarkers = (markerOptions && series.markerAttribs),
  27736. newSymbol;
  27737. state = state || ''; // empty string
  27738. if (
  27739. // already has this state
  27740. (state === point.state && !move) ||
  27741. // selected points don't respond to hover
  27742. (point.selected && state !== 'select') ||
  27743. // series' state options is disabled
  27744. (stateOptions.enabled === false) ||
  27745. // general point marker's state options is disabled
  27746. (state && (stateDisabled ||
  27747. (normalDisabled &&
  27748. markerStateOptions.enabled === false))) ||
  27749. // individual point marker's state options is disabled
  27750. (state &&
  27751. pointMarker.states &&
  27752. pointMarker.states[state] &&
  27753. pointMarker.states[state].enabled === false) // #1610
  27754. ) {
  27755. return;
  27756. }
  27757. point.state = state;
  27758. if (hasMarkers) {
  27759. markerAttribs = series.markerAttribs(point, state);
  27760. }
  27761. // Apply hover styles to the existing point
  27762. // Prevent from dummy null points (#14966)
  27763. if (point.graphic && !point.hasDummyGraphic) {
  27764. if (previousState) {
  27765. point.graphic.removeClass('highcharts-point-' + previousState);
  27766. }
  27767. if (state) {
  27768. point.graphic.addClass('highcharts-point-' + state);
  27769. }
  27770. if (!chart.styledMode) {
  27771. pointAttribs = series.pointAttribs(point, state);
  27772. pointAttribsAnimation = pick(chart.options.chart.animation, stateOptions.animation);
  27773. // Some inactive points (e.g. slices in pie) should apply
  27774. // oppacity also for it's labels
  27775. if (series.options.inactiveOtherPoints && isNumber(pointAttribs.opacity)) {
  27776. (point.dataLabels || []).forEach(function (label) {
  27777. if (label) {
  27778. label.animate({
  27779. opacity: pointAttribs.opacity
  27780. }, pointAttribsAnimation);
  27781. }
  27782. });
  27783. if (point.connector) {
  27784. point.connector.animate({
  27785. opacity: pointAttribs.opacity
  27786. }, pointAttribsAnimation);
  27787. }
  27788. }
  27789. point.graphic.animate(pointAttribs, pointAttribsAnimation);
  27790. }
  27791. if (markerAttribs) {
  27792. point.graphic.animate(markerAttribs, pick(
  27793. // Turn off globally:
  27794. chart.options.chart.animation, markerStateOptions.animation, markerOptions.animation));
  27795. }
  27796. // Zooming in from a range with no markers to a range with markers
  27797. if (stateMarkerGraphic) {
  27798. stateMarkerGraphic.hide();
  27799. }
  27800. }
  27801. else {
  27802. // if a graphic is not applied to each point in the normal state,
  27803. // create a shared graphic for the hover state
  27804. if (state && markerStateOptions) {
  27805. newSymbol = pointMarker.symbol || series.symbol;
  27806. // If the point has another symbol than the previous one, throw
  27807. // away the state marker graphic and force a new one (#1459)
  27808. if (stateMarkerGraphic &&
  27809. stateMarkerGraphic.currentSymbol !== newSymbol) {
  27810. stateMarkerGraphic = stateMarkerGraphic.destroy();
  27811. }
  27812. // Add a new state marker graphic
  27813. if (markerAttribs) {
  27814. if (!stateMarkerGraphic) {
  27815. if (newSymbol) {
  27816. series.stateMarkerGraphic = stateMarkerGraphic =
  27817. chart.renderer
  27818. .symbol(newSymbol, markerAttribs.x, markerAttribs.y, markerAttribs.width, markerAttribs.height)
  27819. .add(series.markerGroup);
  27820. stateMarkerGraphic.currentSymbol = newSymbol;
  27821. }
  27822. // Move the existing graphic
  27823. }
  27824. else {
  27825. stateMarkerGraphic[move ? 'animate' : 'attr']({
  27826. x: markerAttribs.x,
  27827. y: markerAttribs.y
  27828. });
  27829. }
  27830. }
  27831. if (!chart.styledMode && stateMarkerGraphic) {
  27832. stateMarkerGraphic.attr(series.pointAttribs(point, state));
  27833. }
  27834. }
  27835. if (stateMarkerGraphic) {
  27836. stateMarkerGraphic[state && point.isInside ? 'show' : 'hide'](); // #2450
  27837. stateMarkerGraphic.element.point = point; // #4310
  27838. }
  27839. }
  27840. // Show me your halo
  27841. haloOptions = stateOptions.halo;
  27842. var markerGraphic = (point.graphic || stateMarkerGraphic);
  27843. var markerVisibility = (markerGraphic && markerGraphic.visibility || 'inherit');
  27844. if (haloOptions &&
  27845. haloOptions.size &&
  27846. markerGraphic &&
  27847. markerVisibility !== 'hidden' &&
  27848. !point.isCluster) {
  27849. if (!halo) {
  27850. series.halo = halo = chart.renderer.path()
  27851. // #5818, #5903, #6705
  27852. .add(markerGraphic.parentGroup);
  27853. }
  27854. halo.show()[move ? 'animate' : 'attr']({
  27855. d: point.haloPath(haloOptions.size)
  27856. });
  27857. halo.attr({
  27858. 'class': 'highcharts-halo highcharts-color-' +
  27859. pick(point.colorIndex, series.colorIndex) +
  27860. (point.className ? ' ' + point.className : ''),
  27861. 'visibility': markerVisibility,
  27862. 'zIndex': -1 // #4929, #8276
  27863. });
  27864. halo.point = point; // #6055
  27865. if (!chart.styledMode) {
  27866. halo.attr(extend({
  27867. 'fill': point.color || series.color,
  27868. 'fill-opacity': haloOptions.opacity
  27869. }, AST.filterUserAttributes(haloOptions.attributes || {})));
  27870. }
  27871. }
  27872. else if (halo && halo.point && halo.point.haloPath) {
  27873. // Animate back to 0 on the current halo point (#6055)
  27874. halo.animate({ d: halo.point.haloPath(0) }, null,
  27875. // Hide after unhovering. The `complete` callback runs in the
  27876. // halo's context (#7681).
  27877. halo.hide);
  27878. }
  27879. fireEvent(point, 'afterSetState', { state: state });
  27880. };
  27881. /**
  27882. * Get the path definition for the halo, which is usually a shadow-like
  27883. * circle around the currently hovered point.
  27884. *
  27885. * @function Highcharts.Point#haloPath
  27886. *
  27887. * @param {number} size
  27888. * The radius of the circular halo.
  27889. *
  27890. * @return {Highcharts.SVGPathArray}
  27891. * The path definition.
  27892. */
  27893. Point.prototype.haloPath = function (size) {
  27894. var series = this.series,
  27895. chart = series.chart;
  27896. return chart.renderer.symbols.circle(Math.floor(this.plotX) - size, this.plotY - size, size * 2, size * 2);
  27897. };
  27898. return Point;
  27899. }());
  27900. H.Point = Point;
  27901. return Point;
  27902. });
  27903. _registerModule(_modules, 'Core/Legend.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/FormatUtilities.js'], _modules['Core/Globals.js'], _modules['Core/Series/Point.js'], _modules['Core/Utilities.js']], function (A, F, H, Point, U) {
  27904. /* *
  27905. *
  27906. * (c) 2010-2021 Torstein Honsi
  27907. *
  27908. * License: www.highcharts.com/license
  27909. *
  27910. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  27911. *
  27912. * */
  27913. var animObject = A.animObject,
  27914. setAnimation = A.setAnimation;
  27915. var format = F.format;
  27916. var isFirefox = H.isFirefox,
  27917. marginNames = H.marginNames,
  27918. win = H.win;
  27919. var addEvent = U.addEvent,
  27920. createElement = U.createElement,
  27921. css = U.css,
  27922. defined = U.defined,
  27923. discardElement = U.discardElement,
  27924. find = U.find,
  27925. fireEvent = U.fireEvent,
  27926. isNumber = U.isNumber,
  27927. merge = U.merge,
  27928. pick = U.pick,
  27929. relativeLength = U.relativeLength,
  27930. stableSort = U.stableSort,
  27931. syncTimeout = U.syncTimeout,
  27932. wrap = U.wrap;
  27933. /**
  27934. * Gets fired when the legend item belonging to a point is clicked. The default
  27935. * action is to toggle the visibility of the point. This can be prevented by
  27936. * returning `false` or calling `event.preventDefault()`.
  27937. *
  27938. * @callback Highcharts.PointLegendItemClickCallbackFunction
  27939. *
  27940. * @param {Highcharts.Point} this
  27941. * The point on which the event occured.
  27942. *
  27943. * @param {Highcharts.PointLegendItemClickEventObject} event
  27944. * The event that occured.
  27945. */
  27946. /**
  27947. * Information about the legend click event.
  27948. *
  27949. * @interface Highcharts.PointLegendItemClickEventObject
  27950. */ /**
  27951. * Related browser event.
  27952. * @name Highcharts.PointLegendItemClickEventObject#browserEvent
  27953. * @type {Highcharts.PointerEvent}
  27954. */ /**
  27955. * Prevent the default action of toggle the visibility of the point.
  27956. * @name Highcharts.PointLegendItemClickEventObject#preventDefault
  27957. * @type {Function}
  27958. */ /**
  27959. * Related point.
  27960. * @name Highcharts.PointLegendItemClickEventObject#target
  27961. * @type {Highcharts.Point}
  27962. */ /**
  27963. * Event type.
  27964. * @name Highcharts.PointLegendItemClickEventObject#type
  27965. * @type {"legendItemClick"}
  27966. */
  27967. /**
  27968. * Gets fired when the legend item belonging to a series is clicked. The default
  27969. * action is to toggle the visibility of the series. This can be prevented by
  27970. * returning `false` or calling `event.preventDefault()`.
  27971. *
  27972. * @callback Highcharts.SeriesLegendItemClickCallbackFunction
  27973. *
  27974. * @param {Highcharts.Series} this
  27975. * The series where the event occured.
  27976. *
  27977. * @param {Highcharts.SeriesLegendItemClickEventObject} event
  27978. * The event that occured.
  27979. */
  27980. /**
  27981. * Information about the legend click event.
  27982. *
  27983. * @interface Highcharts.SeriesLegendItemClickEventObject
  27984. */ /**
  27985. * Related browser event.
  27986. * @name Highcharts.SeriesLegendItemClickEventObject#browserEvent
  27987. * @type {Highcharts.PointerEvent}
  27988. */ /**
  27989. * Prevent the default action of toggle the visibility of the series.
  27990. * @name Highcharts.SeriesLegendItemClickEventObject#preventDefault
  27991. * @type {Function}
  27992. */ /**
  27993. * Related series.
  27994. * @name Highcharts.SeriesLegendItemClickEventObject#target
  27995. * @type {Highcharts.Series}
  27996. */ /**
  27997. * Event type.
  27998. * @name Highcharts.SeriesLegendItemClickEventObject#type
  27999. * @type {"legendItemClick"}
  28000. */
  28001. /* eslint-disable no-invalid-this, valid-jsdoc */
  28002. /**
  28003. * The overview of the chart's series. The legend object is instanciated
  28004. * internally in the chart constructor, and is available from the `chart.legend`
  28005. * property. Each chart has only one legend.
  28006. *
  28007. * @class
  28008. * @name Highcharts.Legend
  28009. *
  28010. * @param {Highcharts.Chart} chart
  28011. * The chart instance.
  28012. *
  28013. * @param {Highcharts.LegendOptions} options
  28014. * Legend options.
  28015. */
  28016. var Legend = /** @class */ (function () {
  28017. /* *
  28018. *
  28019. * Constructors
  28020. *
  28021. * */
  28022. function Legend(chart, options) {
  28023. /* *
  28024. *
  28025. * Properties
  28026. *
  28027. * */
  28028. this.allItems = [];
  28029. this.box = void 0;
  28030. this.contentGroup = void 0;
  28031. this.display = false;
  28032. this.group = void 0;
  28033. this.initialItemY = 0;
  28034. this.itemHeight = 0;
  28035. this.itemMarginBottom = 0;
  28036. this.itemMarginTop = 0;
  28037. this.itemX = 0;
  28038. this.itemY = 0;
  28039. this.lastItemY = 0;
  28040. this.lastLineHeight = 0;
  28041. this.legendHeight = 0;
  28042. this.legendWidth = 0;
  28043. this.maxItemWidth = 0;
  28044. this.maxLegendWidth = 0;
  28045. this.offsetWidth = 0;
  28046. this.options = {};
  28047. this.padding = 0;
  28048. this.pages = [];
  28049. this.proximate = false;
  28050. this.scrollGroup = void 0;
  28051. this.symbolHeight = 0;
  28052. this.symbolWidth = 0;
  28053. this.titleHeight = 0;
  28054. this.totalItemWidth = 0;
  28055. this.widthOption = 0;
  28056. this.chart = chart;
  28057. this.init(chart, options);
  28058. }
  28059. /* *
  28060. *
  28061. * Functions
  28062. *
  28063. * */
  28064. /**
  28065. * Initialize the legend.
  28066. *
  28067. * @private
  28068. * @function Highcharts.Legend#init
  28069. *
  28070. * @param {Highcharts.Chart} chart
  28071. * The chart instance.
  28072. *
  28073. * @param {Highcharts.LegendOptions} options
  28074. * Legend options.
  28075. */
  28076. Legend.prototype.init = function (chart, options) {
  28077. /**
  28078. * Chart of this legend.
  28079. *
  28080. * @readonly
  28081. * @name Highcharts.Legend#chart
  28082. * @type {Highcharts.Chart}
  28083. */
  28084. this.chart = chart;
  28085. this.setOptions(options);
  28086. if (options.enabled) {
  28087. // Render it
  28088. this.render();
  28089. // move checkboxes
  28090. addEvent(this.chart, 'endResize', function () {
  28091. this.legend.positionCheckboxes();
  28092. });
  28093. if (this.proximate) {
  28094. this.unchartrender = addEvent(this.chart, 'render', function () {
  28095. this.legend.proximatePositions();
  28096. this.legend.positionItems();
  28097. });
  28098. }
  28099. else if (this.unchartrender) {
  28100. this.unchartrender();
  28101. }
  28102. }
  28103. };
  28104. /**
  28105. * @private
  28106. * @function Highcharts.Legend#setOptions
  28107. * @param {Highcharts.LegendOptions} options
  28108. */
  28109. Legend.prototype.setOptions = function (options) {
  28110. var padding = pick(options.padding, 8);
  28111. /**
  28112. * Legend options.
  28113. *
  28114. * @readonly
  28115. * @name Highcharts.Legend#options
  28116. * @type {Highcharts.LegendOptions}
  28117. */
  28118. this.options = options;
  28119. if (!this.chart.styledMode) {
  28120. this.itemStyle = options.itemStyle;
  28121. this.itemHiddenStyle = merge(this.itemStyle, options.itemHiddenStyle);
  28122. }
  28123. this.itemMarginTop = options.itemMarginTop || 0;
  28124. this.itemMarginBottom = options.itemMarginBottom || 0;
  28125. this.padding = padding;
  28126. this.initialItemY = padding - 5; // 5 is pixels above the text
  28127. this.symbolWidth = pick(options.symbolWidth, 16);
  28128. this.pages = [];
  28129. this.proximate = options.layout === 'proximate' && !this.chart.inverted;
  28130. this.baseline = void 0; // #12705: baseline has to be reset on every update
  28131. };
  28132. /**
  28133. * Update the legend with new options. Equivalent to running `chart.update`
  28134. * with a legend configuration option.
  28135. *
  28136. * @sample highcharts/legend/legend-update/
  28137. * Legend update
  28138. *
  28139. * @function Highcharts.Legend#update
  28140. *
  28141. * @param {Highcharts.LegendOptions} options
  28142. * Legend options.
  28143. *
  28144. * @param {boolean} [redraw=true]
  28145. * Whether to redraw the chart after the axis is altered. If doing more
  28146. * operations on the chart, it is a good idea to set redraw to false and
  28147. * call {@link Chart#redraw} after. Whether to redraw the chart.
  28148. *
  28149. * @fires Highcharts.Legends#event:afterUpdate
  28150. */
  28151. Legend.prototype.update = function (options, redraw) {
  28152. var chart = this.chart;
  28153. this.setOptions(merge(true, this.options, options));
  28154. this.destroy();
  28155. chart.isDirtyLegend = chart.isDirtyBox = true;
  28156. if (pick(redraw, true)) {
  28157. chart.redraw();
  28158. }
  28159. fireEvent(this, 'afterUpdate');
  28160. };
  28161. /**
  28162. * Set the colors for the legend item.
  28163. *
  28164. * @private
  28165. * @function Highcharts.Legend#colorizeItem
  28166. * @param {Highcharts.BubbleLegend|Highcharts.Point|Highcharts.Series} item
  28167. * A Series or Point instance
  28168. * @param {boolean} [visible=false]
  28169. * Dimmed or colored
  28170. *
  28171. * @todo
  28172. * Make events official: Fires the event `afterColorizeItem`.
  28173. */
  28174. Legend.prototype.colorizeItem = function (item, visible) {
  28175. item.legendGroup[visible ? 'removeClass' : 'addClass']('highcharts-legend-item-hidden');
  28176. if (!this.chart.styledMode) {
  28177. var legend = this,
  28178. options = legend.options,
  28179. legendItem = item.legendItem,
  28180. legendLine = item.legendLine,
  28181. legendSymbol = item.legendSymbol,
  28182. hiddenColor = legend.itemHiddenStyle.color,
  28183. textColor = visible ?
  28184. options.itemStyle.color :
  28185. hiddenColor,
  28186. symbolColor = visible ?
  28187. (item.color || hiddenColor) :
  28188. hiddenColor,
  28189. markerOptions = item.options && item.options.marker,
  28190. symbolAttr = { fill: symbolColor };
  28191. if (legendItem) {
  28192. legendItem.css({
  28193. fill: textColor,
  28194. color: textColor // #1553, oldIE
  28195. });
  28196. }
  28197. if (legendLine) {
  28198. legendLine.attr({ stroke: symbolColor });
  28199. }
  28200. if (legendSymbol) {
  28201. // Apply marker options
  28202. if (markerOptions && legendSymbol.isMarker) { // #585
  28203. symbolAttr = item.pointAttribs();
  28204. if (!visible) {
  28205. // #6769
  28206. symbolAttr.stroke = symbolAttr.fill = hiddenColor;
  28207. }
  28208. }
  28209. legendSymbol.attr(symbolAttr);
  28210. }
  28211. }
  28212. fireEvent(this, 'afterColorizeItem', { item: item, visible: visible });
  28213. };
  28214. /**
  28215. * @private
  28216. * @function Highcharts.Legend#positionItems
  28217. */
  28218. Legend.prototype.positionItems = function () {
  28219. // Now that the legend width and height are established, put the items
  28220. // in the final position
  28221. this.allItems.forEach(this.positionItem, this);
  28222. if (!this.chart.isResizing) {
  28223. this.positionCheckboxes();
  28224. }
  28225. };
  28226. /**
  28227. * Position the legend item.
  28228. *
  28229. * @private
  28230. * @function Highcharts.Legend#positionItem
  28231. * @param {Highcharts.BubbleLegend|Highcharts.Point|Highcharts.Series} item
  28232. * The item to position
  28233. */
  28234. Legend.prototype.positionItem = function (item) {
  28235. var _this = this;
  28236. var legend = this,
  28237. options = legend.options,
  28238. symbolPadding = options.symbolPadding,
  28239. ltr = !options.rtl,
  28240. legendItemPos = item._legendItemPos,
  28241. itemX = legendItemPos[0],
  28242. itemY = legendItemPos[1],
  28243. checkbox = item.checkbox,
  28244. legendGroup = item.legendGroup;
  28245. if (legendGroup && legendGroup.element) {
  28246. var attribs = {
  28247. translateX: ltr ?
  28248. itemX :
  28249. legend.legendWidth - itemX - 2 * symbolPadding - 4,
  28250. translateY: itemY
  28251. };
  28252. var complete = function () {
  28253. fireEvent(_this, 'afterPositionItem', { item: item });
  28254. };
  28255. if (defined(legendGroup.translateY)) {
  28256. legendGroup.animate(attribs, void 0, complete);
  28257. }
  28258. else {
  28259. legendGroup.attr(attribs);
  28260. complete();
  28261. }
  28262. }
  28263. if (checkbox) {
  28264. checkbox.x = itemX;
  28265. checkbox.y = itemY;
  28266. }
  28267. };
  28268. /**
  28269. * Destroy a single legend item, used internally on removing series items.
  28270. *
  28271. * @private
  28272. * @function Highcharts.Legend#destroyItem
  28273. * @param {Highcharts.BubbleLegend|Highcharts.Point|Highcharts.Series} item
  28274. * The item to remove
  28275. */
  28276. Legend.prototype.destroyItem = function (item) {
  28277. var checkbox = item.checkbox;
  28278. // destroy SVG elements
  28279. ['legendItem', 'legendLine', 'legendSymbol', 'legendGroup'].forEach(function (key) {
  28280. if (item[key]) {
  28281. item[key] = item[key].destroy();
  28282. }
  28283. });
  28284. if (checkbox) {
  28285. discardElement(item.checkbox);
  28286. }
  28287. };
  28288. /**
  28289. * Destroy the legend. Used internally. To reflow objects, `chart.redraw`
  28290. * must be called after destruction.
  28291. *
  28292. * @private
  28293. * @function Highcharts.Legend#destroy
  28294. */
  28295. Legend.prototype.destroy = function () {
  28296. /**
  28297. * @private
  28298. * @param {string} key
  28299. * @return {void}
  28300. */
  28301. function destroyItems(key) {
  28302. if (this[key]) {
  28303. this[key] = this[key].destroy();
  28304. }
  28305. }
  28306. // Destroy items
  28307. this.getAllItems().forEach(function (item) {
  28308. ['legendItem', 'legendGroup'].forEach(destroyItems, item);
  28309. });
  28310. // Destroy legend elements
  28311. [
  28312. 'clipRect',
  28313. 'up',
  28314. 'down',
  28315. 'pager',
  28316. 'nav',
  28317. 'box',
  28318. 'title',
  28319. 'group'
  28320. ].forEach(destroyItems, this);
  28321. this.display = null; // Reset in .render on update.
  28322. };
  28323. /**
  28324. * Position the checkboxes after the width is determined.
  28325. *
  28326. * @private
  28327. * @function Highcharts.Legend#positionCheckboxes
  28328. */
  28329. Legend.prototype.positionCheckboxes = function () {
  28330. var alignAttr = this.group && this.group.alignAttr,
  28331. translateY,
  28332. clipHeight = this.clipHeight || this.legendHeight,
  28333. titleHeight = this.titleHeight;
  28334. if (alignAttr) {
  28335. translateY = alignAttr.translateY;
  28336. this.allItems.forEach(function (item) {
  28337. var checkbox = item.checkbox,
  28338. top;
  28339. if (checkbox) {
  28340. top = translateY + titleHeight + checkbox.y +
  28341. (this.scrollOffset || 0) + 3;
  28342. css(checkbox, {
  28343. left: (alignAttr.translateX + item.checkboxOffset +
  28344. checkbox.x - 20) + 'px',
  28345. top: top + 'px',
  28346. display: this.proximate || (top > translateY - 6 &&
  28347. top < translateY + clipHeight - 6) ?
  28348. '' :
  28349. 'none'
  28350. });
  28351. }
  28352. }, this);
  28353. }
  28354. };
  28355. /**
  28356. * Render the legend title on top of the legend.
  28357. *
  28358. * @private
  28359. * @function Highcharts.Legend#renderTitle
  28360. */
  28361. Legend.prototype.renderTitle = function () {
  28362. var options = this.options,
  28363. padding = this.padding,
  28364. titleOptions = options.title,
  28365. titleHeight = 0,
  28366. bBox;
  28367. if (titleOptions.text) {
  28368. if (!this.title) {
  28369. /**
  28370. * SVG element of the legend title.
  28371. *
  28372. * @readonly
  28373. * @name Highcharts.Legend#title
  28374. * @type {Highcharts.SVGElement}
  28375. */
  28376. this.title = this.chart.renderer.label(titleOptions.text, padding - 3, padding - 4, null, null, null, options.useHTML, null, 'legend-title')
  28377. .attr({ zIndex: 1 });
  28378. if (!this.chart.styledMode) {
  28379. this.title.css(titleOptions.style);
  28380. }
  28381. this.title.add(this.group);
  28382. }
  28383. // Set the max title width (#7253)
  28384. if (!titleOptions.width) {
  28385. this.title.css({
  28386. width: this.maxLegendWidth + 'px'
  28387. });
  28388. }
  28389. bBox = this.title.getBBox();
  28390. titleHeight = bBox.height;
  28391. this.offsetWidth = bBox.width; // #1717
  28392. this.contentGroup.attr({ translateY: titleHeight });
  28393. }
  28394. this.titleHeight = titleHeight;
  28395. };
  28396. /**
  28397. * Set the legend item text.
  28398. *
  28399. * @function Highcharts.Legend#setText
  28400. * @param {Highcharts.Point|Highcharts.Series} item
  28401. * The item for which to update the text in the legend.
  28402. */
  28403. Legend.prototype.setText = function (item) {
  28404. var options = this.options;
  28405. item.legendItem.attr({
  28406. text: options.labelFormat ?
  28407. format(options.labelFormat, item, this.chart) :
  28408. options.labelFormatter.call(item)
  28409. });
  28410. };
  28411. /**
  28412. * Render a single specific legend item. Called internally from the `render`
  28413. * function.
  28414. *
  28415. * @private
  28416. * @function Highcharts.Legend#renderItem
  28417. * @param {Highcharts.BubbleLegend|Highcharts.Point|Highcharts.Series} item
  28418. * The item to render.
  28419. */
  28420. Legend.prototype.renderItem = function (item) {
  28421. var legend = this,
  28422. chart = legend.chart,
  28423. renderer = chart.renderer,
  28424. options = legend.options,
  28425. horizontal = options.layout === 'horizontal',
  28426. symbolWidth = legend.symbolWidth,
  28427. symbolPadding = options.symbolPadding || 0,
  28428. itemStyle = legend.itemStyle,
  28429. itemHiddenStyle = legend.itemHiddenStyle,
  28430. itemDistance = horizontal ? pick(options.itemDistance, 20) : 0,
  28431. ltr = !options.rtl,
  28432. bBox,
  28433. li = item.legendItem,
  28434. isSeries = !item.series,
  28435. series = !isSeries && item.series.drawLegendSymbol ?
  28436. item.series :
  28437. item,
  28438. seriesOptions = series.options,
  28439. showCheckbox = legend.createCheckboxForItem &&
  28440. seriesOptions &&
  28441. seriesOptions.showCheckbox,
  28442. // full width minus text width
  28443. itemExtraWidth = symbolWidth + symbolPadding +
  28444. itemDistance + (showCheckbox ? 20 : 0),
  28445. useHTML = options.useHTML,
  28446. itemClassName = item.options.className;
  28447. if (!li) { // generate it once, later move it
  28448. // Generate the group box, a group to hold the symbol and text. Text
  28449. // is to be appended in Legend class.
  28450. item.legendGroup = renderer
  28451. .g('legend-item')
  28452. .addClass('highcharts-' + series.type + '-series ' +
  28453. 'highcharts-color-' + item.colorIndex +
  28454. (itemClassName ? ' ' + itemClassName : '') +
  28455. (isSeries ?
  28456. ' highcharts-series-' + item.index :
  28457. ''))
  28458. .attr({ zIndex: 1 })
  28459. .add(legend.scrollGroup);
  28460. // Generate the list item text and add it to the group
  28461. item.legendItem = li = renderer.text('', ltr ?
  28462. symbolWidth + symbolPadding :
  28463. -symbolPadding, legend.baseline || 0, useHTML);
  28464. if (!chart.styledMode) {
  28465. // merge to prevent modifying original (#1021)
  28466. li.css(merge(item.visible ?
  28467. itemStyle :
  28468. itemHiddenStyle));
  28469. }
  28470. li
  28471. .attr({
  28472. align: ltr ? 'left' : 'right',
  28473. zIndex: 2
  28474. })
  28475. .add(item.legendGroup);
  28476. // Get the baseline for the first item - the font size is equal for
  28477. // all
  28478. if (!legend.baseline) {
  28479. legend.fontMetrics = renderer.fontMetrics(chart.styledMode ? 12 : itemStyle.fontSize, li);
  28480. legend.baseline =
  28481. legend.fontMetrics.f + 3 + legend.itemMarginTop;
  28482. li.attr('y', legend.baseline);
  28483. legend.symbolHeight =
  28484. options.symbolHeight || legend.fontMetrics.f;
  28485. if (options.squareSymbol) {
  28486. legend.symbolWidth = pick(options.symbolWidth, Math.max(legend.symbolHeight, 16));
  28487. itemExtraWidth = legend.symbolWidth + symbolPadding +
  28488. itemDistance + (showCheckbox ? 20 : 0);
  28489. if (ltr) {
  28490. li.attr('x', legend.symbolWidth + symbolPadding);
  28491. }
  28492. }
  28493. }
  28494. // Draw the legend symbol inside the group box
  28495. series.drawLegendSymbol(legend, item);
  28496. if (legend.setItemEvents) {
  28497. legend.setItemEvents(item, li, useHTML);
  28498. }
  28499. }
  28500. // Add the HTML checkbox on top
  28501. if (showCheckbox && !item.checkbox && legend.createCheckboxForItem) {
  28502. legend.createCheckboxForItem(item);
  28503. }
  28504. // Colorize the items
  28505. legend.colorizeItem(item, item.visible);
  28506. // Take care of max width and text overflow (#6659)
  28507. if (chart.styledMode || !itemStyle.width) {
  28508. li.css({
  28509. width: ((options.itemWidth ||
  28510. legend.widthOption ||
  28511. chart.spacingBox.width) - itemExtraWidth) + 'px'
  28512. });
  28513. }
  28514. // Always update the text
  28515. legend.setText(item);
  28516. // calculate the positions for the next line
  28517. bBox = li.getBBox();
  28518. item.itemWidth = item.checkboxOffset =
  28519. options.itemWidth ||
  28520. item.legendItemWidth ||
  28521. bBox.width + itemExtraWidth;
  28522. legend.maxItemWidth = Math.max(legend.maxItemWidth, item.itemWidth);
  28523. legend.totalItemWidth += item.itemWidth;
  28524. legend.itemHeight = item.itemHeight = Math.round(item.legendItemHeight || bBox.height || legend.symbolHeight);
  28525. };
  28526. /**
  28527. * Get the position of the item in the layout. We now know the
  28528. * maxItemWidth from the previous loop.
  28529. *
  28530. * @private
  28531. * @function Highcharts.Legend#layoutItem
  28532. * @param {Highcharts.BubbleLegend|Highcharts.Point|Highcharts.Series} item
  28533. */
  28534. Legend.prototype.layoutItem = function (item) {
  28535. var options = this.options,
  28536. padding = this.padding,
  28537. horizontal = options.layout === 'horizontal',
  28538. itemHeight = item.itemHeight,
  28539. itemMarginBottom = this.itemMarginBottom,
  28540. itemMarginTop = this.itemMarginTop,
  28541. itemDistance = horizontal ? pick(options.itemDistance, 20) : 0,
  28542. maxLegendWidth = this.maxLegendWidth,
  28543. itemWidth = (options.alignColumns &&
  28544. this.totalItemWidth > maxLegendWidth) ?
  28545. this.maxItemWidth :
  28546. item.itemWidth;
  28547. // If the item exceeds the width, start a new line
  28548. if (horizontal &&
  28549. this.itemX - padding + itemWidth > maxLegendWidth) {
  28550. this.itemX = padding;
  28551. if (this.lastLineHeight) { // Not for the first line (#10167)
  28552. this.itemY += (itemMarginTop +
  28553. this.lastLineHeight +
  28554. itemMarginBottom);
  28555. }
  28556. this.lastLineHeight = 0; // reset for next line (#915, #3976)
  28557. }
  28558. // Set the edge positions
  28559. this.lastItemY = itemMarginTop + this.itemY + itemMarginBottom;
  28560. this.lastLineHeight = Math.max(// #915
  28561. itemHeight, this.lastLineHeight);
  28562. // cache the position of the newly generated or reordered items
  28563. item._legendItemPos = [this.itemX, this.itemY];
  28564. // advance
  28565. if (horizontal) {
  28566. this.itemX += itemWidth;
  28567. }
  28568. else {
  28569. this.itemY +=
  28570. itemMarginTop + itemHeight + itemMarginBottom;
  28571. this.lastLineHeight = itemHeight;
  28572. }
  28573. // the width of the widest item
  28574. this.offsetWidth = this.widthOption || Math.max((horizontal ? this.itemX - padding - (item.checkbox ?
  28575. // decrease by itemDistance only when no checkbox #4853
  28576. 0 :
  28577. itemDistance) : itemWidth) + padding, this.offsetWidth);
  28578. };
  28579. /**
  28580. * Get all items, which is one item per series for most series and one
  28581. * item per point for pie series and its derivatives. Fires the event
  28582. * `afterGetAllItems`.
  28583. *
  28584. * @private
  28585. * @function Highcharts.Legend#getAllItems
  28586. * @return {Array<(Highcharts.BubbleLegend|Highcharts.Point|Highcharts.Series)>}
  28587. * The current items in the legend.
  28588. * @fires Highcharts.Legend#event:afterGetAllItems
  28589. */
  28590. Legend.prototype.getAllItems = function () {
  28591. var allItems = [];
  28592. this.chart.series.forEach(function (series) {
  28593. var seriesOptions = series && series.options;
  28594. // Handle showInLegend. If the series is linked to another series,
  28595. // defaults to false.
  28596. if (series && pick(seriesOptions.showInLegend, !defined(seriesOptions.linkedTo) ? void 0 : false, true)) {
  28597. // Use points or series for the legend item depending on
  28598. // legendType
  28599. allItems = allItems.concat(series.legendItems ||
  28600. (seriesOptions.legendType === 'point' ?
  28601. series.data :
  28602. series));
  28603. }
  28604. });
  28605. fireEvent(this, 'afterGetAllItems', { allItems: allItems });
  28606. return allItems;
  28607. };
  28608. /**
  28609. * Get a short, three letter string reflecting the alignment and layout.
  28610. *
  28611. * @private
  28612. * @function Highcharts.Legend#getAlignment
  28613. * @return {string}
  28614. * The alignment, empty string if floating
  28615. */
  28616. Legend.prototype.getAlignment = function () {
  28617. var options = this.options;
  28618. // Use the first letter of each alignment option in order to detect
  28619. // the side. (#4189 - use charAt(x) notation instead of [x] for IE7)
  28620. if (this.proximate) {
  28621. return options.align.charAt(0) + 'tv';
  28622. }
  28623. return options.floating ? '' : (options.align.charAt(0) +
  28624. options.verticalAlign.charAt(0) +
  28625. options.layout.charAt(0));
  28626. };
  28627. /**
  28628. * Adjust the chart margins by reserving space for the legend on only one
  28629. * side of the chart. If the position is set to a corner, top or bottom is
  28630. * reserved for horizontal legends and left or right for vertical ones.
  28631. *
  28632. * @private
  28633. * @function Highcharts.Legend#adjustMargins
  28634. * @param {Array<number>} margin
  28635. * @param {Array<number>} spacing
  28636. */
  28637. Legend.prototype.adjustMargins = function (margin, spacing) {
  28638. var chart = this.chart,
  28639. options = this.options,
  28640. alignment = this.getAlignment();
  28641. if (alignment) {
  28642. ([
  28643. /(lth|ct|rth)/,
  28644. /(rtv|rm|rbv)/,
  28645. /(rbh|cb|lbh)/,
  28646. /(lbv|lm|ltv)/
  28647. ]).forEach(function (alignments, side) {
  28648. if (alignments.test(alignment) && !defined(margin[side])) {
  28649. // Now we have detected on which side of the chart we should
  28650. // reserve space for the legend
  28651. chart[marginNames[side]] = Math.max(chart[marginNames[side]], (chart.legend[(side + 1) % 2 ? 'legendHeight' : 'legendWidth'] +
  28652. [1, -1, -1, 1][side] * options[(side % 2) ? 'x' : 'y'] +
  28653. pick(options.margin, 12) +
  28654. spacing[side] +
  28655. (chart.titleOffset[side] || 0)));
  28656. }
  28657. });
  28658. }
  28659. };
  28660. /**
  28661. * @private
  28662. * @function Highcharts.Legend#proximatePositions
  28663. */
  28664. Legend.prototype.proximatePositions = function () {
  28665. var chart = this.chart,
  28666. boxes = [],
  28667. alignLeft = this.options.align === 'left';
  28668. this.allItems.forEach(function (item) {
  28669. var lastPoint,
  28670. height,
  28671. useFirstPoint = alignLeft,
  28672. target,
  28673. top;
  28674. if (item.yAxis) {
  28675. if (item.xAxis.options.reversed) {
  28676. useFirstPoint = !useFirstPoint;
  28677. }
  28678. if (item.points) {
  28679. lastPoint = find(useFirstPoint ?
  28680. item.points :
  28681. item.points.slice(0).reverse(), function (item) {
  28682. return isNumber(item.plotY);
  28683. });
  28684. }
  28685. height = this.itemMarginTop +
  28686. item.legendItem.getBBox().height +
  28687. this.itemMarginBottom;
  28688. top = item.yAxis.top - chart.plotTop;
  28689. if (item.visible) {
  28690. target = lastPoint ?
  28691. lastPoint.plotY :
  28692. item.yAxis.height;
  28693. target += top - 0.3 * height;
  28694. }
  28695. else {
  28696. target = top + item.yAxis.height;
  28697. }
  28698. boxes.push({
  28699. target: target,
  28700. size: height,
  28701. item: item
  28702. });
  28703. }
  28704. }, this);
  28705. H.distribute(boxes, chart.plotHeight);
  28706. boxes.forEach(function (box) {
  28707. box.item._legendItemPos[1] =
  28708. chart.plotTop - chart.spacing[0] + box.pos;
  28709. });
  28710. };
  28711. /**
  28712. * Render the legend. This method can be called both before and after
  28713. * `chart.render`. If called after, it will only rearrange items instead
  28714. * of creating new ones. Called internally on initial render and after
  28715. * redraws.
  28716. *
  28717. * @private
  28718. * @function Highcharts.Legend#render
  28719. */
  28720. Legend.prototype.render = function () {
  28721. var legend = this,
  28722. chart = legend.chart,
  28723. renderer = chart.renderer,
  28724. legendGroup = legend.group,
  28725. allItems,
  28726. display,
  28727. legendWidth,
  28728. legendHeight,
  28729. box = legend.box,
  28730. options = legend.options,
  28731. padding = legend.padding,
  28732. allowedWidth;
  28733. legend.itemX = padding;
  28734. legend.itemY = legend.initialItemY;
  28735. legend.offsetWidth = 0;
  28736. legend.lastItemY = 0;
  28737. legend.widthOption = relativeLength(options.width, chart.spacingBox.width - padding);
  28738. // Compute how wide the legend is allowed to be
  28739. allowedWidth =
  28740. chart.spacingBox.width - 2 * padding - options.x;
  28741. if (['rm', 'lm'].indexOf(legend.getAlignment().substring(0, 2)) > -1) {
  28742. allowedWidth /= 2;
  28743. }
  28744. legend.maxLegendWidth = legend.widthOption || allowedWidth;
  28745. if (!legendGroup) {
  28746. /**
  28747. * SVG group of the legend.
  28748. *
  28749. * @readonly
  28750. * @name Highcharts.Legend#group
  28751. * @type {Highcharts.SVGElement}
  28752. */
  28753. legend.group = legendGroup = renderer.g('legend')
  28754. .addClass(options.className || '')
  28755. .attr({ zIndex: 7 })
  28756. .add();
  28757. legend.contentGroup = renderer.g()
  28758. .attr({ zIndex: 1 }) // above background
  28759. .add(legendGroup);
  28760. legend.scrollGroup = renderer.g()
  28761. .add(legend.contentGroup);
  28762. }
  28763. legend.renderTitle();
  28764. // add each series or point
  28765. allItems = legend.getAllItems();
  28766. // sort by legendIndex
  28767. stableSort(allItems, function (a, b) {
  28768. return ((a.options && a.options.legendIndex) || 0) -
  28769. ((b.options && b.options.legendIndex) || 0);
  28770. });
  28771. // reversed legend
  28772. if (options.reversed) {
  28773. allItems.reverse();
  28774. }
  28775. /**
  28776. * All items for the legend, which is an array of series for most series
  28777. * and an array of points for pie series and its derivatives.
  28778. *
  28779. * @readonly
  28780. * @name Highcharts.Legend#allItems
  28781. * @type {Array<(Highcharts.Point|Highcharts.Series)>}
  28782. */
  28783. legend.allItems = allItems;
  28784. legend.display = display = !!allItems.length;
  28785. // Render the items. First we run a loop to set the text and properties
  28786. // and read all the bounding boxes. The next loop computes the item
  28787. // positions based on the bounding boxes.
  28788. legend.lastLineHeight = 0;
  28789. legend.maxItemWidth = 0;
  28790. legend.totalItemWidth = 0;
  28791. legend.itemHeight = 0;
  28792. allItems.forEach(legend.renderItem, legend);
  28793. allItems.forEach(legend.layoutItem, legend);
  28794. // Get the box
  28795. legendWidth = (legend.widthOption || legend.offsetWidth) + padding;
  28796. legendHeight = legend.lastItemY + legend.lastLineHeight +
  28797. legend.titleHeight;
  28798. legendHeight = legend.handleOverflow(legendHeight);
  28799. legendHeight += padding;
  28800. // Draw the border and/or background
  28801. if (!box) {
  28802. /**
  28803. * SVG element of the legend box.
  28804. *
  28805. * @readonly
  28806. * @name Highcharts.Legend#box
  28807. * @type {Highcharts.SVGElement}
  28808. */
  28809. legend.box = box = renderer.rect()
  28810. .addClass('highcharts-legend-box')
  28811. .attr({
  28812. r: options.borderRadius
  28813. })
  28814. .add(legendGroup);
  28815. box.isNew = true;
  28816. }
  28817. // Presentational
  28818. if (!chart.styledMode) {
  28819. box
  28820. .attr({
  28821. stroke: options.borderColor,
  28822. 'stroke-width': options.borderWidth || 0,
  28823. fill: options.backgroundColor || 'none'
  28824. })
  28825. .shadow(options.shadow);
  28826. }
  28827. if (legendWidth > 0 && legendHeight > 0) {
  28828. box[box.isNew ? 'attr' : 'animate'](box.crisp.call({}, {
  28829. x: 0,
  28830. y: 0,
  28831. width: legendWidth,
  28832. height: legendHeight
  28833. }, box.strokeWidth()));
  28834. box.isNew = false;
  28835. }
  28836. // hide the border if no items
  28837. box[display ? 'show' : 'hide']();
  28838. // Open for responsiveness
  28839. if (chart.styledMode && legendGroup.getStyle('display') === 'none') {
  28840. legendWidth = legendHeight = 0;
  28841. }
  28842. legend.legendWidth = legendWidth;
  28843. legend.legendHeight = legendHeight;
  28844. if (display) {
  28845. legend.align();
  28846. }
  28847. if (!this.proximate) {
  28848. this.positionItems();
  28849. }
  28850. fireEvent(this, 'afterRender');
  28851. };
  28852. /**
  28853. * Align the legend to chart's box.
  28854. *
  28855. * @private
  28856. * @function Highcharts.align
  28857. * @param {Highcharts.BBoxObject} alignTo
  28858. * @return {void}
  28859. */
  28860. Legend.prototype.align = function (alignTo) {
  28861. if (alignTo === void 0) { alignTo = this.chart.spacingBox; }
  28862. var chart = this.chart,
  28863. options = this.options;
  28864. // If aligning to the top and the layout is horizontal, adjust for
  28865. // the title (#7428)
  28866. var y = alignTo.y;
  28867. if (/(lth|ct|rth)/.test(this.getAlignment()) &&
  28868. chart.titleOffset[0] > 0) {
  28869. y += chart.titleOffset[0];
  28870. }
  28871. else if (/(lbh|cb|rbh)/.test(this.getAlignment()) &&
  28872. chart.titleOffset[2] > 0) {
  28873. y -= chart.titleOffset[2];
  28874. }
  28875. if (y !== alignTo.y) {
  28876. alignTo = merge(alignTo, { y: y });
  28877. }
  28878. this.group.align(merge(options, {
  28879. width: this.legendWidth,
  28880. height: this.legendHeight,
  28881. verticalAlign: this.proximate ? 'top' : options.verticalAlign
  28882. }), true, alignTo);
  28883. };
  28884. /**
  28885. * Set up the overflow handling by adding navigation with up and down arrows
  28886. * below the legend.
  28887. *
  28888. * @private
  28889. * @function Highcharts.Legend#handleOverflow
  28890. * @param {number} legendHeight
  28891. * @return {number}
  28892. */
  28893. Legend.prototype.handleOverflow = function (legendHeight) {
  28894. var legend = this,
  28895. chart = this.chart,
  28896. renderer = chart.renderer,
  28897. options = this.options,
  28898. optionsY = options.y,
  28899. alignTop = options.verticalAlign === 'top',
  28900. padding = this.padding,
  28901. spaceHeight = (chart.spacingBox.height +
  28902. (alignTop ? -optionsY : optionsY) - padding),
  28903. maxHeight = options.maxHeight,
  28904. clipHeight,
  28905. clipRect = this.clipRect,
  28906. navOptions = options.navigation,
  28907. animation = pick(navOptions.animation,
  28908. true),
  28909. arrowSize = navOptions.arrowSize || 12,
  28910. nav = this.nav,
  28911. pages = this.pages,
  28912. lastY,
  28913. allItems = this.allItems,
  28914. clipToHeight = function (height) {
  28915. if (typeof height === 'number') {
  28916. clipRect.attr({
  28917. height: height
  28918. });
  28919. }
  28920. else if (clipRect) { // Reset (#5912)
  28921. legend.clipRect = clipRect.destroy();
  28922. legend.contentGroup.clip();
  28923. }
  28924. // useHTML
  28925. if (legend.contentGroup.div) {
  28926. legend.contentGroup.div.style.clip = height ?
  28927. 'rect(' + padding + 'px,9999px,' +
  28928. (padding + height) + 'px,0)' :
  28929. 'auto';
  28930. }
  28931. }, addTracker = function (key) {
  28932. legend[key] = renderer
  28933. .circle(0, 0, arrowSize * 1.3)
  28934. .translate(arrowSize / 2, arrowSize / 2)
  28935. .add(nav);
  28936. if (!chart.styledMode) {
  28937. legend[key].attr('fill', 'rgba(0,0,0,0.0001)');
  28938. }
  28939. return legend[key];
  28940. };
  28941. // Adjust the height
  28942. if (options.layout === 'horizontal' &&
  28943. options.verticalAlign !== 'middle' &&
  28944. !options.floating) {
  28945. spaceHeight /= 2;
  28946. }
  28947. if (maxHeight) {
  28948. spaceHeight = Math.min(spaceHeight, maxHeight);
  28949. }
  28950. // Reset the legend height and adjust the clipping rectangle
  28951. pages.length = 0;
  28952. if (legendHeight &&
  28953. spaceHeight > 0 &&
  28954. legendHeight > spaceHeight &&
  28955. navOptions.enabled !== false) {
  28956. this.clipHeight = clipHeight =
  28957. Math.max(spaceHeight - 20 - this.titleHeight - padding, 0);
  28958. this.currentPage = pick(this.currentPage, 1);
  28959. this.fullHeight = legendHeight;
  28960. // Fill pages with Y positions so that the top of each a legend item
  28961. // defines the scroll top for each page (#2098)
  28962. allItems.forEach(function (item, i) {
  28963. var y = item._legendItemPos[1],
  28964. h = Math.round(item.legendItem.getBBox().height),
  28965. len = pages.length;
  28966. if (!len || (y - pages[len - 1] > clipHeight &&
  28967. (lastY || y) !== pages[len - 1])) {
  28968. pages.push(lastY || y);
  28969. len++;
  28970. }
  28971. // Keep track of which page each item is on
  28972. item.pageIx = len - 1;
  28973. if (lastY) {
  28974. allItems[i - 1].pageIx = len - 1;
  28975. }
  28976. if (i === allItems.length - 1 &&
  28977. y + h - pages[len - 1] > clipHeight &&
  28978. y !== lastY // #2617
  28979. ) {
  28980. pages.push(y);
  28981. item.pageIx = len;
  28982. }
  28983. if (y !== lastY) {
  28984. lastY = y;
  28985. }
  28986. });
  28987. // Only apply clipping if needed. Clipping causes blurred legend in
  28988. // PDF export (#1787)
  28989. if (!clipRect) {
  28990. clipRect = legend.clipRect =
  28991. renderer.clipRect(0, padding, 9999, 0);
  28992. legend.contentGroup.clip(clipRect);
  28993. }
  28994. clipToHeight(clipHeight);
  28995. // Add navigation elements
  28996. if (!nav) {
  28997. this.nav = nav = renderer.g()
  28998. .attr({ zIndex: 1 })
  28999. .add(this.group);
  29000. this.up = renderer
  29001. .symbol('triangle', 0, 0, arrowSize, arrowSize)
  29002. .add(nav);
  29003. addTracker('upTracker')
  29004. .on('click', function () {
  29005. legend.scroll(-1, animation);
  29006. });
  29007. this.pager = renderer.text('', 15, 10)
  29008. .addClass('highcharts-legend-navigation');
  29009. if (!chart.styledMode) {
  29010. this.pager.css(navOptions.style);
  29011. }
  29012. this.pager.add(nav);
  29013. this.down = renderer
  29014. .symbol('triangle-down', 0, 0, arrowSize, arrowSize)
  29015. .add(nav);
  29016. addTracker('downTracker')
  29017. .on('click', function () {
  29018. legend.scroll(1, animation);
  29019. });
  29020. }
  29021. // Set initial position
  29022. legend.scroll(0);
  29023. legendHeight = spaceHeight;
  29024. // Reset
  29025. }
  29026. else if (nav) {
  29027. clipToHeight();
  29028. this.nav = nav.destroy(); // #6322
  29029. this.scrollGroup.attr({
  29030. translateY: 1
  29031. });
  29032. this.clipHeight = 0; // #1379
  29033. }
  29034. return legendHeight;
  29035. };
  29036. /**
  29037. * Scroll the legend by a number of pages.
  29038. *
  29039. * @private
  29040. * @function Highcharts.Legend#scroll
  29041. *
  29042. * @param {number} scrollBy
  29043. * The number of pages to scroll.
  29044. *
  29045. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
  29046. * Whether and how to apply animation.
  29047. *
  29048. * @return {void}
  29049. */
  29050. Legend.prototype.scroll = function (scrollBy, animation) {
  29051. var _this = this;
  29052. var chart = this.chart,
  29053. pages = this.pages,
  29054. pageCount = pages.length,
  29055. currentPage = this.currentPage + scrollBy,
  29056. clipHeight = this.clipHeight,
  29057. navOptions = this.options.navigation,
  29058. pager = this.pager,
  29059. padding = this.padding;
  29060. // When resizing while looking at the last page
  29061. if (currentPage > pageCount) {
  29062. currentPage = pageCount;
  29063. }
  29064. if (currentPage > 0) {
  29065. if (typeof animation !== 'undefined') {
  29066. setAnimation(animation, chart);
  29067. }
  29068. this.nav.attr({
  29069. translateX: padding,
  29070. translateY: clipHeight + this.padding + 7 + this.titleHeight,
  29071. visibility: 'visible'
  29072. });
  29073. [this.up, this.upTracker].forEach(function (elem) {
  29074. elem.attr({
  29075. 'class': currentPage === 1 ?
  29076. 'highcharts-legend-nav-inactive' :
  29077. 'highcharts-legend-nav-active'
  29078. });
  29079. });
  29080. pager.attr({
  29081. text: currentPage + '/' + pageCount
  29082. });
  29083. [this.down, this.downTracker].forEach(function (elem) {
  29084. elem.attr({
  29085. // adjust to text width
  29086. x: 18 + this.pager.getBBox().width,
  29087. 'class': currentPage === pageCount ?
  29088. 'highcharts-legend-nav-inactive' :
  29089. 'highcharts-legend-nav-active'
  29090. });
  29091. }, this);
  29092. if (!chart.styledMode) {
  29093. this.up
  29094. .attr({
  29095. fill: currentPage === 1 ?
  29096. navOptions.inactiveColor :
  29097. navOptions.activeColor
  29098. });
  29099. this.upTracker
  29100. .css({
  29101. cursor: currentPage === 1 ? 'default' : 'pointer'
  29102. });
  29103. this.down
  29104. .attr({
  29105. fill: currentPage === pageCount ?
  29106. navOptions.inactiveColor :
  29107. navOptions.activeColor
  29108. });
  29109. this.downTracker
  29110. .css({
  29111. cursor: currentPage === pageCount ?
  29112. 'default' :
  29113. 'pointer'
  29114. });
  29115. }
  29116. this.scrollOffset = -pages[currentPage - 1] + this.initialItemY;
  29117. this.scrollGroup.animate({
  29118. translateY: this.scrollOffset
  29119. });
  29120. this.currentPage = currentPage;
  29121. this.positionCheckboxes();
  29122. // Fire event after scroll animation is complete
  29123. var animOptions = animObject(pick(animation,
  29124. chart.renderer.globalAnimation,
  29125. true));
  29126. syncTimeout(function () {
  29127. fireEvent(_this, 'afterScroll', { currentPage: currentPage });
  29128. }, animOptions.duration);
  29129. }
  29130. };
  29131. /**
  29132. * @private
  29133. * @function Highcharts.Legend#setItemEvents
  29134. * @param {Highcharts.BubbleLegend|Point|Highcharts.Series} item
  29135. * @param {Highcharts.SVGElement} legendItem
  29136. * @param {boolean} [useHTML=false]
  29137. * @fires Highcharts.Point#event:legendItemClick
  29138. * @fires Highcharts.Series#event:legendItemClick
  29139. */
  29140. Legend.prototype.setItemEvents = function (item, legendItem, useHTML) {
  29141. var legend = this,
  29142. boxWrapper = legend.chart.renderer.boxWrapper,
  29143. isPoint = item instanceof Point,
  29144. activeClass = 'highcharts-legend-' +
  29145. (isPoint ? 'point' : 'series') + '-active',
  29146. styledMode = legend.chart.styledMode,
  29147. // When `useHTML`, the symbol is rendered in other group, so
  29148. // we need to apply events listeners to both places
  29149. legendItems = useHTML ?
  29150. [legendItem,
  29151. item.legendSymbol] :
  29152. [item.legendGroup];
  29153. // Set the events on the item group, or in case of useHTML, the item
  29154. // itself (#1249)
  29155. legendItems.forEach(function (element) {
  29156. if (element) {
  29157. element
  29158. .on('mouseover', function () {
  29159. if (item.visible) {
  29160. legend.allItems.forEach(function (inactiveItem) {
  29161. if (item !== inactiveItem) {
  29162. inactiveItem.setState('inactive', !isPoint);
  29163. }
  29164. });
  29165. }
  29166. item.setState('hover');
  29167. // A CSS class to dim or hide other than the hovered
  29168. // series.
  29169. // Works only if hovered series is visible (#10071).
  29170. if (item.visible) {
  29171. boxWrapper.addClass(activeClass);
  29172. }
  29173. if (!styledMode) {
  29174. legendItem.css(legend.options.itemHoverStyle);
  29175. }
  29176. })
  29177. .on('mouseout', function () {
  29178. if (!legend.chart.styledMode) {
  29179. legendItem.css(merge(item.visible ?
  29180. legend.itemStyle :
  29181. legend.itemHiddenStyle));
  29182. }
  29183. legend.allItems.forEach(function (inactiveItem) {
  29184. if (item !== inactiveItem) {
  29185. inactiveItem.setState('', !isPoint);
  29186. }
  29187. });
  29188. // A CSS class to dim or hide other than the hovered
  29189. // series.
  29190. boxWrapper.removeClass(activeClass);
  29191. item.setState();
  29192. })
  29193. .on('click', function (event) {
  29194. var strLegendItemClick = 'legendItemClick',
  29195. fnLegendItemClick = function () {
  29196. if (item.setVisible) {
  29197. item.setVisible();
  29198. }
  29199. // Reset inactive state
  29200. legend.allItems.forEach(function (inactiveItem) {
  29201. if (item !== inactiveItem) {
  29202. inactiveItem.setState(item.visible ? 'inactive' : '', !isPoint);
  29203. }
  29204. });
  29205. };
  29206. // A CSS class to dim or hide other than the hovered
  29207. // series. Event handling in iOS causes the activeClass
  29208. // to be added prior to click in some cases (#7418).
  29209. boxWrapper.removeClass(activeClass);
  29210. // Pass over the click/touch event. #4.
  29211. event = {
  29212. browserEvent: event
  29213. };
  29214. // click the name or symbol
  29215. if (item.firePointEvent) { // point
  29216. item.firePointEvent(strLegendItemClick, event, fnLegendItemClick);
  29217. }
  29218. else {
  29219. fireEvent(item, strLegendItemClick, event, fnLegendItemClick);
  29220. }
  29221. });
  29222. }
  29223. });
  29224. };
  29225. /**
  29226. * @private
  29227. * @function Highcharts.Legend#createCheckboxForItem
  29228. * @param {Highcharts.BubbleLegend|Point|Highcharts.Series} item
  29229. * @fires Highcharts.Series#event:checkboxClick
  29230. */
  29231. Legend.prototype.createCheckboxForItem = function (item) {
  29232. var legend = this;
  29233. item.checkbox = createElement('input', {
  29234. type: 'checkbox',
  29235. className: 'highcharts-legend-checkbox',
  29236. checked: item.selected,
  29237. defaultChecked: item.selected // required by IE7
  29238. }, legend.options.itemCheckboxStyle, legend.chart.container);
  29239. addEvent(item.checkbox, 'click', function (event) {
  29240. var target = event.target;
  29241. fireEvent(item.series || item, 'checkboxClick', {
  29242. checked: target.checked,
  29243. item: item
  29244. }, function () {
  29245. item.select();
  29246. });
  29247. });
  29248. };
  29249. return Legend;
  29250. }());
  29251. // Workaround for #2030, horizontal legend items not displaying in IE11 Preview,
  29252. // and for #2580, a similar drawing flaw in Firefox 26.
  29253. // Explore if there's a general cause for this. The problem may be related
  29254. // to nested group elements, as the legend item texts are within 4 group
  29255. // elements.
  29256. if (/Trident\/7\.0/.test(win.navigator && win.navigator.userAgent) ||
  29257. isFirefox) {
  29258. wrap(Legend.prototype, 'positionItem', function (proceed, item) {
  29259. var legend = this,
  29260. // If chart destroyed in sync, this is undefined (#2030)
  29261. runPositionItem = function () {
  29262. if (item._legendItemPos) {
  29263. proceed.call(legend,
  29264. item);
  29265. }
  29266. };
  29267. // Do it now, for export and to get checkbox placement
  29268. runPositionItem();
  29269. // Do it after to work around the core issue
  29270. if (!legend.bubbleLegend) {
  29271. setTimeout(runPositionItem);
  29272. }
  29273. });
  29274. }
  29275. H.Legend = Legend;
  29276. return H.Legend;
  29277. });
  29278. _registerModule(_modules, 'Core/Series/SeriesRegistry.js', [_modules['Core/Globals.js'], _modules['Core/DefaultOptions.js'], _modules['Core/Series/Point.js'], _modules['Core/Utilities.js']], function (H, D, Point, U) {
  29279. /* *
  29280. *
  29281. * (c) 2010-2021 Torstein Honsi
  29282. *
  29283. * License: www.highcharts.com/license
  29284. *
  29285. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  29286. *
  29287. * */
  29288. var defaultOptions = D.defaultOptions;
  29289. var error = U.error,
  29290. extendClass = U.extendClass,
  29291. merge = U.merge;
  29292. /* *
  29293. *
  29294. * Namespace
  29295. *
  29296. * */
  29297. var SeriesRegistry;
  29298. (function (SeriesRegistry) {
  29299. /* *
  29300. *
  29301. * Static Properties
  29302. *
  29303. * */
  29304. /**
  29305. * @internal
  29306. * @todo Move `Globals.seriesTypes` code to her.
  29307. */
  29308. SeriesRegistry.seriesTypes = H.seriesTypes;
  29309. /* *
  29310. *
  29311. * Static Functions
  29312. *
  29313. * */
  29314. /* eslint-disable valid-jsdoc */
  29315. /**
  29316. * Internal function to initialize an individual series.
  29317. * @private
  29318. */
  29319. function getSeries(chart, options) {
  29320. if (options === void 0) { options = {}; }
  29321. var optionsChart = chart.options.chart,
  29322. type = (options.type ||
  29323. optionsChart.type ||
  29324. optionsChart.defaultSeriesType ||
  29325. ''),
  29326. SeriesClass = SeriesRegistry.seriesTypes[type];
  29327. // No such series type
  29328. if (!SeriesRegistry) {
  29329. error(17, true, chart, { missingModuleFor: type });
  29330. }
  29331. var series = new SeriesClass();
  29332. if (typeof series.init === 'function') {
  29333. series.init(chart, options);
  29334. }
  29335. return series;
  29336. }
  29337. SeriesRegistry.getSeries = getSeries;
  29338. /**
  29339. * Registers class pattern of a series.
  29340. *
  29341. * @private
  29342. */
  29343. function registerSeriesType(seriesType, seriesClass) {
  29344. var defaultPlotOptions = defaultOptions.plotOptions || {},
  29345. seriesOptions = seriesClass.defaultOptions;
  29346. if (!seriesClass.prototype.pointClass) {
  29347. seriesClass.prototype.pointClass = Point;
  29348. }
  29349. seriesClass.prototype.type = seriesType;
  29350. if (seriesOptions) {
  29351. defaultPlotOptions[seriesType] = seriesOptions;
  29352. }
  29353. SeriesRegistry.seriesTypes[seriesType] = seriesClass;
  29354. }
  29355. SeriesRegistry.registerSeriesType = registerSeriesType;
  29356. /**
  29357. * Old factory to create new series prototypes.
  29358. *
  29359. * @deprecated
  29360. * @function Highcharts.seriesType
  29361. *
  29362. * @param {string} type
  29363. * The series type name.
  29364. *
  29365. * @param {string} parent
  29366. * The parent series type name. Use `line` to inherit from the basic
  29367. * {@link Series} object.
  29368. *
  29369. * @param {Highcharts.SeriesOptionsType|Highcharts.Dictionary<*>} options
  29370. * The additional default options that are merged with the parent's options.
  29371. *
  29372. * @param {Highcharts.Dictionary<*>} [props]
  29373. * The properties (functions and primitives) to set on the new prototype.
  29374. *
  29375. * @param {Highcharts.Dictionary<*>} [pointProps]
  29376. * Members for a series-specific extension of the {@link Point} prototype if
  29377. * needed.
  29378. *
  29379. * @return {Highcharts.Series}
  29380. * The newly created prototype as extended from {@link Series} or its
  29381. * derivatives.
  29382. */
  29383. function seriesType(type, parent, options, seriesProto, pointProto) {
  29384. var defaultPlotOptions = defaultOptions.plotOptions || {};
  29385. parent = parent || '';
  29386. // Merge the options
  29387. defaultPlotOptions[type] = merge(defaultPlotOptions[parent], options);
  29388. // Create the class
  29389. registerSeriesType(type, extendClass(SeriesRegistry.seriesTypes[parent] || function () { }, seriesProto));
  29390. SeriesRegistry.seriesTypes[type].prototype.type = type;
  29391. // Create the point class if needed
  29392. if (pointProto) {
  29393. SeriesRegistry.seriesTypes[type].prototype.pointClass =
  29394. extendClass(Point, pointProto);
  29395. }
  29396. return SeriesRegistry.seriesTypes[type];
  29397. }
  29398. SeriesRegistry.seriesType = seriesType;
  29399. /* eslint-enable valid-jsdoc */
  29400. })(SeriesRegistry || (SeriesRegistry = {}));
  29401. /* *
  29402. *
  29403. * Compatibility
  29404. *
  29405. * */
  29406. H.seriesType = SeriesRegistry.seriesType;
  29407. /* *
  29408. *
  29409. * Export
  29410. *
  29411. * */
  29412. return SeriesRegistry;
  29413. });
  29414. _registerModule(_modules, 'Core/Chart/Chart.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Axis/Axis.js'], _modules['Core/FormatUtilities.js'], _modules['Core/Foundation.js'], _modules['Core/Globals.js'], _modules['Core/Legend.js'], _modules['Core/MSPointer.js'], _modules['Core/DefaultOptions.js'], _modules['Core/Color/Palette.js'], _modules['Core/Pointer.js'], _modules['Core/Renderer/RendererRegistry.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Time.js'], _modules['Core/Utilities.js'], _modules['Core/Renderer/HTML/AST.js']], function (A, Axis, FormatUtilities, Foundation, H, Legend, MSPointer, D, palette, Pointer, RendererRegistry, SeriesRegistry, Time, U, AST) {
  29415. /* *
  29416. *
  29417. * (c) 2010-2021 Torstein Honsi
  29418. *
  29419. * License: www.highcharts.com/license
  29420. *
  29421. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  29422. *
  29423. * */
  29424. var animate = A.animate,
  29425. animObject = A.animObject,
  29426. setAnimation = A.setAnimation;
  29427. var numberFormat = FormatUtilities.numberFormat;
  29428. var registerEventOptions = Foundation.registerEventOptions;
  29429. var charts = H.charts,
  29430. doc = H.doc,
  29431. marginNames = H.marginNames,
  29432. win = H.win;
  29433. var defaultOptions = D.defaultOptions,
  29434. defaultTime = D.defaultTime;
  29435. var seriesTypes = SeriesRegistry.seriesTypes;
  29436. var addEvent = U.addEvent,
  29437. attr = U.attr,
  29438. cleanRecursively = U.cleanRecursively,
  29439. createElement = U.createElement,
  29440. css = U.css,
  29441. defined = U.defined,
  29442. discardElement = U.discardElement,
  29443. erase = U.erase,
  29444. error = U.error,
  29445. extend = U.extend,
  29446. find = U.find,
  29447. fireEvent = U.fireEvent,
  29448. getStyle = U.getStyle,
  29449. isArray = U.isArray,
  29450. isFunction = U.isFunction,
  29451. isNumber = U.isNumber,
  29452. isObject = U.isObject,
  29453. isString = U.isString,
  29454. merge = U.merge,
  29455. objectEach = U.objectEach,
  29456. pick = U.pick,
  29457. pInt = U.pInt,
  29458. relativeLength = U.relativeLength,
  29459. removeEvent = U.removeEvent,
  29460. splat = U.splat,
  29461. syncTimeout = U.syncTimeout,
  29462. uniqueKey = U.uniqueKey;
  29463. /* *
  29464. *
  29465. * Class
  29466. *
  29467. * */
  29468. /* eslint-disable no-invalid-this, valid-jsdoc */
  29469. /**
  29470. * The Chart class. The recommended constructor is {@link Highcharts#chart}.
  29471. *
  29472. * @example
  29473. * let chart = Highcharts.chart('container', {
  29474. * title: {
  29475. * text: 'My chart'
  29476. * },
  29477. * series: [{
  29478. * data: [1, 3, 2, 4]
  29479. * }]
  29480. * })
  29481. *
  29482. * @class
  29483. * @name Highcharts.Chart
  29484. *
  29485. * @param {string|Highcharts.HTMLDOMElement} [renderTo]
  29486. * The DOM element to render to, or its id.
  29487. *
  29488. * @param {Highcharts.Options} options
  29489. * The chart options structure.
  29490. *
  29491. * @param {Highcharts.ChartCallbackFunction} [callback]
  29492. * Function to run when the chart has loaded and and all external images
  29493. * are loaded. Defining a
  29494. * [chart.events.load](https://api.highcharts.com/highcharts/chart.events.load)
  29495. * handler is equivalent.
  29496. */
  29497. var Chart = /** @class */ (function () {
  29498. function Chart(a, b, c) {
  29499. this.axes = void 0;
  29500. this.axisOffset = void 0;
  29501. this.bounds = void 0;
  29502. this.chartHeight = void 0;
  29503. this.chartWidth = void 0;
  29504. this.clipBox = void 0;
  29505. this.colorCounter = void 0;
  29506. this.container = void 0;
  29507. this.eventOptions = void 0;
  29508. this.index = void 0;
  29509. this.isResizing = void 0;
  29510. this.labelCollectors = void 0;
  29511. this.legend = void 0;
  29512. this.margin = void 0;
  29513. this.numberFormatter = void 0;
  29514. this.options = void 0;
  29515. this.plotBox = void 0;
  29516. this.plotHeight = void 0;
  29517. this.plotLeft = void 0;
  29518. this.plotTop = void 0;
  29519. this.plotWidth = void 0;
  29520. this.pointCount = void 0;
  29521. this.pointer = void 0;
  29522. this.renderer = void 0;
  29523. this.renderTo = void 0;
  29524. this.series = void 0;
  29525. this.sharedClips = {};
  29526. this.spacing = void 0;
  29527. this.spacingBox = void 0;
  29528. this.symbolCounter = void 0;
  29529. this.time = void 0;
  29530. this.titleOffset = void 0;
  29531. this.userOptions = void 0;
  29532. this.xAxis = void 0;
  29533. this.yAxis = void 0;
  29534. this.getArgs(a, b, c);
  29535. }
  29536. /**
  29537. * Factory function for basic charts.
  29538. *
  29539. * @example
  29540. * // Render a chart in to div#container
  29541. * let chart = Highcharts.chart('container', {
  29542. * title: {
  29543. * text: 'My chart'
  29544. * },
  29545. * series: [{
  29546. * data: [1, 3, 2, 4]
  29547. * }]
  29548. * });
  29549. *
  29550. * @function Highcharts.chart
  29551. *
  29552. * @param {string|Highcharts.HTMLDOMElement} [renderTo]
  29553. * The DOM element to render to, or its id.
  29554. *
  29555. * @param {Highcharts.Options} options
  29556. * The chart options structure.
  29557. *
  29558. * @param {Highcharts.ChartCallbackFunction} [callback]
  29559. * Function to run when the chart has loaded and and all external images are
  29560. * loaded. Defining a
  29561. * [chart.events.load](https://api.highcharts.com/highcharts/chart.events.load)
  29562. * handler is equivalent.
  29563. *
  29564. * @return {Highcharts.Chart}
  29565. * Returns the Chart object.
  29566. */
  29567. Chart.chart = function (a, b, c) {
  29568. return new Chart(a, b, c);
  29569. };
  29570. /* *
  29571. *
  29572. * Functions
  29573. *
  29574. * */
  29575. /**
  29576. * Handle the arguments passed to the constructor.
  29577. *
  29578. * @private
  29579. * @function Highcharts.Chart#getArgs
  29580. *
  29581. * @param {...Array<*>} arguments
  29582. * All arguments for the constructor.
  29583. *
  29584. * @fires Highcharts.Chart#event:init
  29585. * @fires Highcharts.Chart#event:afterInit
  29586. */
  29587. Chart.prototype.getArgs = function (a, b, c) {
  29588. // Remove the optional first argument, renderTo, and
  29589. // set it on this.
  29590. if (isString(a) || a.nodeName) {
  29591. this.renderTo = a;
  29592. this.init(b, c);
  29593. }
  29594. else {
  29595. this.init(a, b);
  29596. }
  29597. };
  29598. /**
  29599. * Overridable function that initializes the chart. The constructor's
  29600. * arguments are passed on directly.
  29601. *
  29602. * @function Highcharts.Chart#init
  29603. *
  29604. * @param {Highcharts.Options} userOptions
  29605. * Custom options.
  29606. *
  29607. * @param {Function} [callback]
  29608. * Function to run when the chart has loaded and and all external
  29609. * images are loaded.
  29610. *
  29611. * @return {void}
  29612. *
  29613. * @fires Highcharts.Chart#event:init
  29614. * @fires Highcharts.Chart#event:afterInit
  29615. */
  29616. Chart.prototype.init = function (userOptions, callback) {
  29617. // Handle regular options
  29618. var userPlotOptions = userOptions.plotOptions || {};
  29619. // Fire the event with a default function
  29620. fireEvent(this, 'init', { args: arguments }, function () {
  29621. var options = merge(defaultOptions,
  29622. userOptions); // do the merge
  29623. var optionsChart = options.chart;
  29624. // Override (by copy of user options) or clear tooltip options
  29625. // in chart.options.plotOptions (#6218)
  29626. objectEach(options.plotOptions, function (typeOptions, type) {
  29627. if (isObject(typeOptions)) { // #8766
  29628. typeOptions.tooltip = (userPlotOptions[type] && // override by copy:
  29629. merge(userPlotOptions[type].tooltip)) || void 0; // or clear
  29630. }
  29631. });
  29632. // User options have higher priority than default options
  29633. // (#6218). In case of exporting: path is changed
  29634. options.tooltip.userOptions = (userOptions.chart &&
  29635. userOptions.chart.forExport &&
  29636. userOptions.tooltip.userOptions) || userOptions.tooltip;
  29637. /**
  29638. * The original options given to the constructor or a chart factory
  29639. * like {@link Highcharts.chart} and {@link Highcharts.stockChart}.
  29640. *
  29641. * @name Highcharts.Chart#userOptions
  29642. * @type {Highcharts.Options}
  29643. */
  29644. this.userOptions = userOptions;
  29645. this.margin = [];
  29646. this.spacing = [];
  29647. // Pixel data bounds for touch zoom
  29648. this.bounds = { h: {}, v: {} };
  29649. // An array of functions that returns labels that should be
  29650. // considered for anti-collision
  29651. this.labelCollectors = [];
  29652. this.callback = callback;
  29653. this.isResizing = 0;
  29654. /**
  29655. * The options structure for the chart after merging
  29656. * {@link #defaultOptions} and {@link #userOptions}. It contains
  29657. * members for the sub elements like series, legend, tooltip etc.
  29658. *
  29659. * @name Highcharts.Chart#options
  29660. * @type {Highcharts.Options}
  29661. */
  29662. this.options = options;
  29663. /**
  29664. * All the axes in the chart.
  29665. *
  29666. * @see Highcharts.Chart.xAxis
  29667. * @see Highcharts.Chart.yAxis
  29668. *
  29669. * @name Highcharts.Chart#axes
  29670. * @type {Array<Highcharts.Axis>}
  29671. */
  29672. this.axes = [];
  29673. /**
  29674. * All the current series in the chart.
  29675. *
  29676. * @name Highcharts.Chart#series
  29677. * @type {Array<Highcharts.Series>}
  29678. */
  29679. this.series = [];
  29680. /**
  29681. * The `Time` object associated with the chart. Since v6.0.5,
  29682. * time settings can be applied individually for each chart. If
  29683. * no individual settings apply, the `Time` object is shared by
  29684. * all instances.
  29685. *
  29686. * @name Highcharts.Chart#time
  29687. * @type {Highcharts.Time}
  29688. */
  29689. this.time =
  29690. userOptions.time && Object.keys(userOptions.time).length ?
  29691. new Time(userOptions.time) :
  29692. H.time;
  29693. /**
  29694. * Callback function to override the default function that formats
  29695. * all the numbers in the chart. Returns a string with the formatted
  29696. * number.
  29697. *
  29698. * @name Highcharts.Chart#numberFormatter
  29699. * @type {Highcharts.NumberFormatterCallbackFunction}
  29700. */
  29701. this.numberFormatter = optionsChart.numberFormatter || numberFormat;
  29702. /**
  29703. * Whether the chart is in styled mode, meaning all presentatinoal
  29704. * attributes are avoided.
  29705. *
  29706. * @name Highcharts.Chart#styledMode
  29707. * @type {boolean}
  29708. */
  29709. this.styledMode = optionsChart.styledMode;
  29710. this.hasCartesianSeries = optionsChart.showAxes;
  29711. var chart = this;
  29712. /**
  29713. * Index position of the chart in the {@link Highcharts#charts}
  29714. * property.
  29715. *
  29716. * @name Highcharts.Chart#index
  29717. * @type {number}
  29718. * @readonly
  29719. */
  29720. chart.index = charts.length; // Add the chart to the global lookup
  29721. charts.push(chart);
  29722. H.chartCount++;
  29723. // Chart event handlers
  29724. registerEventOptions(this, optionsChart);
  29725. /**
  29726. * A collection of the X axes in the chart.
  29727. *
  29728. * @name Highcharts.Chart#xAxis
  29729. * @type {Array<Highcharts.Axis>}
  29730. */
  29731. chart.xAxis = [];
  29732. /**
  29733. * A collection of the Y axes in the chart.
  29734. *
  29735. * @name Highcharts.Chart#yAxis
  29736. * @type {Array<Highcharts.Axis>}
  29737. *
  29738. * @todo
  29739. * Make events official: Fire the event `afterInit`.
  29740. */
  29741. chart.yAxis = [];
  29742. chart.pointCount = chart.colorCounter = chart.symbolCounter = 0;
  29743. // Fire after init but before first render, before axes and series
  29744. // have been initialized.
  29745. fireEvent(chart, 'afterInit');
  29746. chart.firstRender();
  29747. });
  29748. };
  29749. /**
  29750. * Internal function to unitialize an individual series.
  29751. *
  29752. * @private
  29753. * @function Highcharts.Chart#initSeries
  29754. */
  29755. Chart.prototype.initSeries = function (options) {
  29756. var chart = this,
  29757. optionsChart = chart.options.chart,
  29758. type = (options.type ||
  29759. optionsChart.type ||
  29760. optionsChart.defaultSeriesType),
  29761. SeriesClass = seriesTypes[type];
  29762. // No such series type
  29763. if (!SeriesClass) {
  29764. error(17, true, chart, { missingModuleFor: type });
  29765. }
  29766. var series = new SeriesClass();
  29767. if (typeof series.init === 'function') {
  29768. series.init(chart, options);
  29769. }
  29770. return series;
  29771. };
  29772. /**
  29773. * Internal function to set data for all series with enabled sorting.
  29774. *
  29775. * @private
  29776. * @function Highcharts.Chart#setSeriesData
  29777. */
  29778. Chart.prototype.setSeriesData = function () {
  29779. this.getSeriesOrderByLinks().forEach(function (series) {
  29780. // We need to set data for series with sorting after series init
  29781. if (!series.points && !series.data && series.enabledDataSorting) {
  29782. series.setData(series.options.data, false);
  29783. }
  29784. });
  29785. };
  29786. /**
  29787. * Sort and return chart series in order depending on the number of linked
  29788. * series.
  29789. *
  29790. * @private
  29791. * @function Highcharts.Series#getSeriesOrderByLinks
  29792. * @return {Array<Highcharts.Series>}
  29793. */
  29794. Chart.prototype.getSeriesOrderByLinks = function () {
  29795. return this.series.concat().sort(function (a, b) {
  29796. if (a.linkedSeries.length || b.linkedSeries.length) {
  29797. return b.linkedSeries.length - a.linkedSeries.length;
  29798. }
  29799. return 0;
  29800. });
  29801. };
  29802. /**
  29803. * Order all series above a given index. When series are added and ordered
  29804. * by configuration, only the last series is handled (#248, #1123, #2456,
  29805. * #6112). This function is called on series initialization and destroy.
  29806. *
  29807. * @private
  29808. * @function Highcharts.Series#orderSeries
  29809. * @param {number} [fromIndex]
  29810. * If this is given, only the series above this index are handled.
  29811. */
  29812. Chart.prototype.orderSeries = function (fromIndex) {
  29813. var series = this.series;
  29814. for (var i = (fromIndex || 0), iEnd = series.length; i < iEnd; ++i) {
  29815. if (series[i]) {
  29816. /**
  29817. * Contains the series' index in the `Chart.series` array.
  29818. *
  29819. * @name Highcharts.Series#index
  29820. * @type {number}
  29821. * @readonly
  29822. */
  29823. series[i].index = i;
  29824. series[i].name = series[i].getName();
  29825. }
  29826. }
  29827. };
  29828. /**
  29829. * Check whether a given point is within the plot area.
  29830. *
  29831. * @function Highcharts.Chart#isInsidePlot
  29832. *
  29833. * @param {number} plotX
  29834. * Pixel x relative to the plot area.
  29835. *
  29836. * @param {number} plotY
  29837. * Pixel y relative to the plot area.
  29838. *
  29839. * @param {Highcharts.ChartIsInsideOptionsObject} [options]
  29840. * Options object.
  29841. *
  29842. * @return {boolean}
  29843. * Returns true if the given point is inside the plot area.
  29844. */
  29845. Chart.prototype.isInsidePlot = function (plotX, plotY, options) {
  29846. var _a;
  29847. if (options === void 0) { options = {}; }
  29848. var _b = this,
  29849. inverted = _b.inverted,
  29850. plotBox = _b.plotBox,
  29851. plotLeft = _b.plotLeft,
  29852. plotTop = _b.plotTop,
  29853. scrollablePlotBox = _b.scrollablePlotBox;
  29854. var scrollLeft = 0,
  29855. scrollTop = 0;
  29856. if (options.visiblePlotOnly && this.scrollingContainer) {
  29857. (_a = this.scrollingContainer, scrollLeft = _a.scrollLeft, scrollTop = _a.scrollTop);
  29858. }
  29859. var series = options.series,
  29860. box = (options.visiblePlotOnly && scrollablePlotBox) || plotBox,
  29861. x = options.inverted ? plotY : plotX,
  29862. y = options.inverted ? plotX : plotY,
  29863. e = {
  29864. x: x,
  29865. y: y,
  29866. isInsidePlot: true
  29867. };
  29868. if (!options.ignoreX) {
  29869. var xAxis = (series && (inverted ? series.yAxis : series.xAxis)) || {
  29870. pos: plotLeft,
  29871. len: Infinity
  29872. };
  29873. var chartX = options.paneCoordinates ? xAxis.pos + x : plotLeft + x;
  29874. if (!(chartX >= Math.max(scrollLeft + plotLeft, xAxis.pos) &&
  29875. chartX <= Math.min(scrollLeft + plotLeft + box.width, xAxis.pos + xAxis.len))) {
  29876. e.isInsidePlot = false;
  29877. }
  29878. }
  29879. if (!options.ignoreY && e.isInsidePlot) {
  29880. var yAxis = (series && (inverted ? series.xAxis : series.yAxis)) || {
  29881. pos: plotTop,
  29882. len: Infinity
  29883. };
  29884. var chartY = options.paneCoordinates ? yAxis.pos + y : plotTop + y;
  29885. if (!(chartY >= Math.max(scrollTop + plotTop, yAxis.pos) &&
  29886. chartY <= Math.min(scrollTop + plotTop + box.height, yAxis.pos + yAxis.len))) {
  29887. e.isInsidePlot = false;
  29888. }
  29889. }
  29890. fireEvent(this, 'afterIsInsidePlot', e);
  29891. return e.isInsidePlot;
  29892. };
  29893. /**
  29894. * Redraw the chart after changes have been done to the data, axis extremes
  29895. * chart size or chart elements. All methods for updating axes, series or
  29896. * points have a parameter for redrawing the chart. This is `true` by
  29897. * default. But in many cases you want to do more than one operation on the
  29898. * chart before redrawing, for example add a number of points. In those
  29899. * cases it is a waste of resources to redraw the chart for each new point
  29900. * added. So you add the points and call `chart.redraw()` after.
  29901. *
  29902. * @function Highcharts.Chart#redraw
  29903. *
  29904. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
  29905. * If or how to apply animation to the redraw.
  29906. *
  29907. * @fires Highcharts.Chart#event:afterSetExtremes
  29908. * @fires Highcharts.Chart#event:beforeRedraw
  29909. * @fires Highcharts.Chart#event:predraw
  29910. * @fires Highcharts.Chart#event:redraw
  29911. * @fires Highcharts.Chart#event:render
  29912. * @fires Highcharts.Chart#event:updatedData
  29913. */
  29914. Chart.prototype.redraw = function (animation) {
  29915. fireEvent(this, 'beforeRedraw');
  29916. var chart = this,
  29917. axes = chart.hasCartesianSeries ? chart.axes : chart.colorAxis || [],
  29918. series = chart.series,
  29919. pointer = chart.pointer,
  29920. legend = chart.legend,
  29921. legendUserOptions = chart.userOptions.legend,
  29922. renderer = chart.renderer,
  29923. isHiddenChart = renderer.isHidden(),
  29924. afterRedraw = [];
  29925. var hasDirtyStacks,
  29926. hasStackedSeries,
  29927. i,
  29928. isDirtyBox = chart.isDirtyBox,
  29929. redrawLegend = chart.isDirtyLegend,
  29930. serie;
  29931. // Handle responsive rules, not only on resize (#6130)
  29932. if (chart.setResponsive) {
  29933. chart.setResponsive(false);
  29934. }
  29935. // Set the global animation. When chart.hasRendered is not true, the
  29936. // redraw call comes from a responsive rule and animation should not
  29937. // occur.
  29938. setAnimation(chart.hasRendered ? animation : false, chart);
  29939. if (isHiddenChart) {
  29940. chart.temporaryDisplay();
  29941. }
  29942. // Adjust title layout (reflow multiline text)
  29943. chart.layOutTitles();
  29944. // link stacked series
  29945. i = series.length;
  29946. while (i--) {
  29947. serie = series[i];
  29948. if (serie.options.stacking || serie.options.centerInCategory) {
  29949. hasStackedSeries = true;
  29950. if (serie.isDirty) {
  29951. hasDirtyStacks = true;
  29952. break;
  29953. }
  29954. }
  29955. }
  29956. if (hasDirtyStacks) { // mark others as dirty
  29957. i = series.length;
  29958. while (i--) {
  29959. serie = series[i];
  29960. if (serie.options.stacking) {
  29961. serie.isDirty = true;
  29962. }
  29963. }
  29964. }
  29965. // Handle updated data in the series
  29966. series.forEach(function (serie) {
  29967. if (serie.isDirty) {
  29968. if (serie.options.legendType === 'point') {
  29969. if (typeof serie.updateTotals === 'function') {
  29970. serie.updateTotals();
  29971. }
  29972. redrawLegend = true;
  29973. }
  29974. else if (legendUserOptions &&
  29975. (legendUserOptions.labelFormatter ||
  29976. legendUserOptions.labelFormat)) {
  29977. redrawLegend = true; // #2165
  29978. }
  29979. }
  29980. if (serie.isDirtyData) {
  29981. fireEvent(serie, 'updatedData');
  29982. }
  29983. });
  29984. // handle added or removed series
  29985. if (redrawLegend && legend && legend.options.enabled) {
  29986. // draw legend graphics
  29987. legend.render();
  29988. chart.isDirtyLegend = false;
  29989. }
  29990. // reset stacks
  29991. if (hasStackedSeries) {
  29992. chart.getStacks();
  29993. }
  29994. // set axes scales
  29995. axes.forEach(function (axis) {
  29996. axis.updateNames();
  29997. axis.setScale();
  29998. });
  29999. chart.getMargins(); // #3098
  30000. // If one axis is dirty, all axes must be redrawn (#792, #2169)
  30001. axes.forEach(function (axis) {
  30002. if (axis.isDirty) {
  30003. isDirtyBox = true;
  30004. }
  30005. });
  30006. // redraw axes
  30007. axes.forEach(function (axis) {
  30008. // Fire 'afterSetExtremes' only if extremes are set
  30009. var key = axis.min + ',' + axis.max;
  30010. if (axis.extKey !== key) { // #821, #4452
  30011. axis.extKey = key;
  30012. // prevent a recursive call to chart.redraw() (#1119)
  30013. afterRedraw.push(function () {
  30014. fireEvent(axis, 'afterSetExtremes', extend(axis.eventArgs, axis.getExtremes())); // #747, #751
  30015. delete axis.eventArgs;
  30016. });
  30017. }
  30018. if (isDirtyBox || hasStackedSeries) {
  30019. axis.redraw();
  30020. }
  30021. });
  30022. // the plot areas size has changed
  30023. if (isDirtyBox) {
  30024. chart.drawChartBox();
  30025. }
  30026. // Fire an event before redrawing series, used by the boost module to
  30027. // clear previous series renderings.
  30028. fireEvent(chart, 'predraw');
  30029. // redraw affected series
  30030. series.forEach(function (serie) {
  30031. if ((isDirtyBox || serie.isDirty) && serie.visible) {
  30032. serie.redraw();
  30033. }
  30034. // Set it here, otherwise we will have unlimited 'updatedData' calls
  30035. // for a hidden series after setData(). Fixes #6012
  30036. serie.isDirtyData = false;
  30037. });
  30038. // move tooltip or reset
  30039. if (pointer) {
  30040. pointer.reset(true);
  30041. }
  30042. // redraw if canvas
  30043. renderer.draw();
  30044. // Fire the events
  30045. fireEvent(chart, 'redraw');
  30046. fireEvent(chart, 'render');
  30047. if (isHiddenChart) {
  30048. chart.temporaryDisplay(true);
  30049. }
  30050. // Fire callbacks that are put on hold until after the redraw
  30051. afterRedraw.forEach(function (callback) {
  30052. callback.call();
  30053. });
  30054. };
  30055. /**
  30056. * Get an axis, series or point object by `id` as given in the configuration
  30057. * options. Returns `undefined` if no item is found.
  30058. *
  30059. * @sample highcharts/plotoptions/series-id/
  30060. * Get series by id
  30061. *
  30062. * @function Highcharts.Chart#get
  30063. *
  30064. * @param {string} id
  30065. * The id as given in the configuration options.
  30066. *
  30067. * @return {Highcharts.Axis|Highcharts.Series|Highcharts.Point|undefined}
  30068. * The retrieved item.
  30069. */
  30070. Chart.prototype.get = function (id) {
  30071. var series = this.series;
  30072. /**
  30073. * @private
  30074. * @param {Highcharts.Axis|Highcharts.Series} item
  30075. * @return {boolean}
  30076. */
  30077. function itemById(item) {
  30078. return (item.id === id ||
  30079. (item.options && item.options.id === id));
  30080. }
  30081. var ret =
  30082. // Search axes
  30083. find(this.axes,
  30084. itemById) ||
  30085. // Search series
  30086. find(this.series,
  30087. itemById);
  30088. // Search points
  30089. for (var i = 0; !ret && i < series.length; i++) {
  30090. ret = find(series[i].points || [], itemById);
  30091. }
  30092. return ret;
  30093. };
  30094. /**
  30095. * Create the Axis instances based on the config options.
  30096. *
  30097. * @private
  30098. * @function Highcharts.Chart#getAxes
  30099. * @fires Highcharts.Chart#event:afterGetAxes
  30100. * @fires Highcharts.Chart#event:getAxes
  30101. */
  30102. Chart.prototype.getAxes = function () {
  30103. var chart = this,
  30104. options = this.options,
  30105. xAxisOptions = options.xAxis = splat(options.xAxis || {}),
  30106. yAxisOptions = options.yAxis = splat(options.yAxis || {});
  30107. fireEvent(this, 'getAxes');
  30108. // make sure the options are arrays and add some members
  30109. xAxisOptions.forEach(function (axis, i) {
  30110. axis.index = i;
  30111. axis.isX = true;
  30112. });
  30113. yAxisOptions.forEach(function (axis, i) {
  30114. axis.index = i;
  30115. });
  30116. // concatenate all axis options into one array
  30117. var optionsArray = xAxisOptions.concat(yAxisOptions);
  30118. optionsArray.forEach(function (axisOptions) {
  30119. new Axis(chart, axisOptions); // eslint-disable-line no-new
  30120. });
  30121. fireEvent(this, 'afterGetAxes');
  30122. };
  30123. /**
  30124. * Returns an array of all currently selected points in the chart. Points
  30125. * can be selected by clicking or programmatically by the
  30126. * {@link Highcharts.Point#select}
  30127. * function.
  30128. *
  30129. * @sample highcharts/plotoptions/series-allowpointselect-line/
  30130. * Get selected points
  30131. *
  30132. * @function Highcharts.Chart#getSelectedPoints
  30133. *
  30134. * @return {Array<Highcharts.Point>}
  30135. * The currently selected points.
  30136. */
  30137. Chart.prototype.getSelectedPoints = function () {
  30138. var points = [];
  30139. this.series.forEach(function (serie) {
  30140. // For one-to-one points inspect series.data in order to retrieve
  30141. // points outside the visible range (#6445). For grouped data,
  30142. // inspect the generated series.points.
  30143. points = points.concat(serie.getPointsCollection().filter(function (point) {
  30144. return pick(point.selectedStaging, point.selected);
  30145. }));
  30146. });
  30147. return points;
  30148. };
  30149. /**
  30150. * Returns an array of all currently selected series in the chart. Series
  30151. * can be selected either programmatically by the
  30152. * {@link Highcharts.Series#select}
  30153. * function or by checking the checkbox next to the legend item if
  30154. * [series.showCheckBox](https://api.highcharts.com/highcharts/plotOptions.series.showCheckbox)
  30155. * is true.
  30156. *
  30157. * @sample highcharts/members/chart-getselectedseries/
  30158. * Get selected series
  30159. *
  30160. * @function Highcharts.Chart#getSelectedSeries
  30161. *
  30162. * @return {Array<Highcharts.Series>}
  30163. * The currently selected series.
  30164. */
  30165. Chart.prototype.getSelectedSeries = function () {
  30166. return this.series.filter(function (serie) {
  30167. return serie.selected;
  30168. });
  30169. };
  30170. /**
  30171. * Set a new title or subtitle for the chart.
  30172. *
  30173. * @sample highcharts/members/chart-settitle/
  30174. * Set title text and styles
  30175. *
  30176. * @function Highcharts.Chart#setTitle
  30177. *
  30178. * @param {Highcharts.TitleOptions} [titleOptions]
  30179. * New title options. The title text itself is set by the
  30180. * `titleOptions.text` property.
  30181. *
  30182. * @param {Highcharts.SubtitleOptions} [subtitleOptions]
  30183. * New subtitle options. The subtitle text itself is set by the
  30184. * `subtitleOptions.text` property.
  30185. *
  30186. * @param {boolean} [redraw]
  30187. * Whether to redraw the chart or wait for a later call to
  30188. * `chart.redraw()`.
  30189. */
  30190. Chart.prototype.setTitle = function (titleOptions, subtitleOptions, redraw) {
  30191. this.applyDescription('title', titleOptions);
  30192. this.applyDescription('subtitle', subtitleOptions);
  30193. // The initial call also adds the caption. On update, chart.update will
  30194. // relay to Chart.setCaption.
  30195. this.applyDescription('caption', void 0);
  30196. this.layOutTitles(redraw);
  30197. };
  30198. /**
  30199. * Apply a title, subtitle or caption for the chart
  30200. *
  30201. * @private
  30202. * @function Highcharts.Chart#applyDescription
  30203. * @param name {string}
  30204. * Either title, subtitle or caption
  30205. * @param {Highcharts.TitleOptions|Highcharts.SubtitleOptions|Highcharts.CaptionOptions|undefined} explicitOptions
  30206. * The options to set, will be merged with default options.
  30207. */
  30208. Chart.prototype.applyDescription = function (name, explicitOptions) {
  30209. var chart = this;
  30210. // Default style
  30211. var style = name === 'title' ? {
  30212. color: palette.neutralColor80,
  30213. fontSize: this.options.isStock ? '16px' : '18px' // #2944
  30214. } : {
  30215. color: palette.neutralColor60
  30216. };
  30217. // Merge default options with explicit options
  30218. var options = this.options[name] = merge(
  30219. // Default styles
  30220. (!this.styledMode && { style: style }),
  30221. this.options[name],
  30222. explicitOptions);
  30223. var elem = this[name];
  30224. if (elem && explicitOptions) {
  30225. this[name] = elem = elem.destroy(); // remove old
  30226. }
  30227. if (options && !elem) {
  30228. elem = this.renderer.text(options.text, 0, 0, options.useHTML)
  30229. .attr({
  30230. align: options.align,
  30231. 'class': 'highcharts-' + name,
  30232. zIndex: options.zIndex || 4
  30233. })
  30234. .add();
  30235. // Update methods, shortcut to Chart.setTitle, Chart.setSubtitle and
  30236. // Chart.setCaption
  30237. elem.update = function (updateOptions) {
  30238. var fn = {
  30239. title: 'setTitle',
  30240. subtitle: 'setSubtitle',
  30241. caption: 'setCaption'
  30242. }[name];
  30243. chart[fn](updateOptions);
  30244. };
  30245. // Presentational
  30246. if (!this.styledMode) {
  30247. elem.css(options.style);
  30248. }
  30249. /**
  30250. * The chart title. The title has an `update` method that allows
  30251. * modifying the options directly or indirectly via
  30252. * `chart.update`.
  30253. *
  30254. * @sample highcharts/members/title-update/
  30255. * Updating titles
  30256. *
  30257. * @name Highcharts.Chart#title
  30258. * @type {Highcharts.TitleObject}
  30259. */
  30260. /**
  30261. * The chart subtitle. The subtitle has an `update` method that
  30262. * allows modifying the options directly or indirectly via
  30263. * `chart.update`.
  30264. *
  30265. * @name Highcharts.Chart#subtitle
  30266. * @type {Highcharts.SubtitleObject}
  30267. */
  30268. this[name] = elem;
  30269. }
  30270. };
  30271. /**
  30272. * Internal function to lay out the chart title, subtitle and caption, and
  30273. * cache the full offset height for use in `getMargins`. The result is
  30274. * stored in `this.titleOffset`.
  30275. *
  30276. * @private
  30277. * @function Highcharts.Chart#layOutTitles
  30278. *
  30279. * @param {boolean} [redraw=true]
  30280. * @fires Highcharts.Chart#event:afterLayOutTitles
  30281. */
  30282. Chart.prototype.layOutTitles = function (redraw) {
  30283. var titleOffset = [0, 0, 0],
  30284. renderer = this.renderer,
  30285. spacingBox = this.spacingBox;
  30286. // Lay out the title and the subtitle respectively
  30287. ['title', 'subtitle', 'caption'].forEach(function (key) {
  30288. var title = this[key], titleOptions = this.options[key], verticalAlign = titleOptions.verticalAlign || 'top', offset = key === 'title' ?
  30289. verticalAlign === 'top' ? -3 : 0 :
  30290. // Floating subtitle (#6574)
  30291. verticalAlign === 'top' ? titleOffset[0] + 2 : 0;
  30292. var titleSize,
  30293. height;
  30294. if (title) {
  30295. if (!this.styledMode) {
  30296. titleSize = titleOptions.style && titleOptions.style.fontSize;
  30297. }
  30298. titleSize = renderer.fontMetrics(titleSize, title).b;
  30299. title
  30300. .css({
  30301. width: (titleOptions.width ||
  30302. spacingBox.width + (titleOptions.widthAdjust || 0)) + 'px'
  30303. });
  30304. // Skip the cache for HTML (#3481, #11666)
  30305. height = Math.round(title.getBBox(titleOptions.useHTML).height);
  30306. title.align(extend({
  30307. y: verticalAlign === 'bottom' ?
  30308. titleSize :
  30309. offset + titleSize,
  30310. height: height
  30311. }, titleOptions), false, 'spacingBox');
  30312. if (!titleOptions.floating) {
  30313. if (verticalAlign === 'top') {
  30314. titleOffset[0] = Math.ceil(titleOffset[0] +
  30315. height);
  30316. }
  30317. else if (verticalAlign === 'bottom') {
  30318. titleOffset[2] = Math.ceil(titleOffset[2] +
  30319. height);
  30320. }
  30321. }
  30322. }
  30323. }, this);
  30324. // Handle title.margin and caption.margin
  30325. if (titleOffset[0] &&
  30326. (this.options.title.verticalAlign || 'top') === 'top') {
  30327. titleOffset[0] += this.options.title.margin;
  30328. }
  30329. if (titleOffset[2] &&
  30330. this.options.caption.verticalAlign === 'bottom') {
  30331. titleOffset[2] += this.options.caption.margin;
  30332. }
  30333. var requiresDirtyBox = (!this.titleOffset ||
  30334. this.titleOffset.join(',') !== titleOffset.join(','));
  30335. // Used in getMargins
  30336. this.titleOffset = titleOffset;
  30337. fireEvent(this, 'afterLayOutTitles');
  30338. if (!this.isDirtyBox && requiresDirtyBox) {
  30339. this.isDirtyBox = this.isDirtyLegend = requiresDirtyBox;
  30340. // Redraw if necessary (#2719, #2744)
  30341. if (this.hasRendered && pick(redraw, true) && this.isDirtyBox) {
  30342. this.redraw();
  30343. }
  30344. }
  30345. };
  30346. /**
  30347. * Internal function to get the chart width and height according to options
  30348. * and container size. Sets {@link Chart.chartWidth} and
  30349. * {@link Chart.chartHeight}.
  30350. *
  30351. * @private
  30352. * @function Highcharts.Chart#getChartSize
  30353. */
  30354. Chart.prototype.getChartSize = function () {
  30355. var chart = this,
  30356. optionsChart = chart.options.chart,
  30357. widthOption = optionsChart.width,
  30358. heightOption = optionsChart.height,
  30359. renderTo = chart.renderTo;
  30360. // Get inner width and height
  30361. if (!defined(widthOption)) {
  30362. chart.containerWidth = getStyle(renderTo, 'width');
  30363. }
  30364. if (!defined(heightOption)) {
  30365. chart.containerHeight = getStyle(renderTo, 'height');
  30366. }
  30367. /**
  30368. * The current pixel width of the chart.
  30369. *
  30370. * @name Highcharts.Chart#chartWidth
  30371. * @type {number}
  30372. */
  30373. chart.chartWidth = Math.max(// #1393
  30374. 0, widthOption || chart.containerWidth || 600 // #1460
  30375. );
  30376. /**
  30377. * The current pixel height of the chart.
  30378. *
  30379. * @name Highcharts.Chart#chartHeight
  30380. * @type {number}
  30381. */
  30382. chart.chartHeight = Math.max(0, relativeLength(heightOption, chart.chartWidth) ||
  30383. (chart.containerHeight > 1 ?
  30384. chart.containerHeight :
  30385. 400));
  30386. };
  30387. /**
  30388. * If the renderTo element has no offsetWidth, most likely one or more of
  30389. * its parents are hidden. Loop up the DOM tree to temporarily display the
  30390. * parents, then save the original display properties, and when the true
  30391. * size is retrieved, reset them. Used on first render and on redraws.
  30392. *
  30393. * @private
  30394. * @function Highcharts.Chart#temporaryDisplay
  30395. *
  30396. * @param {boolean} [revert]
  30397. * Revert to the saved original styles.
  30398. */
  30399. Chart.prototype.temporaryDisplay = function (revert) {
  30400. var node = this.renderTo,
  30401. tempStyle;
  30402. if (!revert) {
  30403. while (node && node.style) {
  30404. // When rendering to a detached node, it needs to be temporarily
  30405. // attached in order to read styling and bounding boxes (#5783,
  30406. // #7024).
  30407. if (!doc.body.contains(node) && !node.parentNode) {
  30408. node.hcOrigDetached = true;
  30409. doc.body.appendChild(node);
  30410. }
  30411. if (getStyle(node, 'display', false) === 'none' ||
  30412. node.hcOricDetached) {
  30413. node.hcOrigStyle = {
  30414. display: node.style.display,
  30415. height: node.style.height,
  30416. overflow: node.style.overflow
  30417. };
  30418. tempStyle = {
  30419. display: 'block',
  30420. overflow: 'hidden'
  30421. };
  30422. if (node !== this.renderTo) {
  30423. tempStyle.height = 0;
  30424. }
  30425. css(node, tempStyle);
  30426. // If it still doesn't have an offset width after setting
  30427. // display to block, it probably has an !important priority
  30428. // #2631, 6803
  30429. if (!node.offsetWidth) {
  30430. node.style.setProperty('display', 'block', 'important');
  30431. }
  30432. }
  30433. node = node.parentNode;
  30434. if (node === doc.body) {
  30435. break;
  30436. }
  30437. }
  30438. }
  30439. else {
  30440. while (node && node.style) {
  30441. if (node.hcOrigStyle) {
  30442. css(node, node.hcOrigStyle);
  30443. delete node.hcOrigStyle;
  30444. }
  30445. if (node.hcOrigDetached) {
  30446. doc.body.removeChild(node);
  30447. node.hcOrigDetached = false;
  30448. }
  30449. node = node.parentNode;
  30450. }
  30451. }
  30452. };
  30453. /**
  30454. * Set the {@link Chart.container|chart container's} class name, in
  30455. * addition to `highcharts-container`.
  30456. *
  30457. * @function Highcharts.Chart#setClassName
  30458. *
  30459. * @param {string} [className]
  30460. * The additional class name.
  30461. */
  30462. Chart.prototype.setClassName = function (className) {
  30463. this.container.className = 'highcharts-container ' + (className || '');
  30464. };
  30465. /**
  30466. * Get the containing element, determine the size and create the inner
  30467. * container div to hold the chart.
  30468. *
  30469. * @private
  30470. * @function Highcharts.Chart#afterGetContainer
  30471. * @fires Highcharts.Chart#event:afterGetContainer
  30472. */
  30473. Chart.prototype.getContainer = function () {
  30474. var chart = this,
  30475. options = chart.options,
  30476. optionsChart = options.chart,
  30477. indexAttrName = 'data-highcharts-chart',
  30478. containerId = uniqueKey();
  30479. var containerStyle,
  30480. renderTo = chart.renderTo;
  30481. if (!renderTo) {
  30482. chart.renderTo = renderTo =
  30483. optionsChart.renderTo;
  30484. }
  30485. if (isString(renderTo)) {
  30486. chart.renderTo = renderTo =
  30487. doc.getElementById(renderTo);
  30488. }
  30489. // Display an error if the renderTo is wrong
  30490. if (!renderTo) {
  30491. error(13, true, chart);
  30492. }
  30493. // If the container already holds a chart, destroy it. The check for
  30494. // hasRendered is there because web pages that are saved to disk from
  30495. // the browser, will preserve the data-highcharts-chart attribute and
  30496. // the SVG contents, but not an interactive chart. So in this case,
  30497. // charts[oldChartIndex] will point to the wrong chart if any (#2609).
  30498. var oldChartIndex = pInt(attr(renderTo,
  30499. indexAttrName));
  30500. if (isNumber(oldChartIndex) &&
  30501. charts[oldChartIndex] &&
  30502. charts[oldChartIndex].hasRendered) {
  30503. charts[oldChartIndex].destroy();
  30504. }
  30505. // Make a reference to the chart from the div
  30506. attr(renderTo, indexAttrName, chart.index);
  30507. // remove previous chart
  30508. renderTo.innerHTML = '';
  30509. // If the container doesn't have an offsetWidth, it has or is a child of
  30510. // a node that has display:none. We need to temporarily move it out to a
  30511. // visible state to determine the size, else the legend and tooltips
  30512. // won't render properly. The skipClone option is used in sparklines as
  30513. // a micro optimization, saving about 1-2 ms each chart.
  30514. if (!optionsChart.skipClone && !renderTo.offsetWidth) {
  30515. chart.temporaryDisplay();
  30516. }
  30517. // get the width and height
  30518. chart.getChartSize();
  30519. var chartWidth = chart.chartWidth;
  30520. var chartHeight = chart.chartHeight;
  30521. // Allow table cells and flex-boxes to shrink without the chart blocking
  30522. // them out (#6427)
  30523. css(renderTo, { overflow: 'hidden' });
  30524. // Create the inner container
  30525. if (!chart.styledMode) {
  30526. containerStyle = extend({
  30527. position: 'relative',
  30528. // needed for context menu (avoidscrollbars) and content
  30529. // overflow in IE
  30530. overflow: 'hidden',
  30531. width: chartWidth + 'px',
  30532. height: chartHeight + 'px',
  30533. textAlign: 'left',
  30534. lineHeight: 'normal',
  30535. zIndex: 0,
  30536. '-webkit-tap-highlight-color': 'rgba(0,0,0,0)',
  30537. userSelect: 'none',
  30538. 'touch-action': 'manipulation',
  30539. outline: 'none'
  30540. }, optionsChart.style || {});
  30541. }
  30542. /**
  30543. * The containing HTML element of the chart. The container is
  30544. * dynamically inserted into the element given as the `renderTo`
  30545. * parameter in the {@link Highcharts#chart} constructor.
  30546. *
  30547. * @name Highcharts.Chart#container
  30548. * @type {Highcharts.HTMLDOMElement}
  30549. */
  30550. var container = createElement('div', {
  30551. id: containerId
  30552. },
  30553. containerStyle,
  30554. renderTo);
  30555. chart.container = container;
  30556. // cache the cursor (#1650)
  30557. chart._cursor = container.style.cursor;
  30558. // Initialize the renderer
  30559. var Renderer = RendererRegistry.getRendererType(optionsChart.renderer);
  30560. /**
  30561. * The renderer instance of the chart. Each chart instance has only one
  30562. * associated renderer.
  30563. *
  30564. * @name Highcharts.Chart#renderer
  30565. * @type {Highcharts.SVGRenderer}
  30566. */
  30567. chart.renderer = new Renderer(container, chartWidth, chartHeight, void 0, optionsChart.forExport, options.exporting && options.exporting.allowHTML, chart.styledMode);
  30568. // Set the initial animation from the options
  30569. setAnimation(void 0, chart);
  30570. chart.setClassName(optionsChart.className);
  30571. if (!chart.styledMode) {
  30572. chart.renderer.setStyle(optionsChart.style);
  30573. }
  30574. else {
  30575. // Initialize definitions
  30576. for (var key in options.defs) { // eslint-disable-line guard-for-in
  30577. this.renderer.definition(options.defs[key]);
  30578. }
  30579. }
  30580. // Add a reference to the charts index
  30581. chart.renderer.chartIndex = chart.index;
  30582. fireEvent(this, 'afterGetContainer');
  30583. };
  30584. /**
  30585. * Calculate margins by rendering axis labels in a preliminary position.
  30586. * Title, subtitle and legend have already been rendered at this stage, but
  30587. * will be moved into their final positions.
  30588. *
  30589. * @private
  30590. * @function Highcharts.Chart#getMargins
  30591. * @fires Highcharts.Chart#event:getMargins
  30592. */
  30593. Chart.prototype.getMargins = function (skipAxes) {
  30594. var _a = this,
  30595. spacing = _a.spacing,
  30596. margin = _a.margin,
  30597. titleOffset = _a.titleOffset;
  30598. this.resetMargins();
  30599. // Adjust for title and subtitle
  30600. if (titleOffset[0] && !defined(margin[0])) {
  30601. this.plotTop = Math.max(this.plotTop, titleOffset[0] + spacing[0]);
  30602. }
  30603. if (titleOffset[2] && !defined(margin[2])) {
  30604. this.marginBottom = Math.max(this.marginBottom, titleOffset[2] + spacing[2]);
  30605. }
  30606. // Adjust for legend
  30607. if (this.legend && this.legend.display) {
  30608. this.legend.adjustMargins(margin, spacing);
  30609. }
  30610. fireEvent(this, 'getMargins');
  30611. if (!skipAxes) {
  30612. this.getAxisMargins();
  30613. }
  30614. };
  30615. /**
  30616. * @private
  30617. * @function Highcharts.Chart#getAxisMargins
  30618. */
  30619. Chart.prototype.getAxisMargins = function () {
  30620. var chart = this,
  30621. // [top, right, bottom, left]
  30622. axisOffset = chart.axisOffset = [0, 0, 0, 0],
  30623. colorAxis = chart.colorAxis,
  30624. margin = chart.margin,
  30625. getOffset = function (axes) {
  30626. axes.forEach(function (axis) {
  30627. if (axis.visible) {
  30628. axis.getOffset();
  30629. }
  30630. });
  30631. };
  30632. // pre-render axes to get labels offset width
  30633. if (chart.hasCartesianSeries) {
  30634. getOffset(chart.axes);
  30635. }
  30636. else if (colorAxis && colorAxis.length) {
  30637. getOffset(colorAxis);
  30638. }
  30639. // Add the axis offsets
  30640. marginNames.forEach(function (m, side) {
  30641. if (!defined(margin[side])) {
  30642. chart[m] += axisOffset[side];
  30643. }
  30644. });
  30645. chart.setChartSize();
  30646. };
  30647. /**
  30648. * Reflows the chart to its container. By default, the chart reflows
  30649. * automatically to its container following a `window.resize` event, as per
  30650. * the [chart.reflow](https://api.highcharts.com/highcharts/chart.reflow)
  30651. * option. However, there are no reliable events for div resize, so if the
  30652. * container is resized without a window resize event, this must be called
  30653. * explicitly.
  30654. *
  30655. * @sample highcharts/members/chart-reflow/
  30656. * Resize div and reflow
  30657. * @sample highcharts/chart/events-container/
  30658. * Pop up and reflow
  30659. *
  30660. * @function Highcharts.Chart#reflow
  30661. *
  30662. * @param {global.Event} [e]
  30663. * Event arguments. Used primarily when the function is called
  30664. * internally as a response to window resize.
  30665. */
  30666. Chart.prototype.reflow = function (e) {
  30667. var chart = this, optionsChart = chart.options.chart, renderTo = chart.renderTo, hasUserSize = (defined(optionsChart.width) &&
  30668. defined(optionsChart.height)), width = optionsChart.width || getStyle(renderTo, 'width'), height = optionsChart.height || getStyle(renderTo, 'height'), target = e ? e.target : win;
  30669. delete chart.pointer.chartPosition;
  30670. // Width and height checks for display:none. Target is doc in IE8 and
  30671. // Opera, win in Firefox, Chrome and IE9.
  30672. if (!hasUserSize &&
  30673. !chart.isPrinting &&
  30674. width &&
  30675. height &&
  30676. (target === win || target === doc)) {
  30677. if (width !== chart.containerWidth ||
  30678. height !== chart.containerHeight) {
  30679. U.clearTimeout(chart.reflowTimeout);
  30680. // When called from window.resize, e is set, else it's called
  30681. // directly (#2224)
  30682. chart.reflowTimeout = syncTimeout(function () {
  30683. // Set size, it may have been destroyed in the meantime
  30684. // (#1257)
  30685. if (chart.container) {
  30686. chart.setSize(void 0, void 0, false);
  30687. }
  30688. }, e ? 100 : 0);
  30689. }
  30690. chart.containerWidth = width;
  30691. chart.containerHeight = height;
  30692. }
  30693. };
  30694. /**
  30695. * Toggle the event handlers necessary for auto resizing, depending on the
  30696. * `chart.reflow` option.
  30697. *
  30698. * @private
  30699. * @function Highcharts.Chart#setReflow
  30700. */
  30701. Chart.prototype.setReflow = function (reflow) {
  30702. var chart = this;
  30703. if (reflow !== false && !this.unbindReflow) {
  30704. this.unbindReflow = addEvent(win, 'resize', function (e) {
  30705. // a removed event listener still runs in Edge and IE if the
  30706. // listener was removed while the event runs, so check if the
  30707. // chart is not destroyed (#11609)
  30708. if (chart.options) {
  30709. chart.reflow(e);
  30710. }
  30711. });
  30712. addEvent(this, 'destroy', this.unbindReflow);
  30713. }
  30714. else if (reflow === false && this.unbindReflow) {
  30715. // Unbind and unset
  30716. this.unbindReflow = this.unbindReflow();
  30717. }
  30718. // The following will add listeners to re-fit the chart before and after
  30719. // printing (#2284). However it only works in WebKit. Should have worked
  30720. // in Firefox, but not supported in IE.
  30721. /*
  30722. if (win.matchMedia) {
  30723. win.matchMedia('print').addListener(function reflow() {
  30724. chart.reflow();
  30725. });
  30726. }
  30727. //*/
  30728. };
  30729. /**
  30730. * Resize the chart to a given width and height. In order to set the width
  30731. * only, the height argument may be skipped. To set the height only, pass
  30732. * `undefined` for the width.
  30733. *
  30734. * @sample highcharts/members/chart-setsize-button/
  30735. * Test resizing from buttons
  30736. * @sample highcharts/members/chart-setsize-jquery-resizable/
  30737. * Add a jQuery UI resizable
  30738. * @sample stock/members/chart-setsize/
  30739. * Highcharts Stock with UI resizable
  30740. *
  30741. * @function Highcharts.Chart#setSize
  30742. *
  30743. * @param {number|null} [width]
  30744. * The new pixel width of the chart. Since v4.2.6, the argument can
  30745. * be `undefined` in order to preserve the current value (when
  30746. * setting height only), or `null` to adapt to the width of the
  30747. * containing element.
  30748. *
  30749. * @param {number|null} [height]
  30750. * The new pixel height of the chart. Since v4.2.6, the argument can
  30751. * be `undefined` in order to preserve the current value, or `null`
  30752. * in order to adapt to the height of the containing element.
  30753. *
  30754. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=true]
  30755. * Whether and how to apply animation.
  30756. *
  30757. * @return {void}
  30758. *
  30759. * @fires Highcharts.Chart#event:endResize
  30760. * @fires Highcharts.Chart#event:resize
  30761. */
  30762. Chart.prototype.setSize = function (width, height, animation) {
  30763. var chart = this,
  30764. renderer = chart.renderer;
  30765. // Handle the isResizing counter
  30766. chart.isResizing += 1;
  30767. // set the animation for the current process
  30768. setAnimation(animation, chart);
  30769. var globalAnimation = renderer.globalAnimation;
  30770. chart.oldChartHeight = chart.chartHeight;
  30771. chart.oldChartWidth = chart.chartWidth;
  30772. if (typeof width !== 'undefined') {
  30773. chart.options.chart.width = width;
  30774. }
  30775. if (typeof height !== 'undefined') {
  30776. chart.options.chart.height = height;
  30777. }
  30778. chart.getChartSize();
  30779. // Resize the container with the global animation applied if enabled
  30780. // (#2503)
  30781. if (!chart.styledMode) {
  30782. (globalAnimation ? animate : css)(chart.container, {
  30783. width: chart.chartWidth + 'px',
  30784. height: chart.chartHeight + 'px'
  30785. }, globalAnimation);
  30786. }
  30787. chart.setChartSize(true);
  30788. renderer.setSize(chart.chartWidth, chart.chartHeight, globalAnimation);
  30789. // handle axes
  30790. chart.axes.forEach(function (axis) {
  30791. axis.isDirty = true;
  30792. axis.setScale();
  30793. });
  30794. chart.isDirtyLegend = true; // force legend redraw
  30795. chart.isDirtyBox = true; // force redraw of plot and chart border
  30796. chart.layOutTitles(); // #2857
  30797. chart.getMargins();
  30798. chart.redraw(globalAnimation);
  30799. chart.oldChartHeight = null;
  30800. fireEvent(chart, 'resize');
  30801. // Fire endResize and set isResizing back. If animation is disabled,
  30802. // fire without delay
  30803. syncTimeout(function () {
  30804. if (chart) {
  30805. fireEvent(chart, 'endResize', null, function () {
  30806. chart.isResizing -= 1;
  30807. });
  30808. }
  30809. }, animObject(globalAnimation).duration);
  30810. };
  30811. /**
  30812. * Set the public chart properties. This is done before and after the
  30813. * pre-render to determine margin sizes.
  30814. *
  30815. * @private
  30816. * @function Highcharts.Chart#setChartSize
  30817. * @fires Highcharts.Chart#event:afterSetChartSize
  30818. */
  30819. Chart.prototype.setChartSize = function (skipAxes) {
  30820. var chart = this,
  30821. inverted = chart.inverted,
  30822. renderer = chart.renderer,
  30823. chartWidth = chart.chartWidth,
  30824. chartHeight = chart.chartHeight,
  30825. optionsChart = chart.options.chart,
  30826. spacing = chart.spacing,
  30827. clipOffset = chart.clipOffset;
  30828. var plotLeft,
  30829. plotTop,
  30830. plotWidth,
  30831. plotHeight;
  30832. /**
  30833. * The current left position of the plot area in pixels.
  30834. *
  30835. * @name Highcharts.Chart#plotLeft
  30836. * @type {number}
  30837. */
  30838. chart.plotLeft = plotLeft = Math.round(chart.plotLeft);
  30839. /**
  30840. * The current top position of the plot area in pixels.
  30841. *
  30842. * @name Highcharts.Chart#plotTop
  30843. * @type {number}
  30844. */
  30845. chart.plotTop = plotTop = Math.round(chart.plotTop);
  30846. /**
  30847. * The current width of the plot area in pixels.
  30848. *
  30849. * @name Highcharts.Chart#plotWidth
  30850. * @type {number}
  30851. */
  30852. chart.plotWidth = plotWidth = Math.max(0, Math.round(chartWidth - plotLeft - chart.marginRight));
  30853. /**
  30854. * The current height of the plot area in pixels.
  30855. *
  30856. * @name Highcharts.Chart#plotHeight
  30857. * @type {number}
  30858. */
  30859. chart.plotHeight = plotHeight = Math.max(0, Math.round(chartHeight - plotTop - chart.marginBottom));
  30860. chart.plotSizeX = inverted ? plotHeight : plotWidth;
  30861. chart.plotSizeY = inverted ? plotWidth : plotHeight;
  30862. chart.plotBorderWidth = optionsChart.plotBorderWidth || 0;
  30863. // Set boxes used for alignment
  30864. chart.spacingBox = renderer.spacingBox = {
  30865. x: spacing[3],
  30866. y: spacing[0],
  30867. width: chartWidth - spacing[3] - spacing[1],
  30868. height: chartHeight - spacing[0] - spacing[2]
  30869. };
  30870. chart.plotBox = renderer.plotBox = {
  30871. x: plotLeft,
  30872. y: plotTop,
  30873. width: plotWidth,
  30874. height: plotHeight
  30875. };
  30876. var plotBorderWidth = 2 * Math.floor(chart.plotBorderWidth / 2),
  30877. clipX = Math.ceil(Math.max(plotBorderWidth,
  30878. clipOffset[3]) / 2),
  30879. clipY = Math.ceil(Math.max(plotBorderWidth,
  30880. clipOffset[0]) / 2);
  30881. chart.clipBox = {
  30882. x: clipX,
  30883. y: clipY,
  30884. width: Math.floor(chart.plotSizeX -
  30885. Math.max(plotBorderWidth, clipOffset[1]) / 2 -
  30886. clipX),
  30887. height: Math.max(0, Math.floor(chart.plotSizeY -
  30888. Math.max(plotBorderWidth, clipOffset[2]) / 2 -
  30889. clipY))
  30890. };
  30891. if (!skipAxes) {
  30892. chart.axes.forEach(function (axis) {
  30893. axis.setAxisSize();
  30894. axis.setAxisTranslation();
  30895. });
  30896. renderer.alignElements();
  30897. }
  30898. fireEvent(chart, 'afterSetChartSize', { skipAxes: skipAxes });
  30899. };
  30900. /**
  30901. * Initial margins before auto size margins are applied.
  30902. *
  30903. * @private
  30904. * @function Highcharts.Chart#resetMargins
  30905. */
  30906. Chart.prototype.resetMargins = function () {
  30907. fireEvent(this, 'resetMargins');
  30908. var chart = this,
  30909. chartOptions = chart.options.chart;
  30910. // Create margin and spacing array
  30911. ['margin', 'spacing'].forEach(function splashArrays(target) {
  30912. var value = chartOptions[target],
  30913. values = isObject(value) ? value : [value,
  30914. value,
  30915. value,
  30916. value];
  30917. [
  30918. 'Top',
  30919. 'Right',
  30920. 'Bottom',
  30921. 'Left'
  30922. ].forEach(function (sideName, side) {
  30923. chart[target][side] = pick(chartOptions[target + sideName], values[side]);
  30924. });
  30925. });
  30926. // Set margin names like chart.plotTop, chart.plotLeft,
  30927. // chart.marginRight, chart.marginBottom.
  30928. marginNames.forEach(function (m, side) {
  30929. chart[m] = pick(chart.margin[side], chart.spacing[side]);
  30930. });
  30931. chart.axisOffset = [0, 0, 0, 0]; // top, right, bottom, left
  30932. chart.clipOffset = [0, 0, 0, 0];
  30933. };
  30934. /**
  30935. * Internal function to draw or redraw the borders and backgrounds for chart
  30936. * and plot area.
  30937. *
  30938. * @private
  30939. * @function Highcharts.Chart#drawChartBox
  30940. * @fires Highcharts.Chart#event:afterDrawChartBox
  30941. */
  30942. Chart.prototype.drawChartBox = function () {
  30943. var chart = this,
  30944. optionsChart = chart.options.chart,
  30945. renderer = chart.renderer,
  30946. chartWidth = chart.chartWidth,
  30947. chartHeight = chart.chartHeight,
  30948. styledMode = chart.styledMode,
  30949. plotBGImage = chart.plotBGImage,
  30950. chartBackgroundColor = optionsChart.backgroundColor,
  30951. plotBackgroundColor = optionsChart.plotBackgroundColor,
  30952. plotBackgroundImage = optionsChart.plotBackgroundImage,
  30953. plotLeft = chart.plotLeft,
  30954. plotTop = chart.plotTop,
  30955. plotWidth = chart.plotWidth,
  30956. plotHeight = chart.plotHeight,
  30957. plotBox = chart.plotBox,
  30958. clipRect = chart.clipRect,
  30959. clipBox = chart.clipBox;
  30960. var chartBackground = chart.chartBackground,
  30961. plotBackground = chart.plotBackground,
  30962. plotBorder = chart.plotBorder,
  30963. chartBorderWidth,
  30964. mgn,
  30965. bgAttr,
  30966. verb = 'animate';
  30967. // Chart area
  30968. if (!chartBackground) {
  30969. chart.chartBackground = chartBackground = renderer.rect()
  30970. .addClass('highcharts-background')
  30971. .add();
  30972. verb = 'attr';
  30973. }
  30974. if (!styledMode) {
  30975. // Presentational
  30976. chartBorderWidth = optionsChart.borderWidth || 0;
  30977. mgn = chartBorderWidth + (optionsChart.shadow ? 8 : 0);
  30978. bgAttr = {
  30979. fill: chartBackgroundColor || 'none'
  30980. };
  30981. if (chartBorderWidth || chartBackground['stroke-width']) { // #980
  30982. bgAttr.stroke = optionsChart.borderColor;
  30983. bgAttr['stroke-width'] = chartBorderWidth;
  30984. }
  30985. chartBackground
  30986. .attr(bgAttr)
  30987. .shadow(optionsChart.shadow);
  30988. }
  30989. else {
  30990. chartBorderWidth = mgn = chartBackground.strokeWidth();
  30991. }
  30992. chartBackground[verb]({
  30993. x: mgn / 2,
  30994. y: mgn / 2,
  30995. width: chartWidth - mgn - chartBorderWidth % 2,
  30996. height: chartHeight - mgn - chartBorderWidth % 2,
  30997. r: optionsChart.borderRadius
  30998. });
  30999. // Plot background
  31000. verb = 'animate';
  31001. if (!plotBackground) {
  31002. verb = 'attr';
  31003. chart.plotBackground = plotBackground = renderer.rect()
  31004. .addClass('highcharts-plot-background')
  31005. .add();
  31006. }
  31007. plotBackground[verb](plotBox);
  31008. if (!styledMode) {
  31009. // Presentational attributes for the background
  31010. plotBackground
  31011. .attr({
  31012. fill: plotBackgroundColor || 'none'
  31013. })
  31014. .shadow(optionsChart.plotShadow);
  31015. // Create the background image
  31016. if (plotBackgroundImage) {
  31017. if (!plotBGImage) {
  31018. chart.plotBGImage = renderer.image(plotBackgroundImage, plotLeft, plotTop, plotWidth, plotHeight).add();
  31019. }
  31020. else {
  31021. if (plotBackgroundImage !== plotBGImage.attr('href')) {
  31022. plotBGImage.attr('href', plotBackgroundImage);
  31023. }
  31024. plotBGImage.animate(plotBox);
  31025. }
  31026. }
  31027. }
  31028. // Plot clip
  31029. if (!clipRect) {
  31030. chart.clipRect = renderer.clipRect(clipBox);
  31031. }
  31032. else {
  31033. clipRect.animate({
  31034. width: clipBox.width,
  31035. height: clipBox.height
  31036. });
  31037. }
  31038. // Plot area border
  31039. verb = 'animate';
  31040. if (!plotBorder) {
  31041. verb = 'attr';
  31042. chart.plotBorder = plotBorder = renderer.rect()
  31043. .addClass('highcharts-plot-border')
  31044. .attr({
  31045. zIndex: 1 // Above the grid
  31046. })
  31047. .add();
  31048. }
  31049. if (!styledMode) {
  31050. // Presentational
  31051. plotBorder.attr({
  31052. stroke: optionsChart.plotBorderColor,
  31053. 'stroke-width': optionsChart.plotBorderWidth || 0,
  31054. fill: 'none'
  31055. });
  31056. }
  31057. plotBorder[verb](plotBorder.crisp({
  31058. x: plotLeft,
  31059. y: plotTop,
  31060. width: plotWidth,
  31061. height: plotHeight
  31062. }, -plotBorder.strokeWidth())); // #3282 plotBorder should be negative;
  31063. // reset
  31064. chart.isDirtyBox = false;
  31065. fireEvent(this, 'afterDrawChartBox');
  31066. };
  31067. /**
  31068. * Detect whether a certain chart property is needed based on inspecting its
  31069. * options and series. This mainly applies to the chart.inverted property,
  31070. * and in extensions to the chart.angular and chart.polar properties.
  31071. *
  31072. * @private
  31073. * @function Highcharts.Chart#propFromSeries
  31074. * @return {void}
  31075. */
  31076. Chart.prototype.propFromSeries = function () {
  31077. var chart = this,
  31078. optionsChart = chart.options.chart,
  31079. seriesOptions = chart.options.series;
  31080. var i,
  31081. klass,
  31082. value;
  31083. /**
  31084. * The flag is set to `true` if a series of the chart is inverted.
  31085. *
  31086. * @name Highcharts.Chart#inverted
  31087. * @type {boolean|undefined}
  31088. */
  31089. ['inverted', 'angular', 'polar'].forEach(function (key) {
  31090. // The default series type's class
  31091. klass = seriesTypes[(optionsChart.type || optionsChart.defaultSeriesType)];
  31092. // Get the value from available chart-wide properties
  31093. value =
  31094. // It is set in the options:
  31095. optionsChart[key] ||
  31096. // The default series class:
  31097. (klass && klass.prototype[key]);
  31098. // requires it
  31099. // 4. Check if any the chart's series require it
  31100. i = seriesOptions && seriesOptions.length;
  31101. while (!value && i--) {
  31102. klass = seriesTypes[seriesOptions[i].type];
  31103. if (klass && klass.prototype[key]) {
  31104. value = true;
  31105. }
  31106. }
  31107. // Set the chart property
  31108. chart[key] = value;
  31109. });
  31110. };
  31111. /**
  31112. * Internal function to link two or more series together, based on the
  31113. * `linkedTo` option. This is done from `Chart.render`, and after
  31114. * `Chart.addSeries` and `Series.remove`.
  31115. *
  31116. * @private
  31117. * @function Highcharts.Chart#linkSeries
  31118. * @fires Highcharts.Chart#event:afterLinkSeries
  31119. */
  31120. Chart.prototype.linkSeries = function () {
  31121. var chart = this,
  31122. chartSeries = chart.series;
  31123. // Reset links
  31124. chartSeries.forEach(function (series) {
  31125. series.linkedSeries.length = 0;
  31126. });
  31127. // Apply new links
  31128. chartSeries.forEach(function (series) {
  31129. var linkedTo = series.options.linkedTo;
  31130. if (isString(linkedTo)) {
  31131. if (linkedTo === ':previous') {
  31132. linkedTo = chart.series[series.index - 1];
  31133. }
  31134. else {
  31135. linkedTo = chart.get(linkedTo);
  31136. }
  31137. // #3341 avoid mutual linking
  31138. if (linkedTo && linkedTo.linkedParent !== series) {
  31139. linkedTo.linkedSeries.push(series);
  31140. series.linkedParent = linkedTo;
  31141. if (linkedTo.enabledDataSorting) {
  31142. series.setDataSortingOptions();
  31143. }
  31144. series.visible = pick(series.options.visible, linkedTo.options.visible, series.visible); // #3879
  31145. }
  31146. }
  31147. });
  31148. fireEvent(this, 'afterLinkSeries');
  31149. };
  31150. /**
  31151. * Render series for the chart.
  31152. *
  31153. * @private
  31154. * @function Highcharts.Chart#renderSeries
  31155. */
  31156. Chart.prototype.renderSeries = function () {
  31157. this.series.forEach(function (serie) {
  31158. serie.translate();
  31159. serie.render();
  31160. });
  31161. };
  31162. /**
  31163. * Render labels for the chart.
  31164. *
  31165. * @private
  31166. * @function Highcharts.Chart#renderLabels
  31167. */
  31168. Chart.prototype.renderLabels = function () {
  31169. var chart = this,
  31170. labels = chart.options.labels;
  31171. if (labels.items) {
  31172. labels.items.forEach(function (label) {
  31173. var style = extend(labels.style,
  31174. label.style),
  31175. x = pInt(style.left) + chart.plotLeft,
  31176. y = pInt(style.top) + chart.plotTop + 12;
  31177. // delete to prevent rewriting in IE
  31178. delete style.left;
  31179. delete style.top;
  31180. chart.renderer.text(label.html, x, y)
  31181. .attr({ zIndex: 2 })
  31182. .css(style)
  31183. .add();
  31184. });
  31185. }
  31186. };
  31187. /**
  31188. * Render all graphics for the chart. Runs internally on initialization.
  31189. *
  31190. * @private
  31191. * @function Highcharts.Chart#render
  31192. */
  31193. Chart.prototype.render = function () {
  31194. var chart = this,
  31195. axes = chart.axes,
  31196. colorAxis = chart.colorAxis,
  31197. renderer = chart.renderer,
  31198. options = chart.options,
  31199. renderAxes = function (axes) {
  31200. axes.forEach(function (axis) {
  31201. if (axis.visible) {
  31202. axis.render();
  31203. }
  31204. });
  31205. };
  31206. var correction = 0; // correction for X axis labels
  31207. // Title
  31208. chart.setTitle();
  31209. /**
  31210. * The overview of the chart's series.
  31211. *
  31212. * @name Highcharts.Chart#legend
  31213. * @type {Highcharts.Legend}
  31214. */
  31215. chart.legend = new Legend(chart, options.legend);
  31216. // Get stacks
  31217. if (chart.getStacks) {
  31218. chart.getStacks();
  31219. }
  31220. // Get chart margins
  31221. chart.getMargins(true);
  31222. chart.setChartSize();
  31223. // Record preliminary dimensions for later comparison
  31224. var tempWidth = chart.plotWidth;
  31225. axes.some(function (axis) {
  31226. if (axis.horiz &&
  31227. axis.visible &&
  31228. axis.options.labels.enabled &&
  31229. axis.series.length) {
  31230. // 21 is the most common correction for X axis labels
  31231. correction = 21;
  31232. return true;
  31233. }
  31234. });
  31235. // use Math.max to prevent negative plotHeight
  31236. chart.plotHeight = Math.max(chart.plotHeight - correction, 0);
  31237. var tempHeight = chart.plotHeight;
  31238. // Get margins by pre-rendering axes
  31239. axes.forEach(function (axis) {
  31240. axis.setScale();
  31241. });
  31242. chart.getAxisMargins();
  31243. // If the plot area size has changed significantly, calculate tick
  31244. // positions again
  31245. var redoHorizontal = tempWidth / chart.plotWidth > 1.1;
  31246. // Height is more sensitive, use lower threshold
  31247. var redoVertical = tempHeight / chart.plotHeight > 1.05;
  31248. if (redoHorizontal || redoVertical) {
  31249. axes.forEach(function (axis) {
  31250. if ((axis.horiz && redoHorizontal) ||
  31251. (!axis.horiz && redoVertical)) {
  31252. // update to reflect the new margins
  31253. axis.setTickInterval(true);
  31254. }
  31255. });
  31256. chart.getMargins(); // second pass to check for new labels
  31257. }
  31258. // Draw the borders and backgrounds
  31259. chart.drawChartBox();
  31260. // Axes
  31261. if (chart.hasCartesianSeries) {
  31262. renderAxes(axes);
  31263. }
  31264. else if (colorAxis && colorAxis.length) {
  31265. renderAxes(colorAxis);
  31266. }
  31267. // The series
  31268. if (!chart.seriesGroup) {
  31269. chart.seriesGroup = renderer.g('series-group')
  31270. .attr({ zIndex: 3 })
  31271. .add();
  31272. }
  31273. chart.renderSeries();
  31274. // Labels
  31275. chart.renderLabels();
  31276. // Credits
  31277. chart.addCredits();
  31278. // Handle responsiveness
  31279. if (chart.setResponsive) {
  31280. chart.setResponsive();
  31281. }
  31282. // Set flag
  31283. chart.hasRendered = true;
  31284. };
  31285. /**
  31286. * Set a new credits label for the chart.
  31287. *
  31288. * @sample highcharts/credits/credits-update/
  31289. * Add and update credits
  31290. *
  31291. * @function Highcharts.Chart#addCredits
  31292. *
  31293. * @param {Highcharts.CreditsOptions} [credits]
  31294. * A configuration object for the new credits.
  31295. */
  31296. Chart.prototype.addCredits = function (credits) {
  31297. var chart = this,
  31298. creds = merge(true,
  31299. this.options.credits,
  31300. credits);
  31301. if (creds.enabled && !this.credits) {
  31302. /**
  31303. * The chart's credits label. The label has an `update` method that
  31304. * allows setting new options as per the
  31305. * [credits options set](https://api.highcharts.com/highcharts/credits).
  31306. *
  31307. * @name Highcharts.Chart#credits
  31308. * @type {Highcharts.SVGElement}
  31309. */
  31310. this.credits = this.renderer.text(creds.text + (this.mapCredits || ''), 0, 0)
  31311. .addClass('highcharts-credits')
  31312. .on('click', function () {
  31313. if (creds.href) {
  31314. win.location.href = creds.href;
  31315. }
  31316. })
  31317. .attr({
  31318. align: creds.position.align,
  31319. zIndex: 8
  31320. });
  31321. if (!chart.styledMode) {
  31322. this.credits.css(creds.style);
  31323. }
  31324. this.credits
  31325. .add()
  31326. .align(creds.position);
  31327. // Dynamically update
  31328. this.credits.update = function (options) {
  31329. chart.credits = chart.credits.destroy();
  31330. chart.addCredits(options);
  31331. };
  31332. }
  31333. };
  31334. /**
  31335. * Remove the chart and purge memory. This method is called internally
  31336. * before adding a second chart into the same container, as well as on
  31337. * window unload to prevent leaks.
  31338. *
  31339. * @sample highcharts/members/chart-destroy/
  31340. * Destroy the chart from a button
  31341. * @sample stock/members/chart-destroy/
  31342. * Destroy with Highcharts Stock
  31343. *
  31344. * @function Highcharts.Chart#destroy
  31345. *
  31346. * @fires Highcharts.Chart#event:destroy
  31347. */
  31348. Chart.prototype.destroy = function () {
  31349. var chart = this,
  31350. axes = chart.axes,
  31351. series = chart.series,
  31352. container = chart.container,
  31353. parentNode = container && container.parentNode;
  31354. var i;
  31355. // fire the chart.destoy event
  31356. fireEvent(chart, 'destroy');
  31357. // Delete the chart from charts lookup array
  31358. if (chart.renderer.forExport) {
  31359. erase(charts, chart); // #6569
  31360. }
  31361. else {
  31362. charts[chart.index] = void 0;
  31363. }
  31364. H.chartCount--;
  31365. chart.renderTo.removeAttribute('data-highcharts-chart');
  31366. // remove events
  31367. removeEvent(chart);
  31368. // ==== Destroy collections:
  31369. // Destroy axes
  31370. i = axes.length;
  31371. while (i--) {
  31372. axes[i] = axes[i].destroy();
  31373. }
  31374. // Destroy scroller & scroller series before destroying base series
  31375. if (this.scroller && this.scroller.destroy) {
  31376. this.scroller.destroy();
  31377. }
  31378. // Destroy each series
  31379. i = series.length;
  31380. while (i--) {
  31381. series[i] = series[i].destroy();
  31382. }
  31383. // ==== Destroy chart properties:
  31384. [
  31385. 'title', 'subtitle', 'chartBackground', 'plotBackground',
  31386. 'plotBGImage', 'plotBorder', 'seriesGroup', 'clipRect', 'credits',
  31387. 'pointer', 'rangeSelector', 'legend', 'resetZoomButton', 'tooltip',
  31388. 'renderer'
  31389. ].forEach(function (name) {
  31390. var prop = chart[name];
  31391. if (prop && prop.destroy) {
  31392. chart[name] = prop.destroy();
  31393. }
  31394. });
  31395. // Remove container and all SVG, check container as it can break in IE
  31396. // when destroyed before finished loading
  31397. if (container) {
  31398. container.innerHTML = '';
  31399. removeEvent(container);
  31400. if (parentNode) {
  31401. discardElement(container);
  31402. }
  31403. }
  31404. // clean it all up
  31405. objectEach(chart, function (val, key) {
  31406. delete chart[key];
  31407. });
  31408. };
  31409. /**
  31410. * Prepare for first rendering after all data are loaded.
  31411. *
  31412. * @private
  31413. * @function Highcharts.Chart#firstRender
  31414. * @fires Highcharts.Chart#event:beforeRender
  31415. */
  31416. Chart.prototype.firstRender = function () {
  31417. var chart = this,
  31418. options = chart.options;
  31419. // Hook for oldIE to check whether the chart is ready to render
  31420. if (chart.isReadyToRender && !chart.isReadyToRender()) {
  31421. return;
  31422. }
  31423. // Create the container
  31424. chart.getContainer();
  31425. chart.resetMargins();
  31426. chart.setChartSize();
  31427. // Set the common chart properties (mainly invert) from the given series
  31428. chart.propFromSeries();
  31429. // get axes
  31430. chart.getAxes();
  31431. // Initialize the series
  31432. (isArray(options.series) ? options.series : []).forEach(
  31433. // #9680
  31434. function (serieOptions) {
  31435. chart.initSeries(serieOptions);
  31436. });
  31437. chart.linkSeries();
  31438. chart.setSeriesData();
  31439. // Run an event after axes and series are initialized, but before
  31440. // render. At this stage, the series data is indexed and cached in the
  31441. // xData and yData arrays, so we can access those before rendering. Used
  31442. // in Highcharts Stock.
  31443. fireEvent(chart, 'beforeRender');
  31444. // depends on inverted and on margins being set
  31445. if (Pointer) {
  31446. if (MSPointer.isRequired()) {
  31447. chart.pointer = new MSPointer(chart, options);
  31448. }
  31449. else {
  31450. /**
  31451. * The Pointer that keeps track of mouse and touch interaction.
  31452. *
  31453. * @memberof Highcharts.Chart
  31454. * @name pointer
  31455. * @type {Highcharts.Pointer}
  31456. * @instance
  31457. */
  31458. chart.pointer = new Pointer(chart, options);
  31459. }
  31460. }
  31461. chart.render();
  31462. chart.pointer.getChartPosition(); // #14973
  31463. // Fire the load event if there are no external images
  31464. if (!chart.renderer.imgCount && !chart.hasLoaded) {
  31465. chart.onload();
  31466. }
  31467. // If the chart was rendered outside the top container, put it back in
  31468. // (#3679)
  31469. chart.temporaryDisplay(true);
  31470. };
  31471. /**
  31472. * Internal function that runs on chart load, async if any images are loaded
  31473. * in the chart. Runs the callbacks and triggers the `load` and `render`
  31474. * events.
  31475. *
  31476. * @private
  31477. * @function Highcharts.Chart#onload
  31478. * @fires Highcharts.Chart#event:load
  31479. * @fires Highcharts.Chart#event:render
  31480. */
  31481. Chart.prototype.onload = function () {
  31482. // Run callbacks, first the ones registered by modules, then user's one
  31483. this.callbacks.concat([this.callback]).forEach(function (fn) {
  31484. // Chart destroyed in its own callback (#3600)
  31485. if (fn && typeof this.index !== 'undefined') {
  31486. fn.apply(this, [this]);
  31487. }
  31488. }, this);
  31489. fireEvent(this, 'load');
  31490. fireEvent(this, 'render');
  31491. // Set up auto resize, check for not destroyed (#6068)
  31492. if (defined(this.index)) {
  31493. this.setReflow(this.options.chart.reflow);
  31494. }
  31495. // Don't run again
  31496. this.hasLoaded = true;
  31497. };
  31498. /**
  31499. * Add a series to the chart after render time. Note that this method should
  31500. * never be used when adding data synchronously at chart render time, as it
  31501. * adds expense to the calculations and rendering. When adding data at the
  31502. * same time as the chart is initialized, add the series as a configuration
  31503. * option instead. With multiple axes, the `offset` is dynamically adjusted.
  31504. *
  31505. * @sample highcharts/members/chart-addseries/
  31506. * Add a series from a button
  31507. * @sample stock/members/chart-addseries/
  31508. * Add a series in Highcharts Stock
  31509. *
  31510. * @function Highcharts.Chart#addSeries
  31511. *
  31512. * @param {Highcharts.SeriesOptionsType} options
  31513. * The config options for the series.
  31514. *
  31515. * @param {boolean} [redraw=true]
  31516. * Whether to redraw the chart after adding.
  31517. *
  31518. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
  31519. * Whether to apply animation, and optionally animation
  31520. * configuration.
  31521. *
  31522. * @return {Highcharts.Series}
  31523. * The newly created series object.
  31524. *
  31525. * @fires Highcharts.Chart#event:addSeries
  31526. * @fires Highcharts.Chart#event:afterAddSeries
  31527. */
  31528. Chart.prototype.addSeries = function (options, redraw, animation) {
  31529. var chart = this;
  31530. var series;
  31531. if (options) { // <- not necessary
  31532. redraw = pick(redraw, true); // defaults to true
  31533. fireEvent(chart, 'addSeries', { options: options }, function () {
  31534. series = chart.initSeries(options);
  31535. chart.isDirtyLegend = true;
  31536. chart.linkSeries();
  31537. if (series.enabledDataSorting) {
  31538. // We need to call `setData` after `linkSeries`
  31539. series.setData(options.data, false);
  31540. }
  31541. fireEvent(chart, 'afterAddSeries', { series: series });
  31542. if (redraw) {
  31543. chart.redraw(animation);
  31544. }
  31545. });
  31546. }
  31547. return series;
  31548. };
  31549. /**
  31550. * Add an axis to the chart after render time. Note that this method should
  31551. * never be used when adding data synchronously at chart render time, as it
  31552. * adds expense to the calculations and rendering. When adding data at the
  31553. * same time as the chart is initialized, add the axis as a configuration
  31554. * option instead.
  31555. *
  31556. * @sample highcharts/members/chart-addaxis/
  31557. * Add and remove axes
  31558. *
  31559. * @function Highcharts.Chart#addAxis
  31560. *
  31561. * @param {Highcharts.AxisOptions} options
  31562. * The axis options.
  31563. *
  31564. * @param {boolean} [isX=false]
  31565. * Whether it is an X axis or a value axis.
  31566. *
  31567. * @param {boolean} [redraw=true]
  31568. * Whether to redraw the chart after adding.
  31569. *
  31570. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=true]
  31571. * Whether and how to apply animation in the redraw.
  31572. *
  31573. * @return {Highcharts.Axis}
  31574. * The newly generated Axis object.
  31575. */
  31576. Chart.prototype.addAxis = function (options, isX, redraw, animation) {
  31577. return this.createAxis(isX ? 'xAxis' : 'yAxis', { axis: options, redraw: redraw, animation: animation });
  31578. };
  31579. /**
  31580. * Add a color axis to the chart after render time. Note that this method
  31581. * should never be used when adding data synchronously at chart render time,
  31582. * as it adds expense to the calculations and rendering. When adding data at
  31583. * the same time as the chart is initialized, add the axis as a
  31584. * configuration option instead.
  31585. *
  31586. * @sample highcharts/members/chart-addaxis/
  31587. * Add and remove axes
  31588. *
  31589. * @function Highcharts.Chart#addColorAxis
  31590. *
  31591. * @param {Highcharts.ColorAxisOptions} options
  31592. * The axis options.
  31593. *
  31594. * @param {boolean} [redraw=true]
  31595. * Whether to redraw the chart after adding.
  31596. *
  31597. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=true]
  31598. * Whether and how to apply animation in the redraw.
  31599. *
  31600. * @return {Highcharts.ColorAxis}
  31601. * The newly generated Axis object.
  31602. */
  31603. Chart.prototype.addColorAxis = function (options, redraw, animation) {
  31604. return this.createAxis('colorAxis', { axis: options, redraw: redraw, animation: animation });
  31605. };
  31606. /**
  31607. * Factory for creating different axis types.
  31608. *
  31609. * @private
  31610. * @function Highcharts.Chart#createAxis
  31611. *
  31612. * @param {string} type
  31613. * An axis type.
  31614. *
  31615. * @param {...Array<*>} arguments
  31616. * All arguments for the constructor.
  31617. *
  31618. * @return {Highcharts.Axis | Highcharts.ColorAxis}
  31619. * The newly generated Axis object.
  31620. */
  31621. Chart.prototype.createAxis = function (type, options) {
  31622. var isColorAxis = type === 'colorAxis',
  31623. axisOptions = options.axis,
  31624. redraw = options.redraw,
  31625. animation = options.animation,
  31626. userOptions = merge(axisOptions, {
  31627. index: this[type].length,
  31628. isX: type === 'xAxis'
  31629. });
  31630. var axis;
  31631. if (isColorAxis) {
  31632. axis = new H.ColorAxis(this, userOptions);
  31633. }
  31634. else {
  31635. axis = new Axis(this, userOptions);
  31636. }
  31637. if (isColorAxis) {
  31638. this.isDirtyLegend = true;
  31639. // Clear before 'bindAxes' (#11924)
  31640. this.axes.forEach(function (axis) {
  31641. axis.series = [];
  31642. });
  31643. this.series.forEach(function (series) {
  31644. series.bindAxes();
  31645. series.isDirtyData = true;
  31646. });
  31647. }
  31648. if (pick(redraw, true)) {
  31649. this.redraw(animation);
  31650. }
  31651. return axis;
  31652. };
  31653. /**
  31654. * Dim the chart and show a loading text or symbol. Options for the loading
  31655. * screen are defined in {@link
  31656. * https://api.highcharts.com/highcharts/loading|the loading options}.
  31657. *
  31658. * @sample highcharts/members/chart-hideloading/
  31659. * Show and hide loading from a button
  31660. * @sample highcharts/members/chart-showloading/
  31661. * Apply different text labels
  31662. * @sample stock/members/chart-show-hide-loading/
  31663. * Toggle loading in Highcharts Stock
  31664. *
  31665. * @function Highcharts.Chart#showLoading
  31666. *
  31667. * @param {string} [str]
  31668. * An optional text to show in the loading label instead of the
  31669. * default one. The default text is set in
  31670. * [lang.loading](https://api.highcharts.com/highcharts/lang.loading).
  31671. */
  31672. Chart.prototype.showLoading = function (str) {
  31673. var chart = this,
  31674. options = chart.options,
  31675. loadingOptions = options.loading,
  31676. setLoadingSize = function () {
  31677. if (loadingDiv) {
  31678. css(loadingDiv, {
  31679. left: chart.plotLeft + 'px',
  31680. top: chart.plotTop + 'px',
  31681. width: chart.plotWidth + 'px',
  31682. height: chart.plotHeight + 'px'
  31683. });
  31684. }
  31685. };
  31686. var loadingDiv = chart.loadingDiv,
  31687. loadingSpan = chart.loadingSpan;
  31688. // create the layer at the first call
  31689. if (!loadingDiv) {
  31690. chart.loadingDiv = loadingDiv = createElement('div', {
  31691. className: 'highcharts-loading highcharts-loading-hidden'
  31692. }, null, chart.container);
  31693. }
  31694. if (!loadingSpan) {
  31695. chart.loadingSpan = loadingSpan = createElement('span', { className: 'highcharts-loading-inner' }, null, loadingDiv);
  31696. addEvent(chart, 'redraw', setLoadingSize); // #1080
  31697. }
  31698. loadingDiv.className = 'highcharts-loading';
  31699. // Update text
  31700. AST.setElementHTML(loadingSpan, pick(str, options.lang.loading, ''));
  31701. if (!chart.styledMode) {
  31702. // Update visuals
  31703. css(loadingDiv, extend(loadingOptions.style, {
  31704. zIndex: 10
  31705. }));
  31706. css(loadingSpan, loadingOptions.labelStyle);
  31707. // Show it
  31708. if (!chart.loadingShown) {
  31709. css(loadingDiv, {
  31710. opacity: 0,
  31711. display: ''
  31712. });
  31713. animate(loadingDiv, {
  31714. opacity: loadingOptions.style.opacity || 0.5
  31715. }, {
  31716. duration: loadingOptions.showDuration || 0
  31717. });
  31718. }
  31719. }
  31720. chart.loadingShown = true;
  31721. setLoadingSize();
  31722. };
  31723. /**
  31724. * Hide the loading layer.
  31725. *
  31726. * @see Highcharts.Chart#showLoading
  31727. *
  31728. * @sample highcharts/members/chart-hideloading/
  31729. * Show and hide loading from a button
  31730. * @sample stock/members/chart-show-hide-loading/
  31731. * Toggle loading in Highcharts Stock
  31732. *
  31733. * @function Highcharts.Chart#hideLoading
  31734. */
  31735. Chart.prototype.hideLoading = function () {
  31736. var options = this.options,
  31737. loadingDiv = this.loadingDiv;
  31738. if (loadingDiv) {
  31739. loadingDiv.className =
  31740. 'highcharts-loading highcharts-loading-hidden';
  31741. if (!this.styledMode) {
  31742. animate(loadingDiv, {
  31743. opacity: 0
  31744. }, {
  31745. duration: options.loading.hideDuration || 100,
  31746. complete: function () {
  31747. css(loadingDiv, { display: 'none' });
  31748. }
  31749. });
  31750. }
  31751. }
  31752. this.loadingShown = false;
  31753. };
  31754. /**
  31755. * A generic function to update any element of the chart. Elements can be
  31756. * enabled and disabled, moved, re-styled, re-formatted etc.
  31757. *
  31758. * A special case is configuration objects that take arrays, for example
  31759. * [xAxis](https://api.highcharts.com/highcharts/xAxis),
  31760. * [yAxis](https://api.highcharts.com/highcharts/yAxis) or
  31761. * [series](https://api.highcharts.com/highcharts/series). For these
  31762. * collections, an `id` option is used to map the new option set to an
  31763. * existing object. If an existing object of the same id is not found, the
  31764. * corresponding item is updated. So for example, running `chart.update`
  31765. * with a series item without an id, will cause the existing chart's series
  31766. * with the same index in the series array to be updated. When the
  31767. * `oneToOne` parameter is true, `chart.update` will also take care of
  31768. * adding and removing items from the collection. Read more under the
  31769. * parameter description below.
  31770. *
  31771. * Note that when changing series data, `chart.update` may mutate the passed
  31772. * data options.
  31773. *
  31774. * See also the
  31775. * [responsive option set](https://api.highcharts.com/highcharts/responsive).
  31776. * Switching between `responsive.rules` basically runs `chart.update` under
  31777. * the hood.
  31778. *
  31779. * @sample highcharts/members/chart-update/
  31780. * Update chart geometry
  31781. *
  31782. * @function Highcharts.Chart#update
  31783. *
  31784. * @param {Highcharts.Options} options
  31785. * A configuration object for the new chart options.
  31786. *
  31787. * @param {boolean} [redraw=true]
  31788. * Whether to redraw the chart.
  31789. *
  31790. * @param {boolean} [oneToOne=false]
  31791. * When `true`, the `series`, `xAxis`, `yAxis` and `annotations`
  31792. * collections will be updated one to one, and items will be either
  31793. * added or removed to match the new updated options. For example,
  31794. * if the chart has two series and we call `chart.update` with a
  31795. * configuration containing three series, one will be added. If we
  31796. * call `chart.update` with one series, one will be removed. Setting
  31797. * an empty `series` array will remove all series, but leaving out
  31798. * the`series` property will leave all series untouched. If the
  31799. * series have id's, the new series options will be matched by id,
  31800. * and the remaining ones removed.
  31801. *
  31802. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=true]
  31803. * Whether to apply animation, and optionally animation
  31804. * configuration.
  31805. *
  31806. * @fires Highcharts.Chart#event:update
  31807. * @fires Highcharts.Chart#event:afterUpdate
  31808. */
  31809. Chart.prototype.update = function (options, redraw, oneToOne, animation) {
  31810. var chart = this,
  31811. adders = {
  31812. credits: 'addCredits',
  31813. title: 'setTitle',
  31814. subtitle: 'setSubtitle',
  31815. caption: 'setCaption'
  31816. },
  31817. isResponsiveOptions = options.isResponsiveOptions,
  31818. itemsForRemoval = [];
  31819. var updateAllAxes,
  31820. updateAllSeries,
  31821. runSetSize;
  31822. fireEvent(chart, 'update', { options: options });
  31823. // If there are responsive rules in action, undo the responsive rules
  31824. // before we apply the updated options and replay the responsive rules
  31825. // on top from the chart.redraw function (#9617).
  31826. if (!isResponsiveOptions) {
  31827. chart.setResponsive(false, true);
  31828. }
  31829. options = cleanRecursively(options, chart.options);
  31830. chart.userOptions = merge(chart.userOptions, options);
  31831. // If the top-level chart option is present, some special updates are
  31832. // required
  31833. var optionsChart = options.chart;
  31834. if (optionsChart) {
  31835. merge(true, chart.options.chart, optionsChart);
  31836. // Setter function
  31837. if ('className' in optionsChart) {
  31838. chart.setClassName(optionsChart.className);
  31839. }
  31840. if ('reflow' in optionsChart) {
  31841. chart.setReflow(optionsChart.reflow);
  31842. }
  31843. if ('inverted' in optionsChart ||
  31844. 'polar' in optionsChart ||
  31845. 'type' in optionsChart) {
  31846. // Parse options.chart.inverted and options.chart.polar together
  31847. // with the available series.
  31848. chart.propFromSeries();
  31849. updateAllAxes = true;
  31850. }
  31851. if ('alignTicks' in optionsChart) { // #6452
  31852. updateAllAxes = true;
  31853. }
  31854. if ('events' in optionsChart) {
  31855. // Chart event handlers
  31856. registerEventOptions(this, optionsChart);
  31857. }
  31858. objectEach(optionsChart, function (val, key) {
  31859. if (chart.propsRequireUpdateSeries.indexOf('chart.' + key) !==
  31860. -1) {
  31861. updateAllSeries = true;
  31862. }
  31863. // Only dirty box
  31864. if (chart.propsRequireDirtyBox.indexOf(key) !== -1) {
  31865. chart.isDirtyBox = true;
  31866. }
  31867. // Chart setSize
  31868. if (chart.propsRequireReflow.indexOf(key) !== -1) {
  31869. if (isResponsiveOptions) {
  31870. chart.isDirtyBox = true;
  31871. }
  31872. else {
  31873. runSetSize = true;
  31874. }
  31875. }
  31876. });
  31877. if (!chart.styledMode && 'style' in optionsChart) {
  31878. chart.renderer.setStyle(optionsChart.style);
  31879. }
  31880. }
  31881. // Moved up, because tooltip needs updated plotOptions (#6218)
  31882. if (!chart.styledMode && options.colors) {
  31883. this.options.colors = options.colors;
  31884. }
  31885. if (options.time) {
  31886. // Maintaining legacy global time. If the chart is instanciated
  31887. // first with global time, then updated with time options, we need
  31888. // to create a new Time instance to avoid mutating the global time
  31889. // (#10536).
  31890. if (this.time === defaultTime) {
  31891. this.time = new Time(options.time);
  31892. }
  31893. // If we're updating, the time class is different from other chart
  31894. // classes (chart.legend, chart.tooltip etc) in that it doesn't know
  31895. // about the chart. The other chart[something].update functions also
  31896. // set the chart.options[something]. For the time class however we
  31897. // need to update the chart options separately. #14230.
  31898. merge(true, chart.options.time, options.time);
  31899. }
  31900. // Some option stuctures correspond one-to-one to chart objects that
  31901. // have update methods, for example
  31902. // options.credits => chart.credits
  31903. // options.legend => chart.legend
  31904. // options.title => chart.title
  31905. // options.tooltip => chart.tooltip
  31906. // options.subtitle => chart.subtitle
  31907. // options.mapNavigation => chart.mapNavigation
  31908. // options.navigator => chart.navigator
  31909. // options.scrollbar => chart.scrollbar
  31910. objectEach(options, function (val, key) {
  31911. if (chart[key] &&
  31912. typeof chart[key].update === 'function') {
  31913. chart[key].update(val, false);
  31914. // If a one-to-one object does not exist, look for an adder function
  31915. }
  31916. else if (typeof chart[adders[key]] === 'function') {
  31917. chart[adders[key]](val);
  31918. // Else, just merge the options. For nodes like loading, noData,
  31919. // plotOptions
  31920. }
  31921. else if (key !== 'colors' &&
  31922. chart.collectionsWithUpdate.indexOf(key) === -1) {
  31923. merge(true, chart.options[key], options[key]);
  31924. }
  31925. if (key !== 'chart' &&
  31926. chart.propsRequireUpdateSeries.indexOf(key) !== -1) {
  31927. updateAllSeries = true;
  31928. }
  31929. });
  31930. // Setters for collections. For axes and series, each item is referred
  31931. // by an id. If the id is not found, it defaults to the corresponding
  31932. // item in the collection, so setting one series without an id, will
  31933. // update the first series in the chart. Setting two series without
  31934. // an id will update the first and the second respectively (#6019)
  31935. // chart.update and responsive.
  31936. this.collectionsWithUpdate.forEach(function (coll) {
  31937. var indexMap;
  31938. if (options[coll]) {
  31939. // In stock charts, the navigator series are also part of the
  31940. // chart.series array, but those series should not be handled
  31941. // here (#8196) and neither should the navigator axis (#9671).
  31942. indexMap = [];
  31943. chart[coll].forEach(function (s, i) {
  31944. if (!s.options.isInternal) {
  31945. indexMap.push(pick(s.options.index, i));
  31946. }
  31947. });
  31948. splat(options[coll]).forEach(function (newOptions, i) {
  31949. var hasId = defined(newOptions.id);
  31950. var item;
  31951. // Match by id
  31952. if (hasId) {
  31953. item = chart.get(newOptions.id);
  31954. }
  31955. // No match by id found, match by index instead
  31956. if (!item && chart[coll]) {
  31957. item = chart[coll][indexMap ? indexMap[i] : i];
  31958. // Check if we grabbed an item with an exising but
  31959. // different id (#13541)
  31960. if (item && hasId && defined(item.options.id)) {
  31961. item = void 0;
  31962. }
  31963. }
  31964. if (item && item.coll === coll) {
  31965. item.update(newOptions, false);
  31966. if (oneToOne) {
  31967. item.touched = true;
  31968. }
  31969. }
  31970. // If oneToOne and no matching item is found, add one
  31971. if (!item && oneToOne && chart.collectionsWithInit[coll]) {
  31972. chart.collectionsWithInit[coll][0].apply(chart,
  31973. // [newOptions, ...extraArguments, redraw=false]
  31974. [
  31975. newOptions
  31976. ].concat(
  31977. // Not all initializers require extra args
  31978. chart.collectionsWithInit[coll][1] || []).concat([
  31979. false
  31980. ])).touched = true;
  31981. }
  31982. });
  31983. // Add items for removal
  31984. if (oneToOne) {
  31985. chart[coll].forEach(function (item) {
  31986. if (!item.touched && !item.options.isInternal) {
  31987. itemsForRemoval.push(item);
  31988. }
  31989. else {
  31990. delete item.touched;
  31991. }
  31992. });
  31993. }
  31994. }
  31995. });
  31996. itemsForRemoval.forEach(function (item) {
  31997. if (item.chart) { // #9097, avoid removing twice
  31998. item.remove(false);
  31999. }
  32000. });
  32001. if (updateAllAxes) {
  32002. chart.axes.forEach(function (axis) {
  32003. axis.update({}, false);
  32004. });
  32005. }
  32006. // Certain options require the whole series structure to be thrown away
  32007. // and rebuilt
  32008. if (updateAllSeries) {
  32009. chart.getSeriesOrderByLinks().forEach(function (series) {
  32010. // Avoid removed navigator series
  32011. if (series.chart) {
  32012. series.update({}, false);
  32013. }
  32014. }, this);
  32015. }
  32016. // Update size. Redraw is forced.
  32017. var newWidth = optionsChart && optionsChart.width;
  32018. var newHeight = optionsChart && (isString(optionsChart.height) ?
  32019. relativeLength(optionsChart.height,
  32020. newWidth || chart.chartWidth) :
  32021. optionsChart.height);
  32022. if (
  32023. // In this case, run chart.setSize with newWidth and newHeight which
  32024. // are undefined, only for reflowing chart elements because margin
  32025. // or spacing has been set (#8190)
  32026. runSetSize ||
  32027. // In this case, the size is actually set
  32028. (isNumber(newWidth) && newWidth !== chart.chartWidth) ||
  32029. (isNumber(newHeight) && newHeight !== chart.chartHeight)) {
  32030. chart.setSize(newWidth, newHeight, animation);
  32031. }
  32032. else if (pick(redraw, true)) {
  32033. chart.redraw(animation);
  32034. }
  32035. fireEvent(chart, 'afterUpdate', {
  32036. options: options,
  32037. redraw: redraw,
  32038. animation: animation
  32039. });
  32040. };
  32041. /**
  32042. * Shortcut to set the subtitle options. This can also be done from {@link
  32043. * Chart#update} or {@link Chart#setTitle}.
  32044. *
  32045. * @function Highcharts.Chart#setSubtitle
  32046. *
  32047. * @param {Highcharts.SubtitleOptions} options
  32048. * New subtitle options. The subtitle text itself is set by the
  32049. * `options.text` property.
  32050. */
  32051. Chart.prototype.setSubtitle = function (options, redraw) {
  32052. this.applyDescription('subtitle', options);
  32053. this.layOutTitles(redraw);
  32054. };
  32055. /**
  32056. * Set the caption options. This can also be done from {@link
  32057. * Chart#update}.
  32058. *
  32059. * @function Highcharts.Chart#setCaption
  32060. *
  32061. * @param {Highcharts.CaptionOptions} options
  32062. * New caption options. The caption text itself is set by the
  32063. * `options.text` property.
  32064. */
  32065. Chart.prototype.setCaption = function (options, redraw) {
  32066. this.applyDescription('caption', options);
  32067. this.layOutTitles(redraw);
  32068. };
  32069. /**
  32070. * Display the zoom button, so users can reset zoom to the default view
  32071. * settings.
  32072. *
  32073. * @function Highcharts.Chart#showResetZoom
  32074. *
  32075. * @fires Highcharts.Chart#event:afterShowResetZoom
  32076. * @fires Highcharts.Chart#event:beforeShowResetZoom
  32077. */
  32078. Chart.prototype.showResetZoom = function () {
  32079. var chart = this,
  32080. lang = defaultOptions.lang,
  32081. btnOptions = chart.options.chart.resetZoomButton,
  32082. theme = btnOptions.theme,
  32083. states = theme.states,
  32084. alignTo = (btnOptions.relativeTo === 'chart' ||
  32085. btnOptions.relativeTo === 'spacingBox' ?
  32086. null :
  32087. 'scrollablePlotBox');
  32088. /**
  32089. * @private
  32090. */
  32091. function zoomOut() {
  32092. chart.zoomOut();
  32093. }
  32094. fireEvent(this, 'beforeShowResetZoom', null, function () {
  32095. chart.resetZoomButton = chart.renderer
  32096. .button(lang.resetZoom, null, null, zoomOut, theme, states && states.hover)
  32097. .attr({
  32098. align: btnOptions.position.align,
  32099. title: lang.resetZoomTitle
  32100. })
  32101. .addClass('highcharts-reset-zoom')
  32102. .add()
  32103. .align(btnOptions.position, false, alignTo);
  32104. });
  32105. fireEvent(this, 'afterShowResetZoom');
  32106. };
  32107. /**
  32108. * Zoom the chart out after a user has zoomed in. See also
  32109. * [Axis.setExtremes](/class-reference/Highcharts.Axis#setExtremes).
  32110. *
  32111. * @function Highcharts.Chart#zoomOut
  32112. *
  32113. * @fires Highcharts.Chart#event:selection
  32114. */
  32115. Chart.prototype.zoomOut = function () {
  32116. fireEvent(this, 'selection', { resetSelection: true }, this.zoom);
  32117. };
  32118. /**
  32119. * Zoom into a given portion of the chart given by axis coordinates.
  32120. *
  32121. * @private
  32122. * @function Highcharts.Chart#zoom
  32123. * @param {Highcharts.SelectEventObject} event
  32124. */
  32125. Chart.prototype.zoom = function (event) {
  32126. var chart = this,
  32127. pointer = chart.pointer,
  32128. mouseDownPos = (chart.inverted ? pointer.mouseDownX : pointer.mouseDownY);
  32129. var displayButton = false,
  32130. hasZoomed;
  32131. // If zoom is called with no arguments, reset the axes
  32132. if (!event || event.resetSelection) {
  32133. chart.axes.forEach(function (axis) {
  32134. hasZoomed = axis.zoom();
  32135. });
  32136. pointer.initiated = false; // #6804
  32137. }
  32138. else { // else, zoom in on all axes
  32139. event.xAxis.concat(event.yAxis).forEach(function (axisData) {
  32140. var axis = axisData.axis,
  32141. axisStartPos = chart.inverted ? axis.left : axis.top,
  32142. axisEndPos = chart.inverted ?
  32143. axisStartPos + axis.width : axisStartPos + axis.height,
  32144. isXAxis = axis.isXAxis;
  32145. var isWithinPane = false;
  32146. // Check if zoomed area is within the pane (#1289).
  32147. // In case of multiple panes only one pane should be zoomed.
  32148. if ((!isXAxis &&
  32149. mouseDownPos >= axisStartPos &&
  32150. mouseDownPos <= axisEndPos) ||
  32151. isXAxis ||
  32152. !defined(mouseDownPos)) {
  32153. isWithinPane = true;
  32154. }
  32155. // don't zoom more than minRange
  32156. if (pointer[isXAxis ? 'zoomX' : 'zoomY'] && isWithinPane) {
  32157. hasZoomed = axis.zoom(axisData.min, axisData.max);
  32158. if (axis.displayBtn) {
  32159. displayButton = true;
  32160. }
  32161. }
  32162. });
  32163. }
  32164. // Show or hide the Reset zoom button
  32165. var resetZoomButton = chart.resetZoomButton;
  32166. if (displayButton && !resetZoomButton) {
  32167. chart.showResetZoom();
  32168. }
  32169. else if (!displayButton && isObject(resetZoomButton)) {
  32170. chart.resetZoomButton = resetZoomButton.destroy();
  32171. }
  32172. // Redraw
  32173. if (hasZoomed) {
  32174. chart.redraw(pick(chart.options.chart.animation, event && event.animation, chart.pointCount < 100));
  32175. }
  32176. };
  32177. /**
  32178. * Pan the chart by dragging the mouse across the pane. This function is
  32179. * called on mouse move, and the distance to pan is computed from chartX
  32180. * compared to the first chartX position in the dragging operation.
  32181. *
  32182. * @private
  32183. * @function Highcharts.Chart#pan
  32184. * @param {Highcharts.PointerEventObject} e
  32185. * @param {string} panning
  32186. */
  32187. Chart.prototype.pan = function (e, panning) {
  32188. var chart = this,
  32189. hoverPoints = chart.hoverPoints,
  32190. panningOptions = (typeof panning === 'object' ?
  32191. panning :
  32192. {
  32193. enabled: panning,
  32194. type: 'x'
  32195. }),
  32196. chartOptions = chart.options.chart,
  32197. hasMapNavigation = chart.options.mapNavigation &&
  32198. chart.options.mapNavigation.enabled;
  32199. if (chartOptions && chartOptions.panning) {
  32200. chartOptions.panning = panningOptions;
  32201. }
  32202. var type = panningOptions.type;
  32203. var doRedraw;
  32204. fireEvent(this, 'pan', { originalEvent: e }, function () {
  32205. // remove active points for shared tooltip
  32206. if (hoverPoints) {
  32207. hoverPoints.forEach(function (point) {
  32208. point.setState();
  32209. });
  32210. }
  32211. var axes = chart.xAxis;
  32212. if (type === 'xy') {
  32213. axes = axes.concat(chart.yAxis);
  32214. }
  32215. else if (type === 'y') {
  32216. axes = chart.yAxis;
  32217. }
  32218. var nextMousePos = {};
  32219. axes.forEach(function (axis) {
  32220. if (!axis.options.panningEnabled || axis.options.isInternal) {
  32221. return;
  32222. }
  32223. var horiz = axis.horiz, mousePos = e[horiz ? 'chartX' : 'chartY'], mouseDown = horiz ? 'mouseDownX' : 'mouseDownY', startPos = chart[mouseDown], halfPointRange = axis.minPointOffset || 0, pointRangeDirection = (axis.reversed && !chart.inverted) ||
  32224. (!axis.reversed && chart.inverted) ?
  32225. -1 :
  32226. 1, extremes = axis.getExtremes(), panMin = axis.toValue(startPos - mousePos, true) +
  32227. halfPointRange * pointRangeDirection, panMax = axis.toValue(startPos + axis.len - mousePos, true) -
  32228. ((halfPointRange * pointRangeDirection) ||
  32229. (axis.isXAxis && axis.pointRangePadding) ||
  32230. 0), flipped = panMax < panMin, hasVerticalPanning = axis.hasVerticalPanning();
  32231. var newMin = flipped ? panMax : panMin,
  32232. newMax = flipped ? panMin : panMax,
  32233. panningState = axis.panningState,
  32234. spill;
  32235. // General calculations of panning state.
  32236. // This is related to using vertical panning. (#11315).
  32237. if (hasVerticalPanning &&
  32238. !axis.isXAxis && (!panningState || panningState.isDirty)) {
  32239. axis.series.forEach(function (series) {
  32240. var processedData = series.getProcessedData(true),
  32241. dataExtremes = series.getExtremes(processedData.yData,
  32242. true);
  32243. if (!panningState) {
  32244. panningState = {
  32245. startMin: Number.MAX_VALUE,
  32246. startMax: -Number.MAX_VALUE
  32247. };
  32248. }
  32249. if (isNumber(dataExtremes.dataMin) &&
  32250. isNumber(dataExtremes.dataMax)) {
  32251. panningState.startMin = Math.min(pick(series.options.threshold, Infinity), dataExtremes.dataMin, panningState.startMin);
  32252. panningState.startMax = Math.max(pick(series.options.threshold, -Infinity), dataExtremes.dataMax, panningState.startMax);
  32253. }
  32254. });
  32255. }
  32256. var paddedMin = Math.min(pick(panningState && panningState.startMin,
  32257. extremes.dataMin),
  32258. halfPointRange ?
  32259. extremes.min :
  32260. axis.toValue(axis.toPixels(extremes.min) -
  32261. axis.minPixelPadding));
  32262. var paddedMax = Math.max(pick(panningState && panningState.startMax,
  32263. extremes.dataMax),
  32264. halfPointRange ?
  32265. extremes.max :
  32266. axis.toValue(axis.toPixels(extremes.max) +
  32267. axis.minPixelPadding));
  32268. axis.panningState = panningState;
  32269. // It is not necessary to calculate extremes on ordinal axis,
  32270. // because they are already calculated, so we don't want to
  32271. // override them.
  32272. if (!axis.isOrdinal) {
  32273. // If the new range spills over, either to the min or max,
  32274. // adjust the new range.
  32275. spill = paddedMin - newMin;
  32276. if (spill > 0) {
  32277. newMax += spill;
  32278. newMin = paddedMin;
  32279. }
  32280. spill = newMax - paddedMax;
  32281. if (spill > 0) {
  32282. newMax = paddedMax;
  32283. newMin -= spill;
  32284. }
  32285. // Set new extremes if they are actually new
  32286. if (axis.series.length &&
  32287. newMin !== extremes.min &&
  32288. newMax !== extremes.max &&
  32289. newMin >= paddedMin &&
  32290. newMax <= paddedMax) {
  32291. axis.setExtremes(newMin, newMax, false, false, { trigger: 'pan' });
  32292. if (!chart.resetZoomButton &&
  32293. !hasMapNavigation &&
  32294. // Show reset zoom button only when both newMin and
  32295. // newMax values are between padded axis range.
  32296. newMin !== paddedMin &&
  32297. newMax !== paddedMax &&
  32298. type.match('y')) {
  32299. chart.showResetZoom();
  32300. axis.displayBtn = false;
  32301. }
  32302. doRedraw = true;
  32303. }
  32304. // set new reference for next run:
  32305. nextMousePos[mouseDown] = mousePos;
  32306. }
  32307. });
  32308. objectEach(nextMousePos, function (pos, down) {
  32309. chart[down] = pos;
  32310. });
  32311. if (doRedraw) {
  32312. chart.redraw(false);
  32313. }
  32314. css(chart.container, { cursor: 'move' });
  32315. });
  32316. };
  32317. return Chart;
  32318. }());
  32319. extend(Chart.prototype, {
  32320. // Hook for adding callbacks in modules
  32321. callbacks: [],
  32322. /**
  32323. * These collections (arrays) implement `Chart.addSomethig` method used in
  32324. * chart.update() to create new object in the collection. Equivalent for
  32325. * deleting is resolved by simple `Somethig.remove()`.
  32326. *
  32327. * Note: We need to define these references after initializers are bound to
  32328. * chart's prototype.
  32329. */
  32330. collectionsWithInit: {
  32331. // collectionName: [ initializingMethod, [extraArguments] ]
  32332. xAxis: [Chart.prototype.addAxis, [true]],
  32333. yAxis: [Chart.prototype.addAxis, [false]],
  32334. series: [Chart.prototype.addSeries]
  32335. },
  32336. /**
  32337. * These collections (arrays) implement update() methods with support for
  32338. * one-to-one option.
  32339. */
  32340. collectionsWithUpdate: [
  32341. 'xAxis',
  32342. 'yAxis',
  32343. 'zAxis',
  32344. 'series'
  32345. ],
  32346. /**
  32347. * These properties cause isDirtyBox to be set to true when updating. Can be
  32348. * extended from plugins.
  32349. */
  32350. propsRequireDirtyBox: [
  32351. 'backgroundColor',
  32352. 'borderColor',
  32353. 'borderWidth',
  32354. 'borderRadius',
  32355. 'plotBackgroundColor',
  32356. 'plotBackgroundImage',
  32357. 'plotBorderColor',
  32358. 'plotBorderWidth',
  32359. 'plotShadow',
  32360. 'shadow'
  32361. ],
  32362. /**
  32363. * These properties require a full reflow of chart elements, best
  32364. * implemented through running `Chart.setSize` internally (#8190).
  32365. * @type {Array}
  32366. */
  32367. propsRequireReflow: [
  32368. 'margin',
  32369. 'marginTop',
  32370. 'marginRight',
  32371. 'marginBottom',
  32372. 'marginLeft',
  32373. 'spacing',
  32374. 'spacingTop',
  32375. 'spacingRight',
  32376. 'spacingBottom',
  32377. 'spacingLeft'
  32378. ],
  32379. /**
  32380. * These properties cause all series to be updated when updating. Can be
  32381. * extended from plugins.
  32382. */
  32383. propsRequireUpdateSeries: [
  32384. 'chart.inverted',
  32385. 'chart.polar',
  32386. 'chart.ignoreHiddenSeries',
  32387. 'chart.type',
  32388. 'colors',
  32389. 'plotOptions',
  32390. 'time',
  32391. 'tooltip'
  32392. ]
  32393. });
  32394. /* *
  32395. *
  32396. * Export
  32397. *
  32398. * */
  32399. /* *
  32400. *
  32401. * API Declarations
  32402. *
  32403. * */
  32404. /**
  32405. * Callback for chart constructors.
  32406. *
  32407. * @callback Highcharts.ChartCallbackFunction
  32408. *
  32409. * @param {Highcharts.Chart} chart
  32410. * Created chart.
  32411. */
  32412. /**
  32413. * Format a number and return a string based on input settings.
  32414. *
  32415. * @callback Highcharts.NumberFormatterCallbackFunction
  32416. *
  32417. * @param {number} number
  32418. * The input number to format.
  32419. *
  32420. * @param {number} decimals
  32421. * The amount of decimals. A value of -1 preserves the amount in the
  32422. * input number.
  32423. *
  32424. * @param {string} [decimalPoint]
  32425. * The decimal point, defaults to the one given in the lang options, or
  32426. * a dot.
  32427. *
  32428. * @param {string} [thousandsSep]
  32429. * The thousands separator, defaults to the one given in the lang
  32430. * options, or a space character.
  32431. *
  32432. * @return {string} The formatted number.
  32433. */
  32434. /**
  32435. * The chart title. The title has an `update` method that allows modifying the
  32436. * options directly or indirectly via `chart.update`.
  32437. *
  32438. * @interface Highcharts.TitleObject
  32439. * @extends Highcharts.SVGElement
  32440. */ /**
  32441. * Modify options for the title.
  32442. *
  32443. * @function Highcharts.TitleObject#update
  32444. *
  32445. * @param {Highcharts.TitleOptions} titleOptions
  32446. * Options to modify.
  32447. *
  32448. * @param {boolean} [redraw=true]
  32449. * Whether to redraw the chart after the title is altered. If doing more
  32450. * operations on the chart, it is a good idea to set redraw to false and
  32451. * call {@link Chart#redraw} after.
  32452. */
  32453. /**
  32454. * The chart subtitle. The subtitle has an `update` method that
  32455. * allows modifying the options directly or indirectly via
  32456. * `chart.update`.
  32457. *
  32458. * @interface Highcharts.SubtitleObject
  32459. * @extends Highcharts.SVGElement
  32460. */ /**
  32461. * Modify options for the subtitle.
  32462. *
  32463. * @function Highcharts.SubtitleObject#update
  32464. *
  32465. * @param {Highcharts.SubtitleOptions} subtitleOptions
  32466. * Options to modify.
  32467. *
  32468. * @param {boolean} [redraw=true]
  32469. * Whether to redraw the chart after the subtitle is altered. If doing
  32470. * more operations on the chart, it is a good idea to set redraw to false
  32471. * and call {@link Chart#redraw} after.
  32472. */
  32473. /**
  32474. * The chart caption. The caption has an `update` method that
  32475. * allows modifying the options directly or indirectly via
  32476. * `chart.update`.
  32477. *
  32478. * @interface Highcharts.CaptionObject
  32479. * @extends Highcharts.SVGElement
  32480. */ /**
  32481. * Modify options for the caption.
  32482. *
  32483. * @function Highcharts.CaptionObject#update
  32484. *
  32485. * @param {Highcharts.CaptionOptions} captionOptions
  32486. * Options to modify.
  32487. *
  32488. * @param {boolean} [redraw=true]
  32489. * Whether to redraw the chart after the caption is altered. If doing
  32490. * more operations on the chart, it is a good idea to set redraw to false
  32491. * and call {@link Chart#redraw} after.
  32492. */
  32493. /**
  32494. * @interface Highcharts.ChartIsInsideOptionsObject
  32495. */ /**
  32496. * @name Highcharts.ChartIsInsideOptionsObject#ignoreX
  32497. * @type {boolean|undefined}
  32498. */ /**
  32499. * @name Highcharts.ChartIsInsideOptionsObject#ignoreY
  32500. * @type {boolean|undefined}
  32501. */ /**
  32502. * @name Highcharts.ChartIsInsideOptionsObject#inverted
  32503. * @type {boolean|undefined}
  32504. */ /**
  32505. * @name Highcharts.ChartIsInsideOptionsObject#paneCoordinates
  32506. * @type {boolean|undefined}
  32507. */ /**
  32508. * @name Highcharts.ChartIsInsideOptionsObject#series
  32509. * @type {Highcharts.Series|undefined}
  32510. */ /**
  32511. * @name Highcharts.ChartIsInsideOptionsObject#visiblePlotOnly
  32512. * @type {boolean|undefined}
  32513. */
  32514. ''; // include doclets above in transpilat
  32515. return Chart;
  32516. });
  32517. _registerModule(_modules, 'Mixins/LegendSymbol.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
  32518. /* *
  32519. *
  32520. * (c) 2010-2021 Torstein Honsi
  32521. *
  32522. * License: www.highcharts.com/license
  32523. *
  32524. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  32525. *
  32526. * */
  32527. var merge = U.merge,
  32528. pick = U.pick;
  32529. /* eslint-disable valid-jsdoc */
  32530. /**
  32531. * Legend symbol mixin.
  32532. *
  32533. * @private
  32534. * @mixin Highcharts.LegendSymbolMixin
  32535. */
  32536. var LegendSymbolMixin = H.LegendSymbolMixin = {
  32537. /**
  32538. * Get the series' symbol in the legend
  32539. *
  32540. * @private
  32541. * @function Highcharts.LegendSymbolMixin.drawRectangle
  32542. *
  32543. * @param {Highcharts.Legend} legend
  32544. * The legend object
  32545. *
  32546. * @param {Highcharts.Point|Highcharts.Series} item
  32547. * The series (this) or point
  32548. */
  32549. drawRectangle: function (legend,
  32550. item) {
  32551. var options = legend.options,
  32552. symbolHeight = legend.symbolHeight,
  32553. square = options.squareSymbol,
  32554. symbolWidth = square ? symbolHeight : legend.symbolWidth;
  32555. item.legendSymbol = this.chart.renderer.rect(square ? (legend.symbolWidth - symbolHeight) / 2 : 0, legend.baseline - symbolHeight + 1, // #3988
  32556. symbolWidth, symbolHeight, pick(legend.options.symbolRadius, symbolHeight / 2))
  32557. .addClass('highcharts-point')
  32558. .attr({
  32559. zIndex: 3
  32560. }).add(item.legendGroup);
  32561. },
  32562. /**
  32563. * Get the series' symbol in the legend. This method should be overridable
  32564. * to create custom symbols through
  32565. * Highcharts.seriesTypes[type].prototype.drawLegendSymbols.
  32566. *
  32567. * @private
  32568. * @function Highcharts.LegendSymbolMixin.drawLineMarker
  32569. *
  32570. * @param {Highcharts.Legend} legend
  32571. * The legend object.
  32572. */
  32573. drawLineMarker: function (legend) {
  32574. var options = this.options,
  32575. markerOptions = options.marker,
  32576. radius,
  32577. legendSymbol,
  32578. symbolWidth = legend.symbolWidth,
  32579. symbolHeight = legend.symbolHeight,
  32580. generalRadius = symbolHeight / 2,
  32581. renderer = this.chart.renderer,
  32582. legendItemGroup = this.legendGroup,
  32583. verticalCenter = legend.baseline -
  32584. Math.round(legend.fontMetrics.b * 0.3),
  32585. attr = {};
  32586. // Draw the line
  32587. if (!this.chart.styledMode) {
  32588. attr = {
  32589. 'stroke-width': options.lineWidth || 0
  32590. };
  32591. if (options.dashStyle) {
  32592. attr.dashstyle = options.dashStyle;
  32593. }
  32594. }
  32595. this.legendLine = renderer
  32596. .path([
  32597. ['M', 0, verticalCenter],
  32598. ['L', symbolWidth, verticalCenter]
  32599. ])
  32600. .addClass('highcharts-graph')
  32601. .attr(attr)
  32602. .add(legendItemGroup);
  32603. // Draw the marker
  32604. if (markerOptions && markerOptions.enabled !== false && symbolWidth) {
  32605. // Do not allow the marker to be larger than the symbolHeight
  32606. radius = Math.min(pick(markerOptions.radius, generalRadius), generalRadius);
  32607. // Restrict symbol markers size
  32608. if (this.symbol.indexOf('url') === 0) {
  32609. markerOptions = merge(markerOptions, {
  32610. width: symbolHeight,
  32611. height: symbolHeight
  32612. });
  32613. radius = 0;
  32614. }
  32615. this.legendSymbol = legendSymbol = renderer.symbol(this.symbol, (symbolWidth / 2) - radius, verticalCenter - radius, 2 * radius, 2 * radius, markerOptions)
  32616. .addClass('highcharts-point')
  32617. .add(legendItemGroup);
  32618. legendSymbol.isMarker = true;
  32619. }
  32620. }
  32621. };
  32622. return LegendSymbolMixin;
  32623. });
  32624. _registerModule(_modules, 'Core/Series/Series.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Foundation.js'], _modules['Core/Globals.js'], _modules['Mixins/LegendSymbol.js'], _modules['Core/DefaultOptions.js'], _modules['Core/Color/Palette.js'], _modules['Core/Series/Point.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Utilities.js']], function (A, F, H, LegendSymbolMixin, D, palette, Point, SeriesRegistry, SVGElement, U) {
  32625. /* *
  32626. *
  32627. * (c) 2010-2021 Torstein Honsi
  32628. *
  32629. * License: www.highcharts.com/license
  32630. *
  32631. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  32632. *
  32633. * */
  32634. var animObject = A.animObject,
  32635. setAnimation = A.setAnimation;
  32636. var registerEventOptions = F.registerEventOptions;
  32637. var hasTouch = H.hasTouch,
  32638. svg = H.svg,
  32639. win = H.win;
  32640. var defaultOptions = D.defaultOptions;
  32641. var seriesTypes = SeriesRegistry.seriesTypes;
  32642. var addEvent = U.addEvent,
  32643. arrayMax = U.arrayMax,
  32644. arrayMin = U.arrayMin,
  32645. clamp = U.clamp,
  32646. cleanRecursively = U.cleanRecursively,
  32647. correctFloat = U.correctFloat,
  32648. defined = U.defined,
  32649. erase = U.erase,
  32650. error = U.error,
  32651. extend = U.extend,
  32652. find = U.find,
  32653. fireEvent = U.fireEvent,
  32654. getNestedProperty = U.getNestedProperty,
  32655. isArray = U.isArray,
  32656. isNumber = U.isNumber,
  32657. isString = U.isString,
  32658. merge = U.merge,
  32659. objectEach = U.objectEach,
  32660. pick = U.pick,
  32661. removeEvent = U.removeEvent,
  32662. splat = U.splat,
  32663. syncTimeout = U.syncTimeout;
  32664. /* *
  32665. *
  32666. * Class
  32667. *
  32668. * */
  32669. /**
  32670. * This is the base series prototype that all other series types inherit from.
  32671. * A new series is initialized either through the
  32672. * [series](https://api.highcharts.com/highcharts/series)
  32673. * option structure, or after the chart is initialized, through
  32674. * {@link Highcharts.Chart#addSeries}.
  32675. *
  32676. * The object can be accessed in a number of ways. All series and point event
  32677. * handlers give a reference to the `series` object. The chart object has a
  32678. * {@link Highcharts.Chart#series|series} property that is a collection of all
  32679. * the chart's series. The point objects and axis objects also have the same
  32680. * reference.
  32681. *
  32682. * Another way to reference the series programmatically is by `id`. Add an id
  32683. * in the series configuration options, and get the series object by
  32684. * {@link Highcharts.Chart#get}.
  32685. *
  32686. * Configuration options for the series are given in three levels. Options for
  32687. * all series in a chart are given in the
  32688. * [plotOptions.series](https://api.highcharts.com/highcharts/plotOptions.series)
  32689. * object. Then options for all series of a specific type
  32690. * are given in the plotOptions of that type, for example `plotOptions.line`.
  32691. * Next, options for one single series are given in the series array, or as
  32692. * arguments to `chart.addSeries`.
  32693. *
  32694. * The data in the series is stored in various arrays.
  32695. *
  32696. * - First, `series.options.data` contains all the original config options for
  32697. * each point whether added by options or methods like `series.addPoint`.
  32698. *
  32699. * - Next, `series.data` contains those values converted to points, but in case
  32700. * the series data length exceeds the `cropThreshold`, or if the data is
  32701. * grouped, `series.data` doesn't contain all the points. It only contains the
  32702. * points that have been created on demand.
  32703. *
  32704. * - Then there's `series.points` that contains all currently visible point
  32705. * objects. In case of cropping, the cropped-away points are not part of this
  32706. * array. The `series.points` array starts at `series.cropStart` compared to
  32707. * `series.data` and `series.options.data`. If however the series data is
  32708. * grouped, these can't be correlated one to one.
  32709. *
  32710. * - `series.xData` and `series.processedXData` contain clean x values,
  32711. * equivalent to `series.data` and `series.points`.
  32712. *
  32713. * - `series.yData` and `series.processedYData` contain clean y values,
  32714. * equivalent to `series.data` and `series.points`.
  32715. *
  32716. * @class
  32717. * @name Highcharts.Series
  32718. *
  32719. * @param {Highcharts.Chart} chart
  32720. * The chart instance.
  32721. *
  32722. * @param {Highcharts.SeriesOptionsType|object} options
  32723. * The series options.
  32724. */
  32725. var Series = /** @class */ (function () {
  32726. function Series() {
  32727. /* *
  32728. *
  32729. * Static Functions
  32730. *
  32731. * */
  32732. this._i = void 0;
  32733. this.chart = void 0;
  32734. this.data = void 0;
  32735. this.eventOptions = void 0;
  32736. this.eventsToUnbind = void 0;
  32737. this.index = void 0;
  32738. this.linkedSeries = void 0;
  32739. this.options = void 0;
  32740. this.points = void 0;
  32741. this.processedXData = void 0;
  32742. this.processedYData = void 0;
  32743. this.tooltipOptions = void 0;
  32744. this.userOptions = void 0;
  32745. this.xAxis = void 0;
  32746. this.yAxis = void 0;
  32747. this.zones = void 0;
  32748. /** eslint-enable valid-jsdoc */
  32749. }
  32750. /* *
  32751. *
  32752. * Functions
  32753. *
  32754. * */
  32755. /* eslint-disable valid-jsdoc */
  32756. Series.prototype.init = function (chart, userOptions) {
  32757. fireEvent(this, 'init', { options: userOptions });
  32758. var series = this,
  32759. chartSeries = chart.series;
  32760. // The 'eventsToUnbind' property moved from prototype into the
  32761. // Series init to avoid reference to the same array between
  32762. // the different series and charts. #12959, #13937
  32763. this.eventsToUnbind = [];
  32764. /**
  32765. * Read only. The chart that the series belongs to.
  32766. *
  32767. * @name Highcharts.Series#chart
  32768. * @type {Highcharts.Chart}
  32769. */
  32770. series.chart = chart;
  32771. /**
  32772. * Read only. The series' type, like "line", "area", "column" etc.
  32773. * The type in the series options anc can be altered using
  32774. * {@link Series#update}.
  32775. *
  32776. * @name Highcharts.Series#type
  32777. * @type {string}
  32778. */
  32779. /**
  32780. * Read only. The series' current options. To update, use
  32781. * {@link Series#update}.
  32782. *
  32783. * @name Highcharts.Series#options
  32784. * @type {Highcharts.SeriesOptionsType}
  32785. */
  32786. series.options = series.setOptions(userOptions);
  32787. var options = series.options;
  32788. series.linkedSeries = [];
  32789. // bind the axes
  32790. series.bindAxes();
  32791. extend(series, {
  32792. /**
  32793. * The series name as given in the options. Defaults to
  32794. * "Series {n}".
  32795. *
  32796. * @name Highcharts.Series#name
  32797. * @type {string}
  32798. */
  32799. name: options.name,
  32800. state: '',
  32801. /**
  32802. * Read only. The series' visibility state as set by {@link
  32803. * Series#show}, {@link Series#hide}, or in the initial
  32804. * configuration.
  32805. *
  32806. * @name Highcharts.Series#visible
  32807. * @type {boolean}
  32808. */
  32809. visible: options.visible !== false,
  32810. /**
  32811. * Read only. The series' selected state as set by {@link
  32812. * Highcharts.Series#select}.
  32813. *
  32814. * @name Highcharts.Series#selected
  32815. * @type {boolean}
  32816. */
  32817. selected: options.selected === true // false by default
  32818. });
  32819. registerEventOptions(this, options);
  32820. var events = options.events;
  32821. if ((events && events.click) ||
  32822. (options.point &&
  32823. options.point.events &&
  32824. options.point.events.click) ||
  32825. options.allowPointSelect) {
  32826. chart.runTrackerClick = true;
  32827. }
  32828. series.getColor();
  32829. series.getSymbol();
  32830. // Initialize the parallel data arrays
  32831. series.parallelArrays.forEach(function (key) {
  32832. if (!series[key + 'Data']) {
  32833. series[key + 'Data'] = [];
  32834. }
  32835. });
  32836. // Mark cartesian
  32837. if (series.isCartesian) {
  32838. chart.hasCartesianSeries = true;
  32839. }
  32840. // Get the index and register the series in the chart. The index is
  32841. // one more than the current latest series index (#5960).
  32842. var lastSeries;
  32843. if (chartSeries.length) {
  32844. lastSeries = chartSeries[chartSeries.length - 1];
  32845. }
  32846. series._i = pick(lastSeries && lastSeries._i, -1) + 1;
  32847. series.opacity = series.options.opacity;
  32848. // Insert the series and re-order all series above the insertion
  32849. // point.
  32850. chart.orderSeries(this.insert(chartSeries));
  32851. // Set options for series with sorting and set data later.
  32852. if (options.dataSorting && options.dataSorting.enabled) {
  32853. series.setDataSortingOptions();
  32854. }
  32855. else if (!series.points && !series.data) {
  32856. series.setData(options.data, false);
  32857. }
  32858. fireEvent(this, 'afterInit');
  32859. };
  32860. /**
  32861. * Check whether the series item is itself or inherits from a certain
  32862. * series type.
  32863. *
  32864. * @function Highcharts.Series#is
  32865. * @param {string} type The type of series to check for, can be either
  32866. * featured or custom series types. For example `column`, `pie`,
  32867. * `ohlc` etc.
  32868. *
  32869. * @return {boolean}
  32870. * True if this item is or inherits from the given type.
  32871. */
  32872. Series.prototype.is = function (type) {
  32873. return seriesTypes[type] && this instanceof seriesTypes[type];
  32874. };
  32875. /**
  32876. * Insert the series in a collection with other series, either the chart
  32877. * series or yAxis series, in the correct order according to the index
  32878. * option. Used internally when adding series.
  32879. *
  32880. * @private
  32881. * @function Highcharts.Series#insert
  32882. * @param {Array<Highcharts.Series>} collection
  32883. * A collection of series, like `chart.series` or `xAxis.series`.
  32884. * @return {number}
  32885. * The index of the series in the collection.
  32886. */
  32887. Series.prototype.insert = function (collection) {
  32888. var indexOption = this.options.index,
  32889. i;
  32890. // Insert by index option
  32891. if (isNumber(indexOption)) {
  32892. i = collection.length;
  32893. while (i--) {
  32894. // Loop down until the interted element has higher index
  32895. if (indexOption >=
  32896. pick(collection[i].options.index, collection[i]._i)) {
  32897. collection.splice(i + 1, 0, this);
  32898. break;
  32899. }
  32900. }
  32901. if (i === -1) {
  32902. collection.unshift(this);
  32903. }
  32904. i = i + 1;
  32905. // Or just push it to the end
  32906. }
  32907. else {
  32908. collection.push(this);
  32909. }
  32910. return pick(i, collection.length - 1);
  32911. };
  32912. /**
  32913. * Set the xAxis and yAxis properties of cartesian series, and register
  32914. * the series in the `axis.series` array.
  32915. *
  32916. * @private
  32917. * @function Highcharts.Series#bindAxes
  32918. */
  32919. Series.prototype.bindAxes = function () {
  32920. var series = this,
  32921. seriesOptions = series.options,
  32922. chart = series.chart,
  32923. axisOptions;
  32924. fireEvent(this, 'bindAxes', null, function () {
  32925. // repeat for xAxis and yAxis
  32926. (series.axisTypes || []).forEach(function (AXIS) {
  32927. var index = 0;
  32928. // loop through the chart's axis objects
  32929. chart[AXIS].forEach(function (axis) {
  32930. axisOptions = axis.options;
  32931. // apply if the series xAxis or yAxis option mathches
  32932. // the number of the axis, or if undefined, use the
  32933. // first axis
  32934. if ((seriesOptions[AXIS] === index &&
  32935. !axisOptions.isInternal) ||
  32936. (typeof seriesOptions[AXIS] !==
  32937. 'undefined' &&
  32938. seriesOptions[AXIS] === axisOptions.id) ||
  32939. (typeof seriesOptions[AXIS] ===
  32940. 'undefined' &&
  32941. axisOptions.index === 0)) {
  32942. // register this series in the axis.series lookup
  32943. series.insert(axis.series);
  32944. // set this series.xAxis or series.yAxis reference
  32945. /**
  32946. * Read only. The unique xAxis object associated
  32947. * with the series.
  32948. *
  32949. * @name Highcharts.Series#xAxis
  32950. * @type {Highcharts.Axis}
  32951. */
  32952. /**
  32953. * Read only. The unique yAxis object associated
  32954. * with the series.
  32955. *
  32956. * @name Highcharts.Series#yAxis
  32957. * @type {Highcharts.Axis}
  32958. */
  32959. series[AXIS] = axis;
  32960. // mark dirty for redraw
  32961. axis.isDirty = true;
  32962. }
  32963. if (!axisOptions.isInternal) {
  32964. index++;
  32965. }
  32966. });
  32967. // The series needs an X and an Y axis
  32968. if (!series[AXIS] &&
  32969. series.optionalAxis !== AXIS) {
  32970. error(18, true, chart);
  32971. }
  32972. });
  32973. });
  32974. fireEvent(this, 'afterBindAxes');
  32975. };
  32976. /**
  32977. * For simple series types like line and column, the data values are
  32978. * held in arrays like xData and yData for quick lookup to find extremes
  32979. * and more. For multidimensional series like bubble and map, this can
  32980. * be extended with arrays like zData and valueData by adding to the
  32981. * `series.parallelArrays` array.
  32982. *
  32983. * @private
  32984. * @function Highcharts.Series#updateParallelArrays
  32985. */
  32986. Series.prototype.updateParallelArrays = function (point, i) {
  32987. var series = point.series,
  32988. args = arguments,
  32989. fn = isNumber(i) ?
  32990. // Insert the value in the given position
  32991. function (key) {
  32992. var val = key === 'y' && series.toYData ?
  32993. series.toYData(point) :
  32994. point[key];
  32995. series[key + 'Data'][i] = val;
  32996. } :
  32997. // Apply the method specified in i with the following
  32998. // arguments as arguments
  32999. function (key) {
  33000. Array.prototype[i].apply(series[key + 'Data'], Array.prototype.slice.call(args, 2));
  33001. };
  33002. series.parallelArrays.forEach(fn);
  33003. };
  33004. /**
  33005. * Define hasData functions for series. These return true if there
  33006. * are data points on this series within the plot area.
  33007. *
  33008. * @private
  33009. * @function Highcharts.Series#hasData
  33010. * @return {boolean}
  33011. */
  33012. Series.prototype.hasData = function () {
  33013. return ((this.visible &&
  33014. typeof this.dataMax !== 'undefined' &&
  33015. typeof this.dataMin !== 'undefined') || ( // #3703
  33016. this.visible &&
  33017. this.yData &&
  33018. this.yData.length > 0) // #9758
  33019. );
  33020. };
  33021. /**
  33022. * Return an auto incremented x value based on the pointStart and
  33023. * pointInterval options. This is only used if an x value is not given
  33024. * for the point that calls autoIncrement.
  33025. *
  33026. * @private
  33027. * @function Highcharts.Series#autoIncrement
  33028. * @return {number}
  33029. */
  33030. Series.prototype.autoIncrement = function () {
  33031. var options = this.options,
  33032. xIncrement = this.xIncrement,
  33033. date,
  33034. pointInterval,
  33035. pointIntervalUnit = options.pointIntervalUnit,
  33036. time = this.chart.time;
  33037. xIncrement = pick(xIncrement, options.pointStart, 0);
  33038. this.pointInterval = pointInterval = pick(this.pointInterval, options.pointInterval, 1);
  33039. // Added code for pointInterval strings
  33040. if (pointIntervalUnit) {
  33041. date = new time.Date(xIncrement);
  33042. if (pointIntervalUnit === 'day') {
  33043. time.set('Date', date, time.get('Date', date) + pointInterval);
  33044. }
  33045. else if (pointIntervalUnit === 'month') {
  33046. time.set('Month', date, time.get('Month', date) + pointInterval);
  33047. }
  33048. else if (pointIntervalUnit === 'year') {
  33049. time.set('FullYear', date, time.get('FullYear', date) + pointInterval);
  33050. }
  33051. pointInterval = date.getTime() - xIncrement;
  33052. }
  33053. this.xIncrement = xIncrement + pointInterval;
  33054. return xIncrement;
  33055. };
  33056. /**
  33057. * Internal function to set properties for series if data sorting is
  33058. * enabled.
  33059. *
  33060. * @private
  33061. * @function Highcharts.Series#setDataSortingOptions
  33062. */
  33063. Series.prototype.setDataSortingOptions = function () {
  33064. var options = this.options;
  33065. extend(this, {
  33066. requireSorting: false,
  33067. sorted: false,
  33068. enabledDataSorting: true,
  33069. allowDG: false
  33070. });
  33071. // To allow unsorted data for column series.
  33072. if (!defined(options.pointRange)) {
  33073. options.pointRange = 1;
  33074. }
  33075. };
  33076. /**
  33077. * Set the series options by merging from the options tree. Called
  33078. * internally on initializing and updating series. This function will
  33079. * not redraw the series. For API usage, use {@link Series#update}.
  33080. * @private
  33081. * @function Highcharts.Series#setOptions
  33082. *
  33083. * @param {Highcharts.SeriesOptionsType} itemOptions
  33084. * The series options.
  33085. *
  33086. * @return {Highcharts.SeriesOptionsType}
  33087. *
  33088. * @fires Highcharts.Series#event:afterSetOptions
  33089. */
  33090. Series.prototype.setOptions = function (itemOptions) {
  33091. var chart = this.chart,
  33092. chartOptions = chart.options,
  33093. plotOptions = chartOptions.plotOptions,
  33094. userOptions = chart.userOptions || {},
  33095. seriesUserOptions = merge(itemOptions),
  33096. options,
  33097. zones,
  33098. zone,
  33099. styledMode = chart.styledMode,
  33100. e = {
  33101. plotOptions: plotOptions,
  33102. userOptions: seriesUserOptions
  33103. };
  33104. fireEvent(this, 'setOptions', e);
  33105. // These may be modified by the event
  33106. var typeOptions = e.plotOptions[this.type],
  33107. userPlotOptions = (userOptions.plotOptions || {});
  33108. // use copy to prevent undetected changes (#9762)
  33109. /**
  33110. * Contains series options by the user without defaults.
  33111. * @name Highcharts.Series#userOptions
  33112. * @type {Highcharts.SeriesOptionsType}
  33113. */
  33114. this.userOptions = e.userOptions;
  33115. options = merge(typeOptions, plotOptions.series,
  33116. // #3881, chart instance plotOptions[type] should trump
  33117. // plotOptions.series
  33118. userOptions.plotOptions &&
  33119. userOptions.plotOptions[this.type], seriesUserOptions);
  33120. // The tooltip options are merged between global and series specific
  33121. // options. Importance order asscendingly:
  33122. // globals: (1)tooltip, (2)plotOptions.series,
  33123. // (3)plotOptions[this.type]
  33124. // init userOptions with possible later updates: 4-6 like 1-3 and
  33125. // (7)this series options
  33126. this.tooltipOptions = merge(defaultOptions.tooltip, // 1
  33127. defaultOptions.plotOptions.series &&
  33128. defaultOptions.plotOptions.series.tooltip, // 2
  33129. defaultOptions.plotOptions[this.type].tooltip, // 3
  33130. chartOptions.tooltip.userOptions, // 4
  33131. plotOptions.series &&
  33132. plotOptions.series.tooltip, // 5
  33133. plotOptions[this.type].tooltip, // 6
  33134. seriesUserOptions.tooltip // 7
  33135. );
  33136. // When shared tooltip, stickyTracking is true by default,
  33137. // unless user says otherwise.
  33138. this.stickyTracking = pick(seriesUserOptions.stickyTracking, userPlotOptions[this.type] &&
  33139. userPlotOptions[this.type].stickyTracking, userPlotOptions.series && userPlotOptions.series.stickyTracking, (this.tooltipOptions.shared && !this.noSharedTooltip ?
  33140. true :
  33141. options.stickyTracking));
  33142. // Delete marker object if not allowed (#1125)
  33143. if (typeOptions.marker === null) {
  33144. delete options.marker;
  33145. }
  33146. // Handle color zones
  33147. this.zoneAxis = options.zoneAxis;
  33148. zones = this.zones = (options.zones || []).slice();
  33149. if ((options.negativeColor || options.negativeFillColor) &&
  33150. !options.zones) {
  33151. zone = {
  33152. value: options[this.zoneAxis + 'Threshold'] ||
  33153. options.threshold ||
  33154. 0,
  33155. className: 'highcharts-negative'
  33156. };
  33157. if (!styledMode) {
  33158. zone.color = options.negativeColor;
  33159. zone.fillColor = options.negativeFillColor;
  33160. }
  33161. zones.push(zone);
  33162. }
  33163. if (zones.length) { // Push one extra zone for the rest
  33164. if (defined(zones[zones.length - 1].value)) {
  33165. zones.push(styledMode ? {} : {
  33166. color: this.color,
  33167. fillColor: this.fillColor
  33168. });
  33169. }
  33170. }
  33171. fireEvent(this, 'afterSetOptions', { options: options });
  33172. return options;
  33173. };
  33174. /**
  33175. * Return series name in "Series {Number}" format or the one defined by
  33176. * a user. This method can be simply overridden as series name format
  33177. * can vary (e.g. technical indicators).
  33178. *
  33179. * @function Highcharts.Series#getName
  33180. *
  33181. * @return {string}
  33182. * The series name.
  33183. */
  33184. Series.prototype.getName = function () {
  33185. // #4119
  33186. return pick(this.options.name, 'Series ' + (this.index + 1));
  33187. };
  33188. /**
  33189. * @private
  33190. * @function Highcharts.Series#getCyclic
  33191. */
  33192. Series.prototype.getCyclic = function (prop, value, defaults) {
  33193. var i, chart = this.chart, userOptions = this.userOptions, indexName = prop + 'Index', counterName = prop + 'Counter', len = defaults ? defaults.length : pick(chart.options.chart[prop + 'Count'], chart[prop + 'Count']), setting;
  33194. if (!value) {
  33195. // Pick up either the colorIndex option, or the _colorIndex
  33196. // after Series.update()
  33197. setting = pick(userOptions[indexName], userOptions['_' + indexName]);
  33198. if (defined(setting)) { // after Series.update()
  33199. i = setting;
  33200. }
  33201. else {
  33202. // #6138
  33203. if (!chart.series.length) {
  33204. chart[counterName] = 0;
  33205. }
  33206. userOptions['_' + indexName] = i =
  33207. chart[counterName] % len;
  33208. chart[counterName] += 1;
  33209. }
  33210. if (defaults) {
  33211. value = defaults[i];
  33212. }
  33213. }
  33214. // Set the colorIndex
  33215. if (typeof i !== 'undefined') {
  33216. this[indexName] = i;
  33217. }
  33218. this[prop] = value;
  33219. };
  33220. /**
  33221. * Get the series' color based on either the options or pulled from
  33222. * global options.
  33223. *
  33224. * @private
  33225. * @function Highcharts.Series#getColor
  33226. */
  33227. Series.prototype.getColor = function () {
  33228. if (this.chart.styledMode) {
  33229. this.getCyclic('color');
  33230. }
  33231. else if (this.options.colorByPoint) {
  33232. this.color = palette.neutralColor20;
  33233. }
  33234. else {
  33235. this.getCyclic('color', this.options.color ||
  33236. defaultOptions.plotOptions[this.type].color, this.chart.options.colors);
  33237. }
  33238. };
  33239. /**
  33240. * Get all points' instances created for this series.
  33241. *
  33242. * @private
  33243. * @function Highcharts.Series#getPointsCollection
  33244. * @return {Array<Highcharts.Point>}
  33245. */
  33246. Series.prototype.getPointsCollection = function () {
  33247. return (this.hasGroupedData ? this.points : this.data) || [];
  33248. };
  33249. /**
  33250. * Get the series' symbol based on either the options or pulled from
  33251. * global options.
  33252. *
  33253. * @private
  33254. * @function Highcharts.Series#getSymbol
  33255. * @return {void}
  33256. */
  33257. Series.prototype.getSymbol = function () {
  33258. var seriesMarkerOption = this.options.marker;
  33259. this.getCyclic('symbol', seriesMarkerOption.symbol, this.chart.options.symbols);
  33260. };
  33261. /**
  33262. * Finds the index of an existing point that matches the given point
  33263. * options.
  33264. *
  33265. * @private
  33266. * @function Highcharts.Series#findPointIndex
  33267. * @param {Highcharts.PointOptionsObject} optionsObject
  33268. * The options of the point.
  33269. * @param {number} fromIndex
  33270. * The index to start searching from, used for optimizing
  33271. * series with required sorting.
  33272. * @returns {number|undefined}
  33273. * Returns the index of a matching point, or undefined if no
  33274. * match is found.
  33275. */
  33276. Series.prototype.findPointIndex = function (optionsObject, fromIndex) {
  33277. var id = optionsObject.id,
  33278. x = optionsObject.x,
  33279. oldData = this.points,
  33280. matchingPoint,
  33281. matchedById,
  33282. pointIndex,
  33283. matchKey,
  33284. dataSorting = this.options.dataSorting;
  33285. if (id) {
  33286. matchingPoint = this.chart.get(id);
  33287. }
  33288. else if (this.linkedParent || this.enabledDataSorting) {
  33289. matchKey = (dataSorting && dataSorting.matchByName) ?
  33290. 'name' : 'index';
  33291. matchingPoint = find(oldData, function (oldPoint) {
  33292. return !oldPoint.touched && oldPoint[matchKey] ===
  33293. optionsObject[matchKey];
  33294. });
  33295. // Add unmatched point as a new point
  33296. if (!matchingPoint) {
  33297. return void 0;
  33298. }
  33299. }
  33300. if (matchingPoint) {
  33301. pointIndex = matchingPoint && matchingPoint.index;
  33302. if (typeof pointIndex !== 'undefined') {
  33303. matchedById = true;
  33304. }
  33305. }
  33306. // Search for the same X in the existing data set
  33307. if (typeof pointIndex === 'undefined' && isNumber(x)) {
  33308. pointIndex = this.xData.indexOf(x, fromIndex);
  33309. }
  33310. // Reduce pointIndex if data is cropped
  33311. if (pointIndex !== -1 &&
  33312. typeof pointIndex !== 'undefined' &&
  33313. this.cropped) {
  33314. pointIndex = (pointIndex >= this.cropStart) ?
  33315. pointIndex - this.cropStart : pointIndex;
  33316. }
  33317. if (!matchedById &&
  33318. oldData[pointIndex] && oldData[pointIndex].touched) {
  33319. pointIndex = void 0;
  33320. }
  33321. return pointIndex;
  33322. };
  33323. /**
  33324. * Internal function called from setData. If the point count is the same
  33325. * as is was, or if there are overlapping X values, just run
  33326. * Point.update which is cheaper, allows animation, and keeps references
  33327. * to points. This also allows adding or removing points if the X-es
  33328. * don't match.
  33329. *
  33330. * @private
  33331. * @function Highcharts.Series#updateData
  33332. */
  33333. Series.prototype.updateData = function (data, animation) {
  33334. var options = this.options,
  33335. dataSorting = options.dataSorting,
  33336. oldData = this.points,
  33337. pointsToAdd = [],
  33338. hasUpdatedByKey,
  33339. i,
  33340. point,
  33341. lastIndex,
  33342. requireSorting = this.requireSorting,
  33343. equalLength = data.length === oldData.length,
  33344. succeeded = true;
  33345. this.xIncrement = null;
  33346. // Iterate the new data
  33347. data.forEach(function (pointOptions, i) {
  33348. var id,
  33349. x,
  33350. pointIndex,
  33351. optionsObject = (defined(pointOptions) &&
  33352. this.pointClass.prototype.optionsToObject.call({ series: this },
  33353. pointOptions)) || {};
  33354. // Get the x of the new data point
  33355. x = optionsObject.x;
  33356. id = optionsObject.id;
  33357. if (id || isNumber(x)) {
  33358. pointIndex = this.findPointIndex(optionsObject, lastIndex);
  33359. // Matching X not found
  33360. // or used already due to ununique x values (#8995),
  33361. // add point (but later)
  33362. if (pointIndex === -1 ||
  33363. typeof pointIndex === 'undefined') {
  33364. pointsToAdd.push(pointOptions);
  33365. // Matching X found, update
  33366. }
  33367. else if (oldData[pointIndex] &&
  33368. pointOptions !== options.data[pointIndex]) {
  33369. oldData[pointIndex].update(pointOptions, false, null, false);
  33370. // Mark it touched, below we will remove all points that
  33371. // are not touched.
  33372. oldData[pointIndex].touched = true;
  33373. // Speed optimize by only searching after last known
  33374. // index. Performs ~20% bettor on large data sets.
  33375. if (requireSorting) {
  33376. lastIndex = pointIndex + 1;
  33377. }
  33378. // Point exists, no changes, don't remove it
  33379. }
  33380. else if (oldData[pointIndex]) {
  33381. oldData[pointIndex].touched = true;
  33382. }
  33383. // If the length is equal and some of the nodes had a
  33384. // match in the same position, we don't want to remove
  33385. // non-matches.
  33386. if (!equalLength ||
  33387. i !== pointIndex ||
  33388. (dataSorting && dataSorting.enabled) ||
  33389. this.hasDerivedData) {
  33390. hasUpdatedByKey = true;
  33391. }
  33392. }
  33393. else {
  33394. // Gather all points that are not matched
  33395. pointsToAdd.push(pointOptions);
  33396. }
  33397. }, this);
  33398. // Remove points that don't exist in the updated data set
  33399. if (hasUpdatedByKey) {
  33400. i = oldData.length;
  33401. while (i--) {
  33402. point = oldData[i];
  33403. if (point && !point.touched && point.remove) {
  33404. point.remove(false, animation);
  33405. }
  33406. }
  33407. // If we did not find keys (ids or x-values), and the length is the
  33408. // same, update one-to-one
  33409. }
  33410. else if (equalLength && (!dataSorting || !dataSorting.enabled)) {
  33411. data.forEach(function (point, i) {
  33412. // .update doesn't exist on a linked, hidden series (#3709)
  33413. // (#10187)
  33414. if (point !== oldData[i].y && oldData[i].update) {
  33415. oldData[i].update(point, false, null, false);
  33416. }
  33417. });
  33418. // Don't add new points since those configs are used above
  33419. pointsToAdd.length = 0;
  33420. // Did not succeed in updating data
  33421. }
  33422. else {
  33423. succeeded = false;
  33424. }
  33425. oldData.forEach(function (point) {
  33426. if (point) {
  33427. point.touched = false;
  33428. }
  33429. });
  33430. if (!succeeded) {
  33431. return false;
  33432. }
  33433. // Add new points
  33434. pointsToAdd.forEach(function (point) {
  33435. this.addPoint(point, false, null, null, false);
  33436. }, this);
  33437. if (this.xIncrement === null &&
  33438. this.xData &&
  33439. this.xData.length) {
  33440. this.xIncrement = arrayMax(this.xData);
  33441. this.autoIncrement();
  33442. }
  33443. return true;
  33444. };
  33445. /**
  33446. * Apply a new set of data to the series and optionally redraw it. The
  33447. * new data array is passed by reference (except in case of
  33448. * `updatePoints`), and may later be mutated when updating the chart
  33449. * data.
  33450. *
  33451. * Note the difference in behaviour when setting the same amount of
  33452. * points, or a different amount of points, as handled by the
  33453. * `updatePoints` parameter.
  33454. *
  33455. * @sample highcharts/members/series-setdata/
  33456. * Set new data from a button
  33457. * @sample highcharts/members/series-setdata-pie/
  33458. * Set data in a pie
  33459. * @sample stock/members/series-setdata/
  33460. * Set new data in Highcharts Stock
  33461. * @sample maps/members/series-setdata/
  33462. * Set new data in Highmaps
  33463. *
  33464. * @function Highcharts.Series#setData
  33465. *
  33466. * @param {Array<Highcharts.PointOptionsType>} data
  33467. * Takes an array of data in the same format as described under
  33468. * `series.{type}.data` for the given series type, for example a
  33469. * line series would take data in the form described under
  33470. * [series.line.data](https://api.highcharts.com/highcharts/series.line.data).
  33471. *
  33472. * @param {boolean} [redraw=true]
  33473. * Whether to redraw the chart after the series is altered. If
  33474. * doing more operations on the chart, it is a good idea to set
  33475. * redraw to false and call {@link Chart#redraw} after.
  33476. *
  33477. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
  33478. * When the updated data is the same length as the existing data,
  33479. * points will be updated by default, and animation visualizes
  33480. * how the points are changed. Set false to disable animation, or
  33481. * a configuration object to set duration or easing.
  33482. *
  33483. * @param {boolean} [updatePoints=true]
  33484. * When this is true, points will be updated instead of replaced
  33485. * whenever possible. This occurs a) when the updated data is the
  33486. * same length as the existing data, b) when points are matched
  33487. * by their id's, or c) when points can be matched by X values.
  33488. * This allows updating with animation and performs better. In
  33489. * this case, the original array is not passed by reference. Set
  33490. * `false` to prevent.
  33491. */
  33492. Series.prototype.setData = function (data, redraw, animation, updatePoints) {
  33493. var series = this,
  33494. oldData = series.points,
  33495. oldDataLength = (oldData && oldData.length) || 0,
  33496. dataLength,
  33497. options = series.options,
  33498. chart = series.chart,
  33499. dataSorting = options.dataSorting,
  33500. firstPoint = null,
  33501. xAxis = series.xAxis,
  33502. i,
  33503. turboThreshold = options.turboThreshold,
  33504. pt,
  33505. xData = this.xData,
  33506. yData = this.yData,
  33507. pointArrayMap = series.pointArrayMap,
  33508. valueCount = pointArrayMap && pointArrayMap.length,
  33509. keys = options.keys,
  33510. indexOfX = 0,
  33511. indexOfY = 1,
  33512. updatedData;
  33513. data = data || [];
  33514. dataLength = data.length;
  33515. redraw = pick(redraw, true);
  33516. if (dataSorting && dataSorting.enabled) {
  33517. data = this.sortData(data);
  33518. }
  33519. // First try to run Point.update which is cheaper, allows animation,
  33520. // and keeps references to points.
  33521. if (updatePoints !== false &&
  33522. dataLength &&
  33523. oldDataLength &&
  33524. !series.cropped &&
  33525. !series.hasGroupedData &&
  33526. series.visible &&
  33527. // Soft updating has no benefit in boost, and causes JS error
  33528. // (#8355)
  33529. !series.isSeriesBoosting) {
  33530. updatedData = this.updateData(data, animation);
  33531. }
  33532. if (!updatedData) {
  33533. // Reset properties
  33534. series.xIncrement = null;
  33535. series.colorCounter = 0; // for series with colorByPoint (#1547)
  33536. // Update parallel arrays
  33537. this.parallelArrays.forEach(function (key) {
  33538. series[key + 'Data'].length = 0;
  33539. });
  33540. // In turbo mode, only one- or twodimensional arrays of numbers
  33541. // are allowed. The first value is tested, and we assume that
  33542. // all the rest are defined the same way. Although the 'for'
  33543. // loops are similar, they are repeated inside each if-else
  33544. // conditional for max performance.
  33545. if (turboThreshold && dataLength > turboThreshold) {
  33546. firstPoint = series.getFirstValidPoint(data);
  33547. if (isNumber(firstPoint)) { // assume all points are numbers
  33548. for (i = 0; i < dataLength; i++) {
  33549. xData[i] = this.autoIncrement();
  33550. yData[i] = data[i];
  33551. }
  33552. // Assume all points are arrays when first point is
  33553. }
  33554. else if (isArray(firstPoint)) {
  33555. if (valueCount) { // [x, low, high] or [x, o, h, l, c]
  33556. for (i = 0; i < dataLength; i++) {
  33557. pt = data[i];
  33558. xData[i] = pt[0];
  33559. yData[i] =
  33560. pt.slice(1, valueCount + 1);
  33561. }
  33562. }
  33563. else { // [x, y]
  33564. if (keys) {
  33565. indexOfX = keys.indexOf('x');
  33566. indexOfY = keys.indexOf('y');
  33567. indexOfX = indexOfX >= 0 ? indexOfX : 0;
  33568. indexOfY = indexOfY >= 0 ? indexOfY : 1;
  33569. }
  33570. for (i = 0; i < dataLength; i++) {
  33571. pt = data[i];
  33572. xData[i] = pt[indexOfX];
  33573. yData[i] = pt[indexOfY];
  33574. }
  33575. }
  33576. }
  33577. else {
  33578. // Highcharts expects configs to be numbers or arrays in
  33579. // turbo mode
  33580. error(12, false, chart);
  33581. }
  33582. }
  33583. else {
  33584. for (i = 0; i < dataLength; i++) {
  33585. // stray commas in oldIE:
  33586. if (typeof data[i] !== 'undefined') {
  33587. pt = { series: series };
  33588. series.pointClass.prototype.applyOptions.apply(pt, [data[i]]);
  33589. series.updateParallelArrays(pt, i);
  33590. }
  33591. }
  33592. }
  33593. // Forgetting to cast strings to numbers is a common caveat when
  33594. // handling CSV or JSON
  33595. if (yData && isString(yData[0])) {
  33596. error(14, true, chart);
  33597. }
  33598. series.data = [];
  33599. series.options.data = series.userOptions.data = data;
  33600. // destroy old points
  33601. i = oldDataLength;
  33602. while (i--) {
  33603. if (oldData[i] && oldData[i].destroy) {
  33604. oldData[i].destroy();
  33605. }
  33606. }
  33607. // reset minRange (#878)
  33608. if (xAxis) {
  33609. xAxis.minRange = xAxis.userMinRange;
  33610. }
  33611. // redraw
  33612. series.isDirty = chart.isDirtyBox = true;
  33613. series.isDirtyData = !!oldData;
  33614. animation = false;
  33615. }
  33616. // Typically for pie series, points need to be processed and
  33617. // generated prior to rendering the legend
  33618. if (options.legendType === 'point') {
  33619. this.processData();
  33620. this.generatePoints();
  33621. }
  33622. if (redraw) {
  33623. chart.redraw(animation);
  33624. }
  33625. };
  33626. /**
  33627. * Internal function to sort series data
  33628. *
  33629. * @private
  33630. * @function Highcharts.Series#sortData
  33631. *
  33632. * @param {Array<Highcharts.PointOptionsType>} data
  33633. * Force data grouping.
  33634. *
  33635. * @return {Array<Highcharts.PointOptionsObject>}
  33636. */
  33637. Series.prototype.sortData = function (data) {
  33638. var series = this,
  33639. options = series.options,
  33640. dataSorting = options.dataSorting,
  33641. sortKey = dataSorting.sortKey || 'y',
  33642. sortedData,
  33643. getPointOptionsObject = function (series,
  33644. pointOptions) {
  33645. return (defined(pointOptions) &&
  33646. series.pointClass.prototype.optionsToObject.call({
  33647. series: series
  33648. },
  33649. pointOptions)) || {};
  33650. };
  33651. data.forEach(function (pointOptions, i) {
  33652. data[i] = getPointOptionsObject(series, pointOptions);
  33653. data[i].index = i;
  33654. }, this);
  33655. // Sorting
  33656. sortedData = data.concat().sort(function (a, b) {
  33657. var aValue = getNestedProperty(sortKey,
  33658. a);
  33659. var bValue = getNestedProperty(sortKey,
  33660. b);
  33661. return bValue < aValue ? -1 : bValue > aValue ? 1 : 0;
  33662. });
  33663. // Set x value depending on the position in the array
  33664. sortedData.forEach(function (point, i) {
  33665. point.x = i;
  33666. }, this);
  33667. // Set the same x for linked series points if they don't have their
  33668. // own sorting
  33669. if (series.linkedSeries) {
  33670. series.linkedSeries.forEach(function (linkedSeries) {
  33671. var options = linkedSeries.options,
  33672. seriesData = options.data;
  33673. if ((!options.dataSorting ||
  33674. !options.dataSorting.enabled) &&
  33675. seriesData) {
  33676. seriesData.forEach(function (pointOptions, i) {
  33677. seriesData[i] = getPointOptionsObject(linkedSeries, pointOptions);
  33678. if (data[i]) {
  33679. seriesData[i].x = data[i].x;
  33680. seriesData[i].index = i;
  33681. }
  33682. });
  33683. linkedSeries.setData(seriesData, false);
  33684. }
  33685. });
  33686. }
  33687. return data;
  33688. };
  33689. /**
  33690. * Internal function to process the data by cropping away unused data
  33691. * points if the series is longer than the crop threshold. This saves
  33692. * computing time for large series.
  33693. *
  33694. * @private
  33695. * @function Highcharts.Series#getProcessedData
  33696. * @param {boolean} [forceExtremesFromAll]
  33697. * Force getting extremes of a total series data range.
  33698. * @return {Highcharts.SeriesProcessedDataObject}
  33699. */
  33700. Series.prototype.getProcessedData = function (forceExtremesFromAll) {
  33701. var series = this,
  33702. // copied during slice operation:
  33703. processedXData = series.xData,
  33704. processedYData = series.yData,
  33705. dataLength = processedXData.length,
  33706. croppedData,
  33707. cropStart = 0,
  33708. cropped,
  33709. distance,
  33710. closestPointRange,
  33711. xAxis = series.xAxis,
  33712. i, // loop variable
  33713. options = series.options,
  33714. cropThreshold = options.cropThreshold,
  33715. getExtremesFromAll = forceExtremesFromAll ||
  33716. series.getExtremesFromAll ||
  33717. options.getExtremesFromAll, // #4599
  33718. isCartesian = series.isCartesian,
  33719. xExtremes,
  33720. val2lin = xAxis && xAxis.val2lin,
  33721. isLog = !!(xAxis && xAxis.logarithmic),
  33722. throwOnUnsorted = series.requireSorting,
  33723. min,
  33724. max;
  33725. if (xAxis) {
  33726. // corrected for log axis (#3053)
  33727. xExtremes = xAxis.getExtremes();
  33728. min = xExtremes.min;
  33729. max = xExtremes.max;
  33730. }
  33731. // optionally filter out points outside the plot area
  33732. if (isCartesian &&
  33733. series.sorted &&
  33734. !getExtremesFromAll &&
  33735. (!cropThreshold ||
  33736. dataLength > cropThreshold ||
  33737. series.forceCrop)) {
  33738. // it's outside current extremes
  33739. if (processedXData[dataLength - 1] < min ||
  33740. processedXData[0] > max) {
  33741. processedXData = [];
  33742. processedYData = [];
  33743. // only crop if it's actually spilling out
  33744. }
  33745. else if (series.yData && (processedXData[0] < min ||
  33746. processedXData[dataLength - 1] > max)) {
  33747. croppedData = this.cropData(series.xData, series.yData, min, max);
  33748. processedXData = croppedData.xData;
  33749. processedYData = croppedData.yData;
  33750. cropStart = croppedData.start;
  33751. cropped = true;
  33752. }
  33753. }
  33754. // Find the closest distance between processed points
  33755. i = processedXData.length || 1;
  33756. while (--i) {
  33757. distance = (isLog ?
  33758. (val2lin(processedXData[i]) -
  33759. val2lin(processedXData[i - 1])) :
  33760. (processedXData[i] -
  33761. processedXData[i - 1]));
  33762. if (distance > 0 &&
  33763. (typeof closestPointRange === 'undefined' ||
  33764. distance < closestPointRange)) {
  33765. closestPointRange = distance;
  33766. // Unsorted data is not supported by the line tooltip, as well
  33767. // as data grouping and navigation in Stock charts (#725) and
  33768. // width calculation of columns (#1900)
  33769. }
  33770. else if (distance < 0 && throwOnUnsorted) {
  33771. error(15, false, series.chart);
  33772. throwOnUnsorted = false; // Only once
  33773. }
  33774. }
  33775. return {
  33776. xData: processedXData,
  33777. yData: processedYData,
  33778. cropped: cropped,
  33779. cropStart: cropStart,
  33780. closestPointRange: closestPointRange
  33781. };
  33782. };
  33783. /**
  33784. * Internal function to apply processed data.
  33785. * In Highcharts Stock, this function is extended to provide data grouping.
  33786. *
  33787. * @private
  33788. * @function Highcharts.Series#processData
  33789. * @param {boolean} [force]
  33790. * Force data grouping.
  33791. * @return {boolean|undefined}
  33792. */
  33793. Series.prototype.processData = function (force) {
  33794. var series = this,
  33795. xAxis = series.xAxis,
  33796. processedData;
  33797. // If the series data or axes haven't changed, don't go through
  33798. // this. Return false to pass the message on to override methods
  33799. // like in data grouping.
  33800. if (series.isCartesian &&
  33801. !series.isDirty &&
  33802. !xAxis.isDirty &&
  33803. !series.yAxis.isDirty &&
  33804. !force) {
  33805. return false;
  33806. }
  33807. processedData = series.getProcessedData();
  33808. // Record the properties
  33809. series.cropped = processedData.cropped; // undefined or true
  33810. series.cropStart = processedData.cropStart;
  33811. series.processedXData = processedData.xData;
  33812. series.processedYData = processedData.yData;
  33813. series.closestPointRange = series.basePointRange = processedData.closestPointRange;
  33814. };
  33815. /**
  33816. * Iterate over xData and crop values between min and max. Returns
  33817. * object containing crop start/end cropped xData with corresponding
  33818. * part of yData, dataMin and dataMax within the cropped range.
  33819. *
  33820. * @private
  33821. * @function Highcharts.Series#cropData
  33822. * @param {Array<number>} xData
  33823. * @param {Array<number>} yData
  33824. * @param {number} min
  33825. * @param {number} max
  33826. * @param {number} [cropShoulder]
  33827. * @return {Highcharts.SeriesCropDataObject}
  33828. */
  33829. Series.prototype.cropData = function (xData, yData, min, max, cropShoulder) {
  33830. var dataLength = xData.length,
  33831. cropStart = 0,
  33832. cropEnd = dataLength,
  33833. i,
  33834. j;
  33835. // line-type series need one point outside
  33836. cropShoulder = pick(cropShoulder, this.cropShoulder);
  33837. // iterate up to find slice start
  33838. for (i = 0; i < dataLength; i++) {
  33839. if (xData[i] >= min) {
  33840. cropStart = Math.max(0, i - cropShoulder);
  33841. break;
  33842. }
  33843. }
  33844. // proceed to find slice end
  33845. for (j = i; j < dataLength; j++) {
  33846. if (xData[j] > max) {
  33847. cropEnd = j + cropShoulder;
  33848. break;
  33849. }
  33850. }
  33851. return {
  33852. xData: xData.slice(cropStart, cropEnd),
  33853. yData: yData.slice(cropStart, cropEnd),
  33854. start: cropStart,
  33855. end: cropEnd
  33856. };
  33857. };
  33858. /**
  33859. * Generate the data point after the data has been processed by cropping
  33860. * away unused points and optionally grouped in Highcharts Stock.
  33861. *
  33862. * @private
  33863. * @function Highcharts.Series#generatePoints
  33864. */
  33865. Series.prototype.generatePoints = function () {
  33866. var series = this,
  33867. options = series.options,
  33868. dataOptions = options.data,
  33869. data = series.data,
  33870. dataLength,
  33871. processedXData = series.processedXData,
  33872. processedYData = series.processedYData,
  33873. PointClass = series.pointClass,
  33874. processedDataLength = processedXData.length,
  33875. cropStart = series.cropStart || 0,
  33876. cursor,
  33877. hasGroupedData = series.hasGroupedData,
  33878. keys = options.keys,
  33879. point,
  33880. points = [],
  33881. i,
  33882. groupCropStartIndex = (options.dataGrouping &&
  33883. options.dataGrouping.groupAll ?
  33884. cropStart :
  33885. 0);
  33886. if (!data && !hasGroupedData) {
  33887. var arr = [];
  33888. arr.length = dataOptions.length;
  33889. data = series.data = arr;
  33890. }
  33891. if (keys && hasGroupedData) {
  33892. // grouped data has already applied keys (#6590)
  33893. series.options.keys = false;
  33894. }
  33895. for (i = 0; i < processedDataLength; i++) {
  33896. cursor = cropStart + i;
  33897. if (!hasGroupedData) {
  33898. point = data[cursor];
  33899. // #970:
  33900. if (!point &&
  33901. typeof dataOptions[cursor] !== 'undefined') {
  33902. data[cursor] = point = (new PointClass()).init(series, dataOptions[cursor], processedXData[i]);
  33903. }
  33904. }
  33905. else {
  33906. // splat the y data in case of ohlc data array
  33907. point = (new PointClass()).init(series, [processedXData[i]].concat(splat(processedYData[i])));
  33908. /**
  33909. * Highcharts Stock only. If a point object is created by data
  33910. * grouping, it doesn't reflect actual points in the raw
  33911. * data. In this case, the `dataGroup` property holds
  33912. * information that points back to the raw data.
  33913. *
  33914. * - `dataGroup.start` is the index of the first raw data
  33915. * point in the group.
  33916. *
  33917. * - `dataGroup.length` is the amount of points in the
  33918. * group.
  33919. *
  33920. * @product highstock
  33921. *
  33922. * @name Highcharts.Point#dataGroup
  33923. * @type {Highcharts.DataGroupingInfoObject|undefined}
  33924. */
  33925. point.dataGroup = series.groupMap[groupCropStartIndex + i];
  33926. if (point.dataGroup.options) {
  33927. point.options = point.dataGroup.options;
  33928. extend(point, point.dataGroup.options);
  33929. // Collision of props and options (#9770)
  33930. delete point.dataLabels;
  33931. }
  33932. }
  33933. if (point) { // #6279
  33934. /**
  33935. * Contains the point's index in the `Series.points` array.
  33936. *
  33937. * @name Highcharts.Point#index
  33938. * @type {number}
  33939. * @readonly
  33940. */
  33941. // For faster access in Point.update
  33942. point.index = hasGroupedData ? (groupCropStartIndex + i) : cursor;
  33943. points[i] = point;
  33944. }
  33945. }
  33946. // restore keys options (#6590)
  33947. series.options.keys = keys;
  33948. // Hide cropped-away points - this only runs when the number of
  33949. // points is above cropThreshold, or when swithching view from
  33950. // non-grouped data to grouped data (#637)
  33951. if (data &&
  33952. (processedDataLength !== (dataLength = data.length) ||
  33953. hasGroupedData)) {
  33954. for (i = 0; i < dataLength; i++) {
  33955. // when has grouped data, clear all points
  33956. if (i === cropStart && !hasGroupedData) {
  33957. i += processedDataLength;
  33958. }
  33959. if (data[i]) {
  33960. data[i].destroyElements();
  33961. data[i].plotX = void 0; // #1003
  33962. }
  33963. }
  33964. }
  33965. /**
  33966. * Read only. An array containing those values converted to points.
  33967. * In case the series data length exceeds the `cropThreshold`, or if
  33968. * the data is grouped, `series.data` doesn't contain all the
  33969. * points. Also, in case a series is hidden, the `data` array may be
  33970. * empty. To access raw values, `series.options.data` will always be
  33971. * up to date. `Series.data` only contains the points that have been
  33972. * created on demand. To modify the data, use
  33973. * {@link Highcharts.Series#setData} or
  33974. * {@link Highcharts.Point#update}.
  33975. *
  33976. * @see Series.points
  33977. *
  33978. * @name Highcharts.Series#data
  33979. * @type {Array<Highcharts.Point>}
  33980. */
  33981. series.data = data;
  33982. /**
  33983. * An array containing all currently visible point objects. In case
  33984. * of cropping, the cropped-away points are not part of this array.
  33985. * The `series.points` array starts at `series.cropStart` compared
  33986. * to `series.data` and `series.options.data`. If however the series
  33987. * data is grouped, these can't be correlated one to one. To modify
  33988. * the data, use {@link Highcharts.Series#setData} or
  33989. * {@link Highcharts.Point#update}.
  33990. *
  33991. * @name Highcharts.Series#points
  33992. * @type {Array<Highcharts.Point>}
  33993. */
  33994. series.points = points;
  33995. fireEvent(this, 'afterGeneratePoints');
  33996. };
  33997. /**
  33998. * Get current X extremes for the visible data.
  33999. *
  34000. * @private
  34001. * @function Highcharts.Series#getXExtremes
  34002. *
  34003. * @param {Array<number>} xData
  34004. * The data to inspect. Defaults to the current data within the visible
  34005. * range.
  34006. *
  34007. * @return {Highcharts.RangeObject}
  34008. */
  34009. Series.prototype.getXExtremes = function (xData) {
  34010. return {
  34011. min: arrayMin(xData),
  34012. max: arrayMax(xData)
  34013. };
  34014. };
  34015. /**
  34016. * Calculate Y extremes for the visible data. The result is returned
  34017. * as an object with `dataMin` and `dataMax` properties.
  34018. *
  34019. * @private
  34020. * @function Highcharts.Series#getExtremes
  34021. *
  34022. * @param {Array<number>} [yData]
  34023. * The data to inspect. Defaults to the current data within the visible
  34024. * range.
  34025. * @param {boolean} [forceExtremesFromAll]
  34026. * Force getting extremes of a total series data range.
  34027. *
  34028. * @return {Highcharts.DataExtremesObject}
  34029. */
  34030. Series.prototype.getExtremes = function (yData, forceExtremesFromAll) {
  34031. var xAxis = this.xAxis,
  34032. yAxis = this.yAxis,
  34033. xData = this.processedXData || this.xData,
  34034. yDataLength,
  34035. activeYData = [],
  34036. activeCounter = 0,
  34037. // #2117, need to compensate for log X axis
  34038. xExtremes,
  34039. xMin = 0,
  34040. xMax = 0,
  34041. validValue,
  34042. withinRange,
  34043. // Handle X outside the viewed area. This does not work with
  34044. // non-sorted data like scatter (#7639).
  34045. shoulder = this.requireSorting ? this.cropShoulder : 0,
  34046. positiveValuesOnly = yAxis ? yAxis.positiveValuesOnly : false,
  34047. x,
  34048. y,
  34049. i,
  34050. j;
  34051. yData = yData || this.stackedYData || this.processedYData || [];
  34052. yDataLength = yData.length;
  34053. if (xAxis) {
  34054. xExtremes = xAxis.getExtremes();
  34055. xMin = xExtremes.min;
  34056. xMax = xExtremes.max;
  34057. }
  34058. for (i = 0; i < yDataLength; i++) {
  34059. x = xData[i];
  34060. y = yData[i];
  34061. // For points within the visible range, including the first
  34062. // point outside the visible range (#7061), consider y extremes.
  34063. validValue = ((isNumber(y) || isArray(y)) &&
  34064. ((y.length || y > 0) || !positiveValuesOnly));
  34065. withinRange = (forceExtremesFromAll ||
  34066. this.getExtremesFromAll ||
  34067. this.options.getExtremesFromAll ||
  34068. this.cropped ||
  34069. !xAxis || // for colorAxis support
  34070. ((xData[i + shoulder] || x) >= xMin &&
  34071. (xData[i - shoulder] || x) <= xMax));
  34072. if (validValue && withinRange) {
  34073. j = y.length;
  34074. if (j) { // array, like ohlc or range data
  34075. while (j--) {
  34076. if (isNumber(y[j])) { // #7380, #11513
  34077. activeYData[activeCounter++] = y[j];
  34078. }
  34079. }
  34080. }
  34081. else {
  34082. activeYData[activeCounter++] = y;
  34083. }
  34084. }
  34085. }
  34086. var dataExtremes = {
  34087. dataMin: arrayMin(activeYData),
  34088. dataMax: arrayMax(activeYData)
  34089. };
  34090. fireEvent(this, 'afterGetExtremes', { dataExtremes: dataExtremes });
  34091. return dataExtremes;
  34092. };
  34093. /**
  34094. * Set the current data extremes as `dataMin` and `dataMax` on the
  34095. * Series item. Use this only when the series properties should be
  34096. * updated.
  34097. *
  34098. * @private
  34099. * @function Highcharts.Series#applyExtremes
  34100. */
  34101. Series.prototype.applyExtremes = function () {
  34102. var dataExtremes = this.getExtremes();
  34103. /**
  34104. * Contains the minimum value of the series' data point. Some series
  34105. * types like `networkgraph` do not support this property as they
  34106. * lack a `y`-value.
  34107. * @name Highcharts.Series#dataMin
  34108. * @type {number|undefined}
  34109. * @readonly
  34110. */
  34111. this.dataMin = dataExtremes.dataMin;
  34112. /**
  34113. * Contains the maximum value of the series' data point. Some series
  34114. * types like `networkgraph` do not support this property as they
  34115. * lack a `y`-value.
  34116. * @name Highcharts.Series#dataMax
  34117. * @type {number|undefined}
  34118. * @readonly
  34119. */
  34120. this.dataMax = dataExtremes.dataMax;
  34121. return dataExtremes;
  34122. };
  34123. /**
  34124. * Find and return the first non null point in the data
  34125. *
  34126. * @private
  34127. * @function Highcharts.Series.getFirstValidPoint
  34128. *
  34129. * @param {Array<Highcharts.PointOptionsType>} data
  34130. * Array of options for points
  34131. *
  34132. * @return {Highcharts.PointOptionsType}
  34133. */
  34134. Series.prototype.getFirstValidPoint = function (data) {
  34135. var firstPoint = null,
  34136. dataLength = data.length,
  34137. i = 0;
  34138. while (firstPoint === null && i < dataLength) {
  34139. firstPoint = data[i];
  34140. i++;
  34141. }
  34142. return firstPoint;
  34143. };
  34144. /**
  34145. * Translate data points from raw data values to chart specific
  34146. * positioning data needed later in the `drawPoints` and `drawGraph`
  34147. * functions. This function can be overridden in plugins and custom
  34148. * series type implementations.
  34149. *
  34150. * @function Highcharts.Series#translate
  34151. *
  34152. * @fires Highcharts.Series#events:translate
  34153. */
  34154. Series.prototype.translate = function () {
  34155. if (!this.processedXData) { // hidden series
  34156. this.processData();
  34157. }
  34158. this.generatePoints();
  34159. var series = this,
  34160. options = series.options,
  34161. stacking = options.stacking,
  34162. xAxis = series.xAxis,
  34163. categories = xAxis.categories,
  34164. enabledDataSorting = series.enabledDataSorting,
  34165. yAxis = series.yAxis,
  34166. points = series.points,
  34167. dataLength = points.length,
  34168. hasModifyValue = !!series.modifyValue,
  34169. i,
  34170. pointPlacement = series.pointPlacementToXValue(), // #7860
  34171. dynamicallyPlaced = Boolean(pointPlacement),
  34172. threshold = options.threshold,
  34173. stackThreshold = options.startFromThreshold ? threshold : 0,
  34174. plotX,
  34175. lastPlotX,
  34176. stackIndicator,
  34177. zoneAxis = this.zoneAxis || 'y',
  34178. closestPointRangePx = Number.MAX_VALUE;
  34179. /**
  34180. * Plotted coordinates need to be within a limited range. Drawing
  34181. * too far outside the viewport causes various rendering issues
  34182. * (#3201, #3923, #7555).
  34183. * @private
  34184. */
  34185. function limitedRange(val) {
  34186. return clamp(val, -1e5, 1e5);
  34187. }
  34188. // Translate each point
  34189. for (i = 0; i < dataLength; i++) {
  34190. var point = points[i],
  34191. xValue = point.x,
  34192. yValue = point.y,
  34193. yBottom = point.low,
  34194. stack = stacking && yAxis.stacking && yAxis.stacking.stacks[(series.negStacks &&
  34195. yValue <
  34196. (stackThreshold ? 0 : threshold) ?
  34197. '-' :
  34198. '') + series.stackKey],
  34199. pointStack = void 0,
  34200. stackValues = void 0;
  34201. if (yAxis.positiveValuesOnly && !yAxis.validatePositiveValue(yValue) ||
  34202. xAxis.positiveValuesOnly && !xAxis.validatePositiveValue(xValue)) {
  34203. point.isNull = true;
  34204. }
  34205. // Get the plotX translation
  34206. point.plotX = plotX = correctFloat(// #5236
  34207. limitedRange(xAxis.translate(// #3923
  34208. xValue, 0, 0, 0, 1, pointPlacement, this.type === 'flags')) // #3923
  34209. );
  34210. // Calculate the bottom y value for stacked series
  34211. if (stacking &&
  34212. series.visible &&
  34213. stack &&
  34214. stack[xValue]) {
  34215. stackIndicator = series.getStackIndicator(stackIndicator, xValue, series.index);
  34216. if (!point.isNull) {
  34217. pointStack = stack[xValue];
  34218. stackValues =
  34219. pointStack.points[stackIndicator.key];
  34220. }
  34221. }
  34222. if (isArray(stackValues)) {
  34223. yBottom = stackValues[0];
  34224. yValue = stackValues[1];
  34225. if (yBottom === stackThreshold &&
  34226. stackIndicator.key ===
  34227. stack[xValue].base) {
  34228. yBottom = pick((isNumber(threshold) && threshold), yAxis.min);
  34229. }
  34230. // #1200, #1232
  34231. if (yAxis.positiveValuesOnly && yBottom <= 0) {
  34232. yBottom = null;
  34233. }
  34234. point.total = point.stackTotal = pointStack.total;
  34235. point.percentage =
  34236. pointStack.total &&
  34237. (point.y / pointStack.total * 100);
  34238. point.stackY = yValue;
  34239. // Place the stack label
  34240. // in case of variwide series (where widths of points are
  34241. // different in most cases), stack labels are positioned
  34242. // wrongly, so the call of the setOffset is omited here and
  34243. // labels are correctly positioned later, at the end of the
  34244. // variwide's translate function (#10962)
  34245. if (!series.irregularWidths) {
  34246. pointStack.setOffset(series.pointXOffset || 0, series.barW || 0);
  34247. }
  34248. }
  34249. // Set translated yBottom or remove it
  34250. point.yBottom = defined(yBottom) ?
  34251. limitedRange(yAxis.translate(yBottom, 0, 1, 0, 1)) :
  34252. null;
  34253. // general hook, used for Highcharts Stock compare mode
  34254. if (hasModifyValue) {
  34255. yValue = series.modifyValue(yValue, point);
  34256. }
  34257. // Set the the plotY value, reset it for redraws
  34258. // #3201
  34259. point.plotY = void 0;
  34260. if (isNumber(yValue)) {
  34261. var translated = yAxis.translate(yValue,
  34262. false,
  34263. true,
  34264. false,
  34265. true);
  34266. if (typeof translated !== 'undefined') {
  34267. point.plotY = limitedRange(translated);
  34268. }
  34269. }
  34270. point.isInside = this.isPointInside(point);
  34271. // Set client related positions for mouse tracking
  34272. point.clientX = dynamicallyPlaced ?
  34273. correctFloat(xAxis.translate(xValue, 0, 0, 0, 1, pointPlacement)) :
  34274. plotX; // #1514, #5383, #5518
  34275. // Negative points. For bubble charts, this means negative z
  34276. // values (#9728)
  34277. point.negative = point[zoneAxis] < (options[zoneAxis + 'Threshold'] ||
  34278. threshold ||
  34279. 0);
  34280. // some API data
  34281. point.category = (categories &&
  34282. typeof categories[point.x] !== 'undefined' ?
  34283. categories[point.x] :
  34284. point.x);
  34285. // Determine auto enabling of markers (#3635, #5099)
  34286. if (!point.isNull && point.visible !== false) {
  34287. if (typeof lastPlotX !== 'undefined') {
  34288. closestPointRangePx = Math.min(closestPointRangePx, Math.abs(plotX - lastPlotX));
  34289. }
  34290. lastPlotX = plotX;
  34291. }
  34292. // Find point zone
  34293. point.zone = (this.zones.length && point.getZone());
  34294. // Animate new points with data sorting
  34295. if (!point.graphic && series.group && enabledDataSorting) {
  34296. point.isNew = true;
  34297. }
  34298. }
  34299. series.closestPointRangePx = closestPointRangePx;
  34300. fireEvent(this, 'afterTranslate');
  34301. };
  34302. /**
  34303. * Return the series points with null points filtered out.
  34304. *
  34305. * @function Highcharts.Series#getValidPoints
  34306. *
  34307. * @param {Array<Highcharts.Point>} [points]
  34308. * The points to inspect, defaults to {@link Series.points}.
  34309. *
  34310. * @param {boolean} [insideOnly=false]
  34311. * Whether to inspect only the points that are inside the visible view.
  34312. *
  34313. * @param {boolean} [allowNull=false]
  34314. * Whether to allow null points to pass as valid points.
  34315. *
  34316. * @return {Array<Highcharts.Point>}
  34317. * The valid points.
  34318. */
  34319. Series.prototype.getValidPoints = function (points, insideOnly, allowNull) {
  34320. var chart = this.chart;
  34321. // #3916, #5029, #5085
  34322. return (points || this.points || []).filter(function (point) {
  34323. if (insideOnly && !chart.isInsidePlot(point.plotX, point.plotY, { inverted: chart.inverted })) {
  34324. return false;
  34325. }
  34326. return point.visible !== false &&
  34327. (allowNull || !point.isNull);
  34328. });
  34329. };
  34330. /**
  34331. * Get the clipping for the series. Could be called for a series to
  34332. * initiate animating the clip or to set the final clip (only width
  34333. * and x).
  34334. *
  34335. * @private
  34336. * @function Highcharts.Series#getClip
  34337. *
  34338. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
  34339. * Initialize the animation.
  34340. *
  34341. * @param {boolean} [finalBox]
  34342. * Final size for the clip - end state for the animation.
  34343. *
  34344. * @return {Highcharts.Dictionary<number>}
  34345. */
  34346. Series.prototype.getClipBox = function (animation, finalBox) {
  34347. var series = this,
  34348. options = series.options,
  34349. chart = series.chart,
  34350. inverted = chart.inverted,
  34351. xAxis = series.xAxis,
  34352. yAxis = xAxis && series.yAxis,
  34353. clipBox,
  34354. scrollablePlotAreaOptions = chart.options.chart.scrollablePlotArea || {};
  34355. if (animation && options.clip === false && yAxis) {
  34356. // support for not clipped series animation (#10450)
  34357. clipBox = inverted ? {
  34358. y: -chart.chartWidth + yAxis.len + yAxis.pos,
  34359. height: chart.chartWidth,
  34360. width: chart.chartHeight,
  34361. x: -chart.chartHeight + xAxis.len + xAxis.pos
  34362. } : {
  34363. y: -yAxis.pos,
  34364. height: chart.chartHeight,
  34365. width: chart.chartWidth,
  34366. x: -xAxis.pos
  34367. };
  34368. // x and width will be changed later when setting for animation
  34369. // initial state in Series.setClip
  34370. }
  34371. else {
  34372. clipBox = series.clipBox || chart.clipBox;
  34373. if (finalBox) {
  34374. clipBox.width = chart.plotSizeX;
  34375. clipBox.x = (chart.scrollablePixelsX || 0) *
  34376. (scrollablePlotAreaOptions.scrollPositionX || 0);
  34377. }
  34378. }
  34379. return !finalBox ? clipBox : {
  34380. width: clipBox.width,
  34381. x: clipBox.x
  34382. };
  34383. };
  34384. /**
  34385. * Get the shared clip key, creating it if it doesn't exist.
  34386. *
  34387. * @private
  34388. * @function Highcharts.Series#getSharedClipKey
  34389. */
  34390. Series.prototype.getSharedClipKey = function (animation) {
  34391. if (this.sharedClipKey) {
  34392. return this.sharedClipKey;
  34393. }
  34394. var sharedClipKey = [
  34395. animation && animation.duration,
  34396. animation && animation.easing,
  34397. animation && animation.defer,
  34398. this.getClipBox(animation).height,
  34399. this.options.xAxis,
  34400. this.options.yAxis
  34401. ].join(',');
  34402. if (this.options.clip !== false || animation) {
  34403. this.sharedClipKey = sharedClipKey;
  34404. }
  34405. return sharedClipKey;
  34406. };
  34407. /**
  34408. * Set the clipping for the series. For animated series it is called
  34409. * twice, first to initiate animating the clip then the second time
  34410. * without the animation to set the final clip.
  34411. *
  34412. * @private
  34413. * @function Highcharts.Series#setClip
  34414. */
  34415. Series.prototype.setClip = function (animation) {
  34416. var chart = this.chart,
  34417. options = this.options,
  34418. renderer = chart.renderer,
  34419. inverted = chart.inverted,
  34420. seriesClipBox = this.clipBox,
  34421. clipBox = this.getClipBox(animation),
  34422. sharedClipKey = this.getSharedClipKey(animation), // #4526
  34423. clipRect = chart.sharedClips[sharedClipKey],
  34424. markerClipRect = chart.sharedClips[sharedClipKey + 'm'];
  34425. if (animation) {
  34426. clipBox.width = 0;
  34427. if (inverted) {
  34428. clipBox.x = chart.plotHeight +
  34429. (options.clip !== false ? 0 : chart.plotTop);
  34430. }
  34431. }
  34432. // If a clipping rectangle with the same properties is currently
  34433. // present in the chart, use that.
  34434. if (!clipRect) {
  34435. // When animation is set, prepare the initial positions
  34436. if (animation) {
  34437. chart.sharedClips[sharedClipKey + 'm'] = markerClipRect =
  34438. renderer.clipRect(
  34439. // include the width of the first marker
  34440. inverted ? (chart.plotSizeX || 0) + 99 : -99, inverted ? -chart.plotLeft : -chart.plotTop, 99, inverted ? chart.chartWidth : chart.chartHeight);
  34441. }
  34442. chart.sharedClips[sharedClipKey] = clipRect = renderer.clipRect(clipBox);
  34443. // Create hashmap for series indexes
  34444. clipRect.count = { length: 0 };
  34445. // When the series is rendered again before starting animating, in
  34446. // compliance to a responsive rule
  34447. }
  34448. else if (!chart.hasLoaded) {
  34449. clipRect.attr(clipBox);
  34450. }
  34451. if (animation) {
  34452. if (!clipRect.count[this.index]) {
  34453. clipRect.count[this.index] = true;
  34454. clipRect.count.length += 1;
  34455. }
  34456. }
  34457. if (options.clip !== false || animation) {
  34458. this.group.clip(animation || seriesClipBox ? clipRect : chart.clipRect);
  34459. this.markerGroup.clip(markerClipRect);
  34460. }
  34461. // Remove the shared clipping rectangle when all series are shown
  34462. if (!animation) {
  34463. if (clipRect.count[this.index]) {
  34464. delete clipRect.count[this.index];
  34465. clipRect.count.length -= 1;
  34466. }
  34467. if (clipRect.count.length === 0) {
  34468. if (!seriesClipBox) {
  34469. chart.sharedClips[sharedClipKey] = clipRect.destroy();
  34470. }
  34471. if (markerClipRect) {
  34472. chart.sharedClips[sharedClipKey + 'm'] = markerClipRect.destroy();
  34473. }
  34474. }
  34475. }
  34476. };
  34477. /**
  34478. * Animate in the series. Called internally twice. First with the `init`
  34479. * parameter set to true, which sets up the initial state of the
  34480. * animation. Then when ready, it is called with the `init` parameter
  34481. * undefined, in order to perform the actual animation. After the
  34482. * second run, the function is removed.
  34483. *
  34484. * @function Highcharts.Series#animate
  34485. *
  34486. * @param {boolean} [init]
  34487. * Initialize the animation.
  34488. */
  34489. Series.prototype.animate = function (init) {
  34490. var series = this,
  34491. chart = series.chart,
  34492. animation = animObject(series.options.animation),
  34493. sharedClipKey = this.sharedClipKey;
  34494. // Initialize the animation. Set up the clipping rectangle.
  34495. if (init) {
  34496. series.setClip(animation);
  34497. // Run the animation
  34498. }
  34499. else if (sharedClipKey) {
  34500. var clipRect = chart.sharedClips[sharedClipKey];
  34501. var markerClipRect = chart.sharedClips[sharedClipKey + 'm'];
  34502. var finalBox = series.getClipBox(animation,
  34503. true);
  34504. if (clipRect) {
  34505. clipRect.animate(finalBox, animation);
  34506. }
  34507. if (markerClipRect) {
  34508. markerClipRect.animate({
  34509. width: finalBox.width + 99,
  34510. x: finalBox.x - (chart.inverted ? 0 : 99)
  34511. }, animation);
  34512. }
  34513. }
  34514. };
  34515. /**
  34516. * This runs after animation to land on the final plot clipping.
  34517. *
  34518. * @private
  34519. * @function Highcharts.Series#afterAnimate
  34520. *
  34521. * @fires Highcharts.Series#event:afterAnimate
  34522. */
  34523. Series.prototype.afterAnimate = function () {
  34524. this.setClip();
  34525. fireEvent(this, 'afterAnimate');
  34526. this.finishedAnimating = true;
  34527. };
  34528. /**
  34529. * Draw the markers for line-like series types, and columns or other
  34530. * graphical representation for {@link Point} objects for other series
  34531. * types. The resulting element is typically stored as
  34532. * {@link Point.graphic}, and is created on the first call and updated
  34533. * and moved on subsequent calls.
  34534. *
  34535. * @function Highcharts.Series#drawPoints
  34536. */
  34537. Series.prototype.drawPoints = function () {
  34538. var series = this,
  34539. points = series.points,
  34540. chart = series.chart,
  34541. i,
  34542. point,
  34543. graphic,
  34544. verb,
  34545. options = series.options,
  34546. seriesMarkerOptions = options.marker,
  34547. pointMarkerOptions,
  34548. hasPointMarker,
  34549. markerGroup = (series[series.specialGroup] ||
  34550. series.markerGroup),
  34551. xAxis = series.xAxis,
  34552. markerAttribs,
  34553. globallyEnabled = pick(seriesMarkerOptions.enabled, !xAxis || xAxis.isRadial ? true : null,
  34554. // Use larger or equal as radius is null in bubbles (#6321)
  34555. series.closestPointRangePx >= (seriesMarkerOptions.enabledThreshold *
  34556. seriesMarkerOptions.radius));
  34557. if (seriesMarkerOptions.enabled !== false ||
  34558. series._hasPointMarkers) {
  34559. for (i = 0; i < points.length; i++) {
  34560. point = points[i];
  34561. graphic = point.graphic;
  34562. verb = graphic ? 'animate' : 'attr';
  34563. pointMarkerOptions = point.marker || {};
  34564. hasPointMarker = !!point.marker;
  34565. var shouldDrawMarker = ((globallyEnabled &&
  34566. typeof pointMarkerOptions.enabled === 'undefined') || pointMarkerOptions.enabled) && !point.isNull && point.visible !== false;
  34567. // only draw the point if y is defined
  34568. if (shouldDrawMarker) {
  34569. // Shortcuts
  34570. var symbol = pick(pointMarkerOptions.symbol,
  34571. series.symbol, 'rect');
  34572. markerAttribs = series.markerAttribs(point, (point.selected && 'select'));
  34573. // Set starting position for point sliding animation.
  34574. if (series.enabledDataSorting) {
  34575. point.startXPos = xAxis.reversed ?
  34576. -(markerAttribs.width || 0) :
  34577. xAxis.width;
  34578. }
  34579. var isInside = point.isInside !== false;
  34580. if (graphic) { // update
  34581. // Since the marker group isn't clipped, each
  34582. // individual marker must be toggled
  34583. graphic[isInside ? 'show' : 'hide'](isInside)
  34584. .animate(markerAttribs);
  34585. }
  34586. else if (isInside &&
  34587. ((markerAttribs.width || 0) > 0 || point.hasImage)) {
  34588. /**
  34589. * The graphic representation of the point.
  34590. * Typically this is a simple shape, like a `rect`
  34591. * for column charts or `path` for line markers, but
  34592. * for some complex series types like boxplot or 3D
  34593. * charts, the graphic may be a `g` element
  34594. * containing other shapes. The graphic is generated
  34595. * the first time {@link Series#drawPoints} runs,
  34596. * and updated and moved on subsequent runs.
  34597. *
  34598. * @name Point#graphic
  34599. * @type {SVGElement}
  34600. */
  34601. point.graphic = graphic = chart.renderer
  34602. .symbol(symbol, markerAttribs.x, markerAttribs.y, markerAttribs.width, markerAttribs.height, hasPointMarker ?
  34603. pointMarkerOptions :
  34604. seriesMarkerOptions)
  34605. .add(markerGroup);
  34606. // Sliding animation for new points
  34607. if (series.enabledDataSorting &&
  34608. chart.hasRendered) {
  34609. graphic.attr({
  34610. x: point.startXPos
  34611. });
  34612. verb = 'animate';
  34613. }
  34614. }
  34615. if (graphic && verb === 'animate') { // update
  34616. // Since the marker group isn't clipped, each
  34617. // individual marker must be toggled
  34618. graphic[isInside ? 'show' : 'hide'](isInside)
  34619. .animate(markerAttribs);
  34620. }
  34621. // Presentational attributes
  34622. if (graphic && !chart.styledMode) {
  34623. graphic[verb](series.pointAttribs(point, (point.selected && 'select')));
  34624. }
  34625. if (graphic) {
  34626. graphic.addClass(point.getClassName(), true);
  34627. }
  34628. }
  34629. else if (graphic) {
  34630. point.graphic = graphic.destroy(); // #1269
  34631. }
  34632. }
  34633. }
  34634. };
  34635. /**
  34636. * Get non-presentational attributes for a point. Used internally for
  34637. * both styled mode and classic. Can be overridden for different series
  34638. * types.
  34639. *
  34640. * @see Series#pointAttribs
  34641. *
  34642. * @function Highcharts.Series#markerAttribs
  34643. *
  34644. * @param {Highcharts.Point} point
  34645. * The Point to inspect.
  34646. *
  34647. * @param {string} [state]
  34648. * The state, can be either `hover`, `select` or undefined.
  34649. *
  34650. * @return {Highcharts.SVGAttributes}
  34651. * A hash containing those attributes that are not settable from CSS.
  34652. */
  34653. Series.prototype.markerAttribs = function (point, state) {
  34654. var seriesOptions = this.options,
  34655. seriesMarkerOptions = seriesOptions.marker,
  34656. seriesStateOptions,
  34657. pointMarkerOptions = point.marker || {},
  34658. symbol = (pointMarkerOptions.symbol ||
  34659. seriesMarkerOptions.symbol),
  34660. pointStateOptions,
  34661. radius = pick(pointMarkerOptions.radius,
  34662. seriesMarkerOptions.radius),
  34663. attribs;
  34664. // Handle hover and select states
  34665. if (state) {
  34666. seriesStateOptions = seriesMarkerOptions.states[state];
  34667. pointStateOptions = pointMarkerOptions.states &&
  34668. pointMarkerOptions.states[state];
  34669. radius = pick(pointStateOptions && pointStateOptions.radius, seriesStateOptions && seriesStateOptions.radius, radius + (seriesStateOptions && seriesStateOptions.radiusPlus ||
  34670. 0));
  34671. }
  34672. point.hasImage = symbol && symbol.indexOf('url') === 0;
  34673. if (point.hasImage) {
  34674. radius = 0; // and subsequently width and height is not set
  34675. }
  34676. attribs = {
  34677. // Math.floor for #1843:
  34678. x: seriesOptions.crisp ?
  34679. Math.floor(point.plotX - radius) :
  34680. point.plotX - radius,
  34681. y: point.plotY - radius
  34682. };
  34683. if (radius) {
  34684. attribs.width = attribs.height = 2 * radius;
  34685. }
  34686. return attribs;
  34687. };
  34688. /**
  34689. * Internal function to get presentational attributes for each point.
  34690. * Unlike {@link Series#markerAttribs}, this function should return
  34691. * those attributes that can also be set in CSS. In styled mode,
  34692. * `pointAttribs` won't be called.
  34693. *
  34694. * @private
  34695. * @function Highcharts.Series#pointAttribs
  34696. *
  34697. * @param {Highcharts.Point} [point]
  34698. * The point instance to inspect.
  34699. *
  34700. * @param {string} [state]
  34701. * The point state, can be either `hover`, `select` or 'normal'. If
  34702. * undefined, normal state is assumed.
  34703. *
  34704. * @return {Highcharts.SVGAttributes}
  34705. * The presentational attributes to be set on the point.
  34706. */
  34707. Series.prototype.pointAttribs = function (point, state) {
  34708. var seriesMarkerOptions = this.options.marker,
  34709. seriesStateOptions,
  34710. pointOptions = point && point.options,
  34711. pointMarkerOptions = ((pointOptions && pointOptions.marker) || {}),
  34712. pointStateOptions,
  34713. color = this.color,
  34714. pointColorOption = pointOptions && pointOptions.color,
  34715. pointColor = point && point.color,
  34716. strokeWidth = pick(pointMarkerOptions.lineWidth,
  34717. seriesMarkerOptions.lineWidth),
  34718. zoneColor = point && point.zone && point.zone.color,
  34719. fill,
  34720. stroke,
  34721. opacity = 1;
  34722. color = (pointColorOption ||
  34723. zoneColor ||
  34724. pointColor ||
  34725. color);
  34726. fill = (pointMarkerOptions.fillColor ||
  34727. seriesMarkerOptions.fillColor ||
  34728. color);
  34729. stroke = (pointMarkerOptions.lineColor ||
  34730. seriesMarkerOptions.lineColor ||
  34731. color);
  34732. // Handle hover and select states
  34733. state = state || 'normal';
  34734. if (state) {
  34735. seriesStateOptions = seriesMarkerOptions.states[state];
  34736. pointStateOptions = (pointMarkerOptions.states &&
  34737. pointMarkerOptions.states[state]) || {};
  34738. strokeWidth = pick(pointStateOptions.lineWidth, seriesStateOptions.lineWidth, strokeWidth + pick(pointStateOptions.lineWidthPlus, seriesStateOptions.lineWidthPlus, 0));
  34739. fill = (pointStateOptions.fillColor ||
  34740. seriesStateOptions.fillColor ||
  34741. fill);
  34742. stroke = (pointStateOptions.lineColor ||
  34743. seriesStateOptions.lineColor ||
  34744. stroke);
  34745. opacity = pick(pointStateOptions.opacity, seriesStateOptions.opacity, opacity);
  34746. }
  34747. return {
  34748. 'stroke': stroke,
  34749. 'stroke-width': strokeWidth,
  34750. 'fill': fill,
  34751. 'opacity': opacity
  34752. };
  34753. };
  34754. /**
  34755. * Clear DOM objects and free up memory.
  34756. *
  34757. * @private
  34758. * @function Highcharts.Series#destroy
  34759. *
  34760. * @fires Highcharts.Series#event:destroy
  34761. */
  34762. Series.prototype.destroy = function (keepEventsForUpdate) {
  34763. var series = this,
  34764. chart = series.chart,
  34765. issue134 = /AppleWebKit\/533/.test(win.navigator.userAgent),
  34766. destroy,
  34767. i,
  34768. data = series.data || [],
  34769. point,
  34770. axis;
  34771. // add event hook
  34772. fireEvent(series, 'destroy');
  34773. // remove events
  34774. this.removeEvents(keepEventsForUpdate);
  34775. // erase from axes
  34776. (series.axisTypes || []).forEach(function (AXIS) {
  34777. axis = series[AXIS];
  34778. if (axis && axis.series) {
  34779. erase(axis.series, series);
  34780. axis.isDirty = axis.forceRedraw = true;
  34781. }
  34782. });
  34783. // remove legend items
  34784. if (series.legendItem) {
  34785. series.chart.legend.destroyItem(series);
  34786. }
  34787. // destroy all points with their elements
  34788. i = data.length;
  34789. while (i--) {
  34790. point = data[i];
  34791. if (point && point.destroy) {
  34792. point.destroy();
  34793. }
  34794. }
  34795. if (series.clips) {
  34796. series.clips.forEach(function (clip) { return clip.destroy(); });
  34797. }
  34798. // Clear the animation timeout if we are destroying the series
  34799. // during initial animation
  34800. U.clearTimeout(series.animationTimeout);
  34801. // Destroy all SVGElements associated to the series
  34802. objectEach(series, function (val, prop) {
  34803. // Survive provides a hook for not destroying
  34804. if (val instanceof SVGElement && !val.survive) {
  34805. // issue 134 workaround
  34806. destroy = issue134 && prop === 'group' ?
  34807. 'hide' :
  34808. 'destroy';
  34809. val[destroy]();
  34810. }
  34811. });
  34812. // remove from hoverSeries
  34813. if (chart.hoverSeries === series) {
  34814. chart.hoverSeries = void 0;
  34815. }
  34816. erase(chart.series, series);
  34817. chart.orderSeries();
  34818. // clear all members
  34819. objectEach(series, function (val, prop) {
  34820. if (!keepEventsForUpdate || prop !== 'hcEvents') {
  34821. delete series[prop];
  34822. }
  34823. });
  34824. };
  34825. /**
  34826. * Clip the graphs into zones for colors and styling.
  34827. *
  34828. * @private
  34829. * @function Highcharts.Series#applyZones
  34830. */
  34831. Series.prototype.applyZones = function () {
  34832. var series = this,
  34833. chart = this.chart,
  34834. renderer = chart.renderer,
  34835. zones = this.zones,
  34836. translatedFrom,
  34837. translatedTo,
  34838. clips = (this.clips || []),
  34839. clipAttr,
  34840. graph = this.graph,
  34841. area = this.area,
  34842. chartSizeMax = Math.max(chart.chartWidth,
  34843. chart.chartHeight),
  34844. axis = this[(this.zoneAxis || 'y') + 'Axis'],
  34845. extremes,
  34846. reversed,
  34847. inverted = chart.inverted,
  34848. horiz,
  34849. pxRange,
  34850. pxPosMin,
  34851. pxPosMax,
  34852. ignoreZones = false,
  34853. zoneArea,
  34854. zoneGraph;
  34855. if (zones.length &&
  34856. (graph || area) &&
  34857. axis &&
  34858. typeof axis.min !== 'undefined') {
  34859. reversed = axis.reversed;
  34860. horiz = axis.horiz;
  34861. // The use of the Color Threshold assumes there are no gaps
  34862. // so it is safe to hide the original graph and area
  34863. // unless it is not waterfall series, then use showLine property
  34864. // to set lines between columns to be visible (#7862)
  34865. if (graph && !this.showLine) {
  34866. graph.hide();
  34867. }
  34868. if (area) {
  34869. area.hide();
  34870. }
  34871. // Create the clips
  34872. extremes = axis.getExtremes();
  34873. zones.forEach(function (threshold, i) {
  34874. translatedFrom = reversed ?
  34875. (horiz ? chart.plotWidth : 0) :
  34876. (horiz ? 0 : (axis.toPixels(extremes.min) || 0));
  34877. translatedFrom = clamp(pick(translatedTo, translatedFrom), 0, chartSizeMax);
  34878. translatedTo = clamp(Math.round(axis.toPixels(pick(threshold.value, extremes.max), true) || 0), 0, chartSizeMax);
  34879. if (ignoreZones) {
  34880. translatedFrom = translatedTo =
  34881. axis.toPixels(extremes.max);
  34882. }
  34883. pxRange = Math.abs(translatedFrom - translatedTo);
  34884. pxPosMin = Math.min(translatedFrom, translatedTo);
  34885. pxPosMax = Math.max(translatedFrom, translatedTo);
  34886. if (axis.isXAxis) {
  34887. clipAttr = {
  34888. x: inverted ? pxPosMax : pxPosMin,
  34889. y: 0,
  34890. width: pxRange,
  34891. height: chartSizeMax
  34892. };
  34893. if (!horiz) {
  34894. clipAttr.x = chart.plotHeight - clipAttr.x;
  34895. }
  34896. }
  34897. else {
  34898. clipAttr = {
  34899. x: 0,
  34900. y: inverted ? pxPosMax : pxPosMin,
  34901. width: chartSizeMax,
  34902. height: pxRange
  34903. };
  34904. if (horiz) {
  34905. clipAttr.y = chart.plotWidth - clipAttr.y;
  34906. }
  34907. }
  34908. // VML SUPPPORT
  34909. if (inverted && renderer.isVML) {
  34910. if (axis.isXAxis) {
  34911. clipAttr = {
  34912. x: 0,
  34913. y: reversed ? pxPosMin : pxPosMax,
  34914. height: clipAttr.width,
  34915. width: chart.chartWidth
  34916. };
  34917. }
  34918. else {
  34919. clipAttr = {
  34920. x: (clipAttr.y -
  34921. chart.plotLeft -
  34922. chart.spacingBox.x),
  34923. y: 0,
  34924. width: clipAttr.height,
  34925. height: chart.chartHeight
  34926. };
  34927. }
  34928. }
  34929. // END OF VML SUPPORT
  34930. if (clips[i]) {
  34931. clips[i].animate(clipAttr);
  34932. }
  34933. else {
  34934. clips[i] = renderer.clipRect(clipAttr);
  34935. }
  34936. // when no data, graph zone is not applied and after setData
  34937. // clip was ignored. As a result, it should be applied each
  34938. // time.
  34939. zoneArea = series['zone-area-' + i];
  34940. zoneGraph = series['zone-graph-' + i];
  34941. if (graph && zoneGraph) {
  34942. zoneGraph.clip(clips[i]);
  34943. }
  34944. if (area && zoneArea) {
  34945. zoneArea.clip(clips[i]);
  34946. }
  34947. // if this zone extends out of the axis, ignore the others
  34948. ignoreZones = threshold.value > extremes.max;
  34949. // Clear translatedTo for indicators
  34950. if (series.resetZones && translatedTo === 0) {
  34951. translatedTo = void 0;
  34952. }
  34953. });
  34954. this.clips = clips;
  34955. }
  34956. else if (series.visible) {
  34957. // If zones were removed, restore graph and area
  34958. if (graph) {
  34959. graph.show(true);
  34960. }
  34961. if (area) {
  34962. area.show(true);
  34963. }
  34964. }
  34965. };
  34966. /**
  34967. * Initialize and perform group inversion on series.group and
  34968. * series.markerGroup.
  34969. *
  34970. * @private
  34971. * @function Highcharts.Series#invertGroups
  34972. */
  34973. Series.prototype.invertGroups = function (inverted) {
  34974. var series = this,
  34975. chart = series.chart;
  34976. /**
  34977. * @private
  34978. */
  34979. function setInvert() {
  34980. ['group', 'markerGroup'].forEach(function (groupName) {
  34981. if (series[groupName]) {
  34982. // VML/HTML needs explicit attributes for flipping
  34983. if (chart.renderer.isVML) {
  34984. series[groupName].attr({
  34985. width: series.yAxis.len,
  34986. height: series.xAxis.len
  34987. });
  34988. }
  34989. series[groupName].width = series.yAxis.len;
  34990. series[groupName].height = series.xAxis.len;
  34991. // If inverted polar, don't invert series group
  34992. series[groupName].invert(series.isRadialSeries ? false : inverted);
  34993. }
  34994. });
  34995. }
  34996. // Pie, go away (#1736)
  34997. if (!series.xAxis) {
  34998. return;
  34999. }
  35000. // A fixed size is needed for inversion to work
  35001. series.eventsToUnbind.push(addEvent(chart, 'resize', setInvert));
  35002. // Do it now
  35003. setInvert();
  35004. // On subsequent render and redraw, just do setInvert without
  35005. // setting up events again
  35006. series.invertGroups = setInvert;
  35007. };
  35008. /**
  35009. * General abstraction for creating plot groups like series.group,
  35010. * series.dataLabelsGroup and series.markerGroup. On subsequent calls,
  35011. * the group will only be adjusted to the updated plot size.
  35012. *
  35013. * @private
  35014. * @function Highcharts.Series#plotGroup
  35015. */
  35016. Series.prototype.plotGroup = function (prop, name, visibility, zIndex, parent) {
  35017. var group = this[prop];
  35018. var isNew = !group,
  35019. attrs = {
  35020. visibility: visibility,
  35021. zIndex: zIndex || 0.1 // IE8 and pointer logic use this
  35022. };
  35023. // Avoid setting undefined opacity, or in styled mode
  35024. if (typeof this.opacity !== 'undefined' &&
  35025. !this.chart.styledMode && this.state !== 'inactive' // #13719
  35026. ) {
  35027. attrs.opacity = this.opacity;
  35028. }
  35029. // Generate it on first call
  35030. if (isNew) {
  35031. this[prop] = group = this.chart.renderer
  35032. .g()
  35033. .add(parent);
  35034. }
  35035. // Add the class names, and replace existing ones as response to
  35036. // Series.update (#6660)
  35037. group.addClass(('highcharts-' + name +
  35038. ' highcharts-series-' + this.index +
  35039. ' highcharts-' + this.type + '-series ' +
  35040. (defined(this.colorIndex) ?
  35041. 'highcharts-color-' + this.colorIndex + ' ' :
  35042. '') +
  35043. (this.options.className || '') +
  35044. (group.hasClass('highcharts-tracker') ?
  35045. ' highcharts-tracker' :
  35046. '')), true);
  35047. // Place it on first and subsequent (redraw) calls
  35048. group.attr(attrs)[isNew ? 'attr' : 'animate'](this.getPlotBox());
  35049. return group;
  35050. };
  35051. /**
  35052. * Get the translation and scale for the plot area of this series.
  35053. *
  35054. * @function Highcharts.Series#getPlotBox
  35055. *
  35056. * @return {Highcharts.SeriesPlotBoxObject}
  35057. */
  35058. Series.prototype.getPlotBox = function () {
  35059. var chart = this.chart,
  35060. xAxis = this.xAxis,
  35061. yAxis = this.yAxis;
  35062. // Swap axes for inverted (#2339)
  35063. if (chart.inverted) {
  35064. xAxis = yAxis;
  35065. yAxis = this.xAxis;
  35066. }
  35067. return {
  35068. translateX: xAxis ? xAxis.left : chart.plotLeft,
  35069. translateY: yAxis ? yAxis.top : chart.plotTop,
  35070. scaleX: 1,
  35071. scaleY: 1
  35072. };
  35073. };
  35074. /**
  35075. * Removes the event handlers attached previously with addEvents.
  35076. * @private
  35077. * @function Highcharts.Series#removeEvents
  35078. */
  35079. Series.prototype.removeEvents = function (keepEventsForUpdate) {
  35080. var series = this;
  35081. if (!keepEventsForUpdate) {
  35082. // remove all events
  35083. removeEvent(series);
  35084. }
  35085. if (series.eventsToUnbind.length) {
  35086. // remove only internal events for proper update
  35087. // #12355 - solves problem with multiple destroy events
  35088. series.eventsToUnbind.forEach(function (unbind) {
  35089. unbind();
  35090. });
  35091. series.eventsToUnbind.length = 0;
  35092. }
  35093. };
  35094. /**
  35095. * Render the graph and markers. Called internally when first rendering
  35096. * and later when redrawing the chart. This function can be extended in
  35097. * plugins, but normally shouldn't be called directly.
  35098. *
  35099. * @function Highcharts.Series#render
  35100. *
  35101. * @fires Highcharts.Series#event:afterRender
  35102. */
  35103. Series.prototype.render = function () {
  35104. var series = this,
  35105. chart = series.chart,
  35106. group,
  35107. options = series.options,
  35108. animOptions = animObject(options.animation),
  35109. // Animation doesn't work in IE8 quirks when the group div is
  35110. // hidden, and looks bad in other oldIE
  35111. animDuration = (!series.finishedAnimating &&
  35112. chart.renderer.isSVG &&
  35113. animOptions.duration),
  35114. visibility = series.visible ?
  35115. 'inherit' : 'hidden', // #2597
  35116. zIndex = options.zIndex,
  35117. hasRendered = series.hasRendered,
  35118. chartSeriesGroup = chart.seriesGroup,
  35119. inverted = chart.inverted;
  35120. fireEvent(this, 'render');
  35121. // the group
  35122. group = series.plotGroup('group', 'series', visibility, zIndex, chartSeriesGroup);
  35123. series.markerGroup = series.plotGroup('markerGroup', 'markers', visibility, zIndex, chartSeriesGroup);
  35124. // initiate the animation
  35125. if (animDuration && series.animate) {
  35126. series.animate(true);
  35127. }
  35128. // SVGRenderer needs to know this before drawing elements (#1089,
  35129. // #1795)
  35130. group.inverted = pick(series.invertible, series.isCartesian) ?
  35131. inverted : false;
  35132. // Draw the graph if any
  35133. if (series.drawGraph) {
  35134. series.drawGraph();
  35135. series.applyZones();
  35136. }
  35137. // Draw the points
  35138. if (series.visible) {
  35139. series.drawPoints();
  35140. }
  35141. /* series.points.forEach(function (point) {
  35142. if (point.redraw) {
  35143. point.redraw();
  35144. }
  35145. }); */
  35146. // Draw the data labels
  35147. if (series.drawDataLabels) {
  35148. series.drawDataLabels();
  35149. }
  35150. // In pie charts, slices are added to the DOM, but actual rendering
  35151. // is postponed until labels reserved their space
  35152. if (series.redrawPoints) {
  35153. series.redrawPoints();
  35154. }
  35155. // draw the mouse tracking area
  35156. if (series.drawTracker &&
  35157. series.options.enableMouseTracking !== false) {
  35158. series.drawTracker();
  35159. }
  35160. // Handle inverted series and tracker groups
  35161. series.invertGroups(inverted);
  35162. // Initial clipping, must be defined after inverting groups for VML.
  35163. // Applies to columns etc. (#3839).
  35164. if (options.clip !== false &&
  35165. !series.sharedClipKey &&
  35166. !hasRendered) {
  35167. group.clip(chart.clipRect);
  35168. }
  35169. // Run the animation
  35170. if (animDuration && series.animate) {
  35171. series.animate();
  35172. }
  35173. // Call the afterAnimate function on animation complete (but don't
  35174. // overwrite the animation.complete option which should be available
  35175. // to the user).
  35176. if (!hasRendered) {
  35177. // Additional time if defer is defined before afterAnimate
  35178. // will be triggered
  35179. if (animDuration && animOptions.defer) {
  35180. animDuration += animOptions.defer;
  35181. }
  35182. series.animationTimeout = syncTimeout(function () {
  35183. series.afterAnimate();
  35184. }, animDuration || 0);
  35185. }
  35186. // Means data is in accordance with what you see
  35187. series.isDirty = false;
  35188. // (See #322) series.isDirty = series.isDirtyData = false; // means
  35189. // data is in accordance with what you see
  35190. series.hasRendered = true;
  35191. fireEvent(series, 'afterRender');
  35192. };
  35193. /**
  35194. * Redraw the series. This function is called internally from
  35195. * `chart.redraw` and normally shouldn't be called directly.
  35196. * @private
  35197. * @function Highcharts.Series#redraw
  35198. */
  35199. Series.prototype.redraw = function () {
  35200. var series = this,
  35201. chart = series.chart,
  35202. // cache it here as it is set to false in render, but used after
  35203. wasDirty = series.isDirty || series.isDirtyData,
  35204. group = series.group,
  35205. xAxis = series.xAxis,
  35206. yAxis = series.yAxis;
  35207. // reposition on resize
  35208. if (group) {
  35209. if (chart.inverted) {
  35210. group.attr({
  35211. width: chart.plotWidth,
  35212. height: chart.plotHeight
  35213. });
  35214. }
  35215. group.animate({
  35216. translateX: pick(xAxis && xAxis.left, chart.plotLeft),
  35217. translateY: pick(yAxis && yAxis.top, chart.plotTop)
  35218. });
  35219. }
  35220. series.translate();
  35221. series.render();
  35222. if (wasDirty) { // #3868, #3945
  35223. delete this.kdTree;
  35224. }
  35225. };
  35226. /**
  35227. * @private
  35228. * @function Highcharts.Series#searchPoint
  35229. */
  35230. Series.prototype.searchPoint = function (e, compareX) {
  35231. var series = this,
  35232. xAxis = series.xAxis,
  35233. yAxis = series.yAxis,
  35234. inverted = series.chart.inverted;
  35235. return this.searchKDTree({
  35236. clientX: inverted ?
  35237. xAxis.len - e.chartY + xAxis.pos :
  35238. e.chartX - xAxis.pos,
  35239. plotY: inverted ?
  35240. yAxis.len - e.chartX + yAxis.pos :
  35241. e.chartY - yAxis.pos
  35242. }, compareX, e);
  35243. };
  35244. /**
  35245. * Build the k-d-tree that is used by mouse and touch interaction to get
  35246. * the closest point. Line-like series typically have a one-dimensional
  35247. * tree where points are searched along the X axis, while scatter-like
  35248. * series typically search in two dimensions, X and Y.
  35249. *
  35250. * @private
  35251. * @function Highcharts.Series#buildKDTree
  35252. */
  35253. Series.prototype.buildKDTree = function (e) {
  35254. // Prevent multiple k-d-trees from being built simultaneously
  35255. // (#6235)
  35256. this.buildingKdTree = true;
  35257. var series = this,
  35258. dimensions = series.options.findNearestPointBy
  35259. .indexOf('y') > -1 ? 2 : 1;
  35260. /**
  35261. * Internal function
  35262. * @private
  35263. */
  35264. function _kdtree(points, depth, dimensions) {
  35265. var axis,
  35266. median,
  35267. length = points && points.length;
  35268. if (length) {
  35269. // alternate between the axis
  35270. axis = series.kdAxisArray[depth % dimensions];
  35271. // sort point array
  35272. points.sort(function (a, b) {
  35273. return a[axis] - b[axis];
  35274. });
  35275. median = Math.floor(length / 2);
  35276. // build and return nod
  35277. return {
  35278. point: points[median],
  35279. left: _kdtree(points.slice(0, median), depth + 1, dimensions),
  35280. right: _kdtree(points.slice(median + 1), depth + 1, dimensions)
  35281. };
  35282. }
  35283. }
  35284. /**
  35285. * Start the recursive build process with a clone of the points
  35286. * array and null points filtered out. (#3873)
  35287. * @private
  35288. */
  35289. function startRecursive() {
  35290. series.kdTree = _kdtree(series.getValidPoints(null,
  35291. // For line-type series restrict to plot area, but
  35292. // column-type series not (#3916, #4511)
  35293. !series.directTouch), dimensions, dimensions);
  35294. series.buildingKdTree = false;
  35295. }
  35296. delete series.kdTree;
  35297. // For testing tooltips, don't build async. Also if touchstart, we
  35298. // may be dealing with click events on mobile, so don't delay
  35299. // (#6817).
  35300. syncTimeout(startRecursive, series.options.kdNow || (e && e.type === 'touchstart') ? 0 : 1);
  35301. };
  35302. /**
  35303. * @private
  35304. * @function Highcharts.Series#searchKDTree
  35305. */
  35306. Series.prototype.searchKDTree = function (point, compareX, e) {
  35307. var series = this,
  35308. kdX = this.kdAxisArray[0],
  35309. kdY = this.kdAxisArray[1],
  35310. kdComparer = compareX ? 'distX' : 'dist',
  35311. kdDimensions = series.options.findNearestPointBy
  35312. .indexOf('y') > -1 ? 2 : 1;
  35313. /**
  35314. * Set the one and two dimensional distance on the point object.
  35315. * @private
  35316. */
  35317. function setDistance(p1, p2) {
  35318. var x = (defined(p1[kdX]) &&
  35319. defined(p2[kdX])) ?
  35320. Math.pow(p1[kdX] - p2[kdX], 2) :
  35321. null,
  35322. y = (defined(p1[kdY]) &&
  35323. defined(p2[kdY])) ?
  35324. Math.pow(p1[kdY] - p2[kdY], 2) :
  35325. null,
  35326. r = (x || 0) + (y || 0);
  35327. p2.dist = defined(r) ? Math.sqrt(r) : Number.MAX_VALUE;
  35328. p2.distX = defined(x) ? Math.sqrt(x) : Number.MAX_VALUE;
  35329. }
  35330. /**
  35331. * @private
  35332. */
  35333. function _search(search, tree, depth, dimensions) {
  35334. var point = tree.point,
  35335. axis = series.kdAxisArray[depth % dimensions],
  35336. tdist,
  35337. sideA,
  35338. sideB,
  35339. ret = point,
  35340. nPoint1,
  35341. nPoint2;
  35342. setDistance(search, point);
  35343. // Pick side based on distance to splitting point
  35344. tdist = search[axis] - point[axis];
  35345. sideA = tdist < 0 ? 'left' : 'right';
  35346. sideB = tdist < 0 ? 'right' : 'left';
  35347. // End of tree
  35348. if (tree[sideA]) {
  35349. nPoint1 = _search(search, tree[sideA], depth + 1, dimensions);
  35350. ret = (nPoint1[kdComparer] <
  35351. ret[kdComparer] ?
  35352. nPoint1 :
  35353. point);
  35354. }
  35355. if (tree[sideB]) {
  35356. // compare distance to current best to splitting point to
  35357. // decide wether to check side B or not
  35358. if (Math.sqrt(tdist * tdist) < ret[kdComparer]) {
  35359. nPoint2 = _search(search, tree[sideB], depth + 1, dimensions);
  35360. ret = (nPoint2[kdComparer] <
  35361. ret[kdComparer] ?
  35362. nPoint2 :
  35363. ret);
  35364. }
  35365. }
  35366. return ret;
  35367. }
  35368. if (!this.kdTree && !this.buildingKdTree) {
  35369. this.buildKDTree(e);
  35370. }
  35371. if (this.kdTree) {
  35372. return _search(point, this.kdTree, kdDimensions, kdDimensions);
  35373. }
  35374. };
  35375. /**
  35376. * @private
  35377. * @function Highcharts.Series#pointPlacementToXValue
  35378. */
  35379. Series.prototype.pointPlacementToXValue = function () {
  35380. var _a = this,
  35381. _b = _a.options,
  35382. pointPlacement = _b.pointPlacement,
  35383. pointRange = _b.pointRange,
  35384. axis = _a.xAxis;
  35385. var factor = pointPlacement;
  35386. // Point placement is relative to each series pointRange (#5889)
  35387. if (factor === 'between') {
  35388. factor = axis.reversed ? -0.5 : 0.5; // #11955
  35389. }
  35390. return isNumber(factor) ?
  35391. factor * (pointRange || axis.pointRange) :
  35392. 0;
  35393. };
  35394. /**
  35395. * @private
  35396. * @function Highcharts.Series#isPointInside
  35397. */
  35398. Series.prototype.isPointInside = function (point) {
  35399. var isInside = typeof point.plotY !== 'undefined' &&
  35400. typeof point.plotX !== 'undefined' &&
  35401. point.plotY >= 0 &&
  35402. point.plotY <= this.yAxis.len && // #3519
  35403. point.plotX >= 0 &&
  35404. point.plotX <= this.xAxis.len;
  35405. return isInside;
  35406. };
  35407. /**
  35408. * Draw the tracker object that sits above all data labels and markers to
  35409. * track mouse events on the graph or points. For the line type charts
  35410. * the tracker uses the same graphPath, but with a greater stroke width
  35411. * for better control.
  35412. * @private
  35413. */
  35414. Series.prototype.drawTracker = function () {
  35415. var series = this,
  35416. options = series.options,
  35417. trackByArea = options.trackByArea,
  35418. trackerPath = [].concat(trackByArea ?
  35419. series.areaPath :
  35420. series.graphPath),
  35421. // trackerPathLength = trackerPath.length,
  35422. chart = series.chart,
  35423. pointer = chart.pointer,
  35424. renderer = chart.renderer,
  35425. snap = chart.options.tooltip.snap,
  35426. tracker = series.tracker,
  35427. i,
  35428. onMouseOver = function (e) {
  35429. if (chart.hoverSeries !== series) {
  35430. series.onMouseOver();
  35431. }
  35432. },
  35433. /*
  35434. * Empirical lowest possible opacities for TRACKER_FILL for an
  35435. * element to stay invisible but clickable
  35436. * IE6: 0.002
  35437. * IE7: 0.002
  35438. * IE8: 0.002
  35439. * IE9: 0.00000000001 (unlimited)
  35440. * IE10: 0.0001 (exporting only)
  35441. * FF: 0.00000000001 (unlimited)
  35442. * Chrome: 0.000001
  35443. * Safari: 0.000001
  35444. * Opera: 0.00000000001 (unlimited)
  35445. */
  35446. TRACKER_FILL = 'rgba(192,192,192,' + (svg ? 0.0001 : 0.002) + ')';
  35447. // Draw the tracker
  35448. if (tracker) {
  35449. tracker.attr({ d: trackerPath });
  35450. }
  35451. else if (series.graph) { // create
  35452. series.tracker = renderer.path(trackerPath)
  35453. .attr({
  35454. visibility: series.visible ? 'visible' : 'hidden',
  35455. zIndex: 2
  35456. })
  35457. .addClass(trackByArea ?
  35458. 'highcharts-tracker-area' :
  35459. 'highcharts-tracker-line')
  35460. .add(series.group);
  35461. if (!chart.styledMode) {
  35462. series.tracker.attr({
  35463. 'stroke-linecap': 'round',
  35464. 'stroke-linejoin': 'round',
  35465. stroke: TRACKER_FILL,
  35466. fill: trackByArea ? TRACKER_FILL : 'none',
  35467. 'stroke-width': series.graph.strokeWidth() +
  35468. (trackByArea ? 0 : 2 * snap)
  35469. });
  35470. }
  35471. // The tracker is added to the series group, which is clipped, but
  35472. // is covered by the marker group. So the marker group also needs to
  35473. // capture events.
  35474. [
  35475. series.tracker,
  35476. series.markerGroup,
  35477. series.dataLabelsGroup
  35478. ].forEach(function (tracker) {
  35479. if (tracker) {
  35480. tracker.addClass('highcharts-tracker')
  35481. .on('mouseover', onMouseOver)
  35482. .on('mouseout', function (e) {
  35483. pointer.onTrackerMouseOut(e);
  35484. });
  35485. if (options.cursor && !chart.styledMode) {
  35486. tracker.css({ cursor: options.cursor });
  35487. }
  35488. if (hasTouch) {
  35489. tracker.on('touchstart', onMouseOver);
  35490. }
  35491. }
  35492. });
  35493. }
  35494. fireEvent(this, 'afterDrawTracker');
  35495. };
  35496. /**
  35497. * Add a point to the series after render time. The point can be added at
  35498. * the end, or by giving it an X value, to the start or in the middle of the
  35499. * series.
  35500. *
  35501. * @sample highcharts/members/series-addpoint-append/
  35502. * Append point
  35503. * @sample highcharts/members/series-addpoint-append-and-shift/
  35504. * Append and shift
  35505. * @sample highcharts/members/series-addpoint-x-and-y/
  35506. * Both X and Y values given
  35507. * @sample highcharts/members/series-addpoint-pie/
  35508. * Append pie slice
  35509. * @sample stock/members/series-addpoint/
  35510. * Append 100 points in Highcharts Stock
  35511. * @sample stock/members/series-addpoint-shift/
  35512. * Append and shift in Highcharts Stock
  35513. * @sample maps/members/series-addpoint/
  35514. * Add a point in Highmaps
  35515. *
  35516. * @function Highcharts.Series#addPoint
  35517. *
  35518. * @param {Highcharts.PointOptionsType} options
  35519. * The point options. If options is a single number, a point with
  35520. * that y value is appended to the series. If it is an array, it will
  35521. * be interpreted as x and y values respectively. If it is an
  35522. * object, advanced options as outlined under `series.data` are
  35523. * applied.
  35524. *
  35525. * @param {boolean} [redraw=true]
  35526. * Whether to redraw the chart after the point is added. When adding
  35527. * more than one point, it is highly recommended that the redraw
  35528. * option be set to false, and instead {@link Chart#redraw} is
  35529. * explicitly called after the adding of points is finished.
  35530. * Otherwise, the chart will redraw after adding each point.
  35531. *
  35532. * @param {boolean} [shift=false]
  35533. * If true, a point is shifted off the start of the series as one is
  35534. * appended to the end.
  35535. *
  35536. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
  35537. * Whether to apply animation, and optionally animation
  35538. * configuration.
  35539. *
  35540. * @param {boolean} [withEvent=true]
  35541. * Used internally, whether to fire the series `addPoint` event.
  35542. *
  35543. * @fires Highcharts.Series#event:addPoint
  35544. */
  35545. Series.prototype.addPoint = function (options, redraw, shift, animation, withEvent) {
  35546. var series = this,
  35547. seriesOptions = series.options,
  35548. data = series.data,
  35549. chart = series.chart,
  35550. xAxis = series.xAxis,
  35551. names = xAxis && xAxis.hasNames && xAxis.names,
  35552. dataOptions = seriesOptions.data,
  35553. point,
  35554. xData = series.xData,
  35555. isInTheMiddle,
  35556. i,
  35557. x;
  35558. // Optional redraw, defaults to true
  35559. redraw = pick(redraw, true);
  35560. // Get options and push the point to xData, yData and series.options. In
  35561. // series.generatePoints the Point instance will be created on demand
  35562. // and pushed to the series.data array.
  35563. point = { series: series };
  35564. series.pointClass.prototype.applyOptions.apply(point, [options]);
  35565. x = point.x;
  35566. // Get the insertion point
  35567. i = xData.length;
  35568. if (series.requireSorting && x < xData[i - 1]) {
  35569. isInTheMiddle = true;
  35570. while (i && xData[i - 1] > x) {
  35571. i--;
  35572. }
  35573. }
  35574. // Insert undefined item
  35575. series.updateParallelArrays(point, 'splice', i, 0, 0);
  35576. // Update it
  35577. series.updateParallelArrays(point, i);
  35578. if (names && point.name) {
  35579. names[x] = point.name;
  35580. }
  35581. dataOptions.splice(i, 0, options);
  35582. if (isInTheMiddle) {
  35583. series.data.splice(i, 0, null);
  35584. series.processData();
  35585. }
  35586. // Generate points to be added to the legend (#1329)
  35587. if (seriesOptions.legendType === 'point') {
  35588. series.generatePoints();
  35589. }
  35590. // Shift the first point off the parallel arrays
  35591. if (shift) {
  35592. if (data[0] && data[0].remove) {
  35593. data[0].remove(false);
  35594. }
  35595. else {
  35596. data.shift();
  35597. series.updateParallelArrays(point, 'shift');
  35598. dataOptions.shift();
  35599. }
  35600. }
  35601. // Fire event
  35602. if (withEvent !== false) {
  35603. fireEvent(series, 'addPoint', { point: point });
  35604. }
  35605. // redraw
  35606. series.isDirty = true;
  35607. series.isDirtyData = true;
  35608. if (redraw) {
  35609. chart.redraw(animation); // Animation is set anyway on redraw, #5665
  35610. }
  35611. };
  35612. /**
  35613. * Remove a point from the series. Unlike the
  35614. * {@link Highcharts.Point#remove} method, this can also be done on a point
  35615. * that is not instanciated because it is outside the view or subject to
  35616. * Highcharts Stock data grouping.
  35617. *
  35618. * @sample highcharts/members/series-removepoint/
  35619. * Remove cropped point
  35620. *
  35621. * @function Highcharts.Series#removePoint
  35622. *
  35623. * @param {number} i
  35624. * The index of the point in the {@link Highcharts.Series.data|data}
  35625. * array.
  35626. *
  35627. * @param {boolean} [redraw=true]
  35628. * Whether to redraw the chart after the point is added. When
  35629. * removing more than one point, it is highly recommended that the
  35630. * `redraw` option be set to `false`, and instead {@link
  35631. * Highcharts.Chart#redraw} is explicitly called after the adding of
  35632. * points is finished.
  35633. *
  35634. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
  35635. * Whether and optionally how the series should be animated.
  35636. *
  35637. * @fires Highcharts.Point#event:remove
  35638. */
  35639. Series.prototype.removePoint = function (i, redraw, animation) {
  35640. var series = this,
  35641. data = series.data,
  35642. point = data[i],
  35643. points = series.points,
  35644. chart = series.chart,
  35645. remove = function () {
  35646. if (points && points.length === data.length) { // #4935
  35647. points.splice(i, 1);
  35648. }
  35649. data.splice(i, 1);
  35650. series.options.data.splice(i, 1);
  35651. series.updateParallelArrays(point || { series: series }, 'splice', i, 1);
  35652. if (point) {
  35653. point.destroy();
  35654. }
  35655. // redraw
  35656. series.isDirty = true;
  35657. series.isDirtyData = true;
  35658. if (redraw) {
  35659. chart.redraw();
  35660. }
  35661. };
  35662. setAnimation(animation, chart);
  35663. redraw = pick(redraw, true);
  35664. // Fire the event with a default handler of removing the point
  35665. if (point) {
  35666. point.firePointEvent('remove', null, remove);
  35667. }
  35668. else {
  35669. remove();
  35670. }
  35671. };
  35672. /**
  35673. * Remove a series and optionally redraw the chart.
  35674. *
  35675. * @sample highcharts/members/series-remove/
  35676. * Remove first series from a button
  35677. *
  35678. * @function Highcharts.Series#remove
  35679. *
  35680. * @param {boolean} [redraw=true]
  35681. * Whether to redraw the chart or wait for an explicit call to
  35682. * {@link Highcharts.Chart#redraw}.
  35683. *
  35684. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
  35685. * Whether to apply animation, and optionally animation
  35686. * configuration.
  35687. *
  35688. * @param {boolean} [withEvent=true]
  35689. * Used internally, whether to fire the series `remove` event.
  35690. *
  35691. * @fires Highcharts.Series#event:remove
  35692. */
  35693. Series.prototype.remove = function (redraw, animation, withEvent, keepEvents) {
  35694. var series = this,
  35695. chart = series.chart;
  35696. /**
  35697. * @private
  35698. */
  35699. function remove() {
  35700. // Destroy elements
  35701. series.destroy(keepEvents);
  35702. // Redraw
  35703. chart.isDirtyLegend = chart.isDirtyBox = true;
  35704. chart.linkSeries();
  35705. if (pick(redraw, true)) {
  35706. chart.redraw(animation);
  35707. }
  35708. }
  35709. // Fire the event with a default handler of removing the point
  35710. if (withEvent !== false) {
  35711. fireEvent(series, 'remove', null, remove);
  35712. }
  35713. else {
  35714. remove();
  35715. }
  35716. };
  35717. /**
  35718. * Update the series with a new set of options. For a clean and precise
  35719. * handling of new options, all methods and elements from the series are
  35720. * removed, and it is initialized from scratch. Therefore, this method is
  35721. * more performance expensive than some other utility methods like {@link
  35722. * Series#setData} or {@link Series#setVisible}.
  35723. *
  35724. * Note that `Series.update` may mutate the passed `data` options.
  35725. *
  35726. * @sample highcharts/members/series-update/
  35727. * Updating series options
  35728. * @sample maps/members/series-update/
  35729. * Update series options in Highmaps
  35730. *
  35731. * @function Highcharts.Series#update
  35732. *
  35733. * @param {Highcharts.SeriesOptionsType} options
  35734. * New options that will be merged with the series' existing options.
  35735. *
  35736. * @param {boolean} [redraw=true]
  35737. * Whether to redraw the chart after the series is altered. If doing
  35738. * more operations on the chart, it is a good idea to set redraw to
  35739. * false and call {@link Chart#redraw} after.
  35740. *
  35741. * @fires Highcharts.Series#event:update
  35742. * @fires Highcharts.Series#event:afterUpdate
  35743. */
  35744. Series.prototype.update = function (options, redraw) {
  35745. options = cleanRecursively(options, this.userOptions);
  35746. fireEvent(this, 'update', { options: options });
  35747. var series = this,
  35748. chart = series.chart,
  35749. // must use user options when changing type because series.options
  35750. // is merged in with type specific plotOptions
  35751. oldOptions = series.userOptions,
  35752. seriesOptions,
  35753. initialType = series.initialType || series.type,
  35754. plotOptions = chart.options.plotOptions,
  35755. newType = (options.type ||
  35756. oldOptions.type ||
  35757. chart.options.chart.type),
  35758. keepPoints = !(
  35759. // Indicators, histograms etc recalculate the data. It should be
  35760. // possible to omit this.
  35761. this.hasDerivedData ||
  35762. // New type requires new point classes
  35763. (newType && newType !== this.type) ||
  35764. // New options affecting how the data points are built
  35765. typeof options.pointStart !== 'undefined' ||
  35766. typeof options.pointInterval !== 'undefined' ||
  35767. // Changes to data grouping requires new points in new group
  35768. series.hasOptionChanged('dataGrouping') ||
  35769. series.hasOptionChanged('pointStart') ||
  35770. series.hasOptionChanged('pointInterval') ||
  35771. series.hasOptionChanged('pointIntervalUnit') ||
  35772. series.hasOptionChanged('keys')),
  35773. initialSeriesProto = seriesTypes[initialType].prototype,
  35774. n,
  35775. groups = [
  35776. 'group',
  35777. 'markerGroup',
  35778. 'dataLabelsGroup',
  35779. 'transformGroup'
  35780. ],
  35781. preserve = [
  35782. 'eventOptions',
  35783. 'navigatorSeries',
  35784. 'baseSeries'
  35785. ],
  35786. // Animation must be enabled when calling update before the initial
  35787. // animation has first run. This happens when calling update
  35788. // directly after chart initialization, or when applying responsive
  35789. // rules (#6912).
  35790. animation = series.finishedAnimating && { animation: false },
  35791. kinds = {};
  35792. newType = newType || initialType;
  35793. if (keepPoints) {
  35794. preserve.push('data', 'isDirtyData', 'points', 'processedXData', 'processedYData', 'xIncrement', 'cropped', '_hasPointMarkers', '_hasPointLabels', 'clips', // #15420
  35795. // Networkgraph (#14397)
  35796. 'nodes', 'layout',
  35797. // Map specific, consider moving it to series-specific preserve-
  35798. // properties (#10617)
  35799. 'mapMap', 'mapData', 'minY', 'maxY', 'minX', 'maxX');
  35800. if (options.visible !== false) {
  35801. preserve.push('area', 'graph');
  35802. }
  35803. series.parallelArrays.forEach(function (key) {
  35804. preserve.push(key + 'Data');
  35805. });
  35806. if (options.data) {
  35807. // setData uses dataSorting options so we need to update them
  35808. // earlier
  35809. if (options.dataSorting) {
  35810. extend(series.options.dataSorting, options.dataSorting);
  35811. }
  35812. this.setData(options.data, false);
  35813. }
  35814. }
  35815. // Do the merge, with some forced options
  35816. options = merge(oldOptions, animation, {
  35817. // When oldOptions.index is null it should't be cleared.
  35818. // Otherwise navigator series will have wrong indexes (#10193).
  35819. index: typeof oldOptions.index === 'undefined' ?
  35820. series.index : oldOptions.index,
  35821. pointStart: pick(
  35822. // when updating from blank (#7933)
  35823. plotOptions && plotOptions.series && plotOptions.series.pointStart, oldOptions.pointStart,
  35824. // when updating after addPoint
  35825. series.xData[0])
  35826. }, (!keepPoints && { data: series.options.data }), options);
  35827. // Merge does not merge arrays, but replaces them. Since points were
  35828. // updated, `series.options.data` has correct merged options, use it:
  35829. if (keepPoints && options.data) {
  35830. options.data = series.options.data;
  35831. }
  35832. // Make sure preserved properties are not destroyed (#3094)
  35833. preserve = groups.concat(preserve);
  35834. preserve.forEach(function (prop) {
  35835. preserve[prop] = series[prop];
  35836. delete series[prop];
  35837. });
  35838. var casting = false;
  35839. if (seriesTypes[newType]) {
  35840. casting = newType !== series.type;
  35841. // Destroy the series and delete all properties, it will be
  35842. // reinserted within the `init` call below
  35843. series.remove(false, false, false, true);
  35844. if (casting) {
  35845. // Modern browsers including IE11
  35846. // @todo slow, consider alternatives mentioned:
  35847. // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf
  35848. if (Object.setPrototypeOf) {
  35849. Object.setPrototypeOf(series, seriesTypes[newType].prototype);
  35850. // Legacy (IE < 11)
  35851. }
  35852. else {
  35853. var ownEvents = Object.hasOwnProperty.call(series, 'hcEvents') &&
  35854. series.hcEvents;
  35855. for (n in initialSeriesProto) { // eslint-disable-line guard-for-in
  35856. series[n] = void 0;
  35857. }
  35858. // Reinsert all methods and properties from the new type
  35859. // prototype (#2270, #3719).
  35860. extend(series, seriesTypes[newType].prototype);
  35861. // The events are tied to the prototype chain, don't copy if
  35862. // they're not the series' own
  35863. if (ownEvents) {
  35864. series.hcEvents = ownEvents;
  35865. }
  35866. else {
  35867. delete series.hcEvents;
  35868. }
  35869. }
  35870. }
  35871. }
  35872. else {
  35873. error(17, true, chart, { missingModuleFor: newType });
  35874. }
  35875. // Re-register groups (#3094) and other preserved properties
  35876. preserve.forEach(function (prop) {
  35877. series[prop] = preserve[prop];
  35878. });
  35879. series.init(chart, options);
  35880. // Remove particular elements of the points. Check `series.options`
  35881. // because we need to consider the options being set on plotOptions as
  35882. // well.
  35883. if (keepPoints && this.points) {
  35884. seriesOptions = series.options;
  35885. // What kind of elements to destroy
  35886. if (seriesOptions.visible === false) {
  35887. kinds.graphic = 1;
  35888. kinds.dataLabel = 1;
  35889. }
  35890. else if (!series._hasPointLabels) {
  35891. var marker = seriesOptions.marker,
  35892. dataLabels = seriesOptions.dataLabels;
  35893. if (marker && (marker.enabled === false ||
  35894. 'symbol' in marker // #10870
  35895. )) {
  35896. kinds.graphic = 1;
  35897. }
  35898. if (dataLabels &&
  35899. dataLabels.enabled === false) {
  35900. kinds.dataLabel = 1;
  35901. }
  35902. }
  35903. this.points.forEach(function (point) {
  35904. if (point && point.series) {
  35905. point.resolveColor();
  35906. // Destroy elements in order to recreate based on updated
  35907. // series options.
  35908. if (Object.keys(kinds).length) {
  35909. point.destroyElements(kinds);
  35910. }
  35911. if (seriesOptions.showInLegend === false &&
  35912. point.legendItem) {
  35913. chart.legend.destroyItem(point);
  35914. }
  35915. }
  35916. }, this);
  35917. }
  35918. series.initialType = initialType;
  35919. chart.linkSeries(); // Links are lost in series.remove (#3028)
  35920. // #15383: Fire updatedData if the type has changed to keep linked
  35921. // series such as indicators updated
  35922. if (casting && series.linkedSeries.length) {
  35923. series.isDirtyData = true;
  35924. }
  35925. fireEvent(this, 'afterUpdate');
  35926. if (pick(redraw, true)) {
  35927. chart.redraw(keepPoints ? void 0 : false);
  35928. }
  35929. };
  35930. /**
  35931. * Used from within series.update
  35932. * @private
  35933. */
  35934. Series.prototype.setName = function (name) {
  35935. this.name = this.options.name = this.userOptions.name = name;
  35936. this.chart.isDirtyLegend = true;
  35937. };
  35938. /**
  35939. * Check if the option has changed.
  35940. * @private
  35941. */
  35942. Series.prototype.hasOptionChanged = function (optionName) {
  35943. var chart = this.chart,
  35944. option = this.options[optionName],
  35945. plotOptions = chart.options.plotOptions,
  35946. oldOption = this.userOptions[optionName];
  35947. if (oldOption) {
  35948. return option !== oldOption;
  35949. }
  35950. return option !==
  35951. pick(plotOptions && plotOptions[this.type] && plotOptions[this.type][optionName], plotOptions && plotOptions.series && plotOptions.series[optionName], option);
  35952. };
  35953. /**
  35954. * Runs on mouse over the series graphical items.
  35955. *
  35956. * @function Highcharts.Series#onMouseOver
  35957. * @fires Highcharts.Series#event:mouseOver
  35958. */
  35959. Series.prototype.onMouseOver = function () {
  35960. var series = this,
  35961. chart = series.chart,
  35962. hoverSeries = chart.hoverSeries,
  35963. pointer = chart.pointer;
  35964. pointer.setHoverChartIndex();
  35965. // set normal state to previous series
  35966. if (hoverSeries && hoverSeries !== series) {
  35967. hoverSeries.onMouseOut();
  35968. }
  35969. // trigger the event, but to save processing time,
  35970. // only if defined
  35971. if (series.options.events.mouseOver) {
  35972. fireEvent(series, 'mouseOver');
  35973. }
  35974. // hover this
  35975. series.setState('hover');
  35976. /**
  35977. * Contains the original hovered series.
  35978. *
  35979. * @name Highcharts.Chart#hoverSeries
  35980. * @type {Highcharts.Series|null}
  35981. */
  35982. chart.hoverSeries = series;
  35983. };
  35984. /**
  35985. * Runs on mouse out of the series graphical items.
  35986. *
  35987. * @function Highcharts.Series#onMouseOut
  35988. *
  35989. * @fires Highcharts.Series#event:mouseOut
  35990. */
  35991. Series.prototype.onMouseOut = function () {
  35992. // trigger the event only if listeners exist
  35993. var series = this,
  35994. options = series.options,
  35995. chart = series.chart,
  35996. tooltip = chart.tooltip,
  35997. hoverPoint = chart.hoverPoint;
  35998. // #182, set to null before the mouseOut event fires
  35999. chart.hoverSeries = null;
  36000. // trigger mouse out on the point, which must be in this series
  36001. if (hoverPoint) {
  36002. hoverPoint.onMouseOut();
  36003. }
  36004. // fire the mouse out event
  36005. if (series && options.events.mouseOut) {
  36006. fireEvent(series, 'mouseOut');
  36007. }
  36008. // hide the tooltip
  36009. if (tooltip &&
  36010. !series.stickyTracking &&
  36011. (!tooltip.shared || series.noSharedTooltip)) {
  36012. tooltip.hide();
  36013. }
  36014. // Reset all inactive states
  36015. chart.series.forEach(function (s) {
  36016. s.setState('', true);
  36017. });
  36018. };
  36019. /**
  36020. * Set the state of the series. Called internally on mouse interaction
  36021. * operations, but it can also be called directly to visually
  36022. * highlight a series.
  36023. *
  36024. * @function Highcharts.Series#setState
  36025. *
  36026. * @param {Highcharts.SeriesStateValue|""} [state]
  36027. * The new state, can be either `'hover'`, `'inactive'`, `'select'`,
  36028. * or `''` (an empty string), `'normal'` or `undefined` to set to
  36029. * normal state.
  36030. * @param {boolean} [inherit]
  36031. * Determines if state should be inherited by points too.
  36032. */
  36033. Series.prototype.setState = function (state, inherit) {
  36034. var series = this,
  36035. options = series.options,
  36036. graph = series.graph,
  36037. inactiveOtherPoints = options.inactiveOtherPoints,
  36038. stateOptions = options.states,
  36039. lineWidth = options.lineWidth,
  36040. opacity = options.opacity,
  36041. // By default a quick animation to hover/inactive,
  36042. // slower to un-hover
  36043. stateAnimation = pick((stateOptions[state || 'normal'] &&
  36044. stateOptions[state || 'normal'].animation),
  36045. series.chart.options.chart.animation),
  36046. attribs,
  36047. i = 0;
  36048. state = state || '';
  36049. if (series.state !== state) {
  36050. // Toggle class names
  36051. [
  36052. series.group,
  36053. series.markerGroup,
  36054. series.dataLabelsGroup
  36055. ].forEach(function (group) {
  36056. if (group) {
  36057. // Old state
  36058. if (series.state) {
  36059. group.removeClass('highcharts-series-' + series.state);
  36060. }
  36061. // New state
  36062. if (state) {
  36063. group.addClass('highcharts-series-' + state);
  36064. }
  36065. }
  36066. });
  36067. series.state = state;
  36068. if (!series.chart.styledMode) {
  36069. if (stateOptions[state] &&
  36070. stateOptions[state].enabled === false) {
  36071. return;
  36072. }
  36073. if (state) {
  36074. lineWidth = (stateOptions[state].lineWidth ||
  36075. lineWidth + (stateOptions[state].lineWidthPlus || 0)); // #4035
  36076. opacity = pick(stateOptions[state].opacity, opacity);
  36077. }
  36078. if (graph && !graph.dashstyle) {
  36079. attribs = {
  36080. 'stroke-width': lineWidth
  36081. };
  36082. // Animate the graph stroke-width.
  36083. graph.animate(attribs, stateAnimation);
  36084. while (series['zone-graph-' + i]) {
  36085. series['zone-graph-' + i].animate(attribs, stateAnimation);
  36086. i = i + 1;
  36087. }
  36088. }
  36089. // For some types (pie, networkgraph, sankey) opacity is
  36090. // resolved on a point level
  36091. if (!inactiveOtherPoints) {
  36092. [
  36093. series.group,
  36094. series.markerGroup,
  36095. series.dataLabelsGroup,
  36096. series.labelBySeries
  36097. ].forEach(function (group) {
  36098. if (group) {
  36099. group.animate({
  36100. opacity: opacity
  36101. }, stateAnimation);
  36102. }
  36103. });
  36104. }
  36105. }
  36106. }
  36107. // Don't loop over points on a series that doesn't apply inactive state
  36108. // to siblings markers (e.g. line, column)
  36109. if (inherit && inactiveOtherPoints && series.points) {
  36110. series.setAllPointsToState(state || void 0);
  36111. }
  36112. };
  36113. /**
  36114. * Set the state for all points in the series.
  36115. *
  36116. * @function Highcharts.Series#setAllPointsToState
  36117. *
  36118. * @private
  36119. *
  36120. * @param {string} [state]
  36121. * Can be either `hover` or undefined to set to normal state.
  36122. */
  36123. Series.prototype.setAllPointsToState = function (state) {
  36124. this.points.forEach(function (point) {
  36125. if (point.setState) {
  36126. point.setState(state);
  36127. }
  36128. });
  36129. };
  36130. /**
  36131. * Show or hide the series.
  36132. *
  36133. * @function Highcharts.Series#setVisible
  36134. *
  36135. * @param {boolean} [visible]
  36136. * True to show the series, false to hide. If undefined, the visibility is
  36137. * toggled.
  36138. *
  36139. * @param {boolean} [redraw=true]
  36140. * Whether to redraw the chart after the series is altered. If doing more
  36141. * operations on the chart, it is a good idea to set redraw to false and
  36142. * call {@link Chart#redraw|chart.redraw()} after.
  36143. *
  36144. * @fires Highcharts.Series#event:hide
  36145. * @fires Highcharts.Series#event:show
  36146. */
  36147. Series.prototype.setVisible = function (vis, redraw) {
  36148. var series = this,
  36149. chart = series.chart,
  36150. legendItem = series.legendItem,
  36151. showOrHide,
  36152. ignoreHiddenSeries = chart.options.chart.ignoreHiddenSeries,
  36153. oldVisibility = series.visible;
  36154. // if called without an argument, toggle visibility
  36155. series.visible =
  36156. vis =
  36157. series.options.visible =
  36158. series.userOptions.visible =
  36159. typeof vis === 'undefined' ? !oldVisibility : vis; // #5618
  36160. showOrHide = vis ? 'show' : 'hide';
  36161. // show or hide elements
  36162. [
  36163. 'group',
  36164. 'dataLabelsGroup',
  36165. 'markerGroup',
  36166. 'tracker',
  36167. 'tt'
  36168. ].forEach(function (key) {
  36169. if (series[key]) {
  36170. series[key][showOrHide]();
  36171. }
  36172. });
  36173. // hide tooltip (#1361)
  36174. if (chart.hoverSeries === series ||
  36175. (chart.hoverPoint && chart.hoverPoint.series) === series) {
  36176. series.onMouseOut();
  36177. }
  36178. if (legendItem) {
  36179. chart.legend.colorizeItem(series, vis);
  36180. }
  36181. // rescale or adapt to resized chart
  36182. series.isDirty = true;
  36183. // in a stack, all other series are affected
  36184. if (series.options.stacking) {
  36185. chart.series.forEach(function (otherSeries) {
  36186. if (otherSeries.options.stacking && otherSeries.visible) {
  36187. otherSeries.isDirty = true;
  36188. }
  36189. });
  36190. }
  36191. // show or hide linked series
  36192. series.linkedSeries.forEach(function (otherSeries) {
  36193. otherSeries.setVisible(vis, false);
  36194. });
  36195. if (ignoreHiddenSeries) {
  36196. chart.isDirtyBox = true;
  36197. }
  36198. fireEvent(series, showOrHide);
  36199. if (redraw !== false) {
  36200. chart.redraw();
  36201. }
  36202. };
  36203. /**
  36204. * Show the series if hidden.
  36205. *
  36206. * @sample highcharts/members/series-hide/
  36207. * Toggle visibility from a button
  36208. *
  36209. * @function Highcharts.Series#show
  36210. * @fires Highcharts.Series#event:show
  36211. */
  36212. Series.prototype.show = function () {
  36213. this.setVisible(true);
  36214. };
  36215. /**
  36216. * Hide the series if visible. If the
  36217. * [chart.ignoreHiddenSeries](https://api.highcharts.com/highcharts/chart.ignoreHiddenSeries)
  36218. * option is true, the chart is redrawn without this series.
  36219. *
  36220. * @sample highcharts/members/series-hide/
  36221. * Toggle visibility from a button
  36222. *
  36223. * @function Highcharts.Series#hide
  36224. * @fires Highcharts.Series#event:hide
  36225. */
  36226. Series.prototype.hide = function () {
  36227. this.setVisible(false);
  36228. };
  36229. /**
  36230. * Select or unselect the series. This means its
  36231. * {@link Highcharts.Series.selected|selected}
  36232. * property is set, the checkbox in the legend is toggled and when selected,
  36233. * the series is returned by the {@link Highcharts.Chart#getSelectedSeries}
  36234. * function.
  36235. *
  36236. * @sample highcharts/members/series-select/
  36237. * Select a series from a button
  36238. *
  36239. * @function Highcharts.Series#select
  36240. *
  36241. * @param {boolean} [selected]
  36242. * True to select the series, false to unselect. If undefined, the selection
  36243. * state is toggled.
  36244. *
  36245. * @fires Highcharts.Series#event:select
  36246. * @fires Highcharts.Series#event:unselect
  36247. */
  36248. Series.prototype.select = function (selected) {
  36249. var series = this;
  36250. series.selected =
  36251. selected =
  36252. this.options.selected = (typeof selected === 'undefined' ?
  36253. !series.selected :
  36254. selected);
  36255. if (series.checkbox) {
  36256. series.checkbox.checked = selected;
  36257. }
  36258. fireEvent(series, selected ? 'select' : 'unselect');
  36259. };
  36260. /**
  36261. * Checks if a tooltip should be shown for a given point.
  36262. *
  36263. * @private
  36264. * @param {number} plotX
  36265. * @param {number} plotY
  36266. * @param {Highcharts.ChartIsInsideOptionsObject} [options]
  36267. * @return {boolean}
  36268. */
  36269. Series.prototype.shouldShowTooltip = function (plotX, plotY, options) {
  36270. if (options === void 0) { options = {}; }
  36271. options.series = this;
  36272. options.visiblePlotOnly = true;
  36273. return this.chart.isInsidePlot(plotX, plotY, options);
  36274. };
  36275. /**
  36276. * General options for all series types.
  36277. *
  36278. * @optionparent plotOptions.series
  36279. */
  36280. Series.defaultOptions = {
  36281. // base series options
  36282. /**
  36283. * The SVG value used for the `stroke-linecap` and `stroke-linejoin`
  36284. * of a line graph. Round means that lines are rounded in the ends and
  36285. * bends.
  36286. *
  36287. * @type {Highcharts.SeriesLinecapValue}
  36288. * @default round
  36289. * @since 3.0.7
  36290. * @apioption plotOptions.line.linecap
  36291. */
  36292. /**
  36293. * Pixel width of the graph line.
  36294. *
  36295. * @see In styled mode, the line stroke-width can be set with the
  36296. * `.highcharts-graph` class name.
  36297. *
  36298. * @sample {highcharts} highcharts/plotoptions/series-linewidth-general/
  36299. * On all series
  36300. * @sample {highcharts} highcharts/plotoptions/series-linewidth-specific/
  36301. * On one single series
  36302. *
  36303. * @product highcharts highstock
  36304. *
  36305. * @private
  36306. */
  36307. lineWidth: 2,
  36308. /**
  36309. * For some series, there is a limit that shuts down initial animation
  36310. * by default when the total number of points in the chart is too high.
  36311. * For example, for a column chart and its derivatives, animation does
  36312. * not run if there is more than 250 points totally. To disable this
  36313. * cap, set `animationLimit` to `Infinity`.
  36314. *
  36315. * @type {number}
  36316. * @apioption plotOptions.series.animationLimit
  36317. */
  36318. /**
  36319. * Allow this series' points to be selected by clicking on the graphic
  36320. * (columns, point markers, pie slices, map areas etc).
  36321. *
  36322. * The selected points can be handled by point select and unselect
  36323. * events, or collectively by the [getSelectedPoints
  36324. * ](/class-reference/Highcharts.Chart#getSelectedPoints) function.
  36325. *
  36326. * And alternative way of selecting points is through dragging.
  36327. *
  36328. * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-line/
  36329. * Line
  36330. * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-column/
  36331. * Column
  36332. * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-pie/
  36333. * Pie
  36334. * @sample {highcharts} highcharts/chart/events-selection-points/
  36335. * Select a range of points through a drag selection
  36336. * @sample {highmaps} maps/plotoptions/series-allowpointselect/
  36337. * Map area
  36338. * @sample {highmaps} maps/plotoptions/mapbubble-allowpointselect/
  36339. * Map bubble
  36340. *
  36341. * @since 1.2.0
  36342. *
  36343. * @private
  36344. */
  36345. allowPointSelect: false,
  36346. /**
  36347. * When true, each point or column edge is rounded to its nearest pixel
  36348. * in order to render sharp on screen. In some cases, when there are a
  36349. * lot of densely packed columns, this leads to visible difference
  36350. * in column widths or distance between columns. In these cases,
  36351. * setting `crisp` to `false` may look better, even though each column
  36352. * is rendered blurry.
  36353. *
  36354. * @sample {highcharts} highcharts/plotoptions/column-crisp-false/
  36355. * Crisp is false
  36356. *
  36357. * @since 5.0.10
  36358. * @product highcharts highstock gantt
  36359. *
  36360. * @private
  36361. */
  36362. crisp: true,
  36363. /**
  36364. * If true, a checkbox is displayed next to the legend item to allow
  36365. * selecting the series. The state of the checkbox is determined by
  36366. * the `selected` option.
  36367. *
  36368. * @productdesc {highmaps}
  36369. * Note that if a `colorAxis` is defined, the color axis is represented
  36370. * in the legend, not the series.
  36371. *
  36372. * @sample {highcharts} highcharts/plotoptions/series-showcheckbox-true/
  36373. * Show select box
  36374. *
  36375. * @since 1.2.0
  36376. *
  36377. * @private
  36378. */
  36379. showCheckbox: false,
  36380. /**
  36381. * Enable or disable the initial animation when a series is displayed.
  36382. * The animation can also be set as a configuration object. Please
  36383. * note that this option only applies to the initial animation of the
  36384. * series itself. For other animations, see [chart.animation](
  36385. * #chart.animation) and the animation parameter under the API methods.
  36386. * The following properties are supported:
  36387. *
  36388. * - `defer`: The animation delay time in milliseconds.
  36389. *
  36390. * - `duration`: The duration of the animation in milliseconds.
  36391. *
  36392. * - `easing`: Can be a string reference to an easing function set on
  36393. * the `Math` object or a function. See the _Custom easing function_
  36394. * demo below.
  36395. *
  36396. * Due to poor performance, animation is disabled in old IE browsers
  36397. * for several chart types.
  36398. *
  36399. * @sample {highcharts} highcharts/plotoptions/series-animation-disabled/
  36400. * Animation disabled
  36401. * @sample {highcharts} highcharts/plotoptions/series-animation-slower/
  36402. * Slower animation
  36403. * @sample {highcharts} highcharts/plotoptions/series-animation-easing/
  36404. * Custom easing function
  36405. * @sample {highstock} stock/plotoptions/animation-slower/
  36406. * Slower animation
  36407. * @sample {highstock} stock/plotoptions/animation-easing/
  36408. * Custom easing function
  36409. * @sample {highmaps} maps/plotoptions/series-animation-true/
  36410. * Animation enabled on map series
  36411. * @sample {highmaps} maps/plotoptions/mapbubble-animation-false/
  36412. * Disabled on mapbubble series
  36413. *
  36414. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  36415. * @default {highcharts} true
  36416. * @default {highstock} true
  36417. * @default {highmaps} false
  36418. *
  36419. * @private
  36420. */
  36421. animation: {
  36422. /** @internal */
  36423. duration: 1000
  36424. },
  36425. /**
  36426. * @default 0
  36427. * @type {number}
  36428. * @since 8.2.0
  36429. * @apioption plotOptions.series.animation.defer
  36430. */
  36431. /**
  36432. * An additional class name to apply to the series' graphical elements.
  36433. * This option does not replace default class names of the graphical
  36434. * element.
  36435. *
  36436. * @type {string}
  36437. * @since 5.0.0
  36438. * @apioption plotOptions.series.className
  36439. */
  36440. /**
  36441. * Disable this option to allow series rendering in the whole plotting
  36442. * area.
  36443. *
  36444. * **Note:** Clipping should be always enabled when
  36445. * [chart.zoomType](#chart.zoomType) is set
  36446. *
  36447. * @sample {highcharts} highcharts/plotoptions/series-clip/
  36448. * Disabled clipping
  36449. *
  36450. * @default true
  36451. * @type {boolean}
  36452. * @since 3.0.0
  36453. * @apioption plotOptions.series.clip
  36454. */
  36455. /**
  36456. * The main color of the series. In line type series it applies to the
  36457. * line and the point markers unless otherwise specified. In bar type
  36458. * series it applies to the bars unless a color is specified per point.
  36459. * The default value is pulled from the `options.colors` array.
  36460. *
  36461. * In styled mode, the color can be defined by the
  36462. * [colorIndex](#plotOptions.series.colorIndex) option. Also, the series
  36463. * color can be set with the `.highcharts-series`,
  36464. * `.highcharts-color-{n}`, `.highcharts-{type}-series` or
  36465. * `.highcharts-series-{n}` class, or individual classes given by the
  36466. * `className` option.
  36467. *
  36468. * @productdesc {highmaps}
  36469. * In maps, the series color is rarely used, as most choropleth maps use
  36470. * the color to denote the value of each point. The series color can
  36471. * however be used in a map with multiple series holding categorized
  36472. * data.
  36473. *
  36474. * @sample {highcharts} highcharts/plotoptions/series-color-general/
  36475. * General plot option
  36476. * @sample {highcharts} highcharts/plotoptions/series-color-specific/
  36477. * One specific series
  36478. * @sample {highcharts} highcharts/plotoptions/series-color-area/
  36479. * Area color
  36480. * @sample {highcharts} highcharts/series/infographic/
  36481. * Pattern fill
  36482. * @sample {highmaps} maps/demo/category-map/
  36483. * Category map by multiple series
  36484. *
  36485. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  36486. * @apioption plotOptions.series.color
  36487. */
  36488. /**
  36489. * Styled mode only. A specific color index to use for the series, so
  36490. * its graphic representations are given the class name
  36491. * `highcharts-color-{n}`.
  36492. *
  36493. * @type {number}
  36494. * @since 5.0.0
  36495. * @apioption plotOptions.series.colorIndex
  36496. */
  36497. /**
  36498. * Whether to connect a graph line across null points, or render a gap
  36499. * between the two points on either side of the null.
  36500. *
  36501. * @sample {highcharts} highcharts/plotoptions/series-connectnulls-false/
  36502. * False by default
  36503. * @sample {highcharts} highcharts/plotoptions/series-connectnulls-true/
  36504. * True
  36505. *
  36506. * @type {boolean}
  36507. * @default false
  36508. * @product highcharts highstock
  36509. * @apioption plotOptions.series.connectNulls
  36510. */
  36511. /**
  36512. * You can set the cursor to "pointer" if you have click events attached
  36513. * to the series, to signal to the user that the points and lines can
  36514. * be clicked.
  36515. *
  36516. * In styled mode, the series cursor can be set with the same classes
  36517. * as listed under [series.color](#plotOptions.series.color).
  36518. *
  36519. * @sample {highcharts} highcharts/plotoptions/series-cursor-line/
  36520. * On line graph
  36521. * @sample {highcharts} highcharts/plotoptions/series-cursor-column/
  36522. * On columns
  36523. * @sample {highcharts} highcharts/plotoptions/series-cursor-scatter/
  36524. * On scatter markers
  36525. * @sample {highstock} stock/plotoptions/cursor/
  36526. * Pointer on a line graph
  36527. * @sample {highmaps} maps/plotoptions/series-allowpointselect/
  36528. * Map area
  36529. * @sample {highmaps} maps/plotoptions/mapbubble-allowpointselect/
  36530. * Map bubble
  36531. *
  36532. * @type {string|Highcharts.CursorValue}
  36533. * @apioption plotOptions.series.cursor
  36534. */
  36535. /**
  36536. * A reserved subspace to store options and values for customized
  36537. * functionality. Here you can add additional data for your own event
  36538. * callbacks and formatter callbacks.
  36539. *
  36540. * @sample {highcharts} highcharts/point/custom/
  36541. * Point and series with custom data
  36542. *
  36543. * @type {Highcharts.Dictionary<*>}
  36544. * @apioption plotOptions.series.custom
  36545. */
  36546. /**
  36547. * Name of the dash style to use for the graph, or for some series types
  36548. * the outline of each shape.
  36549. *
  36550. * In styled mode, the
  36551. * [stroke dash-array](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/series-dashstyle/)
  36552. * can be set with the same classes as listed under
  36553. * [series.color](#plotOptions.series.color).
  36554. *
  36555. * @sample {highcharts} highcharts/plotoptions/series-dashstyle-all/
  36556. * Possible values demonstrated
  36557. * @sample {highcharts} highcharts/plotoptions/series-dashstyle/
  36558. * Chart suitable for printing in black and white
  36559. * @sample {highstock} highcharts/plotoptions/series-dashstyle-all/
  36560. * Possible values demonstrated
  36561. * @sample {highmaps} highcharts/plotoptions/series-dashstyle-all/
  36562. * Possible values demonstrated
  36563. * @sample {highmaps} maps/plotoptions/series-dashstyle/
  36564. * Dotted borders on a map
  36565. *
  36566. * @type {Highcharts.DashStyleValue}
  36567. * @default Solid
  36568. * @since 2.1
  36569. * @apioption plotOptions.series.dashStyle
  36570. */
  36571. /**
  36572. * A description of the series to add to the screen reader information
  36573. * about the series.
  36574. *
  36575. * @type {string}
  36576. * @since 5.0.0
  36577. * @requires modules/accessibility
  36578. * @apioption plotOptions.series.description
  36579. */
  36580. /**
  36581. * Options for the series data sorting.
  36582. *
  36583. * @type {Highcharts.DataSortingOptionsObject}
  36584. * @since 8.0.0
  36585. * @product highcharts highstock
  36586. * @apioption plotOptions.series.dataSorting
  36587. */
  36588. /**
  36589. * Enable or disable data sorting for the series. Use [xAxis.reversed](
  36590. * #xAxis.reversed) to change the sorting order.
  36591. *
  36592. * @sample {highcharts} highcharts/datasorting/animation/
  36593. * Data sorting in scatter-3d
  36594. * @sample {highcharts} highcharts/datasorting/labels-animation/
  36595. * Axis labels animation
  36596. * @sample {highcharts} highcharts/datasorting/dependent-sorting/
  36597. * Dependent series sorting
  36598. * @sample {highcharts} highcharts/datasorting/independent-sorting/
  36599. * Independent series sorting
  36600. *
  36601. * @type {boolean}
  36602. * @since 8.0.0
  36603. * @apioption plotOptions.series.dataSorting.enabled
  36604. */
  36605. /**
  36606. * Whether to allow matching points by name in an update. If this option
  36607. * is disabled, points will be matched by order.
  36608. *
  36609. * @sample {highcharts} highcharts/datasorting/match-by-name/
  36610. * Enabled match by name
  36611. *
  36612. * @type {boolean}
  36613. * @since 8.0.0
  36614. * @apioption plotOptions.series.dataSorting.matchByName
  36615. */
  36616. /**
  36617. * Determines what data value should be used to sort by.
  36618. *
  36619. * @sample {highcharts} highcharts/datasorting/sort-key/
  36620. * Sort key as `z` value
  36621. *
  36622. * @type {string}
  36623. * @since 8.0.0
  36624. * @default y
  36625. * @apioption plotOptions.series.dataSorting.sortKey
  36626. */
  36627. /**
  36628. * Enable or disable the mouse tracking for a specific series. This
  36629. * includes point tooltips and click events on graphs and points. For
  36630. * large datasets it improves performance.
  36631. *
  36632. * @sample {highcharts} highcharts/plotoptions/series-enablemousetracking-false/
  36633. * No mouse tracking
  36634. * @sample {highmaps} maps/plotoptions/series-enablemousetracking-false/
  36635. * No mouse tracking
  36636. *
  36637. * @type {boolean}
  36638. * @default true
  36639. * @apioption plotOptions.series.enableMouseTracking
  36640. */
  36641. /**
  36642. * Whether to use the Y extremes of the total chart width or only the
  36643. * zoomed area when zooming in on parts of the X axis. By default, the
  36644. * Y axis adjusts to the min and max of the visible data. Cartesian
  36645. * series only.
  36646. *
  36647. * @type {boolean}
  36648. * @default false
  36649. * @since 4.1.6
  36650. * @product highcharts highstock gantt
  36651. * @apioption plotOptions.series.getExtremesFromAll
  36652. */
  36653. /**
  36654. * An array specifying which option maps to which key in the data point
  36655. * array. This makes it convenient to work with unstructured data arrays
  36656. * from different sources.
  36657. *
  36658. * @see [series.data](#series.line.data)
  36659. *
  36660. * @sample {highcharts|highstock} highcharts/series/data-keys/
  36661. * An extended data array with keys
  36662. * @sample {highcharts|highstock} highcharts/series/data-nested-keys/
  36663. * Nested keys used to access object properties
  36664. *
  36665. * @type {Array<string>}
  36666. * @since 4.1.6
  36667. * @apioption plotOptions.series.keys
  36668. */
  36669. /**
  36670. * The line cap used for line ends and line joins on the graph.
  36671. *
  36672. * @type {Highcharts.SeriesLinecapValue}
  36673. * @default round
  36674. * @product highcharts highstock
  36675. * @apioption plotOptions.series.linecap
  36676. */
  36677. /**
  36678. * The [id](#series.id) of another series to link to. Additionally,
  36679. * the value can be ":previous" to link to the previous series. When
  36680. * two series are linked, only the first one appears in the legend.
  36681. * Toggling the visibility of this also toggles the linked series.
  36682. *
  36683. * If master series uses data sorting and linked series does not have
  36684. * its own sorting definition, the linked series will be sorted in the
  36685. * same order as the master one.
  36686. *
  36687. * @sample {highcharts|highstock} highcharts/demo/arearange-line/
  36688. * Linked series
  36689. *
  36690. * @type {string}
  36691. * @since 3.0
  36692. * @product highcharts highstock gantt
  36693. * @apioption plotOptions.series.linkedTo
  36694. */
  36695. /**
  36696. * Options for the corresponding navigator series if `showInNavigator`
  36697. * is `true` for this series. Available options are the same as any
  36698. * series, documented at [plotOptions](#plotOptions.series) and
  36699. * [series](#series).
  36700. *
  36701. * These options are merged with options in [navigator.series](
  36702. * #navigator.series), and will take precedence if the same option is
  36703. * defined both places.
  36704. *
  36705. * @see [navigator.series](#navigator.series)
  36706. *
  36707. * @type {Highcharts.PlotSeriesOptions}
  36708. * @since 5.0.0
  36709. * @product highstock
  36710. * @apioption plotOptions.series.navigatorOptions
  36711. */
  36712. /**
  36713. * The color for the parts of the graph or points that are below the
  36714. * [threshold](#plotOptions.series.threshold). Note that `zones` takes
  36715. * precedence over the negative color. Using `negativeColor` is
  36716. * equivalent to applying a zone with value of 0.
  36717. *
  36718. * @see In styled mode, a negative color is applied by setting this option
  36719. * to `true` combined with the `.highcharts-negative` class name.
  36720. *
  36721. * @sample {highcharts} highcharts/plotoptions/series-negative-color/
  36722. * Spline, area and column
  36723. * @sample {highcharts} highcharts/plotoptions/arearange-negativecolor/
  36724. * Arearange
  36725. * @sample {highcharts} highcharts/css/series-negative-color/
  36726. * Styled mode
  36727. * @sample {highstock} highcharts/plotoptions/series-negative-color/
  36728. * Spline, area and column
  36729. * @sample {highstock} highcharts/plotoptions/arearange-negativecolor/
  36730. * Arearange
  36731. * @sample {highmaps} highcharts/plotoptions/series-negative-color/
  36732. * Spline, area and column
  36733. * @sample {highmaps} highcharts/plotoptions/arearange-negativecolor/
  36734. * Arearange
  36735. *
  36736. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  36737. * @since 3.0
  36738. * @apioption plotOptions.series.negativeColor
  36739. */
  36740. /**
  36741. * Same as
  36742. * [accessibility.series.descriptionFormatter](#accessibility.series.descriptionFormatter),
  36743. * but for an individual series. Overrides the chart wide configuration.
  36744. *
  36745. * @type {Function}
  36746. * @since 5.0.12
  36747. * @apioption plotOptions.series.pointDescriptionFormatter
  36748. */
  36749. /**
  36750. * If no x values are given for the points in a series, `pointInterval`
  36751. * defines the interval of the x values. For example, if a series
  36752. * contains one value every decade starting from year 0, set
  36753. * `pointInterval` to `10`. In true `datetime` axes, the `pointInterval`
  36754. * is set in milliseconds.
  36755. *
  36756. * It can be also be combined with `pointIntervalUnit` to draw irregular
  36757. * time intervals.
  36758. *
  36759. * Please note that this options applies to the _series data_, not the
  36760. * interval of the axis ticks, which is independent.
  36761. *
  36762. * @sample {highcharts} highcharts/plotoptions/series-pointstart-datetime/
  36763. * Datetime X axis
  36764. * @sample {highstock} stock/plotoptions/pointinterval-pointstart/
  36765. * Using pointStart and pointInterval
  36766. *
  36767. * @type {number}
  36768. * @default 1
  36769. * @product highcharts highstock gantt
  36770. * @apioption plotOptions.series.pointInterval
  36771. */
  36772. /**
  36773. * On datetime series, this allows for setting the
  36774. * [pointInterval](#plotOptions.series.pointInterval) to irregular time
  36775. * units, `day`, `month` and `year`. A day is usually the same as 24
  36776. * hours, but `pointIntervalUnit` also takes the DST crossover into
  36777. * consideration when dealing with local time. Combine this option with
  36778. * `pointInterval` to draw weeks, quarters, 6 months, 10 years etc.
  36779. *
  36780. * Please note that this options applies to the _series data_, not the
  36781. * interval of the axis ticks, which is independent.
  36782. *
  36783. * @sample {highcharts} highcharts/plotoptions/series-pointintervalunit/
  36784. * One point a month
  36785. * @sample {highstock} highcharts/plotoptions/series-pointintervalunit/
  36786. * One point a month
  36787. *
  36788. * @type {string}
  36789. * @since 4.1.0
  36790. * @product highcharts highstock gantt
  36791. * @validvalue ["day", "month", "year"]
  36792. * @apioption plotOptions.series.pointIntervalUnit
  36793. */
  36794. /**
  36795. * Possible values: `"on"`, `"between"`, `number`.
  36796. *
  36797. * In a column chart, when pointPlacement is `"on"`, the point will not
  36798. * create any padding of the X axis. In a polar column chart this means
  36799. * that the first column points directly north. If the pointPlacement is
  36800. * `"between"`, the columns will be laid out between ticks. This is
  36801. * useful for example for visualising an amount between two points in
  36802. * time or in a certain sector of a polar chart.
  36803. *
  36804. * Since Highcharts 3.0.2, the point placement can also be numeric,
  36805. * where 0 is on the axis value, -0.5 is between this value and the
  36806. * previous, and 0.5 is between this value and the next. Unlike the
  36807. * textual options, numeric point placement options won't affect axis
  36808. * padding.
  36809. *
  36810. * Note that pointPlacement needs a [pointRange](
  36811. * #plotOptions.series.pointRange) to work. For column series this is
  36812. * computed, but for line-type series it needs to be set.
  36813. *
  36814. * For the `xrange` series type and gantt charts, if the Y axis is a
  36815. * category axis, the `pointPlacement` applies to the Y axis rather than
  36816. * the (typically datetime) X axis.
  36817. *
  36818. * Defaults to `undefined` in cartesian charts, `"between"` in polar
  36819. * charts.
  36820. *
  36821. * @see [xAxis.tickmarkPlacement](#xAxis.tickmarkPlacement)
  36822. *
  36823. * @sample {highcharts|highstock} highcharts/plotoptions/series-pointplacement-between/
  36824. * Between in a column chart
  36825. * @sample {highcharts|highstock} highcharts/plotoptions/series-pointplacement-numeric/
  36826. * Numeric placement for custom layout
  36827. * @sample {highcharts|highstock} maps/plotoptions/heatmap-pointplacement/
  36828. * Placement in heatmap
  36829. *
  36830. * @type {string|number}
  36831. * @since 2.3.0
  36832. * @product highcharts highstock gantt
  36833. * @apioption plotOptions.series.pointPlacement
  36834. */
  36835. /**
  36836. * If no x values are given for the points in a series, pointStart
  36837. * defines on what value to start. For example, if a series contains one
  36838. * yearly value starting from 1945, set pointStart to 1945.
  36839. *
  36840. * @sample {highcharts} highcharts/plotoptions/series-pointstart-linear/
  36841. * Linear
  36842. * @sample {highcharts} highcharts/plotoptions/series-pointstart-datetime/
  36843. * Datetime
  36844. * @sample {highstock} stock/plotoptions/pointinterval-pointstart/
  36845. * Using pointStart and pointInterval
  36846. *
  36847. * @type {number}
  36848. * @default 0
  36849. * @product highcharts highstock gantt
  36850. * @apioption plotOptions.series.pointStart
  36851. */
  36852. /**
  36853. * Whether to select the series initially. If `showCheckbox` is true,
  36854. * the checkbox next to the series name in the legend will be checked
  36855. * for a selected series.
  36856. *
  36857. * @sample {highcharts} highcharts/plotoptions/series-selected/
  36858. * One out of two series selected
  36859. *
  36860. * @type {boolean}
  36861. * @default false
  36862. * @since 1.2.0
  36863. * @apioption plotOptions.series.selected
  36864. */
  36865. /**
  36866. * Whether to apply a drop shadow to the graph line. Since 2.3 the
  36867. * shadow can be an object configuration containing `color`, `offsetX`,
  36868. * `offsetY`, `opacity` and `width`.
  36869. *
  36870. * @sample {highcharts} highcharts/plotoptions/series-shadow/
  36871. * Shadow enabled
  36872. *
  36873. * @type {boolean|Highcharts.ShadowOptionsObject}
  36874. * @default false
  36875. * @apioption plotOptions.series.shadow
  36876. */
  36877. /**
  36878. * Whether to display this particular series or series type in the
  36879. * legend. Standalone series are shown in legend by default, and linked
  36880. * series are not. Since v7.2.0 it is possible to show series that use
  36881. * colorAxis by setting this option to `true`.
  36882. *
  36883. * @sample {highcharts} highcharts/plotoptions/series-showinlegend/
  36884. * One series in the legend, one hidden
  36885. *
  36886. * @type {boolean}
  36887. * @apioption plotOptions.series.showInLegend
  36888. */
  36889. /**
  36890. * Whether or not to show the series in the navigator. Takes precedence
  36891. * over [navigator.baseSeries](#navigator.baseSeries) if defined.
  36892. *
  36893. * @type {boolean}
  36894. * @since 5.0.0
  36895. * @product highstock
  36896. * @apioption plotOptions.series.showInNavigator
  36897. */
  36898. /**
  36899. * If set to `true`, the accessibility module will skip past the points
  36900. * in this series for keyboard navigation.
  36901. *
  36902. * @type {boolean}
  36903. * @since 5.0.12
  36904. * @apioption plotOptions.series.skipKeyboardNavigation
  36905. */
  36906. /**
  36907. * Whether to stack the values of each series on top of each other.
  36908. * Possible values are `undefined` to disable, `"normal"` to stack by
  36909. * value or `"percent"`.
  36910. *
  36911. * When stacking is enabled, data must be sorted
  36912. * in ascending X order.
  36913. *
  36914. * Some stacking options are related to specific series types. In the
  36915. * streamgraph series type, the stacking option is set to `"stream"`.
  36916. * The second one is `"overlap"`, which only applies to waterfall
  36917. * series.
  36918. *
  36919. * @see [yAxis.reversedStacks](#yAxis.reversedStacks)
  36920. *
  36921. * @sample {highcharts} highcharts/plotoptions/series-stacking-line/
  36922. * Line
  36923. * @sample {highcharts} highcharts/plotoptions/series-stacking-column/
  36924. * Column
  36925. * @sample {highcharts} highcharts/plotoptions/series-stacking-bar/
  36926. * Bar
  36927. * @sample {highcharts} highcharts/plotoptions/series-stacking-area/
  36928. * Area
  36929. * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-line/
  36930. * Line
  36931. * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-column/
  36932. * Column
  36933. * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-bar/
  36934. * Bar
  36935. * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-area/
  36936. * Area
  36937. * @sample {highcharts} highcharts/plotoptions/series-waterfall-with-normal-stacking
  36938. * Waterfall with normal stacking
  36939. * @sample {highcharts} highcharts/plotoptions/series-waterfall-with-overlap-stacking
  36940. * Waterfall with overlap stacking
  36941. * @sample {highstock} stock/plotoptions/stacking/
  36942. * Area
  36943. *
  36944. * @type {string}
  36945. * @product highcharts highstock
  36946. * @validvalue ["normal", "overlap", "percent", "stream"]
  36947. * @apioption plotOptions.series.stacking
  36948. */
  36949. /**
  36950. * Whether to apply steps to the line. Possible values are `left`,
  36951. * `center` and `right`.
  36952. *
  36953. * @sample {highcharts} highcharts/plotoptions/line-step/
  36954. * Different step line options
  36955. * @sample {highcharts} highcharts/plotoptions/area-step/
  36956. * Stepped, stacked area
  36957. * @sample {highstock} stock/plotoptions/line-step/
  36958. * Step line
  36959. *
  36960. * @type {string}
  36961. * @since 1.2.5
  36962. * @product highcharts highstock
  36963. * @validvalue ["left", "center", "right"]
  36964. * @apioption plotOptions.series.step
  36965. */
  36966. /**
  36967. * The threshold, also called zero level or base level. For line type
  36968. * series this is only used in conjunction with
  36969. * [negativeColor](#plotOptions.series.negativeColor).
  36970. *
  36971. * @see [softThreshold](#plotOptions.series.softThreshold).
  36972. *
  36973. * @type {number|null}
  36974. * @default 0
  36975. * @since 3.0
  36976. * @product highcharts highstock
  36977. * @apioption plotOptions.series.threshold
  36978. */
  36979. /**
  36980. * Set the initial visibility of the series.
  36981. *
  36982. * @sample {highcharts} highcharts/plotoptions/series-visible/
  36983. * Two series, one hidden and one visible
  36984. * @sample {highstock} stock/plotoptions/series-visibility/
  36985. * Hidden series
  36986. *
  36987. * @type {boolean}
  36988. * @default true
  36989. * @apioption plotOptions.series.visible
  36990. */
  36991. /**
  36992. * Defines the Axis on which the zones are applied.
  36993. *
  36994. * @see [zones](#plotOptions.series.zones)
  36995. *
  36996. * @sample {highcharts} highcharts/series/color-zones-zoneaxis-x/
  36997. * Zones on the X-Axis
  36998. * @sample {highstock} highcharts/series/color-zones-zoneaxis-x/
  36999. * Zones on the X-Axis
  37000. *
  37001. * @type {string}
  37002. * @default y
  37003. * @since 4.1.0
  37004. * @product highcharts highstock
  37005. * @apioption plotOptions.series.zoneAxis
  37006. */
  37007. /**
  37008. * General event handlers for the series items. These event hooks can
  37009. * also be attached to the series at run time using the
  37010. * `Highcharts.addEvent` function.
  37011. *
  37012. * @declare Highcharts.SeriesEventsOptionsObject
  37013. *
  37014. * @private
  37015. */
  37016. events: {},
  37017. /**
  37018. * Fires after the series has finished its initial animation, or in case
  37019. * animation is disabled, immediately as the series is displayed.
  37020. *
  37021. * @sample {highcharts} highcharts/plotoptions/series-events-afteranimate/
  37022. * Show label after animate
  37023. * @sample {highstock} highcharts/plotoptions/series-events-afteranimate/
  37024. * Show label after animate
  37025. *
  37026. * @type {Highcharts.SeriesAfterAnimateCallbackFunction}
  37027. * @since 4.0
  37028. * @product highcharts highstock gantt
  37029. * @context Highcharts.Series
  37030. * @apioption plotOptions.series.events.afterAnimate
  37031. */
  37032. /**
  37033. * Fires when the checkbox next to the series' name in the legend is
  37034. * clicked. One parameter, `event`, is passed to the function. The state
  37035. * of the checkbox is found by `event.checked`. The checked item is
  37036. * found by `event.item`. Return `false` to prevent the default action
  37037. * which is to toggle the select state of the series.
  37038. *
  37039. * @sample {highcharts} highcharts/plotoptions/series-events-checkboxclick/
  37040. * Alert checkbox status
  37041. *
  37042. * @type {Highcharts.SeriesCheckboxClickCallbackFunction}
  37043. * @since 1.2.0
  37044. * @context Highcharts.Series
  37045. * @apioption plotOptions.series.events.checkboxClick
  37046. */
  37047. /**
  37048. * Fires when the series is clicked. One parameter, `event`, is passed
  37049. * to the function, containing common event information. Additionally,
  37050. * `event.point` holds a pointer to the nearest point on the graph.
  37051. *
  37052. * @sample {highcharts} highcharts/plotoptions/series-events-click/
  37053. * Alert click info
  37054. * @sample {highstock} stock/plotoptions/series-events-click/
  37055. * Alert click info
  37056. * @sample {highmaps} maps/plotoptions/series-events-click/
  37057. * Display click info in subtitle
  37058. *
  37059. * @type {Highcharts.SeriesClickCallbackFunction}
  37060. * @context Highcharts.Series
  37061. * @apioption plotOptions.series.events.click
  37062. */
  37063. /**
  37064. * Fires when the series is hidden after chart generation time, either
  37065. * by clicking the legend item or by calling `.hide()`.
  37066. *
  37067. * @sample {highcharts} highcharts/plotoptions/series-events-hide/
  37068. * Alert when the series is hidden by clicking the legend item
  37069. *
  37070. * @type {Highcharts.SeriesHideCallbackFunction}
  37071. * @since 1.2.0
  37072. * @context Highcharts.Series
  37073. * @apioption plotOptions.series.events.hide
  37074. */
  37075. /**
  37076. * Fires when the legend item belonging to the series is clicked. One
  37077. * parameter, `event`, is passed to the function. The default action
  37078. * is to toggle the visibility of the series. This can be prevented
  37079. * by returning `false` or calling `event.preventDefault()`.
  37080. *
  37081. * @sample {highcharts} highcharts/plotoptions/series-events-legenditemclick/
  37082. * Confirm hiding and showing
  37083. *
  37084. * @type {Highcharts.SeriesLegendItemClickCallbackFunction}
  37085. * @context Highcharts.Series
  37086. * @apioption plotOptions.series.events.legendItemClick
  37087. */
  37088. /**
  37089. * Fires when the mouse leaves the graph. One parameter, `event`, is
  37090. * passed to the function, containing common event information. If the
  37091. * [stickyTracking](#plotOptions.series) option is true, `mouseOut`
  37092. * doesn't happen before the mouse enters another graph or leaves the
  37093. * plot area.
  37094. *
  37095. * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-sticky/
  37096. * With sticky tracking by default
  37097. * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-no-sticky/
  37098. * Without sticky tracking
  37099. *
  37100. * @type {Highcharts.SeriesMouseOutCallbackFunction}
  37101. * @context Highcharts.Series
  37102. * @apioption plotOptions.series.events.mouseOut
  37103. */
  37104. /**
  37105. * Fires when the mouse enters the graph. One parameter, `event`, is
  37106. * passed to the function, containing common event information.
  37107. *
  37108. * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-sticky/
  37109. * With sticky tracking by default
  37110. * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-no-sticky/
  37111. * Without sticky tracking
  37112. *
  37113. * @type {Highcharts.SeriesMouseOverCallbackFunction}
  37114. * @context Highcharts.Series
  37115. * @apioption plotOptions.series.events.mouseOver
  37116. */
  37117. /**
  37118. * Fires when the series is shown after chart generation time, either
  37119. * by clicking the legend item or by calling `.show()`.
  37120. *
  37121. * @sample {highcharts} highcharts/plotoptions/series-events-show/
  37122. * Alert when the series is shown by clicking the legend item.
  37123. *
  37124. * @type {Highcharts.SeriesShowCallbackFunction}
  37125. * @since 1.2.0
  37126. * @context Highcharts.Series
  37127. * @apioption plotOptions.series.events.show
  37128. */
  37129. /**
  37130. * Options for the point markers of line-like series. Properties like
  37131. * `fillColor`, `lineColor` and `lineWidth` define the visual appearance
  37132. * of the markers. Other series types, like column series, don't have
  37133. * markers, but have visual options on the series level instead.
  37134. *
  37135. * In styled mode, the markers can be styled with the
  37136. * `.highcharts-point`, `.highcharts-point-hover` and
  37137. * `.highcharts-point-select` class names.
  37138. *
  37139. * @declare Highcharts.PointMarkerOptionsObject
  37140. *
  37141. * @private
  37142. */
  37143. marker: {
  37144. /**
  37145. * Enable or disable the point marker. If `undefined`, the markers
  37146. * are hidden when the data is dense, and shown for more widespread
  37147. * data points.
  37148. *
  37149. * @sample {highcharts} highcharts/plotoptions/series-marker-enabled/
  37150. * Disabled markers
  37151. * @sample {highcharts} highcharts/plotoptions/series-marker-enabled-false/
  37152. * Disabled in normal state but enabled on hover
  37153. * @sample {highstock} stock/plotoptions/series-marker/
  37154. * Enabled markers
  37155. *
  37156. * @type {boolean}
  37157. * @default {highcharts} undefined
  37158. * @default {highstock} false
  37159. * @apioption plotOptions.series.marker.enabled
  37160. */
  37161. /**
  37162. * The threshold for how dense the point markers should be before
  37163. * they are hidden, given that `enabled` is not defined. The number
  37164. * indicates the horizontal distance between the two closest points
  37165. * in the series, as multiples of the `marker.radius`. In other
  37166. * words, the default value of 2 means points are hidden if
  37167. * overlapping horizontally.
  37168. *
  37169. * @sample highcharts/plotoptions/series-marker-enabledthreshold
  37170. * A higher threshold
  37171. *
  37172. * @since 6.0.5
  37173. */
  37174. enabledThreshold: 2,
  37175. /**
  37176. * The fill color of the point marker. When `undefined`, the series'
  37177. * or point's color is used.
  37178. *
  37179. * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/
  37180. * White fill
  37181. *
  37182. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  37183. * @apioption plotOptions.series.marker.fillColor
  37184. */
  37185. /**
  37186. * Image markers only. Set the image width explicitly. When using
  37187. * this option, a `width` must also be set.
  37188. *
  37189. * @sample {highcharts} highcharts/plotoptions/series-marker-width-height/
  37190. * Fixed width and height
  37191. * @sample {highstock} highcharts/plotoptions/series-marker-width-height/
  37192. * Fixed width and height
  37193. *
  37194. * @type {number}
  37195. * @since 4.0.4
  37196. * @apioption plotOptions.series.marker.height
  37197. */
  37198. /**
  37199. * The color of the point marker's outline. When `undefined`, the
  37200. * series' or point's color is used.
  37201. *
  37202. * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/
  37203. * Inherit from series color (undefined)
  37204. *
  37205. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  37206. */
  37207. lineColor: palette.backgroundColor,
  37208. /**
  37209. * The width of the point marker's outline.
  37210. *
  37211. * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/
  37212. * 2px blue marker
  37213. */
  37214. lineWidth: 0,
  37215. /**
  37216. * The radius of the point marker.
  37217. *
  37218. * @sample {highcharts} highcharts/plotoptions/series-marker-radius/
  37219. * Bigger markers
  37220. *
  37221. * @default {highstock} 2
  37222. * @default {highcharts} 4
  37223. *
  37224. */
  37225. radius: 4,
  37226. /**
  37227. * A predefined shape or symbol for the marker. When undefined, the
  37228. * symbol is pulled from options.symbols. Other possible values are
  37229. * `'circle'`, `'square'`,`'diamond'`, `'triangle'` and
  37230. * `'triangle-down'`.
  37231. *
  37232. * Additionally, the URL to a graphic can be given on this form:
  37233. * `'url(graphic.png)'`. Note that for the image to be applied to
  37234. * exported charts, its URL needs to be accessible by the export
  37235. * server.
  37236. *
  37237. * Custom callbacks for symbol path generation can also be added to
  37238. * `Highcharts.SVGRenderer.prototype.symbols`. The callback is then
  37239. * used by its method name, as shown in the demo.
  37240. *
  37241. * @sample {highcharts} highcharts/plotoptions/series-marker-symbol/
  37242. * Predefined, graphic and custom markers
  37243. * @sample {highstock} highcharts/plotoptions/series-marker-symbol/
  37244. * Predefined, graphic and custom markers
  37245. *
  37246. * @type {string}
  37247. * @apioption plotOptions.series.marker.symbol
  37248. */
  37249. /**
  37250. * Image markers only. Set the image width explicitly. When using
  37251. * this option, a `height` must also be set.
  37252. *
  37253. * @sample {highcharts} highcharts/plotoptions/series-marker-width-height/
  37254. * Fixed width and height
  37255. * @sample {highstock} highcharts/plotoptions/series-marker-width-height/
  37256. * Fixed width and height
  37257. *
  37258. * @type {number}
  37259. * @since 4.0.4
  37260. * @apioption plotOptions.series.marker.width
  37261. */
  37262. /**
  37263. * States for a single point marker.
  37264. *
  37265. * @declare Highcharts.PointStatesOptionsObject
  37266. */
  37267. states: {
  37268. /**
  37269. * The normal state of a single point marker. Currently only
  37270. * used for setting animation when returning to normal state
  37271. * from hover.
  37272. *
  37273. * @declare Highcharts.PointStatesNormalOptionsObject
  37274. */
  37275. normal: {
  37276. /**
  37277. * Animation when returning to normal state after hovering.
  37278. *
  37279. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  37280. */
  37281. animation: true
  37282. },
  37283. /**
  37284. * The hover state for a single point marker.
  37285. *
  37286. * @declare Highcharts.PointStatesHoverOptionsObject
  37287. */
  37288. hover: {
  37289. /**
  37290. * Animation when hovering over the marker.
  37291. *
  37292. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  37293. */
  37294. animation: {
  37295. /** @internal */
  37296. duration: 50
  37297. },
  37298. /**
  37299. * Enable or disable the point marker.
  37300. *
  37301. * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-enabled/
  37302. * Disabled hover state
  37303. */
  37304. enabled: true,
  37305. /**
  37306. * The fill color of the marker in hover state. When
  37307. * `undefined`, the series' or point's fillColor for normal
  37308. * state is used.
  37309. *
  37310. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  37311. * @apioption plotOptions.series.marker.states.hover.fillColor
  37312. */
  37313. /**
  37314. * The color of the point marker's outline. When
  37315. * `undefined`, the series' or point's lineColor for normal
  37316. * state is used.
  37317. *
  37318. * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-linecolor/
  37319. * White fill color, black line color
  37320. *
  37321. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  37322. * @apioption plotOptions.series.marker.states.hover.lineColor
  37323. */
  37324. /**
  37325. * The width of the point marker's outline. When
  37326. * `undefined`, the series' or point's lineWidth for normal
  37327. * state is used.
  37328. *
  37329. * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-linewidth/
  37330. * 3px line width
  37331. *
  37332. * @type {number}
  37333. * @apioption plotOptions.series.marker.states.hover.lineWidth
  37334. */
  37335. /**
  37336. * The radius of the point marker. In hover state, it
  37337. * defaults to the normal state's radius + 2 as per the
  37338. * [radiusPlus](#plotOptions.series.marker.states.hover.radiusPlus)
  37339. * option.
  37340. *
  37341. * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-radius/
  37342. * 10px radius
  37343. *
  37344. * @type {number}
  37345. * @apioption plotOptions.series.marker.states.hover.radius
  37346. */
  37347. /**
  37348. * The number of pixels to increase the radius of the
  37349. * hovered point.
  37350. *
  37351. * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/
  37352. * 5 pixels greater radius on hover
  37353. * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/
  37354. * 5 pixels greater radius on hover
  37355. *
  37356. * @since 4.0.3
  37357. */
  37358. radiusPlus: 2,
  37359. /**
  37360. * The additional line width for a hovered point.
  37361. *
  37362. * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/
  37363. * 2 pixels wider on hover
  37364. * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/
  37365. * 2 pixels wider on hover
  37366. *
  37367. * @since 4.0.3
  37368. */
  37369. lineWidthPlus: 1
  37370. },
  37371. /**
  37372. * The appearance of the point marker when selected. In order to
  37373. * allow a point to be selected, set the
  37374. * `series.allowPointSelect` option to true.
  37375. *
  37376. * @declare Highcharts.PointStatesSelectOptionsObject
  37377. */
  37378. select: {
  37379. /**
  37380. * Enable or disable visible feedback for selection.
  37381. *
  37382. * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-enabled/
  37383. * Disabled select state
  37384. *
  37385. * @type {boolean}
  37386. * @default true
  37387. * @apioption plotOptions.series.marker.states.select.enabled
  37388. */
  37389. /**
  37390. * The radius of the point marker. In hover state, it
  37391. * defaults to the normal state's radius + 2.
  37392. *
  37393. * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-radius/
  37394. * 10px radius for selected points
  37395. *
  37396. * @type {number}
  37397. * @apioption plotOptions.series.marker.states.select.radius
  37398. */
  37399. /**
  37400. * The fill color of the point marker.
  37401. *
  37402. * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-fillcolor/
  37403. * Solid red discs for selected points
  37404. *
  37405. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  37406. */
  37407. fillColor: palette.neutralColor20,
  37408. /**
  37409. * The color of the point marker's outline. When
  37410. * `undefined`, the series' or point's color is used.
  37411. *
  37412. * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-linecolor/
  37413. * Red line color for selected points
  37414. *
  37415. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  37416. */
  37417. lineColor: palette.neutralColor100,
  37418. /**
  37419. * The width of the point marker's outline.
  37420. *
  37421. * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-linewidth/
  37422. * 3px line width for selected points
  37423. */
  37424. lineWidth: 2
  37425. }
  37426. }
  37427. },
  37428. /**
  37429. * Properties for each single point.
  37430. *
  37431. * @declare Highcharts.PlotSeriesPointOptions
  37432. *
  37433. * @private
  37434. */
  37435. point: {
  37436. /**
  37437. * Fires when a point is clicked. One parameter, `event`, is passed
  37438. * to the function, containing common event information.
  37439. *
  37440. * If the `series.allowPointSelect` option is true, the default
  37441. * action for the point's click event is to toggle the point's
  37442. * select state. Returning `false` cancels this action.
  37443. *
  37444. * @sample {highcharts} highcharts/plotoptions/series-point-events-click/
  37445. * Click marker to alert values
  37446. * @sample {highcharts} highcharts/plotoptions/series-point-events-click-column/
  37447. * Click column
  37448. * @sample {highcharts} highcharts/plotoptions/series-point-events-click-url/
  37449. * Go to URL
  37450. * @sample {highmaps} maps/plotoptions/series-point-events-click/
  37451. * Click marker to display values
  37452. * @sample {highmaps} maps/plotoptions/series-point-events-click-url/
  37453. * Go to URL
  37454. *
  37455. * @type {Highcharts.PointClickCallbackFunction}
  37456. * @context Highcharts.Point
  37457. * @apioption plotOptions.series.point.events.click
  37458. */
  37459. /**
  37460. * Fires when the mouse leaves the area close to the point. One
  37461. * parameter, `event`, is passed to the function, containing common
  37462. * event information.
  37463. *
  37464. * @sample {highcharts} highcharts/plotoptions/series-point-events-mouseover/
  37465. * Show values in the chart's corner on mouse over
  37466. *
  37467. * @type {Highcharts.PointMouseOutCallbackFunction}
  37468. * @context Highcharts.Point
  37469. * @apioption plotOptions.series.point.events.mouseOut
  37470. */
  37471. /**
  37472. * Fires when the mouse enters the area close to the point. One
  37473. * parameter, `event`, is passed to the function, containing common
  37474. * event information.
  37475. *
  37476. * @sample {highcharts} highcharts/plotoptions/series-point-events-mouseover/
  37477. * Show values in the chart's corner on mouse over
  37478. *
  37479. * @type {Highcharts.PointMouseOverCallbackFunction}
  37480. * @context Highcharts.Point
  37481. * @apioption plotOptions.series.point.events.mouseOver
  37482. */
  37483. /**
  37484. * Fires when the point is removed using the `.remove()` method. One
  37485. * parameter, `event`, is passed to the function. Returning `false`
  37486. * cancels the operation.
  37487. *
  37488. * @sample {highcharts} highcharts/plotoptions/series-point-events-remove/
  37489. * Remove point and confirm
  37490. *
  37491. * @type {Highcharts.PointRemoveCallbackFunction}
  37492. * @since 1.2.0
  37493. * @context Highcharts.Point
  37494. * @apioption plotOptions.series.point.events.remove
  37495. */
  37496. /**
  37497. * Fires when the point is selected either programmatically or
  37498. * following a click on the point. One parameter, `event`, is passed
  37499. * to the function. Returning `false` cancels the operation.
  37500. *
  37501. * @sample {highcharts} highcharts/plotoptions/series-point-events-select/
  37502. * Report the last selected point
  37503. * @sample {highmaps} maps/plotoptions/series-allowpointselect/
  37504. * Report select and unselect
  37505. *
  37506. * @type {Highcharts.PointSelectCallbackFunction}
  37507. * @since 1.2.0
  37508. * @context Highcharts.Point
  37509. * @apioption plotOptions.series.point.events.select
  37510. */
  37511. /**
  37512. * Fires when the point is unselected either programmatically or
  37513. * following a click on the point. One parameter, `event`, is passed
  37514. * to the function.
  37515. * Returning `false` cancels the operation.
  37516. *
  37517. * @sample {highcharts} highcharts/plotoptions/series-point-events-unselect/
  37518. * Report the last unselected point
  37519. * @sample {highmaps} maps/plotoptions/series-allowpointselect/
  37520. * Report select and unselect
  37521. *
  37522. * @type {Highcharts.PointUnselectCallbackFunction}
  37523. * @since 1.2.0
  37524. * @context Highcharts.Point
  37525. * @apioption plotOptions.series.point.events.unselect
  37526. */
  37527. /**
  37528. * Fires when the point is updated programmatically through the
  37529. * `.update()` method. One parameter, `event`, is passed to the
  37530. * function. The new point options can be accessed through
  37531. * `event.options`. Returning `false` cancels the operation.
  37532. *
  37533. * @sample {highcharts} highcharts/plotoptions/series-point-events-update/
  37534. * Confirm point updating
  37535. *
  37536. * @type {Highcharts.PointUpdateCallbackFunction}
  37537. * @since 1.2.0
  37538. * @context Highcharts.Point
  37539. * @apioption plotOptions.series.point.events.update
  37540. */
  37541. /**
  37542. * Events for each single point.
  37543. *
  37544. * @declare Highcharts.PointEventsOptionsObject
  37545. */
  37546. events: {}
  37547. },
  37548. /**
  37549. * Options for the series data labels, appearing next to each data
  37550. * point.
  37551. *
  37552. * Since v6.2.0, multiple data labels can be applied to each single
  37553. * point by defining them as an array of configs.
  37554. *
  37555. * In styled mode, the data labels can be styled with the
  37556. * `.highcharts-data-label-box` and `.highcharts-data-label` class names
  37557. * ([see example](https://www.highcharts.com/samples/highcharts/css/series-datalabels)).
  37558. *
  37559. * @sample {highcharts} highcharts/plotoptions/series-datalabels-enabled
  37560. * Data labels enabled
  37561. * @sample {highcharts} highcharts/plotoptions/series-datalabels-multiple
  37562. * Multiple data labels on a bar series
  37563. * @sample {highcharts} highcharts/css/series-datalabels
  37564. * Style mode example
  37565. *
  37566. * @type {*|Array<*>}
  37567. * @product highcharts highstock highmaps gantt
  37568. *
  37569. * @private
  37570. */
  37571. dataLabels: {
  37572. /**
  37573. * Enable or disable the initial animation when a series is
  37574. * displayed for the `dataLabels`. The animation can also be set as
  37575. * a configuration object. Please note that this option only
  37576. * applies to the initial animation.
  37577. * For other animations, see [chart.animation](#chart.animation)
  37578. * and the animation parameter under the API methods.
  37579. * The following properties are supported:
  37580. *
  37581. * - `defer`: The animation delay time in milliseconds.
  37582. *
  37583. * @sample {highcharts} highcharts/plotoptions/animation-defer/
  37584. * Animation defer settings
  37585. *
  37586. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  37587. * @since 8.2.0
  37588. * @apioption plotOptions.series.dataLabels.animation
  37589. */
  37590. animation: {},
  37591. /**
  37592. * The animation delay time in milliseconds.
  37593. * Set to `0` renders dataLabel immediately.
  37594. * As `undefined` inherits defer time from the [series.animation.defer](#plotOptions.series.animation.defer).
  37595. *
  37596. * @type {number}
  37597. * @since 8.2.0
  37598. * @apioption plotOptions.series.dataLabels.animation.defer
  37599. */
  37600. /**
  37601. * The alignment of the data label compared to the point. If
  37602. * `right`, the right side of the label should be touching the
  37603. * point. For points with an extent, like columns, the alignments
  37604. * also dictates how to align it inside the box, as given with the
  37605. * [inside](#plotOptions.column.dataLabels.inside)
  37606. * option. Can be one of `left`, `center` or `right`.
  37607. *
  37608. * @sample {highcharts} highcharts/plotoptions/series-datalabels-align-left/
  37609. * Left aligned
  37610. * @sample {highcharts} highcharts/plotoptions/bar-datalabels-align-inside-bar/
  37611. * Data labels inside the bar
  37612. *
  37613. * @type {Highcharts.AlignValue|null}
  37614. */
  37615. align: 'center',
  37616. /**
  37617. * Whether to allow data labels to overlap. To make the labels less
  37618. * sensitive for overlapping, the
  37619. * [dataLabels.padding](#plotOptions.series.dataLabels.padding)
  37620. * can be set to 0.
  37621. *
  37622. * @sample {highcharts} highcharts/plotoptions/series-datalabels-allowoverlap-false/
  37623. * Don't allow overlap
  37624. *
  37625. * @type {boolean}
  37626. * @default false
  37627. * @since 4.1.0
  37628. * @apioption plotOptions.series.dataLabels.allowOverlap
  37629. */
  37630. /**
  37631. * The background color or gradient for the data label.
  37632. *
  37633. * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
  37634. * Data labels box options
  37635. * @sample {highmaps} maps/plotoptions/series-datalabels-box/
  37636. * Data labels box options
  37637. *
  37638. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  37639. * @since 2.2.1
  37640. * @apioption plotOptions.series.dataLabels.backgroundColor
  37641. */
  37642. /**
  37643. * The border color for the data label. Defaults to `undefined`.
  37644. *
  37645. * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
  37646. * Data labels box options
  37647. *
  37648. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  37649. * @since 2.2.1
  37650. * @apioption plotOptions.series.dataLabels.borderColor
  37651. */
  37652. /**
  37653. * The border radius in pixels for the data label.
  37654. *
  37655. * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
  37656. * Data labels box options
  37657. * @sample {highmaps} maps/plotoptions/series-datalabels-box/
  37658. * Data labels box options
  37659. *
  37660. * @type {number}
  37661. * @default 0
  37662. * @since 2.2.1
  37663. * @apioption plotOptions.series.dataLabels.borderRadius
  37664. */
  37665. /**
  37666. * The border width in pixels for the data label.
  37667. *
  37668. * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
  37669. * Data labels box options
  37670. *
  37671. * @type {number}
  37672. * @default 0
  37673. * @since 2.2.1
  37674. * @apioption plotOptions.series.dataLabels.borderWidth
  37675. */
  37676. /**
  37677. * A class name for the data label. Particularly in styled mode,
  37678. * this can be used to give each series' or point's data label
  37679. * unique styling. In addition to this option, a default color class
  37680. * name is added so that we can give the labels a contrast text
  37681. * shadow.
  37682. *
  37683. * @sample {highcharts} highcharts/css/data-label-contrast/
  37684. * Contrast text shadow
  37685. * @sample {highcharts} highcharts/css/series-datalabels/
  37686. * Styling by CSS
  37687. *
  37688. * @type {string}
  37689. * @since 5.0.0
  37690. * @apioption plotOptions.series.dataLabels.className
  37691. */
  37692. /**
  37693. * The text color for the data labels. Defaults to `undefined`. For
  37694. * certain series types, like column or map, the data labels can be
  37695. * drawn inside the points. In this case the data label will be
  37696. * drawn with maximum contrast by default. Additionally, it will be
  37697. * given a `text-outline` style with the opposite color, to further
  37698. * increase the contrast. This can be overridden by setting the
  37699. * `text-outline` style to `none` in the `dataLabels.style` option.
  37700. *
  37701. * @sample {highcharts} highcharts/plotoptions/series-datalabels-color/
  37702. * Red data labels
  37703. * @sample {highmaps} maps/demo/color-axis/
  37704. * White data labels
  37705. *
  37706. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  37707. * @apioption plotOptions.series.dataLabels.color
  37708. */
  37709. /**
  37710. * Whether to hide data labels that are outside the plot area. By
  37711. * default, the data label is moved inside the plot area according
  37712. * to the
  37713. * [overflow](#plotOptions.series.dataLabels.overflow)
  37714. * option.
  37715. *
  37716. * @type {boolean}
  37717. * @default true
  37718. * @since 2.3.3
  37719. * @apioption plotOptions.series.dataLabels.crop
  37720. */
  37721. /**
  37722. * Whether to defer displaying the data labels until the initial
  37723. * series animation has finished. Setting to `false` renders the
  37724. * data label immediately. If set to `true` inherits the defer
  37725. * time set in [plotOptions.series.animation](#plotOptions.series.animation).
  37726. * If set to a number, a defer time is specified in milliseconds.
  37727. *
  37728. * @sample highcharts/plotoptions/animation-defer
  37729. * Set defer time
  37730. *
  37731. * @since 4.0.0
  37732. * @type {boolean|number}
  37733. * @product highcharts highstock gantt
  37734. */
  37735. defer: true,
  37736. /**
  37737. * Enable or disable the data labels.
  37738. *
  37739. * @sample {highcharts} highcharts/plotoptions/series-datalabels-enabled/
  37740. * Data labels enabled
  37741. * @sample {highmaps} maps/demo/color-axis/
  37742. * Data labels enabled
  37743. *
  37744. * @type {boolean}
  37745. * @default false
  37746. * @apioption plotOptions.series.dataLabels.enabled
  37747. */
  37748. /**
  37749. * A declarative filter to control of which data labels to display.
  37750. * The declarative filter is designed for use when callback
  37751. * functions are not available, like when the chart options require
  37752. * a pure JSON structure or for use with graphical editors. For
  37753. * programmatic control, use the `formatter` instead, and return
  37754. * `undefined` to disable a single data label.
  37755. *
  37756. * @example
  37757. * filter: {
  37758. * property: 'percentage',
  37759. * operator: '>',
  37760. * value: 4
  37761. * }
  37762. *
  37763. * @sample {highcharts} highcharts/demo/pie-monochrome
  37764. * Data labels filtered by percentage
  37765. *
  37766. * @declare Highcharts.DataLabelsFilterOptionsObject
  37767. * @since 6.0.3
  37768. * @apioption plotOptions.series.dataLabels.filter
  37769. */
  37770. /**
  37771. * The operator to compare by. Can be one of `>`, `<`, `>=`, `<=`,
  37772. * `==`, and `===`.
  37773. *
  37774. * @type {string}
  37775. * @validvalue [">", "<", ">=", "<=", "==", "==="]
  37776. * @apioption plotOptions.series.dataLabels.filter.operator
  37777. */
  37778. /**
  37779. * The point property to filter by. Point options are passed
  37780. * directly to properties, additionally there are `y` value,
  37781. * `percentage` and others listed under {@link Highcharts.Point}
  37782. * members.
  37783. *
  37784. * @type {string}
  37785. * @apioption plotOptions.series.dataLabels.filter.property
  37786. */
  37787. /**
  37788. * The value to compare against.
  37789. *
  37790. * @type {number}
  37791. * @apioption plotOptions.series.dataLabels.filter.value
  37792. */
  37793. /**
  37794. * A
  37795. * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
  37796. * for the data label. Available variables are the same as for
  37797. * `formatter`.
  37798. *
  37799. * @sample {highcharts} highcharts/plotoptions/series-datalabels-format/
  37800. * Add a unit
  37801. * @sample {highmaps} maps/plotoptions/series-datalabels-format/
  37802. * Formatted value in the data label
  37803. *
  37804. * @type {string}
  37805. * @default y
  37806. * @default point.value
  37807. * @since 3.0
  37808. * @apioption plotOptions.series.dataLabels.format
  37809. */
  37810. // eslint-disable-next-line valid-jsdoc
  37811. /**
  37812. * Callback JavaScript function to format the data label. Note that
  37813. * if a `format` is defined, the format takes precedence and the
  37814. * formatter is ignored.
  37815. *
  37816. * @sample {highmaps} maps/plotoptions/series-datalabels-format/
  37817. * Formatted value
  37818. *
  37819. * @type {Highcharts.DataLabelsFormatterCallbackFunction}
  37820. */
  37821. formatter: function () {
  37822. var numberFormatter = this.series.chart.numberFormatter;
  37823. return typeof this.y !== 'number' ? '' : numberFormatter(this.y, -1);
  37824. },
  37825. /**
  37826. * For points with an extent, like columns or map areas, whether to
  37827. * align the data label inside the box or to the actual value point.
  37828. * Defaults to `false` in most cases, `true` in stacked columns.
  37829. *
  37830. * @type {boolean}
  37831. * @since 3.0
  37832. * @apioption plotOptions.series.dataLabels.inside
  37833. */
  37834. /**
  37835. * Format for points with the value of null. Works analogously to
  37836. * [format](#plotOptions.series.dataLabels.format). `nullFormat` can
  37837. * be applied only to series which support displaying null points.
  37838. *
  37839. * @sample {highcharts} highcharts/plotoptions/series-datalabels-format/
  37840. * Format data label and tooltip for null point.
  37841. *
  37842. * @type {boolean|string}
  37843. * @since 7.1.0
  37844. * @apioption plotOptions.series.dataLabels.nullFormat
  37845. */
  37846. /**
  37847. * Callback JavaScript function that defines formatting for points
  37848. * with the value of null. Works analogously to
  37849. * [formatter](#plotOptions.series.dataLabels.formatter).
  37850. * `nullPointFormatter` can be applied only to series which support
  37851. * displaying null points.
  37852. *
  37853. * @sample {highcharts} highcharts/plotoptions/series-datalabels-format/
  37854. * Format data label and tooltip for null point.
  37855. *
  37856. * @type {Highcharts.DataLabelsFormatterCallbackFunction}
  37857. * @since 7.1.0
  37858. * @apioption plotOptions.series.dataLabels.nullFormatter
  37859. */
  37860. /**
  37861. * How to handle data labels that flow outside the plot area. The
  37862. * default is `"justify"`, which aligns them inside the plot area.
  37863. * For columns and bars, this means it will be moved inside the bar.
  37864. * To display data labels outside the plot area, set `crop` to
  37865. * `false` and `overflow` to `"allow"`.
  37866. *
  37867. * @type {Highcharts.DataLabelsOverflowValue}
  37868. * @default justify
  37869. * @since 3.0.6
  37870. * @apioption plotOptions.series.dataLabels.overflow
  37871. */
  37872. /**
  37873. * When either the `borderWidth` or the `backgroundColor` is set,
  37874. * this is the padding within the box.
  37875. *
  37876. * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
  37877. * Data labels box options
  37878. * @sample {highmaps} maps/plotoptions/series-datalabels-box/
  37879. * Data labels box options
  37880. *
  37881. * @since 2.2.1
  37882. */
  37883. padding: 5,
  37884. /**
  37885. * Aligns data labels relative to points. If `center` alignment is
  37886. * not possible, it defaults to `right`.
  37887. *
  37888. * @type {Highcharts.AlignValue}
  37889. * @default center
  37890. * @apioption plotOptions.series.dataLabels.position
  37891. */
  37892. /**
  37893. * Text rotation in degrees. Note that due to a more complex
  37894. * structure, backgrounds, borders and padding will be lost on a
  37895. * rotated data label.
  37896. *
  37897. * @sample {highcharts} highcharts/plotoptions/series-datalabels-rotation/
  37898. * Vertical labels
  37899. *
  37900. * @type {number}
  37901. * @default 0
  37902. * @apioption plotOptions.series.dataLabels.rotation
  37903. */
  37904. /**
  37905. * The shadow of the box. Works best with `borderWidth` or
  37906. * `backgroundColor`. Since 2.3 the shadow can be an object
  37907. * configuration containing `color`, `offsetX`, `offsetY`, `opacity`
  37908. * and `width`.
  37909. *
  37910. * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
  37911. * Data labels box options
  37912. *
  37913. * @type {boolean|Highcharts.ShadowOptionsObject}
  37914. * @default false
  37915. * @since 2.2.1
  37916. * @apioption plotOptions.series.dataLabels.shadow
  37917. */
  37918. /**
  37919. * The name of a symbol to use for the border around the label.
  37920. * Symbols are predefined functions on the Renderer object.
  37921. *
  37922. * @sample {highcharts} highcharts/plotoptions/series-datalabels-shape/
  37923. * A callout for annotations
  37924. *
  37925. * @type {string}
  37926. * @default square
  37927. * @since 4.1.2
  37928. * @apioption plotOptions.series.dataLabels.shape
  37929. */
  37930. /**
  37931. * Styles for the label. The default `color` setting is
  37932. * `"contrast"`, which is a pseudo color that Highcharts picks up
  37933. * and applies the maximum contrast to the underlying point item,
  37934. * for example the bar in a bar chart.
  37935. *
  37936. * The `textOutline` is a pseudo property that applies an outline of
  37937. * the given width with the given color, which by default is the
  37938. * maximum contrast to the text. So a bright text color will result
  37939. * in a black text outline for maximum readability on a mixed
  37940. * background. In some cases, especially with grayscale text, the
  37941. * text outline doesn't work well, in which cases it can be disabled
  37942. * by setting it to `"none"`. When `useHTML` is true, the
  37943. * `textOutline` will not be picked up. In this, case, the same
  37944. * effect can be acheived through the `text-shadow` CSS property.
  37945. *
  37946. * For some series types, where each point has an extent, like for
  37947. * example tree maps, the data label may overflow the point. There
  37948. * are two strategies for handling overflow. By default, the text
  37949. * will wrap to multiple lines. The other strategy is to set
  37950. * `style.textOverflow` to `ellipsis`, which will keep the text on
  37951. * one line plus it will break inside long words.
  37952. *
  37953. * @sample {highcharts} highcharts/plotoptions/series-datalabels-style/
  37954. * Bold labels
  37955. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-overflow/
  37956. * Long labels truncated with an ellipsis in a pie
  37957. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-overflow-wrap/
  37958. * Long labels are wrapped in a pie
  37959. * @sample {highmaps} maps/demo/color-axis/
  37960. * Bold labels
  37961. *
  37962. * @type {Highcharts.CSSObject}
  37963. * @since 4.1.0
  37964. * @apioption plotOptions.series.dataLabels.style
  37965. */
  37966. style: {
  37967. /** @internal */
  37968. fontSize: '11px',
  37969. /** @internal */
  37970. fontWeight: 'bold',
  37971. /** @internal */
  37972. color: 'contrast',
  37973. /** @internal */
  37974. textOutline: '1px contrast'
  37975. },
  37976. /**
  37977. * Options for a label text which should follow marker's shape.
  37978. * Border and background are disabled for a label that follows a
  37979. * path.
  37980. *
  37981. * **Note:** Only SVG-based renderer supports this option. Setting
  37982. * `useHTML` to true will disable this option.
  37983. *
  37984. * @declare Highcharts.DataLabelsTextPathOptionsObject
  37985. * @since 7.1.0
  37986. * @apioption plotOptions.series.dataLabels.textPath
  37987. */
  37988. /**
  37989. * Presentation attributes for the text path.
  37990. *
  37991. * @type {Highcharts.SVGAttributes}
  37992. * @since 7.1.0
  37993. * @apioption plotOptions.series.dataLabels.textPath.attributes
  37994. */
  37995. /**
  37996. * Enable or disable `textPath` option for link's or marker's data
  37997. * labels.
  37998. *
  37999. * @type {boolean}
  38000. * @since 7.1.0
  38001. * @apioption plotOptions.series.dataLabels.textPath.enabled
  38002. */
  38003. /**
  38004. * Whether to
  38005. * [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  38006. * to render the labels.
  38007. *
  38008. * @type {boolean}
  38009. * @default false
  38010. * @apioption plotOptions.series.dataLabels.useHTML
  38011. */
  38012. /**
  38013. * The vertical alignment of a data label. Can be one of `top`,
  38014. * `middle` or `bottom`. The default value depends on the data, for
  38015. * instance in a column chart, the label is above positive values
  38016. * and below negative values.
  38017. *
  38018. * @type {Highcharts.VerticalAlignValue|null}
  38019. * @since 2.3.3
  38020. */
  38021. verticalAlign: 'bottom',
  38022. /**
  38023. * The x position offset of the label relative to the point in
  38024. * pixels.
  38025. *
  38026. * @sample {highcharts} highcharts/plotoptions/series-datalabels-rotation/
  38027. * Vertical and positioned
  38028. * @sample {highcharts} highcharts/plotoptions/bar-datalabels-align-inside-bar/
  38029. * Data labels inside the bar
  38030. */
  38031. x: 0,
  38032. /**
  38033. * The Z index of the data labels. The default Z index puts it above
  38034. * the series. Use a Z index of 2 to display it behind the series.
  38035. *
  38036. * @type {number}
  38037. * @default 6
  38038. * @since 2.3.5
  38039. * @apioption plotOptions.series.dataLabels.z
  38040. */
  38041. /**
  38042. * The y position offset of the label relative to the point in
  38043. * pixels.
  38044. *
  38045. * @sample {highcharts} highcharts/plotoptions/series-datalabels-rotation/
  38046. * Vertical and positioned
  38047. */
  38048. y: 0
  38049. },
  38050. /**
  38051. * When the series contains less points than the crop threshold, all
  38052. * points are drawn, even if the points fall outside the visible plot
  38053. * area at the current zoom. The advantage of drawing all points
  38054. * (including markers and columns), is that animation is performed on
  38055. * updates. On the other hand, when the series contains more points than
  38056. * the crop threshold, the series data is cropped to only contain points
  38057. * that fall within the plot area. The advantage of cropping away
  38058. * invisible points is to increase performance on large series.
  38059. *
  38060. * @since 2.2
  38061. * @product highcharts highstock
  38062. *
  38063. * @private
  38064. */
  38065. cropThreshold: 300,
  38066. /**
  38067. * Opacity of a series parts: line, fill (e.g. area) and dataLabels.
  38068. *
  38069. * @see [states.inactive.opacity](#plotOptions.series.states.inactive.opacity)
  38070. *
  38071. * @since 7.1.0
  38072. *
  38073. * @private
  38074. */
  38075. opacity: 1,
  38076. /**
  38077. * The width of each point on the x axis. For example in a column chart
  38078. * with one value each day, the pointRange would be 1 day (= 24 * 3600
  38079. * * 1000 milliseconds). This is normally computed automatically, but
  38080. * this option can be used to override the automatic value.
  38081. *
  38082. * @product highstock
  38083. *
  38084. * @private
  38085. */
  38086. pointRange: 0,
  38087. /**
  38088. * When this is true, the series will not cause the Y axis to cross
  38089. * the zero plane (or [threshold](#plotOptions.series.threshold) option)
  38090. * unless the data actually crosses the plane.
  38091. *
  38092. * For example, if `softThreshold` is `false`, a series of 0, 1, 2,
  38093. * 3 will make the Y axis show negative values according to the
  38094. * `minPadding` option. If `softThreshold` is `true`, the Y axis starts
  38095. * at 0.
  38096. *
  38097. * @since 4.1.9
  38098. * @product highcharts highstock
  38099. *
  38100. * @private
  38101. */
  38102. softThreshold: true,
  38103. /**
  38104. * @declare Highcharts.SeriesStatesOptionsObject
  38105. *
  38106. * @private
  38107. */
  38108. states: {
  38109. /**
  38110. * The normal state of a series, or for point items in column, pie
  38111. * and similar series. Currently only used for setting animation
  38112. * when returning to normal state from hover.
  38113. *
  38114. * @declare Highcharts.SeriesStatesNormalOptionsObject
  38115. */
  38116. normal: {
  38117. /**
  38118. * Animation when returning to normal state after hovering.
  38119. *
  38120. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  38121. */
  38122. animation: true
  38123. },
  38124. /**
  38125. * Options for the hovered series. These settings override the
  38126. * normal state options when a series is moused over or touched.
  38127. *
  38128. * @declare Highcharts.SeriesStatesHoverOptionsObject
  38129. */
  38130. hover: {
  38131. /**
  38132. * Enable separate styles for the hovered series to visualize
  38133. * that the user hovers either the series itself or the legend.
  38134. *
  38135. * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled/
  38136. * Line
  38137. * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled-column/
  38138. * Column
  38139. * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled-pie/
  38140. * Pie
  38141. *
  38142. * @type {boolean}
  38143. * @default true
  38144. * @since 1.2
  38145. * @apioption plotOptions.series.states.hover.enabled
  38146. */
  38147. /**
  38148. * Animation setting for hovering the graph in line-type series.
  38149. *
  38150. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  38151. * @since 5.0.8
  38152. * @product highcharts highstock
  38153. */
  38154. animation: {
  38155. /**
  38156. * The duration of the hover animation in milliseconds. By
  38157. * default the hover state animates quickly in, and slowly
  38158. * back to normal.
  38159. *
  38160. * @internal
  38161. */
  38162. duration: 50
  38163. },
  38164. /**
  38165. * Pixel width of the graph line. By default this property is
  38166. * undefined, and the `lineWidthPlus` property dictates how much
  38167. * to increase the linewidth from normal state.
  38168. *
  38169. * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidth/
  38170. * 5px line on hover
  38171. *
  38172. * @type {number}
  38173. * @product highcharts highstock
  38174. * @apioption plotOptions.series.states.hover.lineWidth
  38175. */
  38176. /**
  38177. * The additional line width for the graph of a hovered series.
  38178. *
  38179. * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/
  38180. * 5 pixels wider
  38181. * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/
  38182. * 5 pixels wider
  38183. *
  38184. * @since 4.0.3
  38185. * @product highcharts highstock
  38186. */
  38187. lineWidthPlus: 1,
  38188. /**
  38189. * In Highcharts 1.0, the appearance of all markers belonging
  38190. * to the hovered series. For settings on the hover state of the
  38191. * individual point, see
  38192. * [marker.states.hover](#plotOptions.series.marker.states.hover).
  38193. *
  38194. * @deprecated
  38195. *
  38196. * @extends plotOptions.series.marker
  38197. * @excluding states
  38198. * @product highcharts highstock
  38199. */
  38200. marker: {
  38201. // lineWidth: base + 1,
  38202. // radius: base + 1
  38203. },
  38204. /**
  38205. * Options for the halo appearing around the hovered point in
  38206. * line-type series as well as outside the hovered slice in pie
  38207. * charts. By default the halo is filled by the current point or
  38208. * series color with an opacity of 0.25\. The halo can be
  38209. * disabled by setting the `halo` option to `null`.
  38210. *
  38211. * In styled mode, the halo is styled with the
  38212. * `.highcharts-halo` class, with colors inherited from
  38213. * `.highcharts-color-{n}`.
  38214. *
  38215. * @sample {highcharts} highcharts/plotoptions/halo/
  38216. * Halo options
  38217. * @sample {highstock} highcharts/plotoptions/halo/
  38218. * Halo options
  38219. *
  38220. * @declare Highcharts.SeriesStatesHoverHaloOptionsObject
  38221. * @type {null|*}
  38222. * @since 4.0
  38223. * @product highcharts highstock
  38224. */
  38225. halo: {
  38226. /**
  38227. * A collection of SVG attributes to override the appearance
  38228. * of the halo, for example `fill`, `stroke` and
  38229. * `stroke-width`.
  38230. *
  38231. * @type {Highcharts.SVGAttributes}
  38232. * @since 4.0
  38233. * @product highcharts highstock
  38234. * @apioption plotOptions.series.states.hover.halo.attributes
  38235. */
  38236. /**
  38237. * The pixel size of the halo. For point markers this is the
  38238. * radius of the halo. For pie slices it is the width of the
  38239. * halo outside the slice. For bubbles it defaults to 5 and
  38240. * is the width of the halo outside the bubble.
  38241. *
  38242. * @since 4.0
  38243. * @product highcharts highstock
  38244. */
  38245. size: 10,
  38246. /**
  38247. * Opacity for the halo unless a specific fill is overridden
  38248. * using the `attributes` setting. Note that Highcharts is
  38249. * only able to apply opacity to colors of hex or rgb(a)
  38250. * formats.
  38251. *
  38252. * @since 4.0
  38253. * @product highcharts highstock
  38254. */
  38255. opacity: 0.25
  38256. }
  38257. },
  38258. /**
  38259. * Specific options for point in selected states, after being
  38260. * selected by
  38261. * [allowPointSelect](#plotOptions.series.allowPointSelect)
  38262. * or programmatically.
  38263. *
  38264. * @sample maps/plotoptions/series-allowpointselect/
  38265. * Allow point select demo
  38266. *
  38267. * @declare Highcharts.SeriesStatesSelectOptionsObject
  38268. * @extends plotOptions.series.states.hover
  38269. * @excluding brightness
  38270. */
  38271. select: {
  38272. animation: {
  38273. /** @internal */
  38274. duration: 0
  38275. }
  38276. },
  38277. /**
  38278. * The opposite state of a hover for series.
  38279. *
  38280. * @sample highcharts/plotoptions/series-states-inactive-disabled
  38281. * Disabled inactive state
  38282. *
  38283. * @declare Highcharts.SeriesStatesInactiveOptionsObject
  38284. */
  38285. inactive: {
  38286. /**
  38287. * Enable or disable the inactive state for a series
  38288. *
  38289. * @sample highcharts/plotoptions/series-states-inactive-disabled
  38290. * Disabled inactive state
  38291. *
  38292. * @type {boolean}
  38293. * @default true
  38294. * @apioption plotOptions.series.states.inactive.enabled
  38295. */
  38296. /**
  38297. * The animation for entering the inactive state.
  38298. *
  38299. * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
  38300. */
  38301. animation: {
  38302. /** @internal */
  38303. duration: 50
  38304. },
  38305. /**
  38306. * Opacity of series elements (dataLabels, line, area).
  38307. *
  38308. * @type {number}
  38309. */
  38310. opacity: 0.2
  38311. }
  38312. },
  38313. /**
  38314. * Sticky tracking of mouse events. When true, the `mouseOut` event on a
  38315. * series isn't triggered until the mouse moves over another series, or
  38316. * out of the plot area. When false, the `mouseOut` event on a series is
  38317. * triggered when the mouse leaves the area around the series' graph or
  38318. * markers. This also implies the tooltip when not shared. When
  38319. * `stickyTracking` is false and `tooltip.shared` is false, the tooltip
  38320. * will be hidden when moving the mouse between series. Defaults to true
  38321. * for line and area type series, but to false for columns, pies etc.
  38322. *
  38323. * **Note:** The boost module will force this option because of
  38324. * technical limitations.
  38325. *
  38326. * @sample {highcharts} highcharts/plotoptions/series-stickytracking-true/
  38327. * True by default
  38328. * @sample {highcharts} highcharts/plotoptions/series-stickytracking-false/
  38329. * False
  38330. *
  38331. * @default {highcharts} true
  38332. * @default {highstock} true
  38333. * @default {highmaps} false
  38334. * @since 2.0
  38335. *
  38336. * @private
  38337. */
  38338. stickyTracking: true,
  38339. /**
  38340. * A configuration object for the tooltip rendering of each single
  38341. * series. Properties are inherited from [tooltip](#tooltip), but only
  38342. * the following properties can be defined on a series level.
  38343. *
  38344. * @declare Highcharts.SeriesTooltipOptionsObject
  38345. * @since 2.3
  38346. * @extends tooltip
  38347. * @excluding animation, backgroundColor, borderColor, borderRadius,
  38348. * borderWidth, className, crosshairs, enabled, formatter,
  38349. * headerShape, hideDelay, outside, padding, positioner,
  38350. * shadow, shape, shared, snap, split, stickOnContact,
  38351. * style, useHTML
  38352. * @apioption plotOptions.series.tooltip
  38353. */
  38354. /**
  38355. * When a series contains a data array that is longer than this, only
  38356. * one dimensional arrays of numbers, or two dimensional arrays with
  38357. * x and y values are allowed. Also, only the first point is tested,
  38358. * and the rest are assumed to be the same format. This saves expensive
  38359. * data checking and indexing in long series. Set it to `0` disable.
  38360. *
  38361. * Note:
  38362. * In boost mode turbo threshold is forced. Only array of numbers or
  38363. * two dimensional arrays are allowed.
  38364. *
  38365. * @since 2.2
  38366. * @product highcharts highstock gantt
  38367. *
  38368. * @private
  38369. */
  38370. turboThreshold: 1000,
  38371. /**
  38372. * An array defining zones within a series. Zones can be applied to the
  38373. * X axis, Y axis or Z axis for bubbles, according to the `zoneAxis`
  38374. * option. The zone definitions have to be in ascending order regarding
  38375. * to the value.
  38376. *
  38377. * In styled mode, the color zones are styled with the
  38378. * `.highcharts-zone-{n}` class, or custom classed from the `className`
  38379. * option
  38380. * ([view live demo](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/color-zones/)).
  38381. *
  38382. * @see [zoneAxis](#plotOptions.series.zoneAxis)
  38383. *
  38384. * @sample {highcharts} highcharts/series/color-zones-simple/
  38385. * Color zones
  38386. * @sample {highstock} highcharts/series/color-zones-simple/
  38387. * Color zones
  38388. *
  38389. * @declare Highcharts.SeriesZonesOptionsObject
  38390. * @type {Array<*>}
  38391. * @since 4.1.0
  38392. * @product highcharts highstock
  38393. * @apioption plotOptions.series.zones
  38394. */
  38395. /**
  38396. * Styled mode only. A custom class name for the zone.
  38397. *
  38398. * @sample highcharts/css/color-zones/
  38399. * Zones styled by class name
  38400. *
  38401. * @type {string}
  38402. * @since 5.0.0
  38403. * @apioption plotOptions.series.zones.className
  38404. */
  38405. /**
  38406. * Defines the color of the series.
  38407. *
  38408. * @see [series color](#plotOptions.series.color)
  38409. *
  38410. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  38411. * @since 4.1.0
  38412. * @product highcharts highstock
  38413. * @apioption plotOptions.series.zones.color
  38414. */
  38415. /**
  38416. * A name for the dash style to use for the graph.
  38417. *
  38418. * @see [plotOptions.series.dashStyle](#plotOptions.series.dashStyle)
  38419. *
  38420. * @sample {highcharts|highstock} highcharts/series/color-zones-dashstyle-dot/
  38421. * Dashed line indicates prognosis
  38422. *
  38423. * @type {Highcharts.DashStyleValue}
  38424. * @since 4.1.0
  38425. * @product highcharts highstock
  38426. * @apioption plotOptions.series.zones.dashStyle
  38427. */
  38428. /**
  38429. * Defines the fill color for the series (in area type series)
  38430. *
  38431. * @see [fillColor](#plotOptions.area.fillColor)
  38432. *
  38433. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  38434. * @since 4.1.0
  38435. * @product highcharts highstock
  38436. * @apioption plotOptions.series.zones.fillColor
  38437. */
  38438. /**
  38439. * The value up to where the zone extends, if undefined the zones
  38440. * stretches to the last value in the series.
  38441. *
  38442. * @type {number}
  38443. * @since 4.1.0
  38444. * @product highcharts highstock
  38445. * @apioption plotOptions.series.zones.value
  38446. */
  38447. /**
  38448. * When using dual or multiple color axes, this number defines which
  38449. * colorAxis the particular series is connected to. It refers to
  38450. * either the
  38451. * {@link #colorAxis.id|axis id}
  38452. * or the index of the axis in the colorAxis array, with 0 being the
  38453. * first. Set this option to false to prevent a series from connecting
  38454. * to the default color axis.
  38455. *
  38456. * Since v7.2.0 the option can also be an axis id or an axis index
  38457. * instead of a boolean flag.
  38458. *
  38459. * @sample highcharts/coloraxis/coloraxis-with-pie/
  38460. * Color axis with pie series
  38461. * @sample highcharts/coloraxis/multiple-coloraxis/
  38462. * Multiple color axis
  38463. *
  38464. * @type {number|string|boolean}
  38465. * @default 0
  38466. * @product highcharts highstock highmaps
  38467. * @apioption plotOptions.series.colorAxis
  38468. */
  38469. /**
  38470. * Determines what data value should be used to calculate point color
  38471. * if `colorAxis` is used. Requires to set `min` and `max` if some
  38472. * custom point property is used or if approximation for data grouping
  38473. * is set to `'sum'`.
  38474. *
  38475. * @sample highcharts/coloraxis/custom-color-key/
  38476. * Custom color key
  38477. * @sample highcharts/coloraxis/changed-default-color-key/
  38478. * Changed default color key
  38479. *
  38480. * @type {string}
  38481. * @default y
  38482. * @since 7.2.0
  38483. * @product highcharts highstock highmaps
  38484. * @apioption plotOptions.series.colorKey
  38485. */
  38486. /**
  38487. * Determines whether the series should look for the nearest point
  38488. * in both dimensions or just the x-dimension when hovering the series.
  38489. * Defaults to `'xy'` for scatter series and `'x'` for most other
  38490. * series. If the data has duplicate x-values, it is recommended to
  38491. * set this to `'xy'` to allow hovering over all points.
  38492. *
  38493. * Applies only to series types using nearest neighbor search (not
  38494. * direct hover) for tooltip.
  38495. *
  38496. * @sample {highcharts} highcharts/series/findnearestpointby/
  38497. * Different hover behaviors
  38498. * @sample {highstock} highcharts/series/findnearestpointby/
  38499. * Different hover behaviors
  38500. * @sample {highmaps} highcharts/series/findnearestpointby/
  38501. * Different hover behaviors
  38502. *
  38503. * @since 5.0.10
  38504. * @validvalue ["x", "xy"]
  38505. *
  38506. * @private
  38507. */
  38508. findNearestPointBy: 'x'
  38509. };
  38510. return Series;
  38511. }());
  38512. extend(Series.prototype, {
  38513. axisTypes: ['xAxis', 'yAxis'],
  38514. coll: 'series',
  38515. colorCounter: 0,
  38516. cropShoulder: 1,
  38517. directTouch: false,
  38518. drawLegendSymbol: LegendSymbolMixin.drawLineMarker,
  38519. isCartesian: true,
  38520. kdAxisArray: ['clientX', 'plotY'],
  38521. // each point's x and y values are stored in this.xData and this.yData:
  38522. parallelArrays: ['x', 'y'],
  38523. pointClass: Point,
  38524. requireSorting: true,
  38525. // requires the data to be sorted:
  38526. sorted: true
  38527. });
  38528. /* *
  38529. *
  38530. * Registry
  38531. *
  38532. * */
  38533. SeriesRegistry.series = Series;
  38534. /* *
  38535. *
  38536. * Default Export
  38537. *
  38538. * */
  38539. /* *
  38540. *
  38541. * API Declarations
  38542. *
  38543. * */
  38544. /**
  38545. * This is a placeholder type of the possible series options for
  38546. * [Highcharts](../highcharts/series), [Highcharts Stock](../highstock/series),
  38547. * [Highmaps](../highmaps/series), and [Gantt](../gantt/series).
  38548. *
  38549. * In TypeScript is this dynamically generated to reference all possible types
  38550. * of series options.
  38551. *
  38552. * @ignore-declaration
  38553. * @typedef {Highcharts.SeriesOptions|Highcharts.Dictionary<*>} Highcharts.SeriesOptionsType
  38554. */
  38555. /**
  38556. * Options for `dataSorting`.
  38557. *
  38558. * @interface Highcharts.DataSortingOptionsObject
  38559. * @since 8.0.0
  38560. */ /**
  38561. * Enable or disable data sorting for the series.
  38562. * @name Highcharts.DataSortingOptionsObject#enabled
  38563. * @type {boolean|undefined}
  38564. */ /**
  38565. * Whether to allow matching points by name in an update.
  38566. * @name Highcharts.DataSortingOptionsObject#matchByName
  38567. * @type {boolean|undefined}
  38568. */ /**
  38569. * Determines what data value should be used to sort by.
  38570. * @name Highcharts.DataSortingOptionsObject#sortKey
  38571. * @type {string|undefined}
  38572. */
  38573. /**
  38574. * Function callback when a series has been animated.
  38575. *
  38576. * @callback Highcharts.SeriesAfterAnimateCallbackFunction
  38577. *
  38578. * @param {Highcharts.Series} this
  38579. * The series where the event occured.
  38580. *
  38581. * @param {Highcharts.SeriesAfterAnimateEventObject} event
  38582. * Event arguments.
  38583. */
  38584. /**
  38585. * Event information regarding completed animation of a series.
  38586. *
  38587. * @interface Highcharts.SeriesAfterAnimateEventObject
  38588. */ /**
  38589. * Animated series.
  38590. * @name Highcharts.SeriesAfterAnimateEventObject#target
  38591. * @type {Highcharts.Series}
  38592. */ /**
  38593. * Event type.
  38594. * @name Highcharts.SeriesAfterAnimateEventObject#type
  38595. * @type {"afterAnimate"}
  38596. */
  38597. /**
  38598. * Function callback when the checkbox next to the series' name in the legend is
  38599. * clicked.
  38600. *
  38601. * @callback Highcharts.SeriesCheckboxClickCallbackFunction
  38602. *
  38603. * @param {Highcharts.Series} this
  38604. * The series where the event occured.
  38605. *
  38606. * @param {Highcharts.SeriesCheckboxClickEventObject} event
  38607. * Event arguments.
  38608. */
  38609. /**
  38610. * Event information regarding check of a series box.
  38611. *
  38612. * @interface Highcharts.SeriesCheckboxClickEventObject
  38613. */ /**
  38614. * Whether the box has been checked.
  38615. * @name Highcharts.SeriesCheckboxClickEventObject#checked
  38616. * @type {boolean}
  38617. */ /**
  38618. * Related series.
  38619. * @name Highcharts.SeriesCheckboxClickEventObject#item
  38620. * @type {Highcharts.Series}
  38621. */ /**
  38622. * Related series.
  38623. * @name Highcharts.SeriesCheckboxClickEventObject#target
  38624. * @type {Highcharts.Series}
  38625. */ /**
  38626. * Event type.
  38627. * @name Highcharts.SeriesCheckboxClickEventObject#type
  38628. * @type {"checkboxClick"}
  38629. */
  38630. /**
  38631. * Function callback when a series is clicked. Return false to cancel toogle
  38632. * actions.
  38633. *
  38634. * @callback Highcharts.SeriesClickCallbackFunction
  38635. *
  38636. * @param {Highcharts.Series} this
  38637. * The series where the event occured.
  38638. *
  38639. * @param {Highcharts.SeriesClickEventObject} event
  38640. * Event arguments.
  38641. */
  38642. /**
  38643. * Common information for a click event on a series.
  38644. *
  38645. * @interface Highcharts.SeriesClickEventObject
  38646. * @extends global.Event
  38647. */ /**
  38648. * Nearest point on the graph.
  38649. * @name Highcharts.SeriesClickEventObject#point
  38650. * @type {Highcharts.Point}
  38651. */
  38652. /**
  38653. * Gets fired when the series is hidden after chart generation time, either by
  38654. * clicking the legend item or by calling `.hide()`.
  38655. *
  38656. * @callback Highcharts.SeriesHideCallbackFunction
  38657. *
  38658. * @param {Highcharts.Series} this
  38659. * The series where the event occured.
  38660. *
  38661. * @param {global.Event} event
  38662. * The event that occured.
  38663. */
  38664. /**
  38665. * The SVG value used for the `stroke-linecap` and `stroke-linejoin` of a line
  38666. * graph.
  38667. *
  38668. * @typedef {"butt"|"round"|"square"|string} Highcharts.SeriesLinecapValue
  38669. */
  38670. /**
  38671. * Gets fired when the legend item belonging to the series is clicked. The
  38672. * default action is to toggle the visibility of the series. This can be
  38673. * prevented by returning `false` or calling `event.preventDefault()`.
  38674. *
  38675. * @callback Highcharts.SeriesLegendItemClickCallbackFunction
  38676. *
  38677. * @param {Highcharts.Series} this
  38678. * The series where the event occured.
  38679. *
  38680. * @param {Highcharts.SeriesLegendItemClickEventObject} event
  38681. * The event that occured.
  38682. */
  38683. /**
  38684. * Information about the event.
  38685. *
  38686. * @interface Highcharts.SeriesLegendItemClickEventObject
  38687. */ /**
  38688. * Related browser event.
  38689. * @name Highcharts.SeriesLegendItemClickEventObject#browserEvent
  38690. * @type {global.PointerEvent}
  38691. */ /**
  38692. * Prevent the default action of toggle the visibility of the series.
  38693. * @name Highcharts.SeriesLegendItemClickEventObject#preventDefault
  38694. * @type {Function}
  38695. */ /**
  38696. * Related series.
  38697. * @name Highcharts.SeriesCheckboxClickEventObject#target
  38698. * @type {Highcharts.Series}
  38699. */ /**
  38700. * Event type.
  38701. * @name Highcharts.SeriesCheckboxClickEventObject#type
  38702. * @type {"checkboxClick"}
  38703. */
  38704. /**
  38705. * Gets fired when the mouse leaves the graph.
  38706. *
  38707. * @callback Highcharts.SeriesMouseOutCallbackFunction
  38708. *
  38709. * @param {Highcharts.Series} this
  38710. * Series where the event occured.
  38711. *
  38712. * @param {global.PointerEvent} event
  38713. * Event that occured.
  38714. */
  38715. /**
  38716. * Gets fired when the mouse enters the graph.
  38717. *
  38718. * @callback Highcharts.SeriesMouseOverCallbackFunction
  38719. *
  38720. * @param {Highcharts.Series} this
  38721. * Series where the event occured.
  38722. *
  38723. * @param {global.PointerEvent} event
  38724. * Event that occured.
  38725. */
  38726. /**
  38727. * Translation and scale for the plot area of a series.
  38728. *
  38729. * @interface Highcharts.SeriesPlotBoxObject
  38730. */ /**
  38731. * @name Highcharts.SeriesPlotBoxObject#scaleX
  38732. * @type {number}
  38733. */ /**
  38734. * @name Highcharts.SeriesPlotBoxObject#scaleY
  38735. * @type {number}
  38736. */ /**
  38737. * @name Highcharts.SeriesPlotBoxObject#translateX
  38738. * @type {number}
  38739. */ /**
  38740. * @name Highcharts.SeriesPlotBoxObject#translateY
  38741. * @type {number}
  38742. */
  38743. /**
  38744. * Gets fired when the series is shown after chart generation time, either by
  38745. * clicking the legend item or by calling `.show()`.
  38746. *
  38747. * @callback Highcharts.SeriesShowCallbackFunction
  38748. *
  38749. * @param {Highcharts.Series} this
  38750. * Series where the event occured.
  38751. *
  38752. * @param {global.Event} event
  38753. * Event that occured.
  38754. */
  38755. /**
  38756. * Possible key values for the series state options.
  38757. *
  38758. * @typedef {"hover"|"inactive"|"normal"|"select"} Highcharts.SeriesStateValue
  38759. */
  38760. ''; // detach doclets above
  38761. /* *
  38762. *
  38763. * API Options
  38764. *
  38765. * */
  38766. /**
  38767. * Series options for specific data and the data itself. In TypeScript you
  38768. * have to cast the series options to specific series types, to get all
  38769. * possible options for a series.
  38770. *
  38771. * @example
  38772. * // TypeScript example
  38773. * Highcharts.chart('container', {
  38774. * series: [{
  38775. * color: '#06C',
  38776. * data: [[0, 1], [2, 3]]
  38777. * } as Highcharts.SeriesLineOptions ]
  38778. * });
  38779. *
  38780. * @type {Array<*>}
  38781. * @apioption series
  38782. */
  38783. /**
  38784. * An id for the series. This can be used after render time to get a pointer
  38785. * to the series object through `chart.get()`.
  38786. *
  38787. * @sample {highcharts} highcharts/plotoptions/series-id/
  38788. * Get series by id
  38789. *
  38790. * @type {string}
  38791. * @since 1.2.0
  38792. * @apioption series.id
  38793. */
  38794. /**
  38795. * The index of the series in the chart, affecting the internal index in the
  38796. * `chart.series` array, the visible Z index as well as the order in the
  38797. * legend.
  38798. *
  38799. * @type {number}
  38800. * @since 2.3.0
  38801. * @apioption series.index
  38802. */
  38803. /**
  38804. * The sequential index of the series in the legend.
  38805. *
  38806. * @see [legend.reversed](#legend.reversed),
  38807. * [yAxis.reversedStacks](#yAxis.reversedStacks)
  38808. *
  38809. * @sample {highcharts|highstock} highcharts/series/legendindex/
  38810. * Legend in opposite order
  38811. *
  38812. * @type {number}
  38813. * @apioption series.legendIndex
  38814. */
  38815. /**
  38816. * The name of the series as shown in the legend, tooltip etc.
  38817. *
  38818. * @sample {highcharts} highcharts/series/name/
  38819. * Series name
  38820. * @sample {highmaps} maps/demo/category-map/
  38821. * Series name
  38822. *
  38823. * @type {string}
  38824. * @apioption series.name
  38825. */
  38826. /**
  38827. * This option allows grouping series in a stacked chart. The stack option
  38828. * can be a string or anything else, as long as the grouped series' stack
  38829. * options match each other after conversion into a string.
  38830. *
  38831. * @sample {highcharts} highcharts/series/stack/
  38832. * Stacked and grouped columns
  38833. *
  38834. * @type {number|string}
  38835. * @since 2.1
  38836. * @product highcharts highstock
  38837. * @apioption series.stack
  38838. */
  38839. /**
  38840. * The type of series, for example `line` or `column`. By default, the
  38841. * series type is inherited from [chart.type](#chart.type), so unless the
  38842. * chart is a combination of series types, there is no need to set it on the
  38843. * series level.
  38844. *
  38845. * @sample {highcharts} highcharts/series/type/
  38846. * Line and column in the same chart
  38847. * @sample highcharts/series/type-dynamic/
  38848. * Dynamic types with button selector
  38849. * @sample {highmaps} maps/demo/mapline-mappoint/
  38850. * Multiple types in the same map
  38851. *
  38852. * @type {string}
  38853. * @apioption series.type
  38854. */
  38855. /**
  38856. * When using dual or multiple x axes, this number defines which xAxis the
  38857. * particular series is connected to. It refers to either the
  38858. * {@link #xAxis.id|axis id}
  38859. * or the index of the axis in the xAxis array, with 0 being the first.
  38860. *
  38861. * @type {number|string}
  38862. * @default 0
  38863. * @product highcharts highstock
  38864. * @apioption series.xAxis
  38865. */
  38866. /**
  38867. * When using dual or multiple y axes, this number defines which yAxis the
  38868. * particular series is connected to. It refers to either the
  38869. * {@link #yAxis.id|axis id}
  38870. * or the index of the axis in the yAxis array, with 0 being the first.
  38871. *
  38872. * @sample {highcharts} highcharts/series/yaxis/
  38873. * Apply the column series to the secondary Y axis
  38874. *
  38875. * @type {number|string}
  38876. * @default 0
  38877. * @product highcharts highstock
  38878. * @apioption series.yAxis
  38879. */
  38880. /**
  38881. * Define the visual z index of the series.
  38882. *
  38883. * @sample {highcharts} highcharts/plotoptions/series-zindex-default/
  38884. * With no z index, the series defined last are on top
  38885. * @sample {highcharts} highcharts/plotoptions/series-zindex/
  38886. * With a z index, the series with the highest z index is on top
  38887. * @sample {highstock} highcharts/plotoptions/series-zindex-default/
  38888. * With no z index, the series defined last are on top
  38889. * @sample {highstock} highcharts/plotoptions/series-zindex/
  38890. * With a z index, the series with the highest z index is on top
  38891. *
  38892. * @type {number}
  38893. * @product highcharts highstock
  38894. * @apioption series.zIndex
  38895. */
  38896. ''; // include precedent doclets in transpilat
  38897. return Series;
  38898. });
  38899. _registerModule(_modules, 'Extensions/ScrollablePlotArea.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Axis/Axis.js'], _modules['Core/Chart/Chart.js'], _modules['Core/Series/Series.js'], _modules['Core/Renderer/RendererRegistry.js'], _modules['Core/Utilities.js']], function (A, Axis, Chart, Series, RendererRegistry, U) {
  38900. /* *
  38901. *
  38902. * (c) 2010-2021 Torstein Honsi
  38903. *
  38904. * License: www.highcharts.com/license
  38905. *
  38906. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  38907. *
  38908. * Highcharts feature to make the Y axis stay fixed when scrolling the chart
  38909. * horizontally on mobile devices. Supports left and right side axes.
  38910. */
  38911. /*
  38912. WIP on vertical scrollable plot area (#9378). To do:
  38913. - Bottom axis positioning
  38914. - Test with Gantt
  38915. - Look for size optimizing the code
  38916. - API and demos
  38917. */
  38918. var stop = A.stop;
  38919. var addEvent = U.addEvent,
  38920. createElement = U.createElement,
  38921. merge = U.merge,
  38922. pick = U.pick;
  38923. /* eslint-disable no-invalid-this, valid-jsdoc */
  38924. addEvent(Chart, 'afterSetChartSize', function (e) {
  38925. var scrollablePlotArea = this.options.chart.scrollablePlotArea,
  38926. scrollableMinWidth = scrollablePlotArea && scrollablePlotArea.minWidth,
  38927. scrollableMinHeight = scrollablePlotArea && scrollablePlotArea.minHeight,
  38928. scrollablePixelsX,
  38929. scrollablePixelsY,
  38930. corrections;
  38931. if (!this.renderer.forExport) {
  38932. // The amount of pixels to scroll, the difference between chart
  38933. // width and scrollable width
  38934. if (scrollableMinWidth) {
  38935. this.scrollablePixelsX = scrollablePixelsX = Math.max(0, scrollableMinWidth - this.chartWidth);
  38936. if (scrollablePixelsX) {
  38937. this.scrollablePlotBox = this.renderer.scrollablePlotBox = merge(this.plotBox);
  38938. this.plotBox.width = this.plotWidth += scrollablePixelsX;
  38939. if (this.inverted) {
  38940. this.clipBox.height += scrollablePixelsX;
  38941. }
  38942. else {
  38943. this.clipBox.width += scrollablePixelsX;
  38944. }
  38945. corrections = {
  38946. // Corrections for right side
  38947. 1: { name: 'right', value: scrollablePixelsX }
  38948. };
  38949. }
  38950. // Currently we can only do either X or Y
  38951. }
  38952. else if (scrollableMinHeight) {
  38953. this.scrollablePixelsY = scrollablePixelsY = Math.max(0, scrollableMinHeight - this.chartHeight);
  38954. if (scrollablePixelsY) {
  38955. this.scrollablePlotBox = this.renderer.scrollablePlotBox = merge(this.plotBox);
  38956. this.plotBox.height = this.plotHeight += scrollablePixelsY;
  38957. if (this.inverted) {
  38958. this.clipBox.width += scrollablePixelsY;
  38959. }
  38960. else {
  38961. this.clipBox.height += scrollablePixelsY;
  38962. }
  38963. corrections = {
  38964. 2: { name: 'bottom', value: scrollablePixelsY }
  38965. };
  38966. }
  38967. }
  38968. if (corrections && !e.skipAxes) {
  38969. this.axes.forEach(function (axis) {
  38970. // For right and bottom axes, only fix the plot line length
  38971. if (corrections[axis.side]) {
  38972. // Get the plot lines right in getPlotLinePath,
  38973. // temporarily set it to the adjusted plot width.
  38974. axis.getPlotLinePath = function () {
  38975. var marginName = corrections[axis.side].name,
  38976. correctionValue = corrections[axis.side].value,
  38977. // axis.right or axis.bottom
  38978. margin = this[marginName],
  38979. path;
  38980. // Temporarily adjust
  38981. this[marginName] = margin - correctionValue;
  38982. path = Axis.prototype.getPlotLinePath.apply(this, arguments);
  38983. // Reset
  38984. this[marginName] = margin;
  38985. return path;
  38986. };
  38987. }
  38988. else {
  38989. // Apply the corrected plotWidth
  38990. axis.setAxisSize();
  38991. axis.setAxisTranslation();
  38992. }
  38993. });
  38994. }
  38995. }
  38996. });
  38997. addEvent(Chart, 'render', function () {
  38998. if (this.scrollablePixelsX || this.scrollablePixelsY) {
  38999. if (this.setUpScrolling) {
  39000. this.setUpScrolling();
  39001. }
  39002. this.applyFixed();
  39003. }
  39004. else if (this.fixedDiv) { // Has been in scrollable mode
  39005. this.applyFixed();
  39006. }
  39007. });
  39008. /**
  39009. * @private
  39010. * @function Highcharts.Chart#setUpScrolling
  39011. * @return {void}
  39012. */
  39013. Chart.prototype.setUpScrolling = function () {
  39014. var _this = this;
  39015. var css = {
  39016. WebkitOverflowScrolling: 'touch',
  39017. overflowX: 'hidden',
  39018. overflowY: 'hidden'
  39019. };
  39020. if (this.scrollablePixelsX) {
  39021. css.overflowX = 'auto';
  39022. }
  39023. if (this.scrollablePixelsY) {
  39024. css.overflowY = 'auto';
  39025. }
  39026. // Insert a container with position relative
  39027. // that scrolling and fixed container renders to (#10555)
  39028. this.scrollingParent = createElement('div', {
  39029. className: 'highcharts-scrolling-parent'
  39030. }, {
  39031. position: 'relative'
  39032. }, this.renderTo);
  39033. // Add the necessary divs to provide scrolling
  39034. this.scrollingContainer = createElement('div', {
  39035. 'className': 'highcharts-scrolling'
  39036. }, css, this.scrollingParent);
  39037. // On scroll, reset the chart position because it applies to the scrolled
  39038. // container
  39039. addEvent(this.scrollingContainer, 'scroll', function () {
  39040. if (_this.pointer) {
  39041. delete _this.pointer.chartPosition;
  39042. }
  39043. });
  39044. this.innerContainer = createElement('div', {
  39045. 'className': 'highcharts-inner-container'
  39046. }, null, this.scrollingContainer);
  39047. // Now move the container inside
  39048. this.innerContainer.appendChild(this.container);
  39049. // Don't run again
  39050. this.setUpScrolling = null;
  39051. };
  39052. /**
  39053. * These elements are moved over to the fixed renderer and stay fixed when the
  39054. * user scrolls the chart
  39055. * @private
  39056. */
  39057. Chart.prototype.moveFixedElements = function () {
  39058. var container = this.container,
  39059. fixedRenderer = this.fixedRenderer,
  39060. fixedSelectors = [
  39061. '.highcharts-contextbutton',
  39062. '.highcharts-credits',
  39063. '.highcharts-legend',
  39064. '.highcharts-legend-checkbox',
  39065. '.highcharts-navigator-series',
  39066. '.highcharts-navigator-xaxis',
  39067. '.highcharts-navigator-yaxis',
  39068. '.highcharts-navigator',
  39069. '.highcharts-reset-zoom',
  39070. '.highcharts-drillup-button',
  39071. '.highcharts-scrollbar',
  39072. '.highcharts-subtitle',
  39073. '.highcharts-title'
  39074. ],
  39075. axisClass;
  39076. if (this.scrollablePixelsX && !this.inverted) {
  39077. axisClass = '.highcharts-yaxis';
  39078. }
  39079. else if (this.scrollablePixelsX && this.inverted) {
  39080. axisClass = '.highcharts-xaxis';
  39081. }
  39082. else if (this.scrollablePixelsY && !this.inverted) {
  39083. axisClass = '.highcharts-xaxis';
  39084. }
  39085. else if (this.scrollablePixelsY && this.inverted) {
  39086. axisClass = '.highcharts-yaxis';
  39087. }
  39088. if (axisClass) {
  39089. fixedSelectors.push(axisClass + ":not(.highcharts-radial-axis)", axisClass + "-labels:not(.highcharts-radial-axis-labels)");
  39090. }
  39091. fixedSelectors.forEach(function (className) {
  39092. [].forEach.call(container.querySelectorAll(className), function (elem) {
  39093. (elem.namespaceURI === fixedRenderer.SVG_NS ?
  39094. fixedRenderer.box :
  39095. fixedRenderer.box.parentNode).appendChild(elem);
  39096. elem.style.pointerEvents = 'auto';
  39097. });
  39098. });
  39099. };
  39100. /**
  39101. * @private
  39102. * @function Highcharts.Chart#applyFixed
  39103. * @return {void}
  39104. */
  39105. Chart.prototype.applyFixed = function () {
  39106. var firstTime = !this.fixedDiv,
  39107. chartOptions = this.options.chart,
  39108. scrollableOptions = chartOptions.scrollablePlotArea,
  39109. Renderer = RendererRegistry.getRendererType();
  39110. var fixedRenderer,
  39111. scrollableWidth,
  39112. scrollableHeight;
  39113. // First render
  39114. if (firstTime) {
  39115. this.fixedDiv = createElement('div', {
  39116. className: 'highcharts-fixed'
  39117. }, {
  39118. position: 'absolute',
  39119. overflow: 'hidden',
  39120. pointerEvents: 'none',
  39121. zIndex: (chartOptions.style && chartOptions.style.zIndex || 0) + 2,
  39122. top: 0
  39123. }, null, true);
  39124. if (this.scrollingContainer) {
  39125. this.scrollingContainer.parentNode.insertBefore(this.fixedDiv, this.scrollingContainer);
  39126. }
  39127. this.renderTo.style.overflow = 'visible';
  39128. this.fixedRenderer = fixedRenderer = new Renderer(this.fixedDiv, this.chartWidth, this.chartHeight, this.options.chart.style);
  39129. // Mask
  39130. this.scrollableMask = fixedRenderer
  39131. .path()
  39132. .attr({
  39133. fill: this.options.chart.backgroundColor || '#fff',
  39134. 'fill-opacity': pick(scrollableOptions.opacity, 0.85),
  39135. zIndex: -1
  39136. })
  39137. .addClass('highcharts-scrollable-mask')
  39138. .add();
  39139. addEvent(this, 'afterShowResetZoom', this.moveFixedElements);
  39140. addEvent(this, 'afterDrilldown', this.moveFixedElements);
  39141. addEvent(this, 'afterLayOutTitles', this.moveFixedElements);
  39142. }
  39143. else {
  39144. // Set the size of the fixed renderer to the visible width
  39145. this.fixedRenderer.setSize(this.chartWidth, this.chartHeight);
  39146. }
  39147. if (this.scrollableDirty || firstTime) {
  39148. this.scrollableDirty = false;
  39149. this.moveFixedElements();
  39150. }
  39151. // Increase the size of the scrollable renderer and background
  39152. scrollableWidth = this.chartWidth + (this.scrollablePixelsX || 0);
  39153. scrollableHeight = this.chartHeight + (this.scrollablePixelsY || 0);
  39154. stop(this.container);
  39155. this.container.style.width = scrollableWidth + 'px';
  39156. this.container.style.height = scrollableHeight + 'px';
  39157. this.renderer.boxWrapper.attr({
  39158. width: scrollableWidth,
  39159. height: scrollableHeight,
  39160. viewBox: [0, 0, scrollableWidth, scrollableHeight].join(' ')
  39161. });
  39162. this.chartBackground.attr({
  39163. width: scrollableWidth,
  39164. height: scrollableHeight
  39165. });
  39166. this.scrollingContainer.style.height = this.chartHeight + 'px';
  39167. // Set scroll position
  39168. if (firstTime) {
  39169. if (scrollableOptions.scrollPositionX) {
  39170. this.scrollingContainer.scrollLeft =
  39171. this.scrollablePixelsX *
  39172. scrollableOptions.scrollPositionX;
  39173. }
  39174. if (scrollableOptions.scrollPositionY) {
  39175. this.scrollingContainer.scrollTop =
  39176. this.scrollablePixelsY *
  39177. scrollableOptions.scrollPositionY;
  39178. }
  39179. }
  39180. // Mask behind the left and right side
  39181. var axisOffset = this.axisOffset,
  39182. maskTop = this.plotTop - axisOffset[0] - 1,
  39183. maskLeft = this.plotLeft - axisOffset[3] - 1,
  39184. maskBottom = this.plotTop + this.plotHeight + axisOffset[2] + 1,
  39185. maskRight = this.plotLeft + this.plotWidth + axisOffset[1] + 1,
  39186. maskPlotRight = this.plotLeft + this.plotWidth -
  39187. (this.scrollablePixelsX || 0),
  39188. maskPlotBottom = this.plotTop + this.plotHeight -
  39189. (this.scrollablePixelsY || 0),
  39190. d;
  39191. if (this.scrollablePixelsX) {
  39192. d = [
  39193. // Left side
  39194. ['M', 0, maskTop],
  39195. ['L', this.plotLeft - 1, maskTop],
  39196. ['L', this.plotLeft - 1, maskBottom],
  39197. ['L', 0, maskBottom],
  39198. ['Z'],
  39199. // Right side
  39200. ['M', maskPlotRight, maskTop],
  39201. ['L', this.chartWidth, maskTop],
  39202. ['L', this.chartWidth, maskBottom],
  39203. ['L', maskPlotRight, maskBottom],
  39204. ['Z']
  39205. ];
  39206. }
  39207. else if (this.scrollablePixelsY) {
  39208. d = [
  39209. // Top side
  39210. ['M', maskLeft, 0],
  39211. ['L', maskLeft, this.plotTop - 1],
  39212. ['L', maskRight, this.plotTop - 1],
  39213. ['L', maskRight, 0],
  39214. ['Z'],
  39215. // Bottom side
  39216. ['M', maskLeft, maskPlotBottom],
  39217. ['L', maskLeft, this.chartHeight],
  39218. ['L', maskRight, this.chartHeight],
  39219. ['L', maskRight, maskPlotBottom],
  39220. ['Z']
  39221. ];
  39222. }
  39223. else {
  39224. d = [['M', 0, 0]];
  39225. }
  39226. if (this.redrawTrigger !== 'adjustHeight') {
  39227. this.scrollableMask.attr({ d: d });
  39228. }
  39229. };
  39230. addEvent(Axis, 'afterInit', function () {
  39231. this.chart.scrollableDirty = true;
  39232. });
  39233. addEvent(Series, 'show', function () {
  39234. this.chart.scrollableDirty = true;
  39235. });
  39236. /* *
  39237. *
  39238. * API Declarations
  39239. *
  39240. * */
  39241. /**
  39242. * Options for a scrollable plot area. This feature provides a minimum size for
  39243. * the plot area of the chart. If the size gets smaller than this, typically
  39244. * on mobile devices, a native browser scrollbar is presented. This scrollbar
  39245. * provides smooth scrolling for the contents of the plot area, whereas the
  39246. * title, legend and unaffected axes are fixed.
  39247. *
  39248. * Since v7.1.2, a scrollable plot area can be defined for either horizontal or
  39249. * vertical scrolling, depending on whether the `minWidth` or `minHeight`
  39250. * option is set.
  39251. *
  39252. * @sample highcharts/chart/scrollable-plotarea
  39253. * Scrollable plot area
  39254. * @sample highcharts/chart/scrollable-plotarea-vertical
  39255. * Vertically scrollable plot area
  39256. * @sample {gantt} highcharts/chart/scrollable-plotarea-vertical
  39257. * Gantt chart with vertically scrollable plot area
  39258. *
  39259. * @since 6.1.0
  39260. * @product highcharts gantt
  39261. * @apioption chart.scrollablePlotArea
  39262. */
  39263. /**
  39264. * The minimum height for the plot area. If it gets smaller than this, the plot
  39265. * area will become scrollable.
  39266. *
  39267. * @type {number}
  39268. * @apioption chart.scrollablePlotArea.minHeight
  39269. */
  39270. /**
  39271. * The minimum width for the plot area. If it gets smaller than this, the plot
  39272. * area will become scrollable.
  39273. *
  39274. * @type {number}
  39275. * @apioption chart.scrollablePlotArea.minWidth
  39276. */
  39277. /**
  39278. * The initial scrolling position of the scrollable plot area. Ranges from 0 to
  39279. * 1, where 0 aligns the plot area to the left and 1 aligns it to the right.
  39280. * Typically we would use 1 if the chart has right aligned Y axes.
  39281. *
  39282. * @type {number}
  39283. * @apioption chart.scrollablePlotArea.scrollPositionX
  39284. */
  39285. /**
  39286. * The initial scrolling position of the scrollable plot area. Ranges from 0 to
  39287. * 1, where 0 aligns the plot area to the top and 1 aligns it to the bottom.
  39288. *
  39289. * @type {number}
  39290. * @apioption chart.scrollablePlotArea.scrollPositionY
  39291. */
  39292. /**
  39293. * The opacity of mask applied on one of the sides of the plot
  39294. * area.
  39295. *
  39296. * @sample {highcharts} highcharts/chart/scrollable-plotarea-opacity
  39297. * Disabled opacity for the mask
  39298. *
  39299. * @type {number}
  39300. * @default 0.85
  39301. * @since 7.1.1
  39302. * @apioption chart.scrollablePlotArea.opacity
  39303. */
  39304. (''); // keep doclets above in transpiled file
  39305. });
  39306. _registerModule(_modules, 'Core/Axis/StackingAxis.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Utilities.js']], function (A, U) {
  39307. /* *
  39308. *
  39309. * (c) 2010-2021 Torstein Honsi
  39310. *
  39311. * License: www.highcharts.com/license
  39312. *
  39313. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  39314. *
  39315. * */
  39316. var getDeferredAnimation = A.getDeferredAnimation;
  39317. var addEvent = U.addEvent,
  39318. destroyObjectProperties = U.destroyObjectProperties,
  39319. fireEvent = U.fireEvent,
  39320. isNumber = U.isNumber,
  39321. objectEach = U.objectEach,
  39322. pick = U.pick;
  39323. /* eslint-disable valid-jsdoc */
  39324. /**
  39325. * Adds stacking support to axes.
  39326. * @private
  39327. * @class
  39328. */
  39329. var StackingAxisAdditions = /** @class */ (function () {
  39330. /* *
  39331. *
  39332. * Constructors
  39333. *
  39334. * */
  39335. function StackingAxisAdditions(axis) {
  39336. this.oldStacks = {};
  39337. this.stacks = {};
  39338. this.stacksTouched = 0;
  39339. this.axis = axis;
  39340. }
  39341. /* *
  39342. *
  39343. * Functions
  39344. *
  39345. * */
  39346. /**
  39347. * Build the stacks from top down
  39348. * @private
  39349. */
  39350. StackingAxisAdditions.prototype.buildStacks = function () {
  39351. var stacking = this;
  39352. var axis = stacking.axis;
  39353. var axisSeries = axis.series;
  39354. var reversedStacks = axis.options.reversedStacks;
  39355. var len = axisSeries.length;
  39356. var actualSeries,
  39357. i;
  39358. if (!axis.isXAxis) {
  39359. stacking.usePercentage = false;
  39360. i = len;
  39361. while (i--) {
  39362. actualSeries = axisSeries[reversedStacks ? i : len - i - 1];
  39363. actualSeries.setStackedPoints();
  39364. actualSeries.setGroupedPoints();
  39365. }
  39366. // Loop up again to compute percent and stream stack
  39367. for (i = 0; i < len; i++) {
  39368. axisSeries[i].modifyStacks();
  39369. }
  39370. fireEvent(axis, 'afterBuildStacks');
  39371. }
  39372. };
  39373. /**
  39374. * @private
  39375. */
  39376. StackingAxisAdditions.prototype.cleanStacks = function () {
  39377. var stacking = this;
  39378. var axis = stacking.axis;
  39379. var stacks;
  39380. if (!axis.isXAxis) {
  39381. if (stacking.oldStacks) {
  39382. stacks = stacking.stacks = stacking.oldStacks;
  39383. }
  39384. // reset stacks
  39385. objectEach(stacks, function (type) {
  39386. objectEach(type, function (stack) {
  39387. stack.cumulative = stack.total;
  39388. });
  39389. });
  39390. }
  39391. };
  39392. /**
  39393. * Set all the stacks to initial states and destroy unused ones.
  39394. * @private
  39395. */
  39396. StackingAxisAdditions.prototype.resetStacks = function () {
  39397. var _this = this;
  39398. var _a = this,
  39399. axis = _a.axis,
  39400. stacks = _a.stacks;
  39401. if (!axis.isXAxis) {
  39402. objectEach(stacks, function (type) {
  39403. objectEach(type, function (stack, x) {
  39404. // Clean up memory after point deletion (#1044, #4320)
  39405. if (isNumber(stack.touched) &&
  39406. stack.touched < _this.stacksTouched) {
  39407. stack.destroy();
  39408. delete type[x];
  39409. // Reset stacks
  39410. }
  39411. else {
  39412. stack.total = null;
  39413. stack.cumulative = null;
  39414. }
  39415. });
  39416. });
  39417. }
  39418. };
  39419. /**
  39420. * @private
  39421. */
  39422. StackingAxisAdditions.prototype.renderStackTotals = function () {
  39423. var stacking = this;
  39424. var axis = stacking.axis;
  39425. var chart = axis.chart;
  39426. var renderer = chart.renderer;
  39427. var stacks = stacking.stacks;
  39428. var stackLabelsAnim = axis.options.stackLabels && axis.options.stackLabels.animation;
  39429. var animationConfig = getDeferredAnimation(chart,
  39430. stackLabelsAnim || false);
  39431. var stackTotalGroup = stacking.stackTotalGroup = (stacking.stackTotalGroup ||
  39432. renderer
  39433. .g('stack-labels')
  39434. .attr({
  39435. visibility: 'visible',
  39436. zIndex: 6,
  39437. opacity: 0
  39438. })
  39439. .add());
  39440. // plotLeft/Top will change when y axis gets wider so we need to
  39441. // translate the stackTotalGroup at every render call. See bug #506
  39442. // and #516
  39443. stackTotalGroup.translate(chart.plotLeft, chart.plotTop);
  39444. // Render each stack total
  39445. objectEach(stacks, function (type) {
  39446. objectEach(type, function (stack) {
  39447. stack.render(stackTotalGroup);
  39448. });
  39449. });
  39450. stackTotalGroup.animate({
  39451. opacity: 1
  39452. }, animationConfig);
  39453. };
  39454. return StackingAxisAdditions;
  39455. }());
  39456. /**
  39457. * Axis with stacking support.
  39458. * @private
  39459. * @class
  39460. */
  39461. var StackingAxis = /** @class */ (function () {
  39462. function StackingAxis() {
  39463. }
  39464. /* *
  39465. *
  39466. * Static Functions
  39467. *
  39468. * */
  39469. /**
  39470. * Extends axis with stacking support.
  39471. * @private
  39472. */
  39473. StackingAxis.compose = function (AxisClass) {
  39474. var axisProto = AxisClass.prototype;
  39475. addEvent(AxisClass, 'init', StackingAxis.onInit);
  39476. addEvent(AxisClass, 'destroy', StackingAxis.onDestroy);
  39477. };
  39478. /**
  39479. * @private
  39480. */
  39481. StackingAxis.onDestroy = function () {
  39482. var stacking = this.stacking;
  39483. if (!stacking) {
  39484. return;
  39485. }
  39486. var stacks = stacking.stacks;
  39487. // Destroy each stack total
  39488. objectEach(stacks, function (stack, stackKey) {
  39489. destroyObjectProperties(stack);
  39490. stacks[stackKey] = null;
  39491. });
  39492. if (stacking &&
  39493. stacking.stackTotalGroup) {
  39494. stacking.stackTotalGroup.destroy();
  39495. }
  39496. };
  39497. /**
  39498. * @private
  39499. */
  39500. StackingAxis.onInit = function () {
  39501. var axis = this;
  39502. if (!axis.stacking) {
  39503. axis.stacking = new StackingAxisAdditions(axis);
  39504. }
  39505. };
  39506. return StackingAxis;
  39507. }());
  39508. return StackingAxis;
  39509. });
  39510. _registerModule(_modules, 'Extensions/Stacking.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Chart/Chart.js'], _modules['Core/FormatUtilities.js'], _modules['Core/Globals.js'], _modules['Core/Series/Series.js'], _modules['Core/Axis/StackingAxis.js'], _modules['Core/Utilities.js']], function (Axis, Chart, F, H, Series, StackingAxis, U) {
  39511. /* *
  39512. *
  39513. * (c) 2010-2021 Torstein Honsi
  39514. *
  39515. * License: www.highcharts.com/license
  39516. *
  39517. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  39518. *
  39519. * */
  39520. var format = F.format;
  39521. var correctFloat = U.correctFloat,
  39522. defined = U.defined,
  39523. destroyObjectProperties = U.destroyObjectProperties,
  39524. isArray = U.isArray,
  39525. isNumber = U.isNumber,
  39526. objectEach = U.objectEach,
  39527. pick = U.pick;
  39528. /* *
  39529. *
  39530. * Class
  39531. *
  39532. * */
  39533. /* eslint-disable no-invalid-this, valid-jsdoc */
  39534. /**
  39535. * The class for stacks. Each stack, on a specific X value and either negative
  39536. * or positive, has its own stack item.
  39537. *
  39538. * @private
  39539. * @class
  39540. * @name Highcharts.StackItem
  39541. * @param {Highcharts.Axis} axis
  39542. * @param {Highcharts.YAxisStackLabelsOptions} options
  39543. * @param {boolean} isNegative
  39544. * @param {number} x
  39545. * @param {Highcharts.OptionsStackingValue} [stackOption]
  39546. */
  39547. var StackItem = /** @class */ (function () {
  39548. function StackItem(axis, options, isNegative, x, stackOption) {
  39549. var inverted = axis.chart.inverted;
  39550. this.axis = axis;
  39551. // Tells if the stack is negative
  39552. this.isNegative = isNegative;
  39553. // Save the options to be able to style the label
  39554. this.options = options = options || {};
  39555. // Save the x value to be able to position the label later
  39556. this.x = x;
  39557. // Initialize total value
  39558. this.total = null;
  39559. // This will keep each points' extremes stored by series.index and point
  39560. // index
  39561. this.points = {};
  39562. this.hasValidPoints = false;
  39563. // Save the stack option on the series configuration object,
  39564. // and whether to treat it as percent
  39565. this.stack = stackOption;
  39566. this.leftCliff = 0;
  39567. this.rightCliff = 0;
  39568. // The align options and text align varies on whether the stack is
  39569. // negative and if the chart is inverted or not.
  39570. // First test the user supplied value, then use the dynamic.
  39571. this.alignOptions = {
  39572. align: options.align ||
  39573. (inverted ? (isNegative ? 'left' : 'right') : 'center'),
  39574. verticalAlign: options.verticalAlign ||
  39575. (inverted ? 'middle' : (isNegative ? 'bottom' : 'top')),
  39576. y: options.y,
  39577. x: options.x
  39578. };
  39579. this.textAlign = options.textAlign ||
  39580. (inverted ? (isNegative ? 'right' : 'left') : 'center');
  39581. }
  39582. /**
  39583. * @private
  39584. * @function Highcharts.StackItem#destroy
  39585. */
  39586. StackItem.prototype.destroy = function () {
  39587. destroyObjectProperties(this, this.axis);
  39588. };
  39589. /**
  39590. * Renders the stack total label and adds it to the stack label group.
  39591. *
  39592. * @private
  39593. * @function Highcharts.StackItem#render
  39594. * @param {Highcharts.SVGElement} group
  39595. */
  39596. StackItem.prototype.render = function (group) {
  39597. var chart = this.axis.chart,
  39598. options = this.options,
  39599. formatOption = options.format,
  39600. attr = {},
  39601. str = formatOption ? // format the text in the label
  39602. format(formatOption,
  39603. this,
  39604. chart) :
  39605. options.formatter.call(this);
  39606. // Change the text to reflect the new total and set visibility to hidden
  39607. // in case the serie is hidden
  39608. if (this.label) {
  39609. this.label.attr({ text: str, visibility: 'hidden' });
  39610. }
  39611. else {
  39612. // Create new label
  39613. this.label = chart.renderer
  39614. .label(str, null, null, options.shape, null, null, options.useHTML, false, 'stack-labels');
  39615. attr = {
  39616. r: options.borderRadius || 0,
  39617. text: str,
  39618. rotation: options.rotation,
  39619. padding: pick(options.padding, 5),
  39620. visibility: 'hidden' // hidden until setOffset is called
  39621. };
  39622. if (!chart.styledMode) {
  39623. attr.fill = options.backgroundColor;
  39624. attr.stroke = options.borderColor;
  39625. attr['stroke-width'] = options.borderWidth;
  39626. this.label.css(options.style);
  39627. }
  39628. this.label.attr(attr);
  39629. if (!this.label.added) {
  39630. this.label.add(group); // add to the labels-group
  39631. }
  39632. }
  39633. // Rank it higher than data labels (#8742)
  39634. this.label.labelrank = chart.plotSizeY;
  39635. };
  39636. /**
  39637. * Sets the offset that the stack has from the x value and repositions the
  39638. * label.
  39639. *
  39640. * @private
  39641. * @function Highcarts.StackItem#setOffset
  39642. * @param {number} xOffset
  39643. * @param {number} xWidth
  39644. * @param {number} [boxBottom]
  39645. * @param {number} [boxTop]
  39646. * @param {number} [defaultX]
  39647. */
  39648. StackItem.prototype.setOffset = function (xOffset, xWidth, boxBottom, boxTop, defaultX) {
  39649. var stackItem = this,
  39650. axis = stackItem.axis,
  39651. chart = axis.chart,
  39652. // stack value translated mapped to chart coordinates
  39653. y = axis.translate(axis.stacking.usePercentage ?
  39654. 100 :
  39655. (boxTop ?
  39656. boxTop :
  39657. stackItem.total), 0, 0, 0, 1),
  39658. yZero = axis.translate(boxBottom ? boxBottom : 0), // stack origin
  39659. // stack height:
  39660. h = defined(y) && Math.abs(y - yZero),
  39661. // x position:
  39662. x = pick(defaultX,
  39663. chart.xAxis[0].translate(stackItem.x)) +
  39664. xOffset,
  39665. stackBox = defined(y) && stackItem.getStackBox(chart,
  39666. stackItem,
  39667. x,
  39668. y,
  39669. xWidth,
  39670. h,
  39671. axis),
  39672. label = stackItem.label,
  39673. isNegative = stackItem.isNegative,
  39674. isJustify = pick(stackItem.options.overflow, 'justify') === 'justify',
  39675. textAlign = stackItem.textAlign,
  39676. visible;
  39677. if (label && stackBox) {
  39678. var bBox = label.getBBox(),
  39679. padding = label.padding,
  39680. boxOffsetX = void 0,
  39681. boxOffsetY = void 0;
  39682. if (textAlign === 'left') {
  39683. boxOffsetX = chart.inverted ? -padding : padding;
  39684. }
  39685. else if (textAlign === 'right') {
  39686. boxOffsetX = bBox.width;
  39687. }
  39688. else {
  39689. if (chart.inverted && textAlign === 'center') {
  39690. boxOffsetX = bBox.width / 2;
  39691. }
  39692. else {
  39693. boxOffsetX = chart.inverted ?
  39694. (isNegative ? bBox.width + padding : -padding) : bBox.width / 2;
  39695. }
  39696. }
  39697. boxOffsetY = chart.inverted ?
  39698. bBox.height / 2 : (isNegative ? -padding : bBox.height);
  39699. // Reset alignOptions property after justify #12337
  39700. stackItem.alignOptions.x = pick(stackItem.options.x, 0);
  39701. stackItem.alignOptions.y = pick(stackItem.options.y, 0);
  39702. // Set the stackBox position
  39703. stackBox.x -= boxOffsetX;
  39704. stackBox.y -= boxOffsetY;
  39705. // Align the label to the box
  39706. label.align(stackItem.alignOptions, null, stackBox);
  39707. // Check if label is inside the plotArea #12294
  39708. if (chart.isInsidePlot(label.alignAttr.x + boxOffsetX - stackItem.alignOptions.x, label.alignAttr.y + boxOffsetY - stackItem.alignOptions.y)) {
  39709. label.show();
  39710. }
  39711. else {
  39712. // Move label away to avoid the overlapping issues
  39713. label.alignAttr.y = -9999;
  39714. isJustify = false;
  39715. }
  39716. if (isJustify) {
  39717. // Justify stackLabel into the stackBox
  39718. Series.prototype.justifyDataLabel.call(this.axis, label, stackItem.alignOptions, label.alignAttr, bBox, stackBox);
  39719. }
  39720. label.attr({
  39721. x: label.alignAttr.x,
  39722. y: label.alignAttr.y
  39723. });
  39724. if (pick(!isJustify && stackItem.options.crop, true)) {
  39725. visible =
  39726. isNumber(label.x) &&
  39727. isNumber(label.y) &&
  39728. chart.isInsidePlot(label.x - padding + label.width, label.y) &&
  39729. chart.isInsidePlot(label.x + padding, label.y);
  39730. if (!visible) {
  39731. label.hide();
  39732. }
  39733. }
  39734. }
  39735. };
  39736. /**
  39737. * @private
  39738. * @function Highcharts.StackItem#getStackBox
  39739. *
  39740. * @param {Highcharts.Chart} chart
  39741. *
  39742. * @param {Highcharts.StackItem} stackItem
  39743. *
  39744. * @param {number} x
  39745. *
  39746. * @param {number} y
  39747. *
  39748. * @param {number} xWidth
  39749. *
  39750. * @param {number} h
  39751. *
  39752. * @param {Highcharts.Axis} axis
  39753. *
  39754. * @return {Highcharts.BBoxObject}
  39755. */
  39756. StackItem.prototype.getStackBox = function (chart, stackItem, x, y, xWidth, h, axis) {
  39757. var reversed = stackItem.axis.reversed,
  39758. inverted = chart.inverted,
  39759. axisPos = axis.height + axis.pos -
  39760. (inverted ? chart.plotLeft : chart.plotTop),
  39761. neg = (stackItem.isNegative && !reversed) ||
  39762. (!stackItem.isNegative && reversed); // #4056
  39763. return {
  39764. x: inverted ? (neg ? y - axis.right : y - h + axis.pos - chart.plotLeft) :
  39765. x + chart.xAxis[0].transB - chart.plotLeft,
  39766. y: inverted ?
  39767. axis.height - x - xWidth :
  39768. (neg ?
  39769. (axisPos - y - h) :
  39770. axisPos - y),
  39771. width: inverted ? h : xWidth,
  39772. height: inverted ? xWidth : h
  39773. };
  39774. };
  39775. return StackItem;
  39776. }());
  39777. /**
  39778. * Generate stacks for each series and calculate stacks total values
  39779. *
  39780. * @private
  39781. * @function Highcharts.Chart#getStacks
  39782. */
  39783. Chart.prototype.getStacks = function () {
  39784. var chart = this,
  39785. inverted = chart.inverted;
  39786. // reset stacks for each yAxis
  39787. chart.yAxis.forEach(function (axis) {
  39788. if (axis.stacking && axis.stacking.stacks && axis.hasVisibleSeries) {
  39789. axis.stacking.oldStacks = axis.stacking.stacks;
  39790. }
  39791. });
  39792. chart.series.forEach(function (series) {
  39793. var xAxisOptions = series.xAxis && series.xAxis.options || {};
  39794. if (series.options.stacking &&
  39795. (series.visible === true ||
  39796. chart.options.chart.ignoreHiddenSeries === false)) {
  39797. series.stackKey = [
  39798. series.type,
  39799. pick(series.options.stack, ''),
  39800. inverted ? xAxisOptions.top : xAxisOptions.left,
  39801. inverted ? xAxisOptions.height : xAxisOptions.width
  39802. ].join(',');
  39803. }
  39804. });
  39805. };
  39806. // Stacking methods defined on the Axis prototype
  39807. StackingAxis.compose(Axis);
  39808. // Stacking methods defined for Series prototype
  39809. /**
  39810. * Set grouped points in a stack-like object. When `centerInCategory` is true,
  39811. * and `stacking` is not enabled, we need a pseudo (horizontal) stack in order
  39812. * to handle grouping of points within the same category.
  39813. *
  39814. * @private
  39815. * @function Highcharts.Series#setStackedPoints
  39816. * @return {void}
  39817. */
  39818. Series.prototype.setGroupedPoints = function () {
  39819. var stacking = this.yAxis.stacking;
  39820. if (this.options.centerInCategory &&
  39821. (this.is('column') || this.is('columnrange')) &&
  39822. // With stacking enabled, we already have stacks that we can compute
  39823. // from
  39824. !this.options.stacking &&
  39825. // With only one series, we don't need to consider centerInCategory
  39826. this.chart.series.length > 1) {
  39827. Series.prototype.setStackedPoints.call(this, 'group');
  39828. // After updating, if we now have proper stacks, we must delete the group
  39829. // pseudo stacks (#14986)
  39830. }
  39831. else if (stacking) {
  39832. objectEach(stacking.stacks, function (type, key) {
  39833. if (key.slice(-5) === 'group') {
  39834. objectEach(type, function (stack) { return stack.destroy(); });
  39835. delete stacking.stacks[key];
  39836. }
  39837. });
  39838. }
  39839. };
  39840. /**
  39841. * Adds series' points value to corresponding stack
  39842. *
  39843. * @private
  39844. * @function Highcharts.Series#setStackedPoints
  39845. */
  39846. Series.prototype.setStackedPoints = function (stackingParam) {
  39847. var stacking = stackingParam || this.options.stacking;
  39848. if (!stacking || (this.visible !== true &&
  39849. this.chart.options.chart.ignoreHiddenSeries !== false)) {
  39850. return;
  39851. }
  39852. var series = this, xData = series.processedXData, yData = series.processedYData, stackedYData = [], yDataLength = yData.length, seriesOptions = series.options, threshold = seriesOptions.threshold, stackThreshold = pick(seriesOptions.startFromThreshold && threshold, 0), stackOption = seriesOptions.stack, stackKey = stackingParam ? series.type + "," + stacking : series.stackKey, negKey = '-' + stackKey, negStacks = series.negStacks, yAxis = series.yAxis, stacks = yAxis.stacking.stacks, oldStacks = yAxis.stacking.oldStacks, stackIndicator, isNegative, stack, other, key, pointKey, i, x, y;
  39853. yAxis.stacking.stacksTouched += 1;
  39854. // loop over the non-null y values and read them into a local array
  39855. for (i = 0; i < yDataLength; i++) {
  39856. x = xData[i];
  39857. y = yData[i];
  39858. stackIndicator = series.getStackIndicator(stackIndicator, x, series.index);
  39859. pointKey = stackIndicator.key;
  39860. // Read stacked values into a stack based on the x value,
  39861. // the sign of y and the stack key. Stacking is also handled for null
  39862. // values (#739)
  39863. isNegative = negStacks && y < (stackThreshold ? 0 : threshold);
  39864. key = isNegative ? negKey : stackKey;
  39865. // Create empty object for this stack if it doesn't exist yet
  39866. if (!stacks[key]) {
  39867. stacks[key] = {};
  39868. }
  39869. // Initialize StackItem for this x
  39870. if (!stacks[key][x]) {
  39871. if (oldStacks[key] &&
  39872. oldStacks[key][x]) {
  39873. stacks[key][x] = oldStacks[key][x];
  39874. stacks[key][x].total = null;
  39875. }
  39876. else {
  39877. stacks[key][x] = new StackItem(yAxis, yAxis.options.stackLabels, isNegative, x, stackOption);
  39878. }
  39879. }
  39880. // If the StackItem doesn't exist, create it first
  39881. stack = stacks[key][x];
  39882. if (y !== null) {
  39883. stack.points[pointKey] = stack.points[series.index] =
  39884. [pick(stack.cumulative, stackThreshold)];
  39885. // Record the base of the stack
  39886. if (!defined(stack.cumulative)) {
  39887. stack.base = pointKey;
  39888. }
  39889. stack.touched = yAxis.stacking.stacksTouched;
  39890. // In area charts, if there are multiple points on the same X value,
  39891. // let the area fill the full span of those points
  39892. if (stackIndicator.index > 0 && series.singleStacks === false) {
  39893. stack.points[pointKey][0] =
  39894. stack.points[series.index + ',' + x + ',0'][0];
  39895. }
  39896. // When updating to null, reset the point stack (#7493)
  39897. }
  39898. else {
  39899. stack.points[pointKey] = stack.points[series.index] =
  39900. null;
  39901. }
  39902. // Add value to the stack total
  39903. if (stacking === 'percent') {
  39904. // Percent stacked column, totals are the same for the positive and
  39905. // negative stacks
  39906. other = isNegative ? stackKey : negKey;
  39907. if (negStacks && stacks[other] && stacks[other][x]) {
  39908. other = stacks[other][x];
  39909. stack.total = other.total =
  39910. Math.max(other.total, stack.total) +
  39911. Math.abs(y) ||
  39912. 0;
  39913. // Percent stacked areas
  39914. }
  39915. else {
  39916. stack.total =
  39917. correctFloat(stack.total + (Math.abs(y) || 0));
  39918. }
  39919. }
  39920. else if (stacking === 'group') {
  39921. if (isArray(y)) {
  39922. y = y[0];
  39923. }
  39924. // In this stack, the total is the number of valid points
  39925. if (y !== null) {
  39926. stack.total = (stack.total || 0) + 1;
  39927. }
  39928. }
  39929. else {
  39930. stack.total = correctFloat(stack.total + (y || 0));
  39931. }
  39932. if (stacking === 'group') {
  39933. // This point's index within the stack, pushed to stack.points[1]
  39934. stack.cumulative = (stack.total || 1) - 1;
  39935. }
  39936. else {
  39937. stack.cumulative =
  39938. pick(stack.cumulative, stackThreshold) + (y || 0);
  39939. }
  39940. if (y !== null) {
  39941. stack.points[pointKey].push(stack.cumulative);
  39942. stackedYData[i] = stack.cumulative;
  39943. stack.hasValidPoints = true;
  39944. }
  39945. }
  39946. if (stacking === 'percent') {
  39947. yAxis.stacking.usePercentage = true;
  39948. }
  39949. if (stacking !== 'group') {
  39950. this.stackedYData = stackedYData; // To be used in getExtremes
  39951. }
  39952. // Reset old stacks
  39953. yAxis.stacking.oldStacks = {};
  39954. };
  39955. /**
  39956. * Iterate over all stacks and compute the absolute values to percent
  39957. *
  39958. * @private
  39959. * @function Highcharts.Series#modifyStacks
  39960. */
  39961. Series.prototype.modifyStacks = function () {
  39962. var series = this,
  39963. yAxis = series.yAxis,
  39964. stackKey = series.stackKey,
  39965. stacks = yAxis.stacking.stacks,
  39966. processedXData = series.processedXData,
  39967. stackIndicator,
  39968. stacking = series.options.stacking;
  39969. if (series[stacking + 'Stacker']) { // Modifier function exists
  39970. [stackKey, '-' + stackKey].forEach(function (key) {
  39971. var i = processedXData.length,
  39972. x,
  39973. stack,
  39974. pointExtremes;
  39975. while (i--) {
  39976. x = processedXData[i];
  39977. stackIndicator = series.getStackIndicator(stackIndicator, x, series.index, key);
  39978. stack = stacks[key] && stacks[key][x];
  39979. pointExtremes =
  39980. stack && stack.points[stackIndicator.key];
  39981. if (pointExtremes) {
  39982. series[stacking + 'Stacker'](pointExtremes, stack, i);
  39983. }
  39984. }
  39985. });
  39986. }
  39987. };
  39988. /**
  39989. * Modifier function for percent stacks. Blows up the stack to 100%.
  39990. *
  39991. * @private
  39992. * @function Highcharts.Series#percentStacker
  39993. */
  39994. Series.prototype.percentStacker = function (pointExtremes, stack, i) {
  39995. var totalFactor = stack.total ? 100 / stack.total : 0;
  39996. // Y bottom value
  39997. pointExtremes[0] = correctFloat(pointExtremes[0] * totalFactor);
  39998. // Y value
  39999. pointExtremes[1] = correctFloat(pointExtremes[1] * totalFactor);
  40000. this.stackedYData[i] = pointExtremes[1];
  40001. };
  40002. /**
  40003. * Get stack indicator, according to it's x-value, to determine points with the
  40004. * same x-value
  40005. *
  40006. * @private
  40007. * @function Highcharts.Series#getStackIndicator
  40008. * @param {Highcharts.StackItemIndicatorObject|undefined} stackIndicator
  40009. * @param {number} x
  40010. * @param {number} index
  40011. * @param {string} [key]
  40012. * @return {Highcharts.StackItemIndicatorObject}
  40013. */
  40014. Series.prototype.getStackIndicator = function (stackIndicator, x, index, key) {
  40015. // Update stack indicator, when:
  40016. // first point in a stack || x changed || stack type (negative vs positive)
  40017. // changed:
  40018. if (!defined(stackIndicator) ||
  40019. stackIndicator.x !== x ||
  40020. (key && stackIndicator.key !== key)) {
  40021. stackIndicator = {
  40022. x: x,
  40023. index: 0,
  40024. key: key
  40025. };
  40026. }
  40027. else {
  40028. (stackIndicator).index++;
  40029. }
  40030. stackIndicator.key =
  40031. [index, x, stackIndicator.index].join(',');
  40032. return stackIndicator;
  40033. };
  40034. H.StackItem = StackItem; // @todo -> master
  40035. /* *
  40036. *
  40037. * Default Export
  40038. *
  40039. * */
  40040. /**
  40041. * Stack of data points
  40042. *
  40043. * @product highcharts
  40044. *
  40045. * @interface Highcharts.StackItemObject
  40046. */ /**
  40047. * Alignment settings
  40048. * @name Highcharts.StackItemObject#alignOptions
  40049. * @type {Highcharts.AlignObject}
  40050. */ /**
  40051. * Related axis
  40052. * @name Highcharts.StackItemObject#axis
  40053. * @type {Highcharts.Axis}
  40054. */ /**
  40055. * Cumulative value of the stacked data points
  40056. * @name Highcharts.StackItemObject#cumulative
  40057. * @type {number}
  40058. */ /**
  40059. * True if on the negative side
  40060. * @name Highcharts.StackItemObject#isNegative
  40061. * @type {boolean}
  40062. */ /**
  40063. * Related SVG element
  40064. * @name Highcharts.StackItemObject#label
  40065. * @type {Highcharts.SVGElement}
  40066. */ /**
  40067. * Related stack options
  40068. * @name Highcharts.StackItemObject#options
  40069. * @type {Highcharts.YAxisStackLabelsOptions}
  40070. */ /**
  40071. * Total value of the stacked data points
  40072. * @name Highcharts.StackItemObject#total
  40073. * @type {number}
  40074. */ /**
  40075. * Shared x value of the stack
  40076. * @name Highcharts.StackItemObject#x
  40077. * @type {number}
  40078. */
  40079. ''; // keeps doclets above in JS file
  40080. return H.StackItem;
  40081. });
  40082. _registerModule(_modules, 'Series/Line/LineSeries.js', [_modules['Core/Color/Palette.js'], _modules['Core/Series/Series.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (palette, Series, SeriesRegistry, U) {
  40083. /* *
  40084. *
  40085. * (c) 2010-2021 Torstein Honsi
  40086. *
  40087. * License: www.highcharts.com/license
  40088. *
  40089. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  40090. *
  40091. * */
  40092. var __extends = (this && this.__extends) || (function () {
  40093. var extendStatics = function (d,
  40094. b) {
  40095. extendStatics = Object.setPrototypeOf ||
  40096. ({ __proto__: [] } instanceof Array && function (d,
  40097. b) { d.__proto__ = b; }) ||
  40098. function (d,
  40099. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  40100. return extendStatics(d, b);
  40101. };
  40102. return function (d, b) {
  40103. extendStatics(d, b);
  40104. function __() { this.constructor = d; }
  40105. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  40106. };
  40107. })();
  40108. var defined = U.defined,
  40109. merge = U.merge;
  40110. /* *
  40111. *
  40112. * Class
  40113. *
  40114. * */
  40115. /**
  40116. * The line series is the base type and is therefor the series base prototype.
  40117. *
  40118. * @private
  40119. */
  40120. var LineSeries = /** @class */ (function (_super) {
  40121. __extends(LineSeries, _super);
  40122. function LineSeries() {
  40123. /* *
  40124. *
  40125. * Static Functions
  40126. *
  40127. * */
  40128. var _this = _super !== null && _super.apply(this,
  40129. arguments) || this;
  40130. /* *
  40131. *
  40132. * Properties
  40133. *
  40134. * */
  40135. _this.data = void 0;
  40136. _this.options = void 0;
  40137. _this.points = void 0;
  40138. return _this;
  40139. }
  40140. /* *
  40141. *
  40142. * Functions
  40143. *
  40144. * */
  40145. /**
  40146. * Draw the graph. Called internally when rendering line-like series
  40147. * types. The first time it generates the `series.graph` item and
  40148. * optionally other series-wide items like `series.area` for area
  40149. * charts. On subsequent calls these items are updated with new
  40150. * positions and attributes.
  40151. *
  40152. * @function Highcharts.Series#drawGraph
  40153. */
  40154. LineSeries.prototype.drawGraph = function () {
  40155. var series = this,
  40156. options = this.options,
  40157. graphPath = (this.gappedPath || this.getGraphPath).call(this),
  40158. styledMode = this.chart.styledMode,
  40159. props = [[
  40160. 'graph',
  40161. 'highcharts-graph'
  40162. ]];
  40163. // Presentational properties
  40164. if (!styledMode) {
  40165. props[0].push((options.lineColor ||
  40166. this.color ||
  40167. palette.neutralColor20 // when colorByPoint = true
  40168. ), options.dashStyle);
  40169. }
  40170. props = series.getZonesGraphs(props);
  40171. // Draw the graph
  40172. props.forEach(function (prop, i) {
  40173. var graphKey = prop[0],
  40174. graph = series[graphKey],
  40175. verb = graph ? 'animate' : 'attr',
  40176. attribs;
  40177. if (graph) {
  40178. graph.endX = series.preventGraphAnimation ?
  40179. null :
  40180. graphPath.xMap;
  40181. graph.animate({ d: graphPath });
  40182. }
  40183. else if (graphPath.length) { // #1487
  40184. /**
  40185. * SVG element of area-based charts. Can be used for styling
  40186. * purposes. If zones are configured, this element will be
  40187. * hidden and replaced by multiple zone areas, accessible
  40188. * via `series['zone-area-x']` (where x is a number,
  40189. * starting with 0).
  40190. *
  40191. * @name Highcharts.Series#area
  40192. * @type {Highcharts.SVGElement|undefined}
  40193. */
  40194. /**
  40195. * SVG element of line-based charts. Can be used for styling
  40196. * purposes. If zones are configured, this element will be
  40197. * hidden and replaced by multiple zone lines, accessible
  40198. * via `series['zone-graph-x']` (where x is a number,
  40199. * starting with 0).
  40200. *
  40201. * @name Highcharts.Series#graph
  40202. * @type {Highcharts.SVGElement|undefined}
  40203. */
  40204. series[graphKey] = graph = series.chart.renderer
  40205. .path(graphPath)
  40206. .addClass(prop[1])
  40207. .attr({ zIndex: 1 }) // #1069
  40208. .add(series.group);
  40209. }
  40210. if (graph && !styledMode) {
  40211. attribs = {
  40212. 'stroke': prop[2],
  40213. 'stroke-width': options.lineWidth,
  40214. // Polygon series use filled graph
  40215. 'fill': (series.fillGraph && series.color) || 'none'
  40216. };
  40217. if (prop[3]) {
  40218. attribs.dashstyle = prop[3];
  40219. }
  40220. else if (options.linecap !== 'square') {
  40221. attribs['stroke-linecap'] =
  40222. attribs['stroke-linejoin'] = 'round';
  40223. }
  40224. graph[verb](attribs)
  40225. // Add shadow to normal series (0) or to first
  40226. // zone (1) #3932
  40227. .shadow((i < 2) && options.shadow);
  40228. }
  40229. // Helpers for animation
  40230. if (graph) {
  40231. graph.startX = graphPath.xMap;
  40232. graph.isArea = graphPath.isArea; // For arearange animation
  40233. }
  40234. });
  40235. };
  40236. // eslint-disable-next-line valid-jsdoc
  40237. /**
  40238. * Get the graph path.
  40239. *
  40240. * @private
  40241. */
  40242. LineSeries.prototype.getGraphPath = function (points, nullsAsZeroes, connectCliffs) {
  40243. var series = this,
  40244. options = series.options,
  40245. step = options.step,
  40246. reversed,
  40247. graphPath = [],
  40248. xMap = [],
  40249. gap;
  40250. points = points || series.points;
  40251. // Bottom of a stack is reversed
  40252. reversed = points.reversed;
  40253. if (reversed) {
  40254. points.reverse();
  40255. }
  40256. // Reverse the steps (#5004)
  40257. step = {
  40258. right: 1,
  40259. center: 2
  40260. }[step] || (step && 3);
  40261. if (step && reversed) {
  40262. step = 4 - step;
  40263. }
  40264. // Remove invalid points, especially in spline (#5015)
  40265. points = this.getValidPoints(points, false, !(options.connectNulls && !nullsAsZeroes && !connectCliffs));
  40266. // Build the line
  40267. points.forEach(function (point, i) {
  40268. var plotX = point.plotX,
  40269. plotY = point.plotY,
  40270. lastPoint = points[i - 1],
  40271. // the path to this point from the previous
  40272. pathToPoint;
  40273. if ((point.leftCliff || (lastPoint && lastPoint.rightCliff)) &&
  40274. !connectCliffs) {
  40275. gap = true; // ... and continue
  40276. }
  40277. // Line series, nullsAsZeroes is not handled
  40278. if (point.isNull && !defined(nullsAsZeroes) && i > 0) {
  40279. gap = !options.connectNulls;
  40280. // Area series, nullsAsZeroes is set
  40281. }
  40282. else if (point.isNull && !nullsAsZeroes) {
  40283. gap = true;
  40284. }
  40285. else {
  40286. if (i === 0 || gap) {
  40287. pathToPoint = [[
  40288. 'M',
  40289. point.plotX,
  40290. point.plotY
  40291. ]];
  40292. // Generate the spline as defined in the SplineSeries object
  40293. }
  40294. else if (series.getPointSpline) {
  40295. pathToPoint = [series.getPointSpline(points, point, i)];
  40296. }
  40297. else if (step) {
  40298. if (step === 1) { // right
  40299. pathToPoint = [[
  40300. 'L',
  40301. lastPoint.plotX,
  40302. plotY
  40303. ]];
  40304. }
  40305. else if (step === 2) { // center
  40306. pathToPoint = [[
  40307. 'L',
  40308. (lastPoint.plotX + plotX) / 2,
  40309. lastPoint.plotY
  40310. ], [
  40311. 'L',
  40312. (lastPoint.plotX + plotX) / 2,
  40313. plotY
  40314. ]];
  40315. }
  40316. else {
  40317. pathToPoint = [[
  40318. 'L',
  40319. plotX,
  40320. lastPoint.plotY
  40321. ]];
  40322. }
  40323. pathToPoint.push([
  40324. 'L',
  40325. plotX,
  40326. plotY
  40327. ]);
  40328. }
  40329. else {
  40330. // normal line to next point
  40331. pathToPoint = [[
  40332. 'L',
  40333. plotX,
  40334. plotY
  40335. ]];
  40336. }
  40337. // Prepare for animation. When step is enabled, there are
  40338. // two path nodes for each x value.
  40339. xMap.push(point.x);
  40340. if (step) {
  40341. xMap.push(point.x);
  40342. if (step === 2) { // step = center (#8073)
  40343. xMap.push(point.x);
  40344. }
  40345. }
  40346. graphPath.push.apply(graphPath, pathToPoint);
  40347. gap = false;
  40348. }
  40349. });
  40350. graphPath.xMap = xMap;
  40351. series.graphPath = graphPath;
  40352. return graphPath;
  40353. };
  40354. // eslint-disable-next-line valid-jsdoc
  40355. /**
  40356. * Get zones properties for building graphs. Extendable by series with
  40357. * multiple lines within one series.
  40358. *
  40359. * @private
  40360. */
  40361. LineSeries.prototype.getZonesGraphs = function (props) {
  40362. // Add the zone properties if any
  40363. this.zones.forEach(function (zone, i) {
  40364. var propset = [
  40365. 'zone-graph-' + i,
  40366. 'highcharts-graph highcharts-zone-graph-' + i + ' ' +
  40367. (zone.className || '')
  40368. ];
  40369. if (!this.chart.styledMode) {
  40370. propset.push((zone.color || this.color), (zone.dashStyle || this.options.dashStyle));
  40371. }
  40372. props.push(propset);
  40373. }, this);
  40374. return props;
  40375. };
  40376. /**
  40377. * General options for all series types.
  40378. *
  40379. * @optionparent plotOptions.series
  40380. */
  40381. LineSeries.defaultOptions = merge(Series.defaultOptions, {
  40382. // nothing here yet
  40383. });
  40384. return LineSeries;
  40385. }(Series));
  40386. SeriesRegistry.registerSeriesType('line', LineSeries);
  40387. /* *
  40388. *
  40389. * Default Export
  40390. *
  40391. * */
  40392. /* *
  40393. *
  40394. * API Options
  40395. *
  40396. * */
  40397. /**
  40398. * A line series displays information as a series of data points connected by
  40399. * straight line segments.
  40400. *
  40401. * @sample {highcharts} highcharts/demo/line-basic/
  40402. * Line chart
  40403. * @sample {highstock} stock/demo/basic-line/
  40404. * Line chart
  40405. *
  40406. * @extends plotOptions.series
  40407. * @product highcharts highstock
  40408. * @apioption plotOptions.line
  40409. */
  40410. /**
  40411. * The SVG value used for the `stroke-linecap` and `stroke-linejoin`
  40412. * of a line graph. Round means that lines are rounded in the ends and
  40413. * bends.
  40414. *
  40415. * @type {Highcharts.SeriesLinecapValue}
  40416. * @default round
  40417. * @since 3.0.7
  40418. * @apioption plotOptions.line.linecap
  40419. */
  40420. /**
  40421. * A `line` series. If the [type](#series.line.type) option is not
  40422. * specified, it is inherited from [chart.type](#chart.type).
  40423. *
  40424. * @extends series,plotOptions.line
  40425. * @excluding dataParser,dataURL
  40426. * @product highcharts highstock
  40427. * @apioption series.line
  40428. */
  40429. /**
  40430. * An array of data points for the series. For the `line` series type,
  40431. * points can be given in the following ways:
  40432. *
  40433. * 1. An array of numerical values. In this case, the numerical values will be
  40434. * interpreted as `y` options. The `x` values will be automatically
  40435. * calculated, either starting at 0 and incremented by 1, or from
  40436. * `pointStart` and `pointInterval` given in the series options. If the axis
  40437. * has categories, these will be used. Example:
  40438. * ```js
  40439. * data: [0, 5, 3, 5]
  40440. * ```
  40441. *
  40442. * 2. An array of arrays with 2 values. In this case, the values correspond to
  40443. * `x,y`. If the first value is a string, it is applied as the name of the
  40444. * point, and the `x` value is inferred.
  40445. * ```js
  40446. * data: [
  40447. * [0, 1],
  40448. * [1, 2],
  40449. * [2, 8]
  40450. * ]
  40451. * ```
  40452. *
  40453. * 3. An array of objects with named values. The following snippet shows only a
  40454. * few settings, see the complete options set below. If the total number of
  40455. * data points exceeds the series'
  40456. * [turboThreshold](#series.line.turboThreshold),
  40457. * this option is not available.
  40458. * ```js
  40459. * data: [{
  40460. * x: 1,
  40461. * y: 9,
  40462. * name: "Point2",
  40463. * color: "#00FF00"
  40464. * }, {
  40465. * x: 1,
  40466. * y: 6,
  40467. * name: "Point1",
  40468. * color: "#FF00FF"
  40469. * }]
  40470. * ```
  40471. *
  40472. * **Note:** In TypeScript you have to extend `PointOptionsObject` with an
  40473. * additional declaration to allow custom data types:
  40474. * ```ts
  40475. * declare module `highcharts` {
  40476. * interface PointOptionsObject {
  40477. * custom: Record<string, (boolean|number|string)>;
  40478. * }
  40479. * }
  40480. * ```
  40481. *
  40482. * @sample {highcharts} highcharts/chart/reflow-true/
  40483. * Numerical values
  40484. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  40485. * Arrays of numeric x and y
  40486. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  40487. * Arrays of datetime x and y
  40488. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  40489. * Arrays of point.name and y
  40490. * @sample {highcharts} highcharts/series/data-array-of-objects/
  40491. * Config objects
  40492. *
  40493. * @declare Highcharts.PointOptionsObject
  40494. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  40495. * @apioption series.line.data
  40496. */
  40497. /**
  40498. * An additional, individual class name for the data point's graphic
  40499. * representation.
  40500. *
  40501. * @type {string}
  40502. * @since 5.0.0
  40503. * @product highcharts gantt
  40504. * @apioption series.line.data.className
  40505. */
  40506. /**
  40507. * Individual color for the point. By default the color is pulled from
  40508. * the global `colors` array.
  40509. *
  40510. * In styled mode, the `color` option doesn't take effect. Instead, use
  40511. * `colorIndex`.
  40512. *
  40513. * @sample {highcharts} highcharts/point/color/
  40514. * Mark the highest point
  40515. *
  40516. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  40517. * @product highcharts highstock gantt
  40518. * @apioption series.line.data.color
  40519. */
  40520. /**
  40521. * A specific color index to use for the point, so its graphic representations
  40522. * are given the class name `highcharts-color-{n}`. In styled mode this will
  40523. * change the color of the graphic. In non-styled mode, the color by is set by
  40524. * the `fill` attribute, so the change in class name won't have a visual effect
  40525. * by default.
  40526. *
  40527. * @type {number}
  40528. * @since 5.0.0
  40529. * @product highcharts gantt
  40530. * @apioption series.line.data.colorIndex
  40531. */
  40532. /**
  40533. * A reserved subspace to store options and values for customized functionality.
  40534. * Here you can add additional data for your own event callbacks and formatter
  40535. * callbacks.
  40536. *
  40537. * @sample {highcharts} highcharts/point/custom/
  40538. * Point and series with custom data
  40539. *
  40540. * @type {Highcharts.Dictionary<*>}
  40541. * @apioption series.line.data.custom
  40542. */
  40543. /**
  40544. * Individual data label for each point. The options are the same as
  40545. * the ones for [plotOptions.series.dataLabels](
  40546. * #plotOptions.series.dataLabels).
  40547. *
  40548. * @sample highcharts/point/datalabels/
  40549. * Show a label for the last value
  40550. *
  40551. * @declare Highcharts.DataLabelsOptions
  40552. * @extends plotOptions.line.dataLabels
  40553. * @product highcharts highstock gantt
  40554. * @apioption series.line.data.dataLabels
  40555. */
  40556. /**
  40557. * A description of the point to add to the screen reader information
  40558. * about the point.
  40559. *
  40560. * @type {string}
  40561. * @since 5.0.0
  40562. * @requires modules/accessibility
  40563. * @apioption series.line.data.description
  40564. */
  40565. /**
  40566. * An id for the point. This can be used after render time to get a
  40567. * pointer to the point object through `chart.get()`.
  40568. *
  40569. * @sample {highcharts} highcharts/point/id/
  40570. * Remove an id'd point
  40571. *
  40572. * @type {string}
  40573. * @since 1.2.0
  40574. * @product highcharts highstock gantt
  40575. * @apioption series.line.data.id
  40576. */
  40577. /**
  40578. * The rank for this point's data label in case of collision. If two
  40579. * data labels are about to overlap, only the one with the highest `labelrank`
  40580. * will be drawn.
  40581. *
  40582. * @type {number}
  40583. * @apioption series.line.data.labelrank
  40584. */
  40585. /**
  40586. * The name of the point as shown in the legend, tooltip, dataLabels, etc.
  40587. *
  40588. * @see [xAxis.uniqueNames](#xAxis.uniqueNames)
  40589. *
  40590. * @sample {highcharts} highcharts/series/data-array-of-objects/
  40591. * Point names
  40592. *
  40593. * @type {string}
  40594. * @apioption series.line.data.name
  40595. */
  40596. /**
  40597. * Whether the data point is selected initially.
  40598. *
  40599. * @type {boolean}
  40600. * @default false
  40601. * @product highcharts highstock gantt
  40602. * @apioption series.line.data.selected
  40603. */
  40604. /**
  40605. * The x value of the point. For datetime axes, the X value is the timestamp
  40606. * in milliseconds since 1970.
  40607. *
  40608. * @type {number}
  40609. * @product highcharts highstock
  40610. * @apioption series.line.data.x
  40611. */
  40612. /**
  40613. * The y value of the point.
  40614. *
  40615. * @type {number|null}
  40616. * @product highcharts highstock
  40617. * @apioption series.line.data.y
  40618. */
  40619. /**
  40620. * The individual point events.
  40621. *
  40622. * @extends plotOptions.series.point.events
  40623. * @product highcharts highstock gantt
  40624. * @apioption series.line.data.events
  40625. */
  40626. /**
  40627. * Options for the point markers of line-like series.
  40628. *
  40629. * @declare Highcharts.PointMarkerOptionsObject
  40630. * @extends plotOptions.series.marker
  40631. * @product highcharts highstock
  40632. * @apioption series.line.data.marker
  40633. */
  40634. ''; // include precedent doclets in transpilat
  40635. return LineSeries;
  40636. });
  40637. _registerModule(_modules, 'Series/Area/AreaSeries.js', [_modules['Core/Color/Color.js'], _modules['Mixins/LegendSymbol.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (Color, LegendSymbolMixin, SeriesRegistry, U) {
  40638. /* *
  40639. *
  40640. * (c) 2010-2021 Torstein Honsi
  40641. *
  40642. * License: www.highcharts.com/license
  40643. *
  40644. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  40645. *
  40646. * */
  40647. var __extends = (this && this.__extends) || (function () {
  40648. var extendStatics = function (d,
  40649. b) {
  40650. extendStatics = Object.setPrototypeOf ||
  40651. ({ __proto__: [] } instanceof Array && function (d,
  40652. b) { d.__proto__ = b; }) ||
  40653. function (d,
  40654. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  40655. return extendStatics(d, b);
  40656. };
  40657. return function (d, b) {
  40658. extendStatics(d, b);
  40659. function __() { this.constructor = d; }
  40660. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  40661. };
  40662. })();
  40663. var color = Color.parse;
  40664. var LineSeries = SeriesRegistry.seriesTypes.line;
  40665. var extend = U.extend,
  40666. merge = U.merge,
  40667. objectEach = U.objectEach,
  40668. pick = U.pick;
  40669. /* *
  40670. *
  40671. * Class
  40672. *
  40673. * */
  40674. /**
  40675. * Area series type.
  40676. *
  40677. * @private
  40678. * @class
  40679. * @name AreaSeries
  40680. *
  40681. * @augments LineSeries
  40682. */
  40683. var AreaSeries = /** @class */ (function (_super) {
  40684. __extends(AreaSeries, _super);
  40685. function AreaSeries() {
  40686. /* *
  40687. *
  40688. * Static Properties
  40689. *
  40690. * */
  40691. var _this = _super !== null && _super.apply(this,
  40692. arguments) || this;
  40693. _this.data = void 0;
  40694. _this.options = void 0;
  40695. _this.points = void 0;
  40696. return _this;
  40697. /* eslint-enable valid-jsdoc */
  40698. }
  40699. /* *
  40700. *
  40701. * Functions
  40702. *
  40703. * */
  40704. /* eslint-disable valid-jsdoc */
  40705. /**
  40706. * Draw the graph and the underlying area. This method calls the Series
  40707. * base function and adds the area. The areaPath is calculated in the
  40708. * getSegmentPath method called from Series.prototype.drawGraph.
  40709. * @private
  40710. */
  40711. AreaSeries.prototype.drawGraph = function () {
  40712. // Define or reset areaPath
  40713. this.areaPath = [];
  40714. // Call the base method
  40715. _super.prototype.drawGraph.apply(this);
  40716. // Define local variables
  40717. var series = this,
  40718. areaPath = this.areaPath,
  40719. options = this.options,
  40720. zones = this.zones,
  40721. props = [[
  40722. 'area',
  40723. 'highcharts-area',
  40724. this.color,
  40725. options.fillColor
  40726. ]]; // area name, main color, fill color
  40727. zones.forEach(function (zone,
  40728. i) {
  40729. props.push([
  40730. 'zone-area-' + i,
  40731. 'highcharts-area highcharts-zone-area-' + i + ' ' +
  40732. zone.className,
  40733. zone.color || series.color,
  40734. zone.fillColor || options.fillColor
  40735. ]);
  40736. });
  40737. props.forEach(function (prop) {
  40738. var areaKey = prop[0],
  40739. area = series[areaKey],
  40740. verb = area ? 'animate' : 'attr',
  40741. attribs = {};
  40742. // Create or update the area
  40743. if (area) { // update
  40744. area.endX = series.preventGraphAnimation ?
  40745. null :
  40746. areaPath.xMap;
  40747. area.animate({ d: areaPath });
  40748. }
  40749. else { // create
  40750. attribs.zIndex = 0; // #1069
  40751. area = series[areaKey] = series.chart.renderer
  40752. .path(areaPath)
  40753. .addClass(prop[1])
  40754. .add(series.group);
  40755. area.isArea = true;
  40756. }
  40757. if (!series.chart.styledMode) {
  40758. attribs.fill = pick(prop[3], color(prop[2])
  40759. .setOpacity(pick(options.fillOpacity, 0.75))
  40760. .get());
  40761. }
  40762. area[verb](attribs);
  40763. area.startX = areaPath.xMap;
  40764. area.shiftUnit = options.step ? 2 : 1;
  40765. });
  40766. };
  40767. /**
  40768. * @private
  40769. */
  40770. AreaSeries.prototype.getGraphPath = function (points) {
  40771. var getGraphPath = LineSeries.prototype.getGraphPath, graphPath, options = this.options, stacking = options.stacking, yAxis = this.yAxis, topPath, bottomPath, bottomPoints = [], graphPoints = [], seriesIndex = this.index, i, areaPath, plotX, stacks = yAxis.stacking.stacks[this.stackKey], threshold = options.threshold, translatedThreshold = Math.round(// #10909
  40772. yAxis.getThreshold(options.threshold)), isNull, yBottom, connectNulls = pick(// #10574
  40773. options.connectNulls, stacking === 'percent'),
  40774. // To display null points in underlying stacked series, this
  40775. // series graph must be broken, and the area also fall down to
  40776. // fill the gap left by the null point. #2069
  40777. addDummyPoints = function (i, otherI, side) {
  40778. var point = points[i], stackedValues = stacking &&
  40779. stacks[point.x].points[seriesIndex], nullVal = point[side + 'Null'] || 0, cliffVal = point[side + 'Cliff'] || 0, top, bottom, isNull = true;
  40780. if (cliffVal || nullVal) {
  40781. top = (nullVal ?
  40782. stackedValues[0] :
  40783. stackedValues[1]) + cliffVal;
  40784. bottom = stackedValues[0] + cliffVal;
  40785. isNull = !!nullVal;
  40786. }
  40787. else if (!stacking &&
  40788. points[otherI] &&
  40789. points[otherI].isNull) {
  40790. top = bottom = threshold;
  40791. }
  40792. // Add to the top and bottom line of the area
  40793. if (typeof top !== 'undefined') {
  40794. graphPoints.push({
  40795. plotX: plotX,
  40796. plotY: top === null ?
  40797. translatedThreshold :
  40798. yAxis.getThreshold(top),
  40799. isNull: isNull,
  40800. isCliff: true
  40801. });
  40802. bottomPoints.push({
  40803. plotX: plotX,
  40804. plotY: bottom === null ?
  40805. translatedThreshold :
  40806. yAxis.getThreshold(bottom),
  40807. doCurve: false // #1041, gaps in areaspline areas
  40808. });
  40809. }
  40810. };
  40811. // Find what points to use
  40812. points = points || this.points;
  40813. // Fill in missing points
  40814. if (stacking) {
  40815. points = this.getStackPoints(points);
  40816. }
  40817. for (i = 0; i < points.length; i++) {
  40818. // Reset after series.update of stacking property (#12033)
  40819. if (!stacking) {
  40820. points[i].leftCliff = points[i].rightCliff =
  40821. points[i].leftNull = points[i].rightNull = void 0;
  40822. }
  40823. isNull = points[i].isNull;
  40824. plotX = pick(points[i].rectPlotX, points[i].plotX);
  40825. yBottom = stacking ? pick(points[i].yBottom, translatedThreshold) : translatedThreshold;
  40826. if (!isNull || connectNulls) {
  40827. if (!connectNulls) {
  40828. addDummyPoints(i, i - 1, 'left');
  40829. }
  40830. // Skip null point when stacking is false and connectNulls
  40831. // true
  40832. if (!(isNull && !stacking && connectNulls)) {
  40833. graphPoints.push(points[i]);
  40834. bottomPoints.push({
  40835. x: i,
  40836. plotX: plotX,
  40837. plotY: yBottom
  40838. });
  40839. }
  40840. if (!connectNulls) {
  40841. addDummyPoints(i, i + 1, 'right');
  40842. }
  40843. }
  40844. }
  40845. topPath = getGraphPath.call(this, graphPoints, true, true);
  40846. bottomPoints.reversed = true;
  40847. bottomPath = getGraphPath.call(this, bottomPoints, true, true);
  40848. var firstBottomPoint = bottomPath[0];
  40849. if (firstBottomPoint && firstBottomPoint[0] === 'M') {
  40850. bottomPath[0] = ['L', firstBottomPoint[1], firstBottomPoint[2]];
  40851. }
  40852. areaPath = topPath.concat(bottomPath);
  40853. if (areaPath.length) {
  40854. areaPath.push(['Z']);
  40855. }
  40856. // TODO: don't set leftCliff and rightCliff when connectNulls?
  40857. graphPath = getGraphPath
  40858. .call(this, graphPoints, false, connectNulls);
  40859. areaPath.xMap = topPath.xMap;
  40860. this.areaPath = areaPath;
  40861. return graphPath;
  40862. };
  40863. /**
  40864. * Return an array of stacked points, where null and missing points are
  40865. * replaced by dummy points in order for gaps to be drawn correctly in
  40866. * stacks.
  40867. * @private
  40868. */
  40869. AreaSeries.prototype.getStackPoints = function (points) {
  40870. var series = this,
  40871. segment = [],
  40872. keys = [],
  40873. xAxis = this.xAxis,
  40874. yAxis = this.yAxis,
  40875. stack = yAxis.stacking.stacks[this.stackKey],
  40876. pointMap = {},
  40877. yAxisSeries = yAxis.series,
  40878. seriesLength = yAxisSeries.length,
  40879. upOrDown = yAxis.options.reversedStacks ? 1 : -1,
  40880. seriesIndex = yAxisSeries.indexOf(series);
  40881. points = points || this.points;
  40882. if (this.options.stacking) {
  40883. for (var i = 0; i < points.length; i++) {
  40884. // Reset after point update (#7326)
  40885. points[i].leftNull = points[i].rightNull = void 0;
  40886. // Create a map where we can quickly look up the points by
  40887. // their X values.
  40888. pointMap[points[i].x] = points[i];
  40889. }
  40890. // Sort the keys (#1651)
  40891. objectEach(stack, function (stackX, x) {
  40892. // nulled after switching between
  40893. // grouping and not (#1651, #2336)
  40894. if (stackX.total !== null) {
  40895. keys.push(x);
  40896. }
  40897. });
  40898. keys.sort(function (a, b) {
  40899. return a - b;
  40900. });
  40901. var visibleSeries_1 = yAxisSeries.map(function (s) { return s.visible; });
  40902. keys.forEach(function (x, idx) {
  40903. var y = 0,
  40904. stackPoint,
  40905. stackedValues;
  40906. if (pointMap[x] && !pointMap[x].isNull) {
  40907. segment.push(pointMap[x]);
  40908. // Find left and right cliff. -1 goes left, 1 goes
  40909. // right.
  40910. [-1, 1].forEach(function (direction) {
  40911. var nullName = direction === 1 ?
  40912. 'rightNull' :
  40913. 'leftNull',
  40914. cliffName = direction === 1 ?
  40915. 'rightCliff' :
  40916. 'leftCliff',
  40917. cliff = 0,
  40918. otherStack = stack[keys[idx + direction]];
  40919. // If there is a stack next to this one,
  40920. // to the left or to the right...
  40921. if (otherStack) {
  40922. var i = seriesIndex;
  40923. // Can go either up or down,
  40924. // depending on reversedStacks
  40925. while (i >= 0 && i < seriesLength) {
  40926. var si = yAxisSeries[i].index;
  40927. stackPoint = otherStack.points[si];
  40928. if (!stackPoint) {
  40929. // If the next point in this series
  40930. // is missing, mark the point
  40931. // with point.leftNull or
  40932. // point.rightNull = true.
  40933. if (si === series.index) {
  40934. pointMap[x][nullName] = true;
  40935. // If there are missing points in
  40936. // the next stack in any of the
  40937. // series below this one, we need
  40938. // to substract the missing values
  40939. // and add a hiatus to the left or
  40940. // right.
  40941. }
  40942. else if (visibleSeries_1[i]) {
  40943. stackedValues =
  40944. stack[x].points[si];
  40945. if (stackedValues) {
  40946. cliff -= stackedValues[1] - stackedValues[0];
  40947. }
  40948. }
  40949. }
  40950. // When reversedStacks is true, loop up,
  40951. // else loop down
  40952. i += upOrDown;
  40953. }
  40954. }
  40955. pointMap[x][cliffName] = cliff;
  40956. });
  40957. // There is no point for this X value in this series, so we
  40958. // insert a dummy point in order for the areas to be drawn
  40959. // correctly.
  40960. }
  40961. else {
  40962. // Loop down the stack to find the series below this
  40963. // one that has a value (#1991)
  40964. var i = seriesIndex;
  40965. while (i >= 0 && i < seriesLength) {
  40966. var si = yAxisSeries[i].index;
  40967. stackPoint = stack[x].points[si];
  40968. if (stackPoint) {
  40969. y = stackPoint[1];
  40970. break;
  40971. }
  40972. // When reversedStacks is true, loop up, else loop
  40973. // down
  40974. i += upOrDown;
  40975. }
  40976. y = pick(y, 0);
  40977. y = yAxis.translate(// #6272
  40978. y, 0, 1, 0, 1);
  40979. segment.push({
  40980. isNull: true,
  40981. plotX: xAxis.translate(// #6272
  40982. x, 0, 0, 0, 1),
  40983. x: x,
  40984. plotY: y,
  40985. yBottom: y
  40986. });
  40987. }
  40988. });
  40989. }
  40990. return segment;
  40991. };
  40992. /**
  40993. * The area series type.
  40994. *
  40995. * @sample {highcharts} highcharts/demo/area-basic/
  40996. * Area chart
  40997. * @sample {highstock} stock/demo/area/
  40998. * Area chart
  40999. *
  41000. * @extends plotOptions.line
  41001. * @excluding useOhlcData
  41002. * @product highcharts highstock
  41003. * @optionparent plotOptions.area
  41004. */
  41005. AreaSeries.defaultOptions = merge(LineSeries.defaultOptions, {
  41006. /**
  41007. * @see [fillColor](#plotOptions.area.fillColor)
  41008. * @see [fillOpacity](#plotOptions.area.fillOpacity)
  41009. *
  41010. * @apioption plotOptions.area.color
  41011. */
  41012. /**
  41013. * Fill color or gradient for the area. When `null`, the series' `color`
  41014. * is used with the series' `fillOpacity`.
  41015. *
  41016. * In styled mode, the fill color can be set with the `.highcharts-area`
  41017. * class name.
  41018. *
  41019. * @see [color](#plotOptions.area.color)
  41020. * @see [fillOpacity](#plotOptions.area.fillOpacity)
  41021. *
  41022. * @sample {highcharts} highcharts/plotoptions/area-fillcolor-default/
  41023. * Null by default
  41024. * @sample {highcharts} highcharts/plotoptions/area-fillcolor-gradient/
  41025. * Gradient
  41026. *
  41027. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  41028. * @product highcharts highstock
  41029. * @apioption plotOptions.area.fillColor
  41030. */
  41031. /**
  41032. * Fill opacity for the area. When you set an explicit `fillColor`,
  41033. * the `fillOpacity` is not applied. Instead, you should define the
  41034. * opacity in the `fillColor` with an rgba color definition. The
  41035. * `fillOpacity` setting, also the default setting, overrides the alpha
  41036. * component of the `color` setting.
  41037. *
  41038. * In styled mode, the fill opacity can be set with the
  41039. * `.highcharts-area` class name.
  41040. *
  41041. * @see [color](#plotOptions.area.color)
  41042. * @see [fillColor](#plotOptions.area.fillColor)
  41043. *
  41044. * @sample {highcharts} highcharts/plotoptions/area-fillopacity/
  41045. * Automatic fill color and fill opacity of 0.1
  41046. *
  41047. * @type {number}
  41048. * @default {highcharts} 0.75
  41049. * @default {highstock} 0.75
  41050. * @product highcharts highstock
  41051. * @apioption plotOptions.area.fillOpacity
  41052. */
  41053. /**
  41054. * A separate color for the graph line. By default the line takes the
  41055. * `color` of the series, but the lineColor setting allows setting a
  41056. * separate color for the line without altering the `fillColor`.
  41057. *
  41058. * In styled mode, the line stroke can be set with the
  41059. * `.highcharts-graph` class name.
  41060. *
  41061. * @sample {highcharts} highcharts/plotoptions/area-linecolor/
  41062. * Dark gray line
  41063. *
  41064. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  41065. * @product highcharts highstock
  41066. * @apioption plotOptions.area.lineColor
  41067. */
  41068. /**
  41069. * A separate color for the negative part of the area.
  41070. *
  41071. * In styled mode, a negative color is set with the
  41072. * `.highcharts-negative` class name.
  41073. *
  41074. * @see [negativeColor](#plotOptions.area.negativeColor)
  41075. *
  41076. * @sample {highcharts} highcharts/css/series-negative-color/
  41077. * Negative color in styled mode
  41078. *
  41079. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  41080. * @since 3.0
  41081. * @product highcharts
  41082. * @apioption plotOptions.area.negativeFillColor
  41083. */
  41084. /**
  41085. * Whether the whole area or just the line should respond to mouseover
  41086. * tooltips and other mouse or touch events.
  41087. *
  41088. * @sample {highcharts|highstock} highcharts/plotoptions/area-trackbyarea/
  41089. * Display the tooltip when the area is hovered
  41090. *
  41091. * @type {boolean}
  41092. * @default false
  41093. * @since 1.1.6
  41094. * @product highcharts highstock
  41095. * @apioption plotOptions.area.trackByArea
  41096. */
  41097. /**
  41098. * The Y axis value to serve as the base for the area, for
  41099. * distinguishing between values above and below a threshold. The area
  41100. * between the graph and the threshold is filled.
  41101. *
  41102. * * If a number is given, the Y axis will scale to the threshold.
  41103. * * If `null`, the scaling behaves like a line series with fill between
  41104. * the graph and the Y axis minimum.
  41105. * * If `Infinity` or `-Infinity`, the area between the graph and the
  41106. * corresponding Y axis extreme is filled (since v6.1.0).
  41107. *
  41108. * @sample {highcharts} highcharts/plotoptions/area-threshold/
  41109. * A threshold of 100
  41110. * @sample {highcharts} highcharts/plotoptions/area-threshold-infinity/
  41111. * A threshold of Infinity
  41112. *
  41113. * @type {number|null}
  41114. * @since 2.0
  41115. * @product highcharts highstock
  41116. */
  41117. threshold: 0
  41118. });
  41119. return AreaSeries;
  41120. }(LineSeries));
  41121. extend(AreaSeries.prototype, {
  41122. singleStacks: false,
  41123. drawLegendSymbol: LegendSymbolMixin.drawRectangle
  41124. });
  41125. SeriesRegistry.registerSeriesType('area', AreaSeries);
  41126. /* *
  41127. *
  41128. * Default Export
  41129. *
  41130. * */
  41131. /* *
  41132. *
  41133. * API Options
  41134. *
  41135. * */
  41136. /**
  41137. * A `area` series. If the [type](#series.area.type) option is not
  41138. * specified, it is inherited from [chart.type](#chart.type).
  41139. *
  41140. * @extends series,plotOptions.area
  41141. * @excluding dataParser, dataURL, useOhlcData
  41142. * @product highcharts highstock
  41143. * @apioption series.area
  41144. */
  41145. /**
  41146. * @see [fillColor](#series.area.fillColor)
  41147. * @see [fillOpacity](#series.area.fillOpacity)
  41148. *
  41149. * @apioption series.area.color
  41150. */
  41151. /**
  41152. * An array of data points for the series. For the `area` series type,
  41153. * points can be given in the following ways:
  41154. *
  41155. * 1. An array of numerical values. In this case, the numerical values will be
  41156. * interpreted as `y` options. The `x` values will be automatically
  41157. * calculated, either starting at 0 and incremented by 1, or from
  41158. * `pointStart` * and `pointInterval` given in the series options. If the
  41159. * axis has categories, these will be used. Example:
  41160. * ```js
  41161. * data: [0, 5, 3, 5]
  41162. * ```
  41163. *
  41164. * 2. An array of arrays with 2 values. In this case, the values correspond to
  41165. * `x,y`. If the first value is a string, it is applied as the name of the
  41166. * point, and the `x` value is inferred.
  41167. * ```js
  41168. * data: [
  41169. * [0, 9],
  41170. * [1, 7],
  41171. * [2, 6]
  41172. * ]
  41173. * ```
  41174. *
  41175. * 3. An array of objects with named values. The following snippet shows only a
  41176. * few settings, see the complete options set below. If the total number of
  41177. * data points exceeds the series'
  41178. * [turboThreshold](#series.area.turboThreshold), this option is not
  41179. * available.
  41180. * ```js
  41181. * data: [{
  41182. * x: 1,
  41183. * y: 9,
  41184. * name: "Point2",
  41185. * color: "#00FF00"
  41186. * }, {
  41187. * x: 1,
  41188. * y: 6,
  41189. * name: "Point1",
  41190. * color: "#FF00FF"
  41191. * }]
  41192. * ```
  41193. *
  41194. * @sample {highcharts} highcharts/chart/reflow-true/
  41195. * Numerical values
  41196. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  41197. * Arrays of numeric x and y
  41198. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  41199. * Arrays of datetime x and y
  41200. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  41201. * Arrays of point.name and y
  41202. * @sample {highcharts} highcharts/series/data-array-of-objects/
  41203. * Config objects
  41204. *
  41205. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  41206. * @extends series.line.data
  41207. * @product highcharts highstock
  41208. * @apioption series.area.data
  41209. */
  41210. /**
  41211. * @see [color](#series.area.color)
  41212. * @see [fillOpacity](#series.area.fillOpacity)
  41213. *
  41214. * @apioption series.area.fillColor
  41215. */
  41216. /**
  41217. * @see [color](#series.area.color)
  41218. * @see [fillColor](#series.area.fillColor)
  41219. *
  41220. * @default {highcharts} 0.75
  41221. * @default {highstock} 0.75
  41222. * @apioption series.area.fillOpacity
  41223. */
  41224. ''; // adds doclets above to transpilat
  41225. return AreaSeries;
  41226. });
  41227. _registerModule(_modules, 'Series/Spline/SplineSeries.js', [_modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (SeriesRegistry, U) {
  41228. /* *
  41229. *
  41230. * (c) 2010-2021 Torstein Honsi
  41231. *
  41232. * License: www.highcharts.com/license
  41233. *
  41234. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  41235. *
  41236. * */
  41237. var __extends = (this && this.__extends) || (function () {
  41238. var extendStatics = function (d,
  41239. b) {
  41240. extendStatics = Object.setPrototypeOf ||
  41241. ({ __proto__: [] } instanceof Array && function (d,
  41242. b) { d.__proto__ = b; }) ||
  41243. function (d,
  41244. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  41245. return extendStatics(d, b);
  41246. };
  41247. return function (d, b) {
  41248. extendStatics(d, b);
  41249. function __() { this.constructor = d; }
  41250. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  41251. };
  41252. })();
  41253. var LineSeries = SeriesRegistry.seriesTypes.line;
  41254. var merge = U.merge,
  41255. pick = U.pick;
  41256. /**
  41257. * Spline series type.
  41258. *
  41259. * @private
  41260. */
  41261. var SplineSeries = /** @class */ (function (_super) {
  41262. __extends(SplineSeries, _super);
  41263. function SplineSeries() {
  41264. /* *
  41265. *
  41266. * Static Properties
  41267. *
  41268. * */
  41269. var _this = _super !== null && _super.apply(this,
  41270. arguments) || this;
  41271. /* *
  41272. *
  41273. * Properties
  41274. *
  41275. * */
  41276. _this.data = void 0;
  41277. _this.options = void 0;
  41278. _this.points = void 0;
  41279. return _this;
  41280. /* eslint-enable valid-jsdoc */
  41281. }
  41282. /* *
  41283. *
  41284. * Functions
  41285. *
  41286. * */
  41287. /* eslint-disable valid-jsdoc */
  41288. /**
  41289. * Get the spline segment from a given point's previous neighbour to the
  41290. * given point.
  41291. *
  41292. * @private
  41293. * @function Highcharts.seriesTypes.spline#getPointSpline
  41294. *
  41295. * @param {Array<Highcharts.Point>}
  41296. *
  41297. * @param {Highcharts.Point} point
  41298. *
  41299. * @param {number} i
  41300. *
  41301. * @return {Highcharts.SVGPathArray}
  41302. */
  41303. SplineSeries.prototype.getPointSpline = function (points, point, i) {
  41304. var
  41305. // 1 means control points midway between points, 2 means 1/3
  41306. // from the point, 3 is 1/4 etc
  41307. smoothing = 1.5,
  41308. denom = smoothing + 1,
  41309. plotX = point.plotX || 0,
  41310. plotY = point.plotY || 0,
  41311. lastPoint = points[i - 1],
  41312. nextPoint = points[i + 1],
  41313. leftContX,
  41314. leftContY,
  41315. rightContX,
  41316. rightContY,
  41317. ret;
  41318. /**
  41319. * @private
  41320. */
  41321. function doCurve(otherPoint) {
  41322. return otherPoint &&
  41323. !otherPoint.isNull &&
  41324. otherPoint.doCurve !== false &&
  41325. // #6387, area splines next to null:
  41326. !point.isCliff;
  41327. }
  41328. // Find control points
  41329. if (doCurve(lastPoint) && doCurve(nextPoint)) {
  41330. var lastX = lastPoint.plotX || 0,
  41331. lastY = lastPoint.plotY || 0,
  41332. nextX = nextPoint.plotX || 0,
  41333. nextY = nextPoint.plotY || 0,
  41334. correction = 0;
  41335. leftContX = (smoothing * plotX + lastX) / denom;
  41336. leftContY = (smoothing * plotY + lastY) / denom;
  41337. rightContX = (smoothing * plotX + nextX) / denom;
  41338. rightContY = (smoothing * plotY + nextY) / denom;
  41339. // Have the two control points make a straight line through main
  41340. // point
  41341. if (rightContX !== leftContX) { // #5016, division by zero
  41342. correction = (((rightContY - leftContY) *
  41343. (rightContX - plotX)) /
  41344. (rightContX - leftContX) + plotY - rightContY);
  41345. }
  41346. leftContY += correction;
  41347. rightContY += correction;
  41348. // to prevent false extremes, check that control points are
  41349. // between neighbouring points' y values
  41350. if (leftContY > lastY && leftContY > plotY) {
  41351. leftContY = Math.max(lastY, plotY);
  41352. // mirror of left control point
  41353. rightContY = 2 * plotY - leftContY;
  41354. }
  41355. else if (leftContY < lastY && leftContY < plotY) {
  41356. leftContY = Math.min(lastY, plotY);
  41357. rightContY = 2 * plotY - leftContY;
  41358. }
  41359. if (rightContY > nextY && rightContY > plotY) {
  41360. rightContY = Math.max(nextY, plotY);
  41361. leftContY = 2 * plotY - rightContY;
  41362. }
  41363. else if (rightContY < nextY && rightContY < plotY) {
  41364. rightContY = Math.min(nextY, plotY);
  41365. leftContY = 2 * plotY - rightContY;
  41366. }
  41367. // record for drawing in next point
  41368. point.rightContX = rightContX;
  41369. point.rightContY = rightContY;
  41370. }
  41371. // Visualize control points for debugging
  41372. /*
  41373. if (leftContX) {
  41374. this.chart.renderer.circle(
  41375. leftContX + this.chart.plotLeft,
  41376. leftContY + this.chart.plotTop,
  41377. 2
  41378. )
  41379. .attr({
  41380. stroke: 'red',
  41381. 'stroke-width': 2,
  41382. fill: 'none',
  41383. zIndex: 9
  41384. })
  41385. .add();
  41386. this.chart.renderer.path(['M', leftContX + this.chart.plotLeft,
  41387. leftContY + this.chart.plotTop,
  41388. 'L', plotX + this.chart.plotLeft, plotY + this.chart.plotTop])
  41389. .attr({
  41390. stroke: 'red',
  41391. 'stroke-width': 2,
  41392. zIndex: 9
  41393. })
  41394. .add();
  41395. }
  41396. if (rightContX) {
  41397. this.chart.renderer.circle(
  41398. rightContX + this.chart.plotLeft,
  41399. rightContY + this.chart.plotTop,
  41400. 2
  41401. )
  41402. .attr({
  41403. stroke: 'green',
  41404. 'stroke-width': 2,
  41405. fill: 'none',
  41406. zIndex: 9
  41407. })
  41408. .add();
  41409. this.chart.renderer.path(['M', rightContX + this.chart.plotLeft,
  41410. rightContY + this.chart.plotTop,
  41411. 'L', plotX + this.chart.plotLeft, plotY + this.chart.plotTop])
  41412. .attr({
  41413. stroke: 'green',
  41414. 'stroke-width': 2,
  41415. zIndex: 9
  41416. })
  41417. .add();
  41418. }
  41419. // */
  41420. ret = [
  41421. 'C',
  41422. pick(lastPoint.rightContX, lastPoint.plotX, 0),
  41423. pick(lastPoint.rightContY, lastPoint.plotY, 0),
  41424. pick(leftContX, plotX, 0),
  41425. pick(leftContY, plotY, 0),
  41426. plotX,
  41427. plotY
  41428. ];
  41429. // reset for updating series later
  41430. lastPoint.rightContX = lastPoint.rightContY = void 0;
  41431. return ret;
  41432. };
  41433. /**
  41434. * A spline series is a special type of line series, where the segments
  41435. * between the data points are smoothed.
  41436. *
  41437. * @sample {highcharts} highcharts/demo/spline-irregular-time/
  41438. * Spline chart
  41439. * @sample {highstock} stock/demo/spline/
  41440. * Spline chart
  41441. *
  41442. * @extends plotOptions.series
  41443. * @excluding step, boostThreshold, boostBlending
  41444. * @product highcharts highstock
  41445. * @optionparent plotOptions.spline
  41446. */
  41447. SplineSeries.defaultOptions = merge(LineSeries.defaultOptions);
  41448. return SplineSeries;
  41449. }(LineSeries));
  41450. SeriesRegistry.registerSeriesType('spline', SplineSeries);
  41451. /* *
  41452. *
  41453. * Default Export
  41454. *
  41455. * */
  41456. /* *
  41457. *
  41458. * API Options
  41459. *
  41460. * */
  41461. /**
  41462. * A `spline` series. If the [type](#series.spline.type) option is
  41463. * not specified, it is inherited from [chart.type](#chart.type).
  41464. *
  41465. * @extends series,plotOptions.spline
  41466. * @excluding dataParser, dataURL, step, boostThreshold, boostBlending
  41467. * @product highcharts highstock
  41468. * @apioption series.spline
  41469. */
  41470. /**
  41471. * An array of data points for the series. For the `spline` series type,
  41472. * points can be given in the following ways:
  41473. *
  41474. * 1. An array of numerical values. In this case, the numerical values will be
  41475. * interpreted as `y` options. The `x` values will be automatically
  41476. * calculated, either starting at 0 and incremented by 1, or from
  41477. * `pointStart` and `pointInterval` given in the series options. If the axis
  41478. * has categories, these will be used. Example:
  41479. * ```js
  41480. * data: [0, 5, 3, 5]
  41481. * ```
  41482. *
  41483. * 2. An array of arrays with 2 values. In this case, the values correspond to
  41484. * `x,y`. If the first value is a string, it is applied as the name of the
  41485. * point, and the `x` value is inferred.
  41486. * ```js
  41487. * data: [
  41488. * [0, 9],
  41489. * [1, 2],
  41490. * [2, 8]
  41491. * ]
  41492. * ```
  41493. *
  41494. * 3. An array of objects with named values. The following snippet shows only a
  41495. * few settings, see the complete options set below. If the total number of
  41496. * data points exceeds the series'
  41497. * [turboThreshold](#series.spline.turboThreshold),
  41498. * this option is not available.
  41499. * ```js
  41500. * data: [{
  41501. * x: 1,
  41502. * y: 9,
  41503. * name: "Point2",
  41504. * color: "#00FF00"
  41505. * }, {
  41506. * x: 1,
  41507. * y: 0,
  41508. * name: "Point1",
  41509. * color: "#FF00FF"
  41510. * }]
  41511. * ```
  41512. *
  41513. * @sample {highcharts} highcharts/chart/reflow-true/
  41514. * Numerical values
  41515. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  41516. * Arrays of numeric x and y
  41517. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  41518. * Arrays of datetime x and y
  41519. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  41520. * Arrays of point.name and y
  41521. * @sample {highcharts} highcharts/series/data-array-of-objects/
  41522. * Config objects
  41523. *
  41524. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  41525. * @extends series.line.data
  41526. * @product highcharts highstock
  41527. * @apioption series.spline.data
  41528. */
  41529. ''; // adds doclets above intro transpilat
  41530. return SplineSeries;
  41531. });
  41532. _registerModule(_modules, 'Series/AreaSpline/AreaSplineSeries.js', [_modules['Series/Area/AreaSeries.js'], _modules['Series/Spline/SplineSeries.js'], _modules['Mixins/LegendSymbol.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (AreaSeries, SplineSeries, LegendSymbolMixin, SeriesRegistry, U) {
  41533. /* *
  41534. *
  41535. * (c) 2010-2021 Torstein Honsi
  41536. *
  41537. * License: www.highcharts.com/license
  41538. *
  41539. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  41540. *
  41541. * */
  41542. var __extends = (this && this.__extends) || (function () {
  41543. var extendStatics = function (d,
  41544. b) {
  41545. extendStatics = Object.setPrototypeOf ||
  41546. ({ __proto__: [] } instanceof Array && function (d,
  41547. b) { d.__proto__ = b; }) ||
  41548. function (d,
  41549. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  41550. return extendStatics(d, b);
  41551. };
  41552. return function (d, b) {
  41553. extendStatics(d, b);
  41554. function __() { this.constructor = d; }
  41555. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  41556. };
  41557. })();
  41558. var areaProto = AreaSeries.prototype;
  41559. var extend = U.extend,
  41560. merge = U.merge;
  41561. /* *
  41562. *
  41563. * Class
  41564. *
  41565. * */
  41566. /**
  41567. * AreaSpline series type.
  41568. *
  41569. * @private
  41570. * @class
  41571. * @name Highcharts.seriesTypes.areaspline
  41572. *
  41573. * @augments Highcharts.Series
  41574. */
  41575. var AreaSplineSeries = /** @class */ (function (_super) {
  41576. __extends(AreaSplineSeries, _super);
  41577. function AreaSplineSeries() {
  41578. /* *
  41579. *
  41580. * Static properties
  41581. *
  41582. * */
  41583. var _this = _super !== null && _super.apply(this,
  41584. arguments) || this;
  41585. /* *
  41586. *
  41587. * Properties
  41588. *
  41589. * */
  41590. _this.data = void 0;
  41591. _this.points = void 0;
  41592. _this.options = void 0;
  41593. return _this;
  41594. }
  41595. /**
  41596. * The area spline series is an area series where the graph between the
  41597. * points is smoothed into a spline.
  41598. *
  41599. * @sample {highcharts} highcharts/demo/areaspline/
  41600. * Area spline chart
  41601. * @sample {highstock} stock/demo/areaspline/
  41602. * Area spline chart
  41603. *
  41604. * @extends plotOptions.area
  41605. * @excluding step, boostThreshold, boostBlending
  41606. * @product highcharts highstock
  41607. * @apioption plotOptions.areaspline
  41608. */
  41609. /**
  41610. * @see [fillColor](#plotOptions.areaspline.fillColor)
  41611. * @see [fillOpacity](#plotOptions.areaspline.fillOpacity)
  41612. *
  41613. * @apioption plotOptions.areaspline.color
  41614. */
  41615. /**
  41616. * @see [color](#plotOptions.areaspline.color)
  41617. * @see [fillOpacity](#plotOptions.areaspline.fillOpacity)
  41618. *
  41619. * @apioption plotOptions.areaspline.fillColor
  41620. */
  41621. /**
  41622. * @see [color](#plotOptions.areaspline.color)
  41623. * @see [fillColor](#plotOptions.areaspline.fillColor)
  41624. *
  41625. * @default {highcharts} 0.75
  41626. * @default {highstock} 0.75
  41627. * @apioption plotOptions.areaspline.fillOpacity
  41628. */
  41629. AreaSplineSeries.defaultOptions = merge(SplineSeries.defaultOptions, AreaSeries.defaultOptions);
  41630. return AreaSplineSeries;
  41631. }(SplineSeries));
  41632. extend(AreaSplineSeries.prototype, {
  41633. getGraphPath: areaProto.getGraphPath,
  41634. getStackPoints: areaProto.getStackPoints,
  41635. drawGraph: areaProto.drawGraph,
  41636. drawLegendSymbol: LegendSymbolMixin.drawRectangle
  41637. });
  41638. SeriesRegistry.registerSeriesType('areaspline', AreaSplineSeries);
  41639. /* *
  41640. *
  41641. * Default export
  41642. *
  41643. * */
  41644. /**
  41645. * A `areaspline` series. If the [type](#series.areaspline.type) option
  41646. * is not specified, it is inherited from [chart.type](#chart.type).
  41647. *
  41648. *
  41649. * @extends series,plotOptions.areaspline
  41650. * @excluding dataParser, dataURL, step, boostThreshold, boostBlending
  41651. * @product highcharts highstock
  41652. * @apioption series.areaspline
  41653. */
  41654. /**
  41655. * @see [fillColor](#series.areaspline.fillColor)
  41656. * @see [fillOpacity](#series.areaspline.fillOpacity)
  41657. *
  41658. * @apioption series.areaspline.color
  41659. */
  41660. /**
  41661. * An array of data points for the series. For the `areaspline` series
  41662. * type, points can be given in the following ways:
  41663. *
  41664. * 1. An array of numerical values. In this case, the numerical values will be
  41665. * interpreted as `y` options. The `x` values will be automatically
  41666. * calculated, either starting at 0 and incremented by 1, or from
  41667. * `pointStart` and `pointInterval` given in the series options. If the axis
  41668. * has categories, these will be used. Example:
  41669. * ```js
  41670. * data: [0, 5, 3, 5]
  41671. * ```
  41672. *
  41673. * 2. An array of arrays with 2 values. In this case, the values correspond to
  41674. * `x,y`. If the first value is a string, it is applied as the name of the
  41675. * point, and the `x` value is inferred.
  41676. * ```js
  41677. * data: [
  41678. * [0, 10],
  41679. * [1, 9],
  41680. * [2, 3]
  41681. * ]
  41682. * ```
  41683. *
  41684. * 3. An array of objects with named values. The following snippet shows only a
  41685. * few settings, see the complete options set below. If the total number of
  41686. * data points exceeds the series'
  41687. * [turboThreshold](#series.areaspline.turboThreshold), this option is not
  41688. * available.
  41689. * ```js
  41690. * data: [{
  41691. * x: 1,
  41692. * y: 4,
  41693. * name: "Point2",
  41694. * color: "#00FF00"
  41695. * }, {
  41696. * x: 1,
  41697. * y: 4,
  41698. * name: "Point1",
  41699. * color: "#FF00FF"
  41700. * }]
  41701. * ```
  41702. *
  41703. * @sample {highcharts} highcharts/chart/reflow-true/
  41704. * Numerical values
  41705. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  41706. * Arrays of numeric x and y
  41707. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  41708. * Arrays of datetime x and y
  41709. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  41710. * Arrays of point.name and y
  41711. * @sample {highcharts} highcharts/series/data-array-of-objects/
  41712. * Config objects
  41713. *
  41714. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  41715. * @extends series.line.data
  41716. * @product highcharts highstock
  41717. * @apioption series.areaspline.data
  41718. */
  41719. /**
  41720. * @see [color](#series.areaspline.color)
  41721. * @see [fillOpacity](#series.areaspline.fillOpacity)
  41722. *
  41723. * @apioption series.areaspline.fillColor
  41724. */
  41725. /**
  41726. * @see [color](#series.areaspline.color)
  41727. * @see [fillColor](#series.areaspline.fillColor)
  41728. *
  41729. * @default {highcharts} 0.75
  41730. * @default {highstock} 0.75
  41731. * @apioption series.areaspline.fillOpacity
  41732. */
  41733. ''; // adds doclets above into transpilat
  41734. return AreaSplineSeries;
  41735. });
  41736. _registerModule(_modules, 'Series/Column/ColumnSeries.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Mixins/LegendSymbol.js'], _modules['Core/Color/Palette.js'], _modules['Core/Series/Series.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (A, Color, H, LegendSymbolMixin, palette, Series, SeriesRegistry, U) {
  41737. /* *
  41738. *
  41739. * (c) 2010-2021 Torstein Honsi
  41740. *
  41741. * License: www.highcharts.com/license
  41742. *
  41743. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  41744. *
  41745. * */
  41746. var __extends = (this && this.__extends) || (function () {
  41747. var extendStatics = function (d,
  41748. b) {
  41749. extendStatics = Object.setPrototypeOf ||
  41750. ({ __proto__: [] } instanceof Array && function (d,
  41751. b) { d.__proto__ = b; }) ||
  41752. function (d,
  41753. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  41754. return extendStatics(d, b);
  41755. };
  41756. return function (d, b) {
  41757. extendStatics(d, b);
  41758. function __() { this.constructor = d; }
  41759. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  41760. };
  41761. })();
  41762. var animObject = A.animObject;
  41763. var color = Color.parse;
  41764. var hasTouch = H.hasTouch,
  41765. noop = H.noop;
  41766. var clamp = U.clamp,
  41767. css = U.css,
  41768. defined = U.defined,
  41769. extend = U.extend,
  41770. fireEvent = U.fireEvent,
  41771. isArray = U.isArray,
  41772. isNumber = U.isNumber,
  41773. merge = U.merge,
  41774. pick = U.pick,
  41775. objectEach = U.objectEach;
  41776. /**
  41777. * The column series type.
  41778. *
  41779. * @private
  41780. * @class
  41781. * @name Highcharts.seriesTypes.column
  41782. *
  41783. * @augments Highcharts.Series
  41784. */
  41785. var ColumnSeries = /** @class */ (function (_super) {
  41786. __extends(ColumnSeries, _super);
  41787. function ColumnSeries() {
  41788. /* *
  41789. *
  41790. * Static Properties
  41791. *
  41792. * */
  41793. var _this = _super !== null && _super.apply(this,
  41794. arguments) || this;
  41795. /* *
  41796. *
  41797. * Properties
  41798. *
  41799. * */
  41800. _this.borderWidth = void 0;
  41801. _this.data = void 0;
  41802. _this.group = void 0;
  41803. _this.options = void 0;
  41804. _this.points = void 0;
  41805. return _this;
  41806. /* eslint-enable valid-jsdoc */
  41807. }
  41808. /* *
  41809. *
  41810. * Functions
  41811. *
  41812. * */
  41813. /* eslint-disable valid-jsdoc */
  41814. /**
  41815. * Animate the column heights one by one from zero.
  41816. *
  41817. * @private
  41818. * @function Highcharts.seriesTypes.column#animate
  41819. *
  41820. * @param {boolean} init
  41821. * Whether to initialize the animation or run it
  41822. */
  41823. ColumnSeries.prototype.animate = function (init) {
  41824. var series = this,
  41825. yAxis = this.yAxis,
  41826. options = series.options,
  41827. inverted = this.chart.inverted,
  41828. attr = {},
  41829. translateProp = inverted ? 'translateX' : 'translateY',
  41830. translateStart,
  41831. translatedThreshold;
  41832. if (init) {
  41833. attr.scaleY = 0.001;
  41834. translatedThreshold = clamp(yAxis.toPixels(options.threshold), yAxis.pos, yAxis.pos + yAxis.len);
  41835. if (inverted) {
  41836. attr.translateX = translatedThreshold - yAxis.len;
  41837. }
  41838. else {
  41839. attr.translateY = translatedThreshold;
  41840. }
  41841. // apply finnal clipping (used in Highcharts Stock) (#7083)
  41842. // animation is done by scaleY, so cliping is for panes
  41843. if (series.clipBox) {
  41844. series.setClip();
  41845. }
  41846. series.group.attr(attr);
  41847. }
  41848. else { // run the animation
  41849. translateStart = Number(series.group.attr(translateProp));
  41850. series.group.animate({ scaleY: 1 }, extend(animObject(series.options.animation), {
  41851. // Do the scale synchronously to ensure smooth
  41852. // updating (#5030, #7228)
  41853. step: function (val, fx) {
  41854. if (series.group) {
  41855. attr[translateProp] = translateStart +
  41856. fx.pos * (yAxis.pos - translateStart);
  41857. series.group.attr(attr);
  41858. }
  41859. }
  41860. }));
  41861. }
  41862. };
  41863. /**
  41864. * Initialize the series. Extends the basic Series.init method by
  41865. * marking other series of the same type as dirty.
  41866. *
  41867. * @private
  41868. * @function Highcharts.seriesTypes.column#init
  41869. */
  41870. ColumnSeries.prototype.init = function (chart, options) {
  41871. _super.prototype.init.apply(this, arguments);
  41872. var series = this;
  41873. chart = series.chart;
  41874. // if the series is added dynamically, force redraw of other
  41875. // series affected by a new column
  41876. if (chart.hasRendered) {
  41877. chart.series.forEach(function (otherSeries) {
  41878. if (otherSeries.type === series.type) {
  41879. otherSeries.isDirty = true;
  41880. }
  41881. });
  41882. }
  41883. };
  41884. /**
  41885. * Return the width and x offset of the columns adjusted for grouping,
  41886. * groupPadding, pointPadding, pointWidth etc.
  41887. *
  41888. * @private
  41889. * @function Highcharts.seriesTypes.column#getColumnMetrics
  41890. * @return {Highcharts.ColumnMetricsObject}
  41891. */
  41892. ColumnSeries.prototype.getColumnMetrics = function () {
  41893. var series = this,
  41894. options = series.options,
  41895. xAxis = series.xAxis,
  41896. yAxis = series.yAxis,
  41897. reversedStacks = xAxis.options.reversedStacks,
  41898. // Keep backward compatibility: reversed xAxis had reversed
  41899. // stacks
  41900. reverseStacks = (xAxis.reversed && !reversedStacks) ||
  41901. (!xAxis.reversed && reversedStacks),
  41902. stackKey,
  41903. stackGroups = {},
  41904. columnCount = 0;
  41905. // Get the total number of column type series. This is called on
  41906. // every series. Consider moving this logic to a chart.orderStacks()
  41907. // function and call it on init, addSeries and removeSeries
  41908. if (options.grouping === false) {
  41909. columnCount = 1;
  41910. }
  41911. else {
  41912. series.chart.series.forEach(function (otherSeries) {
  41913. var otherYAxis = otherSeries.yAxis,
  41914. otherOptions = otherSeries.options,
  41915. columnIndex;
  41916. if (otherSeries.type === series.type &&
  41917. (otherSeries.visible ||
  41918. !series.chart.options.chart.ignoreHiddenSeries) &&
  41919. yAxis.len === otherYAxis.len &&
  41920. yAxis.pos === otherYAxis.pos) { // #642, #2086
  41921. if (otherOptions.stacking && otherOptions.stacking !== 'group') {
  41922. stackKey = otherSeries.stackKey;
  41923. if (typeof stackGroups[stackKey] ===
  41924. 'undefined') {
  41925. stackGroups[stackKey] = columnCount++;
  41926. }
  41927. columnIndex = stackGroups[stackKey];
  41928. }
  41929. else if (otherOptions.grouping !== false) { // #1162
  41930. columnIndex = columnCount++;
  41931. }
  41932. otherSeries.columnIndex = columnIndex;
  41933. }
  41934. });
  41935. }
  41936. var categoryWidth = Math.min(Math.abs(xAxis.transA) * ((xAxis.ordinal && xAxis.ordinal.slope) ||
  41937. options.pointRange ||
  41938. xAxis.closestPointRange ||
  41939. xAxis.tickInterval ||
  41940. 1), // #2610
  41941. xAxis.len // #1535
  41942. ),
  41943. groupPadding = categoryWidth * options.groupPadding,
  41944. groupWidth = categoryWidth - 2 * groupPadding,
  41945. pointOffsetWidth = groupWidth / (columnCount || 1),
  41946. pointWidth = Math.min(options.maxPointWidth || xAxis.len,
  41947. pick(options.pointWidth,
  41948. pointOffsetWidth * (1 - 2 * options.pointPadding))),
  41949. pointPadding = (pointOffsetWidth - pointWidth) / 2,
  41950. // #1251, #3737
  41951. colIndex = (series.columnIndex || 0) + (reverseStacks ? 1 : 0),
  41952. pointXOffset = pointPadding +
  41953. (groupPadding +
  41954. colIndex * pointOffsetWidth -
  41955. (categoryWidth / 2)) * (reverseStacks ? -1 : 1);
  41956. // Save it for reading in linked series (Error bars particularly)
  41957. series.columnMetrics = {
  41958. width: pointWidth,
  41959. offset: pointXOffset,
  41960. paddedWidth: pointOffsetWidth,
  41961. columnCount: columnCount
  41962. };
  41963. return series.columnMetrics;
  41964. };
  41965. /**
  41966. * Make the columns crisp. The edges are rounded to the nearest full
  41967. * pixel.
  41968. *
  41969. * @private
  41970. * @function Highcharts.seriesTypes.column#crispCol
  41971. */
  41972. ColumnSeries.prototype.crispCol = function (x, y, w, h) {
  41973. var chart = this.chart,
  41974. borderWidth = this.borderWidth,
  41975. xCrisp = -(borderWidth % 2 ? 0.5 : 0),
  41976. yCrisp = borderWidth % 2 ? 0.5 : 1,
  41977. right,
  41978. bottom,
  41979. fromTop;
  41980. if (chart.inverted && chart.renderer.isVML) {
  41981. yCrisp += 1;
  41982. }
  41983. // Horizontal. We need to first compute the exact right edge, then
  41984. // round it and compute the width from there.
  41985. if (this.options.crisp) {
  41986. right = Math.round(x + w) + xCrisp;
  41987. x = Math.round(x) + xCrisp;
  41988. w = right - x;
  41989. }
  41990. // Vertical
  41991. bottom = Math.round(y + h) + yCrisp;
  41992. fromTop = Math.abs(y) <= 0.5 && bottom > 0.5; // #4504, #4656
  41993. y = Math.round(y) + yCrisp;
  41994. h = bottom - y;
  41995. // Top edges are exceptions
  41996. if (fromTop && h) { // #5146
  41997. y -= 1;
  41998. h += 1;
  41999. }
  42000. return {
  42001. x: x,
  42002. y: y,
  42003. width: w,
  42004. height: h
  42005. };
  42006. };
  42007. /**
  42008. * Adjust for missing columns, according to the `centerInCategory`
  42009. * option. Missing columns are either single points or stacks where the
  42010. * point or points are either missing or null.
  42011. *
  42012. * @private
  42013. * @function Highcharts.seriesTypes.column#adjustForMissingColumns
  42014. * @param {number} x
  42015. * The x coordinate of the column, left side
  42016. *
  42017. * @param {number} pointWidth
  42018. * The pointWidth, already computed upstream
  42019. *
  42020. * @param {Highcharts.ColumnPoint} point
  42021. * The point instance
  42022. *
  42023. * @param {Highcharts.ColumnMetricsObject} metrics
  42024. * The series-wide column metrics
  42025. *
  42026. * @return {number}
  42027. * The adjusted x position, or the original if not adjusted
  42028. */
  42029. ColumnSeries.prototype.adjustForMissingColumns = function (x, pointWidth, point, metrics) {
  42030. var _this = this;
  42031. var stacking = this.options.stacking;
  42032. if (!point.isNull && metrics.columnCount > 1) {
  42033. var indexInCategory_1 = 0;
  42034. var totalInCategory_1 = 0;
  42035. // Loop over all the stacks on the Y axis. When stacking is
  42036. // enabled, these are real point stacks. When stacking is not
  42037. // enabled, but `centerInCategory` is true, there is one stack
  42038. // handling the grouping of points in each category. This is
  42039. // done in the `setGroupedPoints` function.
  42040. objectEach(this.yAxis.stacking && this.yAxis.stacking.stacks, function (stack) {
  42041. if (typeof point.x === 'number') {
  42042. var stackItem = stack[point.x.toString()];
  42043. if (stackItem) {
  42044. var pointValues = stackItem.points[_this.index],
  42045. total = stackItem.total;
  42046. // If true `stacking` is enabled, count the
  42047. // total number of non-null stacks in the
  42048. // category, and note which index this point is
  42049. // within those stacks.
  42050. if (stacking) {
  42051. if (pointValues) {
  42052. indexInCategory_1 = totalInCategory_1;
  42053. }
  42054. if (stackItem.hasValidPoints) {
  42055. totalInCategory_1++;
  42056. }
  42057. // If `stacking` is not enabled, look for the
  42058. // index and total of the `group` stack.
  42059. }
  42060. else if (isArray(pointValues)) {
  42061. indexInCategory_1 = pointValues[1];
  42062. totalInCategory_1 = total || 0;
  42063. }
  42064. }
  42065. }
  42066. });
  42067. // Compute the adjusted x position
  42068. var boxWidth = (totalInCategory_1 - 1) * metrics.paddedWidth +
  42069. pointWidth;
  42070. x = (point.plotX || 0) + boxWidth / 2 - pointWidth -
  42071. indexInCategory_1 * metrics.paddedWidth;
  42072. }
  42073. return x;
  42074. };
  42075. /**
  42076. * Translate each point to the plot area coordinate system and find
  42077. * shape positions
  42078. *
  42079. * @private
  42080. * @function Highcharts.seriesTypes.column#translate
  42081. */
  42082. ColumnSeries.prototype.translate = function () {
  42083. var series = this,
  42084. chart = series.chart,
  42085. options = series.options,
  42086. dense = series.dense =
  42087. series.closestPointRange * series.xAxis.transA < 2,
  42088. borderWidth = series.borderWidth = pick(options.borderWidth,
  42089. dense ? 0 : 1 // #3635
  42090. ),
  42091. xAxis = series.xAxis,
  42092. yAxis = series.yAxis,
  42093. threshold = options.threshold,
  42094. translatedThreshold = series.translatedThreshold =
  42095. yAxis.getThreshold(threshold),
  42096. minPointLength = pick(options.minPointLength, 5),
  42097. metrics = series.getColumnMetrics(),
  42098. seriesPointWidth = metrics.width,
  42099. // postprocessed for border width
  42100. seriesBarW = series.barW =
  42101. Math.max(seriesPointWidth, 1 + 2 * borderWidth),
  42102. seriesXOffset = series.pointXOffset = metrics.offset,
  42103. dataMin = series.dataMin,
  42104. dataMax = series.dataMax;
  42105. if (chart.inverted) {
  42106. translatedThreshold -= 0.5; // #3355
  42107. }
  42108. // When the pointPadding is 0, we want the columns to be packed
  42109. // tightly, so we allow individual columns to have individual sizes.
  42110. // When pointPadding is greater, we strive for equal-width columns
  42111. // (#2694).
  42112. if (options.pointPadding) {
  42113. seriesBarW = Math.ceil(seriesBarW);
  42114. }
  42115. Series.prototype.translate.apply(series);
  42116. // Record the new values
  42117. series.points.forEach(function (point) {
  42118. var yBottom = pick(point.yBottom,
  42119. translatedThreshold),
  42120. safeDistance = 999 + Math.abs(yBottom),
  42121. pointWidth = seriesPointWidth,
  42122. plotX = point.plotX || 0,
  42123. // Don't draw too far outside plot area (#1303, #2241,
  42124. // #4264)
  42125. plotY = clamp(point.plotY, -safeDistance,
  42126. yAxis.len + safeDistance),
  42127. barX = plotX + seriesXOffset,
  42128. barW = seriesBarW,
  42129. barY = Math.min(plotY,
  42130. yBottom),
  42131. up,
  42132. barH = Math.max(plotY,
  42133. yBottom) - barY;
  42134. // Handle options.minPointLength
  42135. if (minPointLength && Math.abs(barH) < minPointLength) {
  42136. barH = minPointLength;
  42137. up = (!yAxis.reversed && !point.negative) ||
  42138. (yAxis.reversed && point.negative);
  42139. // Reverse zeros if there's no positive value in the series
  42140. // in visible range (#7046)
  42141. if (isNumber(threshold) &&
  42142. isNumber(dataMax) &&
  42143. point.y === threshold &&
  42144. dataMax <= threshold &&
  42145. // and if there's room for it (#7311)
  42146. (yAxis.min || 0) < threshold &&
  42147. // if all points are the same value (i.e zero) not draw
  42148. // as negative points (#10646), but only if there's room
  42149. // for it (#14876)
  42150. (dataMin !== dataMax || (yAxis.max || 0) <= threshold)) {
  42151. up = !up;
  42152. }
  42153. // If stacked...
  42154. barY = (Math.abs(barY - translatedThreshold) > minPointLength ?
  42155. // ...keep position
  42156. yBottom - minPointLength :
  42157. // #1485, #4051
  42158. translatedThreshold -
  42159. (up ? minPointLength : 0));
  42160. }
  42161. // Handle point.options.pointWidth
  42162. // @todo Handle grouping/stacking too. Calculate offset properly
  42163. if (defined(point.options.pointWidth)) {
  42164. pointWidth = barW =
  42165. Math.ceil(point.options.pointWidth);
  42166. barX -= Math.round((pointWidth - seriesPointWidth) / 2);
  42167. }
  42168. // Adjust for null or missing points
  42169. if (options.centerInCategory) {
  42170. barX = series.adjustForMissingColumns(barX, pointWidth, point, metrics);
  42171. }
  42172. // Cache for access in polar
  42173. point.barX = barX;
  42174. point.pointWidth = pointWidth;
  42175. // Fix the tooltip on center of grouped columns (#1216, #424,
  42176. // #3648)
  42177. point.tooltipPos = chart.inverted ?
  42178. [
  42179. clamp(yAxis.len + yAxis.pos - chart.plotLeft - plotY, yAxis.pos - chart.plotLeft, yAxis.len + yAxis.pos - chart.plotLeft),
  42180. xAxis.len + xAxis.pos - chart.plotTop - barX - barW / 2,
  42181. barH
  42182. ] :
  42183. [
  42184. xAxis.left - chart.plotLeft + barX + barW / 2,
  42185. clamp(plotY + yAxis.pos -
  42186. chart.plotTop, yAxis.pos - chart.plotTop, yAxis.len + yAxis.pos - chart.plotTop),
  42187. barH
  42188. ];
  42189. // Register shape type and arguments to be used in drawPoints
  42190. // Allow shapeType defined on pointClass level
  42191. point.shapeType = series.pointClass.prototype.shapeType || 'rect';
  42192. point.shapeArgs = series.crispCol.apply(series, point.isNull ?
  42193. // #3169, drilldown from null must have a position to work
  42194. // from #6585, dataLabel should be placed on xAxis, not
  42195. // floating in the middle of the chart
  42196. [barX, translatedThreshold, barW, 0] :
  42197. [barX, barY, barW, barH]);
  42198. });
  42199. };
  42200. /**
  42201. * Columns have no graph
  42202. *
  42203. * @private
  42204. * @function Highcharts.seriesTypes.column#drawGraph
  42205. */
  42206. ColumnSeries.prototype.drawGraph = function () {
  42207. this.group[this.dense ? 'addClass' : 'removeClass']('highcharts-dense-data');
  42208. };
  42209. /**
  42210. * Get presentational attributes
  42211. *
  42212. * @private
  42213. * @function Highcharts.seriesTypes.column#pointAttribs
  42214. */
  42215. ColumnSeries.prototype.pointAttribs = function (point, state) {
  42216. var options = this.options, stateOptions, ret, p2o = this.pointAttrToOptions || {}, strokeOption = p2o.stroke || 'borderColor', strokeWidthOption = p2o['stroke-width'] || 'borderWidth', fill = (point && point.color) || this.color,
  42217. // set to fill when borderColor null:
  42218. stroke = ((point && point[strokeOption]) ||
  42219. options[strokeOption] ||
  42220. fill), strokeWidth = (point && point[strokeWidthOption]) ||
  42221. options[strokeWidthOption] ||
  42222. this[strokeWidthOption] || 0, dashstyle = (point && point.options.dashStyle) || options.dashStyle, opacity = pick(point && point.opacity, options.opacity, 1), zone, brightness;
  42223. // Handle zone colors
  42224. if (point && this.zones.length) {
  42225. zone = point.getZone();
  42226. // When zones are present, don't use point.color (#4267).
  42227. // Changed order (#6527), added support for colorAxis (#10670)
  42228. fill = (point.options.color ||
  42229. (zone && (zone.color || point.nonZonedColor)) ||
  42230. this.color);
  42231. if (zone) {
  42232. stroke = zone.borderColor || stroke;
  42233. dashstyle = zone.dashStyle || dashstyle;
  42234. strokeWidth = zone.borderWidth || strokeWidth;
  42235. }
  42236. }
  42237. // Select or hover states
  42238. if (state && point) {
  42239. stateOptions = merge(options.states[state],
  42240. // #6401
  42241. point.options.states &&
  42242. point.options.states[state] ||
  42243. {});
  42244. brightness = stateOptions.brightness;
  42245. fill =
  42246. stateOptions.color || (typeof brightness !== 'undefined' &&
  42247. color(fill)
  42248. .brighten(stateOptions.brightness)
  42249. .get()) || fill;
  42250. stroke = stateOptions[strokeOption] || stroke;
  42251. strokeWidth =
  42252. stateOptions[strokeWidthOption] || strokeWidth;
  42253. dashstyle = stateOptions.dashStyle || dashstyle;
  42254. opacity = pick(stateOptions.opacity, opacity);
  42255. }
  42256. ret = {
  42257. fill: fill,
  42258. stroke: stroke,
  42259. 'stroke-width': strokeWidth,
  42260. opacity: opacity
  42261. };
  42262. if (dashstyle) {
  42263. ret.dashstyle = dashstyle;
  42264. }
  42265. return ret;
  42266. };
  42267. /**
  42268. * Draw the columns. For bars, the series.group is rotated, so the same
  42269. * coordinates apply for columns and bars. This method is inherited by
  42270. * scatter series.
  42271. *
  42272. * @private
  42273. * @function Highcharts.seriesTypes.column#drawPoints
  42274. */
  42275. ColumnSeries.prototype.drawPoints = function () {
  42276. var series = this,
  42277. chart = this.chart,
  42278. options = series.options,
  42279. renderer = chart.renderer,
  42280. animationLimit = options.animationLimit || 250,
  42281. shapeArgs;
  42282. // draw the columns
  42283. series.points.forEach(function (point) {
  42284. var plotY = point.plotY,
  42285. graphic = point.graphic,
  42286. hasGraphic = !!graphic,
  42287. verb = graphic && chart.pointCount < animationLimit ?
  42288. 'animate' : 'attr';
  42289. if (isNumber(plotY) && point.y !== null) {
  42290. shapeArgs = point.shapeArgs;
  42291. // When updating a series between 2d and 3d or cartesian and
  42292. // polar, the shape type changes.
  42293. if (graphic && point.hasNewShapeType()) {
  42294. graphic = graphic.destroy();
  42295. }
  42296. // Set starting position for point sliding animation.
  42297. if (series.enabledDataSorting) {
  42298. point.startXPos = series.xAxis.reversed ?
  42299. -(shapeArgs ? (shapeArgs.width || 0) : 0) :
  42300. series.xAxis.width;
  42301. }
  42302. if (!graphic) {
  42303. point.graphic = graphic =
  42304. renderer[point.shapeType](shapeArgs)
  42305. .add(point.group || series.group);
  42306. if (graphic &&
  42307. series.enabledDataSorting &&
  42308. chart.hasRendered &&
  42309. chart.pointCount < animationLimit) {
  42310. graphic.attr({
  42311. x: point.startXPos
  42312. });
  42313. hasGraphic = true;
  42314. verb = 'animate';
  42315. }
  42316. }
  42317. if (graphic && hasGraphic) { // update
  42318. graphic[verb](merge(shapeArgs));
  42319. }
  42320. // Border radius is not stylable (#6900)
  42321. if (options.borderRadius) {
  42322. graphic[verb]({
  42323. r: options.borderRadius
  42324. });
  42325. }
  42326. // Presentational
  42327. if (!chart.styledMode) {
  42328. graphic[verb](series.pointAttribs(point, (point.selected && 'select')))
  42329. .shadow(point.allowShadow !== false && options.shadow, null, options.stacking && !options.borderRadius);
  42330. }
  42331. if (graphic) {
  42332. graphic.addClass(point.getClassName(), true);
  42333. graphic.attr({
  42334. visibility: point.visible ? 'inherit' : 'hidden'
  42335. });
  42336. }
  42337. }
  42338. else if (graphic) {
  42339. point.graphic = graphic.destroy(); // #1269
  42340. }
  42341. });
  42342. };
  42343. /**
  42344. * Draw the tracker for a point.
  42345. * @private
  42346. */
  42347. ColumnSeries.prototype.drawTracker = function () {
  42348. var series = this,
  42349. chart = series.chart,
  42350. pointer = chart.pointer,
  42351. onMouseOver = function (e) {
  42352. var point = pointer.getPointFromEvent(e);
  42353. // undefined on graph in scatterchart
  42354. if (typeof point !== 'undefined') {
  42355. pointer.isDirectTouch = true;
  42356. point.onMouseOver(e);
  42357. }
  42358. }, dataLabels;
  42359. // Add reference to the point
  42360. series.points.forEach(function (point) {
  42361. dataLabels = (isArray(point.dataLabels) ?
  42362. point.dataLabels :
  42363. (point.dataLabel ? [point.dataLabel] : []));
  42364. if (point.graphic) {
  42365. point.graphic.element.point = point;
  42366. }
  42367. dataLabels.forEach(function (dataLabel) {
  42368. if (dataLabel.div) {
  42369. dataLabel.div.point = point;
  42370. }
  42371. else {
  42372. dataLabel.element.point = point;
  42373. }
  42374. });
  42375. });
  42376. // Add the event listeners, we need to do this only once
  42377. if (!series._hasTracking) {
  42378. series.trackerGroups.forEach(function (key) {
  42379. if (series[key]) {
  42380. // we don't always have dataLabelsGroup
  42381. series[key]
  42382. .addClass('highcharts-tracker')
  42383. .on('mouseover', onMouseOver)
  42384. .on('mouseout', function (e) {
  42385. pointer.onTrackerMouseOut(e);
  42386. });
  42387. if (hasTouch) {
  42388. series[key].on('touchstart', onMouseOver);
  42389. }
  42390. if (!chart.styledMode && series.options.cursor) {
  42391. series[key]
  42392. .css(css)
  42393. .css({ cursor: series.options.cursor });
  42394. }
  42395. }
  42396. });
  42397. series._hasTracking = true;
  42398. }
  42399. fireEvent(this, 'afterDrawTracker');
  42400. };
  42401. /**
  42402. * Remove this series from the chart
  42403. *
  42404. * @private
  42405. * @function Highcharts.seriesTypes.column#remove
  42406. */
  42407. ColumnSeries.prototype.remove = function () {
  42408. var series = this,
  42409. chart = series.chart;
  42410. // column and bar series affects other series of the same type
  42411. // as they are either stacked or grouped
  42412. if (chart.hasRendered) {
  42413. chart.series.forEach(function (otherSeries) {
  42414. if (otherSeries.type === series.type) {
  42415. otherSeries.isDirty = true;
  42416. }
  42417. });
  42418. }
  42419. Series.prototype.remove.apply(series, arguments);
  42420. };
  42421. /**
  42422. * Column series display one column per value along an X axis.
  42423. *
  42424. * @sample {highcharts} highcharts/demo/column-basic/
  42425. * Column chart
  42426. * @sample {highstock} stock/demo/column/
  42427. * Column chart
  42428. *
  42429. * @extends plotOptions.line
  42430. * @excluding connectEnds, connectNulls, gapSize, gapUnit, linecap,
  42431. * lineWidth, marker, step, useOhlcData
  42432. * @product highcharts highstock
  42433. * @optionparent plotOptions.column
  42434. */
  42435. ColumnSeries.defaultOptions = merge(Series.defaultOptions, {
  42436. /**
  42437. * The corner radius of the border surrounding each column or bar.
  42438. *
  42439. * @sample {highcharts} highcharts/plotoptions/column-borderradius/
  42440. * Rounded columns
  42441. *
  42442. * @product highcharts highstock gantt
  42443. *
  42444. * @private
  42445. */
  42446. borderRadius: 0,
  42447. /**
  42448. * When using automatic point colors pulled from the global
  42449. * [colors](colors) or series-specific
  42450. * [plotOptions.column.colors](series.colors) collections, this option
  42451. * determines whether the chart should receive one color per series or
  42452. * one color per point.
  42453. *
  42454. * In styled mode, the `colors` or `series.colors` arrays are not
  42455. * supported, and instead this option gives the points individual color
  42456. * class names on the form `highcharts-color-{n}`.
  42457. *
  42458. * @see [series colors](#plotOptions.column.colors)
  42459. *
  42460. * @sample {highcharts} highcharts/plotoptions/column-colorbypoint-false/
  42461. * False by default
  42462. * @sample {highcharts} highcharts/plotoptions/column-colorbypoint-true/
  42463. * True
  42464. *
  42465. * @type {boolean}
  42466. * @default false
  42467. * @since 2.0
  42468. * @product highcharts highstock gantt
  42469. * @apioption plotOptions.column.colorByPoint
  42470. */
  42471. /**
  42472. * A series specific or series type specific color set to apply instead
  42473. * of the global [colors](#colors) when [colorByPoint](
  42474. * #plotOptions.column.colorByPoint) is true.
  42475. *
  42476. * @type {Array<Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject>}
  42477. * @since 3.0
  42478. * @product highcharts highstock gantt
  42479. * @apioption plotOptions.column.colors
  42480. */
  42481. /**
  42482. * When `true`, the columns will center in the category, ignoring null
  42483. * or missing points. When `false`, space will be reserved for null or
  42484. * missing points.
  42485. *
  42486. * @sample {highcharts} highcharts/series-column/centerincategory/
  42487. * Center in category
  42488. *
  42489. * @since 8.0.1
  42490. * @product highcharts highstock gantt
  42491. *
  42492. * @private
  42493. */
  42494. centerInCategory: false,
  42495. /**
  42496. * Padding between each value groups, in x axis units.
  42497. *
  42498. * @sample {highcharts} highcharts/plotoptions/column-grouppadding-default/
  42499. * 0.2 by default
  42500. * @sample {highcharts} highcharts/plotoptions/column-grouppadding-none/
  42501. * No group padding - all columns are evenly spaced
  42502. *
  42503. * @product highcharts highstock gantt
  42504. *
  42505. * @private
  42506. */
  42507. groupPadding: 0.2,
  42508. /**
  42509. * Whether to group non-stacked columns or to let them render
  42510. * independent of each other. Non-grouped columns will be laid out
  42511. * individually and overlap each other.
  42512. *
  42513. * @sample {highcharts} highcharts/plotoptions/column-grouping-false/
  42514. * Grouping disabled
  42515. * @sample {highstock} highcharts/plotoptions/column-grouping-false/
  42516. * Grouping disabled
  42517. *
  42518. * @type {boolean}
  42519. * @default true
  42520. * @since 2.3.0
  42521. * @product highcharts highstock gantt
  42522. * @apioption plotOptions.column.grouping
  42523. */
  42524. /**
  42525. * @ignore-option
  42526. * @private
  42527. */
  42528. marker: null,
  42529. /**
  42530. * The maximum allowed pixel width for a column, translated to the
  42531. * height of a bar in a bar chart. This prevents the columns from
  42532. * becoming too wide when there is a small number of points in the
  42533. * chart.
  42534. *
  42535. * @see [pointWidth](#plotOptions.column.pointWidth)
  42536. *
  42537. * @sample {highcharts} highcharts/plotoptions/column-maxpointwidth-20/
  42538. * Limited to 50
  42539. * @sample {highstock} highcharts/plotoptions/column-maxpointwidth-20/
  42540. * Limited to 50
  42541. *
  42542. * @type {number}
  42543. * @since 4.1.8
  42544. * @product highcharts highstock gantt
  42545. * @apioption plotOptions.column.maxPointWidth
  42546. */
  42547. /**
  42548. * Padding between each column or bar, in x axis units.
  42549. *
  42550. * @sample {highcharts} highcharts/plotoptions/column-pointpadding-default/
  42551. * 0.1 by default
  42552. * @sample {highcharts} highcharts/plotoptions/column-pointpadding-025/
  42553. * 0.25
  42554. * @sample {highcharts} highcharts/plotoptions/column-pointpadding-none/
  42555. * 0 for tightly packed columns
  42556. *
  42557. * @product highcharts highstock gantt
  42558. *
  42559. * @private
  42560. */
  42561. pointPadding: 0.1,
  42562. /**
  42563. * A pixel value specifying a fixed width for each column or bar point.
  42564. * When set to `undefined`, the width is calculated from the
  42565. * `pointPadding` and `groupPadding`. The width effects the dimension
  42566. * that is not based on the point value. For column series it is the
  42567. * hoizontal length and for bar series it is the vertical length.
  42568. *
  42569. * @see [maxPointWidth](#plotOptions.column.maxPointWidth)
  42570. *
  42571. * @sample {highcharts} highcharts/plotoptions/column-pointwidth-20/
  42572. * 20px wide columns regardless of chart width or the amount of
  42573. * data points
  42574. *
  42575. * @type {number}
  42576. * @since 1.2.5
  42577. * @product highcharts highstock gantt
  42578. * @apioption plotOptions.column.pointWidth
  42579. */
  42580. /**
  42581. * A pixel value specifying a fixed width for the column or bar.
  42582. * Overrides pointWidth on the series.
  42583. *
  42584. * @see [series.pointWidth](#plotOptions.column.pointWidth)
  42585. *
  42586. * @type {number}
  42587. * @default undefined
  42588. * @since 7.0.0
  42589. * @product highcharts highstock gantt
  42590. * @apioption series.column.data.pointWidth
  42591. */
  42592. /**
  42593. * The minimal height for a column or width for a bar. By default,
  42594. * 0 values are not shown. To visualize a 0 (or close to zero) point,
  42595. * set the minimal point length to a pixel value like 3\. In stacked
  42596. * column charts, minPointLength might not be respected for tightly
  42597. * packed values.
  42598. *
  42599. * @sample {highcharts} highcharts/plotoptions/column-minpointlength/
  42600. * Zero base value
  42601. * @sample {highcharts} highcharts/plotoptions/column-minpointlength-pos-and-neg/
  42602. * Positive and negative close to zero values
  42603. *
  42604. * @product highcharts highstock gantt
  42605. *
  42606. * @private
  42607. */
  42608. minPointLength: 0,
  42609. /**
  42610. * When the series contains less points than the crop threshold, all
  42611. * points are drawn, event if the points fall outside the visible plot
  42612. * area at the current zoom. The advantage of drawing all points
  42613. * (including markers and columns), is that animation is performed on
  42614. * updates. On the other hand, when the series contains more points than
  42615. * the crop threshold, the series data is cropped to only contain points
  42616. * that fall within the plot area. The advantage of cropping away
  42617. * invisible points is to increase performance on large series.
  42618. *
  42619. * @product highcharts highstock gantt
  42620. *
  42621. * @private
  42622. */
  42623. cropThreshold: 50,
  42624. /**
  42625. * The X axis range that each point is valid for. This determines the
  42626. * width of the column. On a categorized axis, the range will be 1
  42627. * by default (one category unit). On linear and datetime axes, the
  42628. * range will be computed as the distance between the two closest data
  42629. * points.
  42630. *
  42631. * The default `null` means it is computed automatically, but this
  42632. * option can be used to override the automatic value.
  42633. *
  42634. * This option is set by default to 1 if data sorting is enabled.
  42635. *
  42636. * @sample {highcharts} highcharts/plotoptions/column-pointrange/
  42637. * Set the point range to one day on a data set with one week
  42638. * between the points
  42639. *
  42640. * @type {number|null}
  42641. * @since 2.3
  42642. * @product highcharts highstock gantt
  42643. *
  42644. * @private
  42645. */
  42646. pointRange: null,
  42647. states: {
  42648. /**
  42649. * Options for the hovered point. These settings override the normal
  42650. * state options when a point is moused over or touched.
  42651. *
  42652. * @extends plotOptions.series.states.hover
  42653. * @excluding halo, lineWidth, lineWidthPlus, marker
  42654. * @product highcharts highstock gantt
  42655. */
  42656. hover: {
  42657. /** @ignore-option */
  42658. halo: false,
  42659. /**
  42660. * A specific border color for the hovered point. Defaults to
  42661. * inherit the normal state border color.
  42662. *
  42663. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  42664. * @product highcharts gantt
  42665. * @apioption plotOptions.column.states.hover.borderColor
  42666. */
  42667. /**
  42668. * A specific color for the hovered point.
  42669. *
  42670. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  42671. * @product highcharts gantt
  42672. * @apioption plotOptions.column.states.hover.color
  42673. */
  42674. /**
  42675. * How much to brighten the point on interaction. Requires the
  42676. * main color to be defined in hex or rgb(a) format.
  42677. *
  42678. * In styled mode, the hover brightening is by default replaced
  42679. * with a fill-opacity set in the `.highcharts-point:hover`
  42680. * rule.
  42681. *
  42682. * @sample {highcharts} highcharts/plotoptions/column-states-hover-brightness/
  42683. * Brighten by 0.5
  42684. *
  42685. * @product highcharts highstock gantt
  42686. */
  42687. brightness: 0.1
  42688. },
  42689. /**
  42690. * Options for the selected point. These settings override the
  42691. * normal state options when a point is selected.
  42692. *
  42693. * @extends plotOptions.series.states.select
  42694. * @excluding halo, lineWidth, lineWidthPlus, marker
  42695. * @product highcharts highstock gantt
  42696. */
  42697. select: {
  42698. /**
  42699. * A specific color for the selected point.
  42700. *
  42701. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  42702. * @default #cccccc
  42703. * @product highcharts highstock gantt
  42704. */
  42705. color: palette.neutralColor20,
  42706. /**
  42707. * A specific border color for the selected point.
  42708. *
  42709. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  42710. * @default #000000
  42711. * @product highcharts highstock gantt
  42712. */
  42713. borderColor: palette.neutralColor100
  42714. }
  42715. },
  42716. dataLabels: {
  42717. align: void 0,
  42718. verticalAlign: void 0,
  42719. /**
  42720. * The y position offset of the label relative to the point in
  42721. * pixels.
  42722. *
  42723. * @type {number}
  42724. */
  42725. y: void 0
  42726. },
  42727. // false doesn't work well: https://jsfiddle.net/highcharts/hz8fopan/14/
  42728. /**
  42729. * @ignore-option
  42730. * @private
  42731. */
  42732. startFromThreshold: true,
  42733. stickyTracking: false,
  42734. tooltip: {
  42735. distance: 6
  42736. },
  42737. /**
  42738. * The Y axis value to serve as the base for the columns, for
  42739. * distinguishing between values above and below a threshold. If `null`,
  42740. * the columns extend from the padding Y axis minimum.
  42741. *
  42742. * @type {number|null}
  42743. * @since 2.0
  42744. * @product highcharts
  42745. *
  42746. * @private
  42747. */
  42748. threshold: 0,
  42749. /**
  42750. * The width of the border surrounding each column or bar. Defaults to
  42751. * `1` when there is room for a border, but to `0` when the columns are
  42752. * so dense that a border would cover the next column.
  42753. *
  42754. * In styled mode, the stroke width can be set with the
  42755. * `.highcharts-point` rule.
  42756. *
  42757. * @sample {highcharts} highcharts/plotoptions/column-borderwidth/
  42758. * 2px black border
  42759. *
  42760. * @type {number}
  42761. * @default undefined
  42762. * @product highcharts highstock gantt
  42763. * @apioption plotOptions.column.borderWidth
  42764. */
  42765. /**
  42766. * The color of the border surrounding each column or bar.
  42767. *
  42768. * In styled mode, the border stroke can be set with the
  42769. * `.highcharts-point` rule.
  42770. *
  42771. * @sample {highcharts} highcharts/plotoptions/column-bordercolor/
  42772. * Dark gray border
  42773. *
  42774. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  42775. * @default #ffffff
  42776. * @product highcharts highstock gantt
  42777. *
  42778. * @private
  42779. */
  42780. borderColor: palette.backgroundColor
  42781. });
  42782. return ColumnSeries;
  42783. }(Series));
  42784. extend(ColumnSeries.prototype, {
  42785. cropShoulder: 0,
  42786. // When tooltip is not shared, this series (and derivatives) requires
  42787. // direct touch/hover. KD-tree does not apply.
  42788. directTouch: true,
  42789. /**
  42790. * Use a solid rectangle like the area series types
  42791. *
  42792. * @private
  42793. * @function Highcharts.seriesTypes.column#drawLegendSymbol
  42794. *
  42795. * @param {Highcharts.Legend} legend
  42796. * The legend object
  42797. *
  42798. * @param {Highcharts.Series|Highcharts.Point} item
  42799. * The series (this) or point
  42800. */
  42801. drawLegendSymbol: LegendSymbolMixin.drawRectangle,
  42802. getSymbol: noop,
  42803. // use separate negative stacks, unlike area stacks where a negative
  42804. // point is substracted from previous (#1910)
  42805. negStacks: true,
  42806. trackerGroups: ['group', 'dataLabelsGroup']
  42807. });
  42808. SeriesRegistry.registerSeriesType('column', ColumnSeries);
  42809. /* *
  42810. *
  42811. * Export
  42812. *
  42813. * */
  42814. /* *
  42815. *
  42816. * API Declarations
  42817. *
  42818. * */
  42819. /**
  42820. * Adjusted width and x offset of the columns for grouping.
  42821. *
  42822. * @private
  42823. * @interface Highcharts.ColumnMetricsObject
  42824. */ /**
  42825. * Width of the columns.
  42826. * @name Highcharts.ColumnMetricsObject#width
  42827. * @type {number}
  42828. */ /**
  42829. * Offset of the columns.
  42830. * @name Highcharts.ColumnMetricsObject#offset
  42831. * @type {number}
  42832. */
  42833. ''; // detach doclets above
  42834. /* *
  42835. *
  42836. * API Options
  42837. *
  42838. * */
  42839. /**
  42840. * A `column` series. If the [type](#series.column.type) option is
  42841. * not specified, it is inherited from [chart.type](#chart.type).
  42842. *
  42843. * @extends series,plotOptions.column
  42844. * @excluding connectNulls, dataParser, dataURL, gapSize, gapUnit, linecap,
  42845. * lineWidth, marker, connectEnds, step
  42846. * @product highcharts highstock
  42847. * @apioption series.column
  42848. */
  42849. /**
  42850. * An array of data points for the series. For the `column` series type,
  42851. * points can be given in the following ways:
  42852. *
  42853. * 1. An array of numerical values. In this case, the numerical values will be
  42854. * interpreted as `y` options. The `x` values will be automatically
  42855. * calculated, either starting at 0 and incremented by 1, or from
  42856. * `pointStart` and `pointInterval` given in the series options. If the axis
  42857. * has categories, these will be used. Example:
  42858. * ```js
  42859. * data: [0, 5, 3, 5]
  42860. * ```
  42861. *
  42862. * 2. An array of arrays with 2 values. In this case, the values correspond to
  42863. * `x,y`. If the first value is a string, it is applied as the name of the
  42864. * point, and the `x` value is inferred.
  42865. * ```js
  42866. * data: [
  42867. * [0, 6],
  42868. * [1, 2],
  42869. * [2, 6]
  42870. * ]
  42871. * ```
  42872. *
  42873. * 3. An array of objects with named values. The following snippet shows only a
  42874. * few settings, see the complete options set below. If the total number of
  42875. * data points exceeds the series'
  42876. * [turboThreshold](#series.column.turboThreshold), this option is not
  42877. * available.
  42878. * ```js
  42879. * data: [{
  42880. * x: 1,
  42881. * y: 9,
  42882. * name: "Point2",
  42883. * color: "#00FF00"
  42884. * }, {
  42885. * x: 1,
  42886. * y: 6,
  42887. * name: "Point1",
  42888. * color: "#FF00FF"
  42889. * }]
  42890. * ```
  42891. *
  42892. * @sample {highcharts} highcharts/chart/reflow-true/
  42893. * Numerical values
  42894. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  42895. * Arrays of numeric x and y
  42896. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  42897. * Arrays of datetime x and y
  42898. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  42899. * Arrays of point.name and y
  42900. * @sample {highcharts} highcharts/series/data-array-of-objects/
  42901. * Config objects
  42902. *
  42903. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  42904. * @extends series.line.data
  42905. * @excluding marker
  42906. * @product highcharts highstock
  42907. * @apioption series.column.data
  42908. */
  42909. /**
  42910. * The color of the border surrounding the column or bar.
  42911. *
  42912. * In styled mode, the border stroke can be set with the `.highcharts-point`
  42913. * rule.
  42914. *
  42915. * @sample {highcharts} highcharts/plotoptions/column-bordercolor/
  42916. * Dark gray border
  42917. *
  42918. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  42919. * @product highcharts highstock
  42920. * @apioption series.column.data.borderColor
  42921. */
  42922. /**
  42923. * The width of the border surrounding the column or bar.
  42924. *
  42925. * In styled mode, the stroke width can be set with the `.highcharts-point`
  42926. * rule.
  42927. *
  42928. * @sample {highcharts} highcharts/plotoptions/column-borderwidth/
  42929. * 2px black border
  42930. *
  42931. * @type {number}
  42932. * @product highcharts highstock
  42933. * @apioption series.column.data.borderWidth
  42934. */
  42935. /**
  42936. * A name for the dash style to use for the column or bar. Overrides
  42937. * dashStyle on the series.
  42938. *
  42939. * In styled mode, the stroke dash-array can be set with the same classes as
  42940. * listed under [data.color](#series.column.data.color).
  42941. *
  42942. * @see [series.pointWidth](#plotOptions.column.dashStyle)
  42943. *
  42944. * @type {Highcharts.DashStyleValue}
  42945. * @apioption series.column.data.dashStyle
  42946. */
  42947. /**
  42948. * A pixel value specifying a fixed width for the column or bar. Overrides
  42949. * pointWidth on the series. The width effects the dimension that is not based
  42950. * on the point value.
  42951. *
  42952. * @see [series.pointWidth](#plotOptions.column.pointWidth)
  42953. *
  42954. * @type {number}
  42955. * @apioption series.column.data.pointWidth
  42956. */
  42957. /**
  42958. * @excluding halo, lineWidth, lineWidthPlus, marker
  42959. * @product highcharts highstock
  42960. * @apioption series.column.states.hover
  42961. */
  42962. /**
  42963. * @excluding halo, lineWidth, lineWidthPlus, marker
  42964. * @product highcharts highstock
  42965. * @apioption series.column.states.select
  42966. */
  42967. ''; // includes above doclets in transpilat
  42968. return ColumnSeries;
  42969. });
  42970. _registerModule(_modules, 'Series/Bar/BarSeries.js', [_modules['Series/Column/ColumnSeries.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (ColumnSeries, SeriesRegistry, U) {
  42971. /* *
  42972. *
  42973. * (c) 2010-2021 Torstein Honsi
  42974. *
  42975. * License: www.highcharts.com/license
  42976. *
  42977. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  42978. *
  42979. * */
  42980. var __extends = (this && this.__extends) || (function () {
  42981. var extendStatics = function (d,
  42982. b) {
  42983. extendStatics = Object.setPrototypeOf ||
  42984. ({ __proto__: [] } instanceof Array && function (d,
  42985. b) { d.__proto__ = b; }) ||
  42986. function (d,
  42987. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  42988. return extendStatics(d, b);
  42989. };
  42990. return function (d, b) {
  42991. extendStatics(d, b);
  42992. function __() { this.constructor = d; }
  42993. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  42994. };
  42995. })();
  42996. var extend = U.extend,
  42997. merge = U.merge;
  42998. /* *
  42999. *
  43000. * Class
  43001. *
  43002. * */
  43003. /**
  43004. * Bar series type.
  43005. *
  43006. * @private
  43007. * @class
  43008. * @name Highcharts.seriesTypes.bar
  43009. *
  43010. * @augments Highcharts.Series
  43011. */
  43012. var BarSeries = /** @class */ (function (_super) {
  43013. __extends(BarSeries, _super);
  43014. function BarSeries() {
  43015. /* *
  43016. *
  43017. * Static Properties
  43018. *
  43019. * */
  43020. var _this = _super !== null && _super.apply(this,
  43021. arguments) || this;
  43022. /* *
  43023. *
  43024. * Properties
  43025. *
  43026. * */
  43027. _this.data = void 0;
  43028. _this.options = void 0;
  43029. _this.points = void 0;
  43030. return _this;
  43031. }
  43032. /**
  43033. * A bar series is a special type of column series where the columns are
  43034. * horizontal.
  43035. *
  43036. * @sample highcharts/demo/bar-basic/
  43037. * Bar chart
  43038. *
  43039. * @extends plotOptions.column
  43040. * @product highcharts
  43041. * @optionparent plotOptions.bar
  43042. */
  43043. BarSeries.defaultOptions = merge(ColumnSeries.defaultOptions, {
  43044. // nothing here yet
  43045. });
  43046. return BarSeries;
  43047. }(ColumnSeries));
  43048. extend(BarSeries.prototype, {
  43049. inverted: true
  43050. });
  43051. SeriesRegistry.registerSeriesType('bar', BarSeries);
  43052. /* *
  43053. *
  43054. * Default Export
  43055. *
  43056. * */
  43057. /* *
  43058. *
  43059. * API Options
  43060. *
  43061. * */
  43062. /**
  43063. * A `bar` series. If the [type](#series.bar.type) option is not specified,
  43064. * it is inherited from [chart.type](#chart.type).
  43065. *
  43066. * @extends series,plotOptions.bar
  43067. * @excluding connectNulls, dashStyle, dataParser, dataURL, gapSize, gapUnit,
  43068. * linecap, lineWidth, marker, connectEnds, step
  43069. * @product highcharts
  43070. * @apioption series.bar
  43071. */
  43072. /**
  43073. * An array of data points for the series. For the `bar` series type,
  43074. * points can be given in the following ways:
  43075. *
  43076. * 1. An array of numerical values. In this case, the numerical values will be
  43077. * interpreted as `y` options. The `x` values will be automatically
  43078. * calculated, either starting at 0 and incremented by 1, or from
  43079. * `pointStart` and `pointInterval` given in the series options. If the axis
  43080. * has categories, these will be used. Example:
  43081. * ```js
  43082. * data: [0, 5, 3, 5]
  43083. * ```
  43084. *
  43085. * 2. An array of arrays with 2 values. In this case, the values correspond to
  43086. * `x,y`. If the first value is a string, it is applied as the name of the
  43087. * point, and the `x` value is inferred.
  43088. * ```js
  43089. * data: [
  43090. * [0, 5],
  43091. * [1, 10],
  43092. * [2, 3]
  43093. * ]
  43094. * ```
  43095. *
  43096. * 3. An array of objects with named values. The following snippet shows only a
  43097. * few settings, see the complete options set below. If the total number of
  43098. * data points exceeds the series'
  43099. * [turboThreshold](#series.bar.turboThreshold), this option is not
  43100. * available.
  43101. * ```js
  43102. * data: [{
  43103. * x: 1,
  43104. * y: 1,
  43105. * name: "Point2",
  43106. * color: "#00FF00"
  43107. * }, {
  43108. * x: 1,
  43109. * y: 10,
  43110. * name: "Point1",
  43111. * color: "#FF00FF"
  43112. * }]
  43113. * ```
  43114. *
  43115. * @sample {highcharts} highcharts/chart/reflow-true/
  43116. * Numerical values
  43117. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  43118. * Arrays of numeric x and y
  43119. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  43120. * Arrays of datetime x and y
  43121. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  43122. * Arrays of point.name and y
  43123. * @sample {highcharts} highcharts/series/data-array-of-objects/
  43124. * Config objects
  43125. *
  43126. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  43127. * @extends series.column.data
  43128. * @product highcharts
  43129. * @apioption series.bar.data
  43130. */
  43131. /**
  43132. * @excluding halo,lineWidth,lineWidthPlus,marker
  43133. * @product highcharts highstock
  43134. * @apioption series.bar.states.hover
  43135. */
  43136. /**
  43137. * @excluding halo,lineWidth,lineWidthPlus,marker
  43138. * @product highcharts highstock
  43139. * @apioption series.bar.states.select
  43140. */
  43141. ''; // gets doclets above into transpilat
  43142. return BarSeries;
  43143. });
  43144. _registerModule(_modules, 'Series/Scatter/ScatterSeries.js', [_modules['Series/Column/ColumnSeries.js'], _modules['Series/Line/LineSeries.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (ColumnSeries, LineSeries, SeriesRegistry, U) {
  43145. /* *
  43146. *
  43147. * (c) 2010-2021 Torstein Honsi
  43148. *
  43149. * License: www.highcharts.com/license
  43150. *
  43151. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  43152. *
  43153. * */
  43154. var __extends = (this && this.__extends) || (function () {
  43155. var extendStatics = function (d,
  43156. b) {
  43157. extendStatics = Object.setPrototypeOf ||
  43158. ({ __proto__: [] } instanceof Array && function (d,
  43159. b) { d.__proto__ = b; }) ||
  43160. function (d,
  43161. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  43162. return extendStatics(d, b);
  43163. };
  43164. return function (d, b) {
  43165. extendStatics(d, b);
  43166. function __() { this.constructor = d; }
  43167. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  43168. };
  43169. })();
  43170. var addEvent = U.addEvent,
  43171. extend = U.extend,
  43172. merge = U.merge;
  43173. /* *
  43174. *
  43175. * Class
  43176. *
  43177. * */
  43178. /**
  43179. * Scatter series type.
  43180. *
  43181. * @private
  43182. */
  43183. var ScatterSeries = /** @class */ (function (_super) {
  43184. __extends(ScatterSeries, _super);
  43185. function ScatterSeries() {
  43186. var _this = _super !== null && _super.apply(this,
  43187. arguments) || this;
  43188. /* *
  43189. *
  43190. * Properties
  43191. *
  43192. * */
  43193. _this.data = void 0;
  43194. _this.options = void 0;
  43195. _this.points = void 0;
  43196. return _this;
  43197. /* eslint-enable valid-jsdoc */
  43198. }
  43199. /* *
  43200. *
  43201. * Functions
  43202. *
  43203. * */
  43204. /* eslint-disable valid-jsdoc */
  43205. /**
  43206. * Optionally add the jitter effect.
  43207. * @private
  43208. */
  43209. ScatterSeries.prototype.applyJitter = function () {
  43210. var series = this,
  43211. jitter = this.options.jitter,
  43212. len = this.points.length;
  43213. /**
  43214. * Return a repeatable, pseudo-random number based on an integer
  43215. * seed.
  43216. * @private
  43217. */
  43218. function unrandom(seed) {
  43219. var rand = Math.sin(seed) * 10000;
  43220. return rand - Math.floor(rand);
  43221. }
  43222. if (jitter) {
  43223. this.points.forEach(function (point, i) {
  43224. ['x', 'y'].forEach(function (dim, j) {
  43225. var axis,
  43226. plotProp = 'plot' + dim.toUpperCase(),
  43227. min,
  43228. max,
  43229. translatedJitter;
  43230. if (jitter[dim] && !point.isNull) {
  43231. axis = series[dim + 'Axis'];
  43232. translatedJitter =
  43233. jitter[dim] * axis.transA;
  43234. if (axis && !axis.isLog) {
  43235. // Identify the outer bounds of the jitter range
  43236. min = Math.max(0, point[plotProp] - translatedJitter);
  43237. max = Math.min(axis.len, point[plotProp] + translatedJitter);
  43238. // Find a random position within this range
  43239. point[plotProp] = min +
  43240. (max - min) * unrandom(i + j * len);
  43241. // Update clientX for the tooltip k-d-tree
  43242. if (dim === 'x') {
  43243. point.clientX = point.plotX;
  43244. }
  43245. }
  43246. }
  43247. });
  43248. });
  43249. }
  43250. };
  43251. /**
  43252. * @private
  43253. * @function Highcharts.seriesTypes.scatter#drawGraph
  43254. */
  43255. ScatterSeries.prototype.drawGraph = function () {
  43256. if (this.options.lineWidth) {
  43257. _super.prototype.drawGraph.call(this);
  43258. }
  43259. else if (this.graph) {
  43260. this.graph = this.graph.destroy();
  43261. }
  43262. };
  43263. /**
  43264. * A scatter plot uses cartesian coordinates to display values for two
  43265. * variables for a set of data.
  43266. *
  43267. * @sample {highcharts} highcharts/demo/scatter/
  43268. * Scatter plot
  43269. *
  43270. * @extends plotOptions.line
  43271. * @excluding cropThreshold, pointPlacement, shadow, useOhlcData
  43272. * @product highcharts highstock
  43273. * @optionparent plotOptions.scatter
  43274. */
  43275. ScatterSeries.defaultOptions = merge(LineSeries.defaultOptions, {
  43276. /**
  43277. * The width of the line connecting the data points.
  43278. *
  43279. * @sample {highcharts} highcharts/plotoptions/scatter-linewidth-none/
  43280. * 0 by default
  43281. * @sample {highcharts} highcharts/plotoptions/scatter-linewidth-1/
  43282. * 1px
  43283. *
  43284. * @product highcharts highstock
  43285. */
  43286. lineWidth: 0,
  43287. findNearestPointBy: 'xy',
  43288. /**
  43289. * Apply a jitter effect for the rendered markers. When plotting
  43290. * discrete values, a little random noise may help telling the points
  43291. * apart. The jitter setting applies a random displacement of up to `n`
  43292. * axis units in either direction. So for example on a horizontal X
  43293. * axis, setting the `jitter.x` to 0.24 will render the point in a
  43294. * random position between 0.24 units to the left and 0.24 units to the
  43295. * right of the true axis position. On a category axis, setting it to
  43296. * 0.5 will fill up the bin and make the data appear continuous.
  43297. *
  43298. * When rendered on top of a box plot or a column series, a jitter value
  43299. * of 0.24 will correspond to the underlying series' default
  43300. * [groupPadding](
  43301. * https://api.highcharts.com/highcharts/plotOptions.column.groupPadding)
  43302. * and [pointPadding](
  43303. * https://api.highcharts.com/highcharts/plotOptions.column.pointPadding)
  43304. * settings.
  43305. *
  43306. * @sample {highcharts} highcharts/series-scatter/jitter
  43307. * Jitter on a scatter plot
  43308. *
  43309. * @sample {highcharts} highcharts/series-scatter/jitter-boxplot
  43310. * Jittered scatter plot on top of a box plot
  43311. *
  43312. * @product highcharts highstock
  43313. * @since 7.0.2
  43314. */
  43315. jitter: {
  43316. /**
  43317. * The maximal X offset for the random jitter effect.
  43318. */
  43319. x: 0,
  43320. /**
  43321. * The maximal Y offset for the random jitter effect.
  43322. */
  43323. y: 0
  43324. },
  43325. marker: {
  43326. enabled: true // Overrides auto-enabling in line series (#3647)
  43327. },
  43328. /**
  43329. * Sticky tracking of mouse events. When true, the `mouseOut` event
  43330. * on a series isn't triggered until the mouse moves over another
  43331. * series, or out of the plot area. When false, the `mouseOut` event on
  43332. * a series is triggered when the mouse leaves the area around the
  43333. * series' graph or markers. This also implies the tooltip. When
  43334. * `stickyTracking` is false and `tooltip.shared` is false, the tooltip
  43335. * will be hidden when moving the mouse between series.
  43336. *
  43337. * @type {boolean}
  43338. * @default false
  43339. * @product highcharts highstock
  43340. * @apioption plotOptions.scatter.stickyTracking
  43341. */
  43342. /**
  43343. * A configuration object for the tooltip rendering of each single
  43344. * series. Properties are inherited from [tooltip](#tooltip).
  43345. * Overridable properties are `headerFormat`, `pointFormat`,
  43346. * `yDecimals`, `xDateFormat`, `yPrefix` and `ySuffix`. Unlike other
  43347. * series, in a scatter plot the series.name by default shows in the
  43348. * headerFormat and point.x and point.y in the pointFormat.
  43349. *
  43350. * @product highcharts highstock
  43351. */
  43352. tooltip: {
  43353. headerFormat: '<span style="color:{point.color}">\u25CF</span> ' +
  43354. '<span style="font-size: 10px"> {series.name}</span><br/>',
  43355. pointFormat: 'x: <b>{point.x}</b><br/>y: <b>{point.y}</b><br/>'
  43356. }
  43357. });
  43358. return ScatterSeries;
  43359. }(LineSeries));
  43360. extend(ScatterSeries.prototype, {
  43361. drawTracker: ColumnSeries.prototype.drawTracker,
  43362. sorted: false,
  43363. requireSorting: false,
  43364. noSharedTooltip: true,
  43365. trackerGroups: ['group', 'markerGroup', 'dataLabelsGroup'],
  43366. takeOrdinalPosition: false // #2342
  43367. });
  43368. /* *
  43369. *
  43370. * Events
  43371. *
  43372. * */
  43373. /* eslint-disable no-invalid-this */
  43374. addEvent(ScatterSeries, 'afterTranslate', function () {
  43375. this.applyJitter();
  43376. });
  43377. SeriesRegistry.registerSeriesType('scatter', ScatterSeries);
  43378. /* *
  43379. *
  43380. * Default Export
  43381. *
  43382. * */
  43383. /* *
  43384. *
  43385. * API Options
  43386. *
  43387. * */
  43388. /**
  43389. * A `scatter` series. If the [type](#series.scatter.type) option is
  43390. * not specified, it is inherited from [chart.type](#chart.type).
  43391. *
  43392. * @extends series,plotOptions.scatter
  43393. * @excluding cropThreshold, dataParser, dataURL, useOhlcData
  43394. * @product highcharts highstock
  43395. * @apioption series.scatter
  43396. */
  43397. /**
  43398. * An array of data points for the series. For the `scatter` series
  43399. * type, points can be given in the following ways:
  43400. *
  43401. * 1. An array of numerical values. In this case, the numerical values will be
  43402. * interpreted as `y` options. The `x` values will be automatically
  43403. * calculated, either starting at 0 and incremented by 1, or from
  43404. * `pointStart` and `pointInterval` given in the series options. If the axis
  43405. * has categories, these will be used. Example:
  43406. * ```js
  43407. * data: [0, 5, 3, 5]
  43408. * ```
  43409. *
  43410. * 2. An array of arrays with 2 values. In this case, the values correspond to
  43411. * `x,y`. If the first value is a string, it is applied as the name of the
  43412. * point, and the `x` value is inferred.
  43413. * ```js
  43414. * data: [
  43415. * [0, 0],
  43416. * [1, 8],
  43417. * [2, 9]
  43418. * ]
  43419. * ```
  43420. *
  43421. * 3. An array of objects with named values. The following snippet shows only a
  43422. * few settings, see the complete options set below. If the total number of
  43423. * data points exceeds the series'
  43424. * [turboThreshold](#series.scatter.turboThreshold), this option is not
  43425. * available.
  43426. * ```js
  43427. * data: [{
  43428. * x: 1,
  43429. * y: 2,
  43430. * name: "Point2",
  43431. * color: "#00FF00"
  43432. * }, {
  43433. * x: 1,
  43434. * y: 4,
  43435. * name: "Point1",
  43436. * color: "#FF00FF"
  43437. * }]
  43438. * ```
  43439. *
  43440. * @sample {highcharts} highcharts/chart/reflow-true/
  43441. * Numerical values
  43442. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  43443. * Arrays of numeric x and y
  43444. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  43445. * Arrays of datetime x and y
  43446. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  43447. * Arrays of point.name and y
  43448. * @sample {highcharts} highcharts/series/data-array-of-objects/
  43449. * Config objects
  43450. *
  43451. * @type {Array<number|Array<(number|string),(number|null)>|null|*>}
  43452. * @extends series.line.data
  43453. * @product highcharts highstock
  43454. * @apioption series.scatter.data
  43455. */
  43456. ''; // adds doclets above to transpilat
  43457. return ScatterSeries;
  43458. });
  43459. _registerModule(_modules, 'Mixins/CenteredSeries.js', [_modules['Core/Globals.js'], _modules['Core/Series/Series.js'], _modules['Core/Utilities.js']], function (H, Series, U) {
  43460. /* *
  43461. *
  43462. * (c) 2010-2021 Torstein Honsi
  43463. *
  43464. * License: www.highcharts.com/license
  43465. *
  43466. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  43467. *
  43468. * */
  43469. /**
  43470. * @private
  43471. * @interface Highcharts.RadianAngles
  43472. */ /**
  43473. * @name Highcharts.RadianAngles#end
  43474. * @type {number}
  43475. */ /**
  43476. * @name Highcharts.RadianAngles#start
  43477. * @type {number}
  43478. */
  43479. var isNumber = U.isNumber,
  43480. pick = U.pick,
  43481. relativeLength = U.relativeLength;
  43482. var deg2rad = H.deg2rad;
  43483. /* eslint-disable valid-jsdoc */
  43484. /**
  43485. * @private
  43486. * @mixin Highcharts.CenteredSeriesMixin
  43487. */
  43488. var centeredSeriesMixin = H.CenteredSeriesMixin = {
  43489. /**
  43490. * Get the center of the pie based on the size and center options relative
  43491. * to the plot area. Borrowed by the polar and gauge series types.
  43492. *
  43493. * @private
  43494. * @function Highcharts.CenteredSeriesMixin.getCenter
  43495. *
  43496. * @return {Array<number>}
  43497. */
  43498. getCenter: function () {
  43499. var options = this.options,
  43500. chart = this.chart,
  43501. slicingRoom = 2 * (options.slicedOffset || 0),
  43502. handleSlicingRoom,
  43503. plotWidth = chart.plotWidth - 2 * slicingRoom,
  43504. plotHeight = chart.plotHeight - 2 * slicingRoom,
  43505. centerOption = options.center,
  43506. smallestSize = Math.min(plotWidth,
  43507. plotHeight),
  43508. size = options.size,
  43509. innerSize = options.innerSize || 0,
  43510. positions,
  43511. i,
  43512. value;
  43513. if (typeof size === 'string') {
  43514. size = parseFloat(size);
  43515. }
  43516. if (typeof innerSize === 'string') {
  43517. innerSize = parseFloat(innerSize);
  43518. }
  43519. positions = [
  43520. pick(centerOption[0], '50%'),
  43521. pick(centerOption[1], '50%'),
  43522. // Prevent from negative values
  43523. pick(size && size < 0 ? void 0 : options.size, '100%'),
  43524. pick(innerSize && innerSize < 0 ? void 0 : options.innerSize || 0, '0%')
  43525. ];
  43526. // No need for inner size in angular (gauges) series but still required
  43527. // for pie series
  43528. if (chart.angular && !(this instanceof Series)) {
  43529. positions[3] = 0;
  43530. }
  43531. for (i = 0; i < 4; ++i) {
  43532. value = positions[i];
  43533. handleSlicingRoom = i < 2 || (i === 2 && /%$/.test(value));
  43534. // i == 0: centerX, relative to width
  43535. // i == 1: centerY, relative to height
  43536. // i == 2: size, relative to smallestSize
  43537. // i == 3: innerSize, relative to size
  43538. positions[i] = relativeLength(value, [plotWidth, plotHeight, smallestSize, positions[2]][i]) + (handleSlicingRoom ? slicingRoom : 0);
  43539. }
  43540. // innerSize cannot be larger than size (#3632)
  43541. if (positions[3] > positions[2]) {
  43542. positions[3] = positions[2];
  43543. }
  43544. return positions;
  43545. },
  43546. /**
  43547. * getStartAndEndRadians - Calculates start and end angles in radians.
  43548. * Used in series types such as pie and sunburst.
  43549. *
  43550. * @private
  43551. * @function Highcharts.CenteredSeriesMixin.getStartAndEndRadians
  43552. *
  43553. * @param {number} [start]
  43554. * Start angle in degrees.
  43555. *
  43556. * @param {number} [end]
  43557. * Start angle in degrees.
  43558. *
  43559. * @return {Highcharts.RadianAngles}
  43560. * Returns an object containing start and end angles as radians.
  43561. */
  43562. getStartAndEndRadians: function (start, end) {
  43563. var startAngle = isNumber(start) ? start : 0, // must be a number
  43564. endAngle = ((isNumber(end) && // must be a number
  43565. end > startAngle && // must be larger than the start angle
  43566. // difference must be less than 360 degrees
  43567. (end - startAngle) < 360) ?
  43568. end :
  43569. startAngle + 360),
  43570. correction = -90;
  43571. return {
  43572. start: deg2rad * (startAngle + correction),
  43573. end: deg2rad * (endAngle + correction)
  43574. };
  43575. }
  43576. };
  43577. return centeredSeriesMixin;
  43578. });
  43579. _registerModule(_modules, 'Series/Pie/PiePoint.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Series/Point.js'], _modules['Core/Utilities.js']], function (A, Point, U) {
  43580. /* *
  43581. *
  43582. * (c) 2010-2021 Torstein Honsi
  43583. *
  43584. * License: www.highcharts.com/license
  43585. *
  43586. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  43587. *
  43588. * */
  43589. var __extends = (this && this.__extends) || (function () {
  43590. var extendStatics = function (d,
  43591. b) {
  43592. extendStatics = Object.setPrototypeOf ||
  43593. ({ __proto__: [] } instanceof Array && function (d,
  43594. b) { d.__proto__ = b; }) ||
  43595. function (d,
  43596. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  43597. return extendStatics(d, b);
  43598. };
  43599. return function (d, b) {
  43600. extendStatics(d, b);
  43601. function __() { this.constructor = d; }
  43602. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  43603. };
  43604. })();
  43605. var setAnimation = A.setAnimation;
  43606. var addEvent = U.addEvent,
  43607. defined = U.defined,
  43608. extend = U.extend,
  43609. isNumber = U.isNumber,
  43610. pick = U.pick,
  43611. relativeLength = U.relativeLength;
  43612. /* *
  43613. *
  43614. * Class
  43615. *
  43616. * */
  43617. var PiePoint = /** @class */ (function (_super) {
  43618. __extends(PiePoint, _super);
  43619. function PiePoint() {
  43620. /* *
  43621. *
  43622. * Properties
  43623. *
  43624. * */
  43625. var _this = _super !== null && _super.apply(this,
  43626. arguments) || this;
  43627. _this.labelDistance = void 0;
  43628. _this.options = void 0;
  43629. _this.series = void 0;
  43630. return _this;
  43631. }
  43632. /* *
  43633. *
  43634. * Functions
  43635. *
  43636. * */
  43637. /* eslint-disable valid-jsdoc */
  43638. /**
  43639. * Extendable method for getting the path of the connector between the
  43640. * data label and the pie slice.
  43641. * @private
  43642. */
  43643. PiePoint.prototype.getConnectorPath = function () {
  43644. var labelPosition = this.labelPosition,
  43645. options = this.series.options.dataLabels,
  43646. connectorShape = options.connectorShape,
  43647. predefinedShapes = this.connectorShapes;
  43648. // find out whether to use the predefined shape
  43649. if (predefinedShapes[connectorShape]) {
  43650. connectorShape = predefinedShapes[connectorShape];
  43651. }
  43652. return connectorShape.call(this, {
  43653. // pass simplified label position object for user's convenience
  43654. x: labelPosition.final.x,
  43655. y: labelPosition.final.y,
  43656. alignment: labelPosition.alignment
  43657. }, labelPosition.connectorPosition, options);
  43658. };
  43659. /**
  43660. * @private
  43661. */
  43662. PiePoint.prototype.getTranslate = function () {
  43663. return this.sliced ? this.slicedTranslation : {
  43664. translateX: 0,
  43665. translateY: 0
  43666. };
  43667. };
  43668. /**
  43669. * @private
  43670. */
  43671. PiePoint.prototype.haloPath = function (size) {
  43672. var shapeArgs = this.shapeArgs;
  43673. return this.sliced || !this.visible ?
  43674. [] :
  43675. this.series.chart.renderer.symbols.arc(shapeArgs.x, shapeArgs.y, shapeArgs.r + size, shapeArgs.r + size, {
  43676. // Substract 1px to ensure the background is not bleeding
  43677. // through between the halo and the slice (#7495).
  43678. innerR: shapeArgs.r - 1,
  43679. start: shapeArgs.start,
  43680. end: shapeArgs.end
  43681. });
  43682. };
  43683. /**
  43684. * Initialize the pie slice.
  43685. * @private
  43686. */
  43687. PiePoint.prototype.init = function () {
  43688. Point.prototype.init.apply(this, arguments);
  43689. var point = this,
  43690. toggleSlice;
  43691. point.name = pick(point.name, 'Slice');
  43692. // add event listener for select
  43693. toggleSlice = function (e) {
  43694. point.slice(e.type === 'select');
  43695. };
  43696. addEvent(point, 'select', toggleSlice);
  43697. addEvent(point, 'unselect', toggleSlice);
  43698. return point;
  43699. };
  43700. /**
  43701. * Negative points are not valid (#1530, #3623, #5322)
  43702. * @private
  43703. */
  43704. PiePoint.prototype.isValid = function () {
  43705. return isNumber(this.y) && this.y >= 0;
  43706. };
  43707. /**
  43708. * Toggle the visibility of the pie slice.
  43709. * @private
  43710. *
  43711. * @param {boolean} vis
  43712. * Whether to show the slice or not. If undefined, the visibility is
  43713. * toggled.
  43714. */
  43715. PiePoint.prototype.setVisible = function (vis, redraw) {
  43716. var point = this,
  43717. series = point.series,
  43718. chart = series.chart,
  43719. ignoreHiddenPoint = series.options.ignoreHiddenPoint;
  43720. redraw = pick(redraw, ignoreHiddenPoint);
  43721. if (vis !== point.visible) {
  43722. // If called without an argument, toggle visibility
  43723. point.visible = point.options.visible = vis =
  43724. typeof vis === 'undefined' ? !point.visible : vis;
  43725. // update userOptions.data
  43726. series.options.data[series.data.indexOf(point)] =
  43727. point.options;
  43728. // Show and hide associated elements. This is performed
  43729. // regardless of redraw or not, because chart.redraw only
  43730. // handles full series.
  43731. ['graphic', 'dataLabel', 'connector', 'shadowGroup'].forEach(function (key) {
  43732. if (point[key]) {
  43733. point[key][vis ? 'show' : 'hide'](vis);
  43734. }
  43735. });
  43736. if (point.legendItem) {
  43737. chart.legend.colorizeItem(point, vis);
  43738. }
  43739. // #4170, hide halo after hiding point
  43740. if (!vis && point.state === 'hover') {
  43741. point.setState('');
  43742. }
  43743. // Handle ignore hidden slices
  43744. if (ignoreHiddenPoint) {
  43745. series.isDirty = true;
  43746. }
  43747. if (redraw) {
  43748. chart.redraw();
  43749. }
  43750. }
  43751. };
  43752. /**
  43753. * Set or toggle whether the slice is cut out from the pie.
  43754. * @private
  43755. *
  43756. * @param {boolean} sliced
  43757. * When undefined, the slice state is toggled.
  43758. *
  43759. * @param {boolean} redraw
  43760. * Whether to redraw the chart. True by default.
  43761. *
  43762. * @param {boolean|Partial<Highcharts.AnimationOptionsObject>}
  43763. * Animation options.
  43764. */
  43765. PiePoint.prototype.slice = function (sliced, redraw, animation) {
  43766. var point = this,
  43767. series = point.series,
  43768. chart = series.chart;
  43769. setAnimation(animation, chart);
  43770. // redraw is true by default
  43771. redraw = pick(redraw, true);
  43772. /**
  43773. * Pie series only. Whether to display a slice offset from the
  43774. * center.
  43775. * @name Highcharts.Point#sliced
  43776. * @type {boolean|undefined}
  43777. */
  43778. // if called without an argument, toggle
  43779. point.sliced = point.options.sliced = sliced =
  43780. defined(sliced) ? sliced : !point.sliced;
  43781. // update userOptions.data
  43782. series.options.data[series.data.indexOf(point)] =
  43783. point.options;
  43784. if (point.graphic) {
  43785. point.graphic.animate(this.getTranslate());
  43786. }
  43787. if (point.shadowGroup) {
  43788. point.shadowGroup.animate(this.getTranslate());
  43789. }
  43790. };
  43791. return PiePoint;
  43792. }(Point));
  43793. extend(PiePoint.prototype, {
  43794. connectorShapes: {
  43795. // only one available before v7.0.0
  43796. fixedOffset: function (labelPosition, connectorPosition, options) {
  43797. var breakAt = connectorPosition.breakAt,
  43798. touchingSliceAt = connectorPosition.touchingSliceAt,
  43799. lineSegment = options.softConnector ? [
  43800. 'C',
  43801. // 1st control point (of the curve)
  43802. labelPosition.x +
  43803. // 5 gives the connector a little horizontal bend
  43804. (labelPosition.alignment === 'left' ? -5 : 5),
  43805. labelPosition.y,
  43806. 2 * breakAt.x - touchingSliceAt.x,
  43807. 2 * breakAt.y - touchingSliceAt.y,
  43808. breakAt.x,
  43809. breakAt.y //
  43810. ] : [
  43811. 'L',
  43812. breakAt.x,
  43813. breakAt.y
  43814. ];
  43815. // assemble the path
  43816. return ([
  43817. ['M', labelPosition.x, labelPosition.y],
  43818. lineSegment,
  43819. ['L', touchingSliceAt.x, touchingSliceAt.y]
  43820. ]);
  43821. },
  43822. straight: function (labelPosition, connectorPosition) {
  43823. var touchingSliceAt = connectorPosition.touchingSliceAt;
  43824. // direct line to the slice
  43825. return [
  43826. ['M', labelPosition.x, labelPosition.y],
  43827. ['L', touchingSliceAt.x, touchingSliceAt.y]
  43828. ];
  43829. },
  43830. crookedLine: function (labelPosition, connectorPosition, options) {
  43831. var touchingSliceAt = connectorPosition.touchingSliceAt,
  43832. series = this.series,
  43833. pieCenterX = series.center[0],
  43834. plotWidth = series.chart.plotWidth,
  43835. plotLeft = series.chart.plotLeft,
  43836. alignment = labelPosition.alignment,
  43837. radius = this.shapeArgs.r,
  43838. crookDistance = relativeLength(// % to fraction
  43839. options.crookDistance, 1),
  43840. crookX = alignment === 'left' ?
  43841. pieCenterX + radius + (plotWidth + plotLeft -
  43842. pieCenterX - radius) * (1 - crookDistance) :
  43843. plotLeft + (pieCenterX - radius) * crookDistance,
  43844. segmentWithCrook = [
  43845. 'L',
  43846. crookX,
  43847. labelPosition.y
  43848. ],
  43849. useCrook = true;
  43850. // crookedLine formula doesn't make sense if the path overlaps
  43851. // the label - use straight line instead in that case
  43852. if (alignment === 'left' ?
  43853. (crookX > labelPosition.x || crookX < touchingSliceAt.x) :
  43854. (crookX < labelPosition.x || crookX > touchingSliceAt.x)) {
  43855. useCrook = false;
  43856. }
  43857. // assemble the path
  43858. var path = [
  43859. ['M',
  43860. labelPosition.x,
  43861. labelPosition.y]
  43862. ];
  43863. if (useCrook) {
  43864. path.push(segmentWithCrook);
  43865. }
  43866. path.push(['L', touchingSliceAt.x, touchingSliceAt.y]);
  43867. return path;
  43868. }
  43869. }
  43870. });
  43871. /* *
  43872. *
  43873. * Default Export
  43874. *
  43875. * */
  43876. return PiePoint;
  43877. });
  43878. _registerModule(_modules, 'Series/Pie/PieSeries.js', [_modules['Mixins/CenteredSeries.js'], _modules['Series/Column/ColumnSeries.js'], _modules['Core/Globals.js'], _modules['Mixins/LegendSymbol.js'], _modules['Core/Color/Palette.js'], _modules['Series/Pie/PiePoint.js'], _modules['Core/Series/Series.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Renderer/SVG/Symbols.js'], _modules['Core/Utilities.js']], function (CenteredSeriesMixin, ColumnSeries, H, LegendSymbolMixin, palette, PiePoint, Series, SeriesRegistry, Symbols, U) {
  43879. /* *
  43880. *
  43881. * (c) 2010-2021 Torstein Honsi
  43882. *
  43883. * License: www.highcharts.com/license
  43884. *
  43885. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  43886. *
  43887. * */
  43888. var __extends = (this && this.__extends) || (function () {
  43889. var extendStatics = function (d,
  43890. b) {
  43891. extendStatics = Object.setPrototypeOf ||
  43892. ({ __proto__: [] } instanceof Array && function (d,
  43893. b) { d.__proto__ = b; }) ||
  43894. function (d,
  43895. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  43896. return extendStatics(d, b);
  43897. };
  43898. return function (d, b) {
  43899. extendStatics(d, b);
  43900. function __() { this.constructor = d; }
  43901. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  43902. };
  43903. })();
  43904. var getStartAndEndRadians = CenteredSeriesMixin.getStartAndEndRadians;
  43905. var noop = H.noop;
  43906. var clamp = U.clamp,
  43907. extend = U.extend,
  43908. fireEvent = U.fireEvent,
  43909. merge = U.merge,
  43910. pick = U.pick,
  43911. relativeLength = U.relativeLength;
  43912. /* *
  43913. *
  43914. * Class
  43915. *
  43916. * */
  43917. /**
  43918. * Pie series type.
  43919. *
  43920. * @private
  43921. * @class
  43922. * @name Highcharts.seriesTypes.pie
  43923. *
  43924. * @augments Highcharts.Series
  43925. */
  43926. var PieSeries = /** @class */ (function (_super) {
  43927. __extends(PieSeries, _super);
  43928. function PieSeries() {
  43929. /* *
  43930. *
  43931. * Static Properties
  43932. *
  43933. * */
  43934. var _this = _super !== null && _super.apply(this,
  43935. arguments) || this;
  43936. /* *
  43937. *
  43938. * Properties
  43939. *
  43940. * */
  43941. _this.center = void 0;
  43942. _this.data = void 0;
  43943. _this.maxLabelDistance = void 0;
  43944. _this.options = void 0;
  43945. _this.points = void 0;
  43946. return _this;
  43947. /* eslint-enable valid-jsdoc */
  43948. }
  43949. /* *
  43950. *
  43951. * Functions
  43952. *
  43953. * */
  43954. /* eslint-disable valid-jsdoc */
  43955. /**
  43956. * Animates the pies in.
  43957. * @private
  43958. */
  43959. PieSeries.prototype.animate = function (init) {
  43960. var series = this,
  43961. points = series.points,
  43962. startAngleRad = series.startAngleRad;
  43963. if (!init) {
  43964. points.forEach(function (point) {
  43965. var graphic = point.graphic,
  43966. args = point.shapeArgs;
  43967. if (graphic && args) {
  43968. // start values
  43969. graphic.attr({
  43970. // animate from inner radius (#779)
  43971. r: pick(point.startR, (series.center && series.center[3] / 2)),
  43972. start: startAngleRad,
  43973. end: startAngleRad
  43974. });
  43975. // animate
  43976. graphic.animate({
  43977. r: args.r,
  43978. start: args.start,
  43979. end: args.end
  43980. }, series.options.animation);
  43981. }
  43982. });
  43983. }
  43984. };
  43985. /**
  43986. * Called internally to draw auxiliary graph in pie-like series in
  43987. * situtation when the default graph is not sufficient enough to present
  43988. * the data well. Auxiliary graph is saved in the same object as
  43989. * regular graph.
  43990. * @private
  43991. */
  43992. PieSeries.prototype.drawEmpty = function () {
  43993. var centerX,
  43994. centerY,
  43995. start = this.startAngleRad,
  43996. end = this.endAngleRad,
  43997. options = this.options;
  43998. // Draw auxiliary graph if there're no visible points.
  43999. if (this.total === 0 && this.center) {
  44000. centerX = this.center[0];
  44001. centerY = this.center[1];
  44002. if (!this.graph) {
  44003. this.graph = this.chart.renderer
  44004. .arc(centerX, centerY, this.center[1] / 2, 0, start, end)
  44005. .addClass('highcharts-empty-series')
  44006. .add(this.group);
  44007. }
  44008. this.graph.attr({
  44009. d: Symbols.arc(centerX, centerY, this.center[2] / 2, 0, {
  44010. start: start,
  44011. end: end,
  44012. innerR: this.center[3] / 2
  44013. })
  44014. });
  44015. if (!this.chart.styledMode) {
  44016. this.graph.attr({
  44017. 'stroke-width': options.borderWidth,
  44018. fill: options.fillColor || 'none',
  44019. stroke: options.color || palette.neutralColor20
  44020. });
  44021. }
  44022. }
  44023. else if (this.graph) { // Destroy the graph object.
  44024. this.graph = this.graph.destroy();
  44025. }
  44026. };
  44027. /**
  44028. * Slices in pie chart are initialized in DOM, but it's shapes and
  44029. * animations are normally run in `drawPoints()`.
  44030. * @private
  44031. */
  44032. PieSeries.prototype.drawPoints = function () {
  44033. var renderer = this.chart.renderer;
  44034. this.points.forEach(function (point) {
  44035. // When updating a series between 2d and 3d or cartesian and
  44036. // polar, the shape type changes.
  44037. if (point.graphic && point.hasNewShapeType()) {
  44038. point.graphic = point.graphic.destroy();
  44039. }
  44040. if (!point.graphic) {
  44041. point.graphic = renderer[point.shapeType](point.shapeArgs)
  44042. .add(point.series.group);
  44043. point.delayedRendering = true;
  44044. }
  44045. });
  44046. };
  44047. /**
  44048. * Extend the generatePoints method by adding total and percentage
  44049. * properties to each point
  44050. * @private
  44051. */
  44052. PieSeries.prototype.generatePoints = function () {
  44053. _super.prototype.generatePoints.call(this);
  44054. this.updateTotals();
  44055. };
  44056. /**
  44057. * Utility for getting the x value from a given y, used for
  44058. * anticollision logic in data labels. Added point for using specific
  44059. * points' label distance.
  44060. * @private
  44061. */
  44062. PieSeries.prototype.getX = function (y, left, point) {
  44063. var center = this.center,
  44064. // Variable pie has individual radius
  44065. radius = this.radii ?
  44066. this.radii[point.index] || 0 :
  44067. center[2] / 2,
  44068. angle,
  44069. x;
  44070. angle = Math.asin(clamp((y - center[1]) / (radius + point.labelDistance), -1, 1));
  44071. x = center[0] +
  44072. (left ? -1 : 1) *
  44073. (Math.cos(angle) * (radius + point.labelDistance)) +
  44074. (point.labelDistance > 0 ?
  44075. (left ? -1 : 1) * this.options.dataLabels.padding :
  44076. 0);
  44077. return x;
  44078. };
  44079. /**
  44080. * Define hasData function for non-cartesian series. Returns true if the
  44081. * series has points at all.
  44082. * @private
  44083. */
  44084. PieSeries.prototype.hasData = function () {
  44085. return !!this.processedXData.length; // != 0
  44086. };
  44087. /**
  44088. * Draw the data points
  44089. * @private
  44090. */
  44091. PieSeries.prototype.redrawPoints = function () {
  44092. var series = this,
  44093. chart = series.chart,
  44094. renderer = chart.renderer,
  44095. groupTranslation,
  44096. graphic,
  44097. pointAttr,
  44098. shapeArgs,
  44099. shadow = series.options.shadow;
  44100. this.drawEmpty();
  44101. if (shadow && !series.shadowGroup && !chart.styledMode) {
  44102. series.shadowGroup = renderer
  44103. .g('shadow')
  44104. .attr({ zIndex: -1 })
  44105. .add(series.group);
  44106. }
  44107. // draw the slices
  44108. series.points.forEach(function (point) {
  44109. var animateTo = {};
  44110. graphic = point.graphic;
  44111. if (!point.isNull && graphic) {
  44112. var shadowGroup = void 0;
  44113. shapeArgs = point.shapeArgs;
  44114. // If the point is sliced, use special translation, else use
  44115. // plot area translation
  44116. groupTranslation = point.getTranslate();
  44117. if (!chart.styledMode) {
  44118. // Put the shadow behind all points
  44119. shadowGroup = point.shadowGroup;
  44120. if (shadow && !shadowGroup) {
  44121. shadowGroup = point.shadowGroup = renderer
  44122. .g('shadow')
  44123. .add(series.shadowGroup);
  44124. }
  44125. if (shadowGroup) {
  44126. shadowGroup.attr(groupTranslation);
  44127. }
  44128. pointAttr = series.pointAttribs(point, (point.selected && 'select'));
  44129. }
  44130. // Draw the slice
  44131. if (!point.delayedRendering) {
  44132. graphic
  44133. .setRadialReference(series.center);
  44134. if (!chart.styledMode) {
  44135. merge(true, animateTo, pointAttr);
  44136. }
  44137. merge(true, animateTo, shapeArgs, groupTranslation);
  44138. graphic.animate(animateTo);
  44139. }
  44140. else {
  44141. graphic
  44142. .setRadialReference(series.center)
  44143. .attr(shapeArgs)
  44144. .attr(groupTranslation);
  44145. if (!chart.styledMode) {
  44146. graphic
  44147. .attr(pointAttr)
  44148. .attr({ 'stroke-linejoin': 'round' })
  44149. .shadow(shadow, shadowGroup);
  44150. }
  44151. point.delayedRendering = false;
  44152. }
  44153. graphic.attr({
  44154. visibility: point.visible ? 'inherit' : 'hidden'
  44155. });
  44156. graphic.addClass(point.getClassName(), true);
  44157. }
  44158. else if (graphic) {
  44159. point.graphic = graphic.destroy();
  44160. }
  44161. });
  44162. };
  44163. /**
  44164. * Utility for sorting data labels.
  44165. * @private
  44166. */
  44167. PieSeries.prototype.sortByAngle = function (points, sign) {
  44168. points.sort(function (a, b) {
  44169. return ((typeof a.angle !== 'undefined') &&
  44170. (b.angle - a.angle) * sign);
  44171. });
  44172. };
  44173. /**
  44174. * Do translation for pie slices
  44175. * @private
  44176. */
  44177. PieSeries.prototype.translate = function (positions) {
  44178. this.generatePoints();
  44179. var series = this,
  44180. cumulative = 0,
  44181. precision = 1000, // issue #172
  44182. options = series.options,
  44183. slicedOffset = options.slicedOffset,
  44184. connectorOffset = slicedOffset + (options.borderWidth || 0),
  44185. finalConnectorOffset,
  44186. start,
  44187. end,
  44188. angle,
  44189. radians = getStartAndEndRadians(options.startAngle,
  44190. options.endAngle),
  44191. startAngleRad = series.startAngleRad = radians.start,
  44192. endAngleRad = series.endAngleRad = radians.end,
  44193. circ = endAngleRad - startAngleRad, // 2 * Math.PI,
  44194. points = series.points,
  44195. // the x component of the radius vector for a given point
  44196. radiusX,
  44197. radiusY,
  44198. labelDistance = options.dataLabels.distance,
  44199. ignoreHiddenPoint = options.ignoreHiddenPoint,
  44200. i,
  44201. len = points.length,
  44202. point;
  44203. // Get positions - either an integer or a percentage string must be
  44204. // given. If positions are passed as a parameter, we're in a
  44205. // recursive loop for adjusting space for data labels.
  44206. if (!positions) {
  44207. series.center = positions = series.getCenter();
  44208. }
  44209. // Calculate the geometry for each point
  44210. for (i = 0; i < len; i++) {
  44211. point = points[i];
  44212. // set start and end angle
  44213. start = startAngleRad + (cumulative * circ);
  44214. if (point.isValid() &&
  44215. (!ignoreHiddenPoint || point.visible)) {
  44216. cumulative += point.percentage / 100;
  44217. }
  44218. end = startAngleRad + (cumulative * circ);
  44219. // set the shape
  44220. var shapeArgs = {
  44221. x: positions[0],
  44222. y: positions[1],
  44223. r: positions[2] / 2,
  44224. innerR: positions[3] / 2,
  44225. start: Math.round(start * precision) / precision,
  44226. end: Math.round(end * precision) / precision
  44227. };
  44228. point.shapeType = 'arc';
  44229. point.shapeArgs = shapeArgs;
  44230. // Used for distance calculation for specific point.
  44231. point.labelDistance = pick((point.options.dataLabels &&
  44232. point.options.dataLabels.distance), labelDistance);
  44233. // Compute point.labelDistance if it's defined as percentage
  44234. // of slice radius (#8854)
  44235. point.labelDistance = relativeLength(point.labelDistance, shapeArgs.r);
  44236. // Saved for later dataLabels distance calculation.
  44237. series.maxLabelDistance = Math.max(series.maxLabelDistance || 0, point.labelDistance);
  44238. // The angle must stay within -90 and 270 (#2645)
  44239. angle = (end + start) / 2;
  44240. if (angle > 1.5 * Math.PI) {
  44241. angle -= 2 * Math.PI;
  44242. }
  44243. else if (angle < -Math.PI / 2) {
  44244. angle += 2 * Math.PI;
  44245. }
  44246. // Center for the sliced out slice
  44247. point.slicedTranslation = {
  44248. translateX: Math.round(Math.cos(angle) * slicedOffset),
  44249. translateY: Math.round(Math.sin(angle) * slicedOffset)
  44250. };
  44251. // set the anchor point for tooltips
  44252. radiusX = Math.cos(angle) * positions[2] / 2;
  44253. radiusY = Math.sin(angle) * positions[2] / 2;
  44254. point.tooltipPos = [
  44255. positions[0] + radiusX * 0.7,
  44256. positions[1] + radiusY * 0.7
  44257. ];
  44258. point.half = angle < -Math.PI / 2 || angle > Math.PI / 2 ?
  44259. 1 :
  44260. 0;
  44261. point.angle = angle;
  44262. // Set the anchor point for data labels. Use point.labelDistance
  44263. // instead of labelDistance // #1174
  44264. // finalConnectorOffset - not override connectorOffset value.
  44265. finalConnectorOffset = Math.min(connectorOffset, point.labelDistance / 5); // #1678
  44266. point.labelPosition = {
  44267. natural: {
  44268. // initial position of the data label - it's utilized for
  44269. // finding the final position for the label
  44270. x: positions[0] + radiusX + Math.cos(angle) *
  44271. point.labelDistance,
  44272. y: positions[1] + radiusY + Math.sin(angle) *
  44273. point.labelDistance
  44274. },
  44275. 'final': {
  44276. // used for generating connector path -
  44277. // initialized later in drawDataLabels function
  44278. // x: undefined,
  44279. // y: undefined
  44280. },
  44281. // left - pie on the left side of the data label
  44282. // right - pie on the right side of the data label
  44283. // center - data label overlaps the pie
  44284. alignment: point.labelDistance < 0 ?
  44285. 'center' : point.half ? 'right' : 'left',
  44286. connectorPosition: {
  44287. breakAt: {
  44288. x: positions[0] + radiusX + Math.cos(angle) *
  44289. finalConnectorOffset,
  44290. y: positions[1] + radiusY + Math.sin(angle) *
  44291. finalConnectorOffset
  44292. },
  44293. touchingSliceAt: {
  44294. x: positions[0] + radiusX,
  44295. y: positions[1] + radiusY
  44296. }
  44297. }
  44298. };
  44299. }
  44300. fireEvent(series, 'afterTranslate');
  44301. };
  44302. /**
  44303. * Recompute total chart sum and update percentages of points.
  44304. * @private
  44305. */
  44306. PieSeries.prototype.updateTotals = function () {
  44307. var i,
  44308. total = 0,
  44309. points = this.points,
  44310. len = points.length,
  44311. point,
  44312. ignoreHiddenPoint = this.options.ignoreHiddenPoint;
  44313. // Get the total sum
  44314. for (i = 0; i < len; i++) {
  44315. point = points[i];
  44316. if (point.isValid() &&
  44317. (!ignoreHiddenPoint || point.visible)) {
  44318. total += point.y;
  44319. }
  44320. }
  44321. this.total = total;
  44322. // Set each point's properties
  44323. for (i = 0; i < len; i++) {
  44324. point = points[i];
  44325. point.percentage =
  44326. (total > 0 && (point.visible || !ignoreHiddenPoint)) ?
  44327. point.y / total * 100 :
  44328. 0;
  44329. point.total = total;
  44330. }
  44331. };
  44332. /**
  44333. * A pie chart is a circular graphic which is divided into slices to
  44334. * illustrate numerical proportion.
  44335. *
  44336. * @sample highcharts/demo/pie-basic/
  44337. * Pie chart
  44338. *
  44339. * @extends plotOptions.line
  44340. * @excluding animationLimit, boostThreshold, connectEnds, connectNulls,
  44341. * cropThreshold, dashStyle, dataSorting, dragDrop,
  44342. * findNearestPointBy, getExtremesFromAll, label, lineWidth,
  44343. * marker, negativeColor, pointInterval, pointIntervalUnit,
  44344. * pointPlacement, pointStart, softThreshold, stacking, step,
  44345. * threshold, turboThreshold, zoneAxis, zones, dataSorting,
  44346. * boostBlending
  44347. * @product highcharts
  44348. * @optionparent plotOptions.pie
  44349. */
  44350. PieSeries.defaultOptions = merge(Series.defaultOptions, {
  44351. /**
  44352. * @excluding legendItemClick
  44353. * @apioption plotOptions.pie.events
  44354. */
  44355. /**
  44356. * Fires when the checkbox next to the point name in the legend is
  44357. * clicked. One parameter, event, is passed to the function. The state
  44358. * of the checkbox is found by event.checked. The checked item is found
  44359. * by event.item. Return false to prevent the default action which is to
  44360. * toggle the select state of the series.
  44361. *
  44362. * @sample {highcharts} highcharts/plotoptions/series-events-checkboxclick/
  44363. * Alert checkbox status
  44364. *
  44365. * @type {Function}
  44366. * @since 1.2.0
  44367. * @product highcharts
  44368. * @context Highcharts.Point
  44369. * @apioption plotOptions.pie.events.checkboxClick
  44370. */
  44371. /**
  44372. * Fires when the legend item belonging to the pie point (slice) is
  44373. * clicked. The `this` keyword refers to the point itself. One
  44374. * parameter, `event`, is passed to the function, containing common
  44375. * event information. The default action is to toggle the visibility of
  44376. * the point. This can be prevented by calling `event.preventDefault()`.
  44377. *
  44378. * @sample {highcharts} highcharts/plotoptions/pie-point-events-legenditemclick/
  44379. * Confirm toggle visibility
  44380. *
  44381. * @type {Highcharts.PointLegendItemClickCallbackFunction}
  44382. * @since 1.2.0
  44383. * @product highcharts
  44384. * @apioption plotOptions.pie.point.events.legendItemClick
  44385. */
  44386. /**
  44387. * The center of the pie chart relative to the plot area. Can be
  44388. * percentages or pixel values. The default behaviour (as of 3.0) is to
  44389. * center the pie so that all slices and data labels are within the plot
  44390. * area. As a consequence, the pie may actually jump around in a chart
  44391. * with dynamic values, as the data labels move. In that case, the
  44392. * center should be explicitly set, for example to `["50%", "50%"]`.
  44393. *
  44394. * @sample {highcharts} highcharts/plotoptions/pie-center/
  44395. * Centered at 100, 100
  44396. *
  44397. * @type {Array<(number|string|null),(number|string|null)>}
  44398. * @default [null, null]
  44399. * @product highcharts
  44400. *
  44401. * @private
  44402. */
  44403. center: [null, null],
  44404. /**
  44405. * The color of the pie series. A pie series is represented as an empty
  44406. * circle if the total sum of its values is 0. Use this property to
  44407. * define the color of its border.
  44408. *
  44409. * In styled mode, the color can be defined by the
  44410. * [colorIndex](#plotOptions.series.colorIndex) option. Also, the series
  44411. * color can be set with the `.highcharts-series`,
  44412. * `.highcharts-color-{n}`, `.highcharts-{type}-series` or
  44413. * `.highcharts-series-{n}` class, or individual classes given by the
  44414. * `className` option.
  44415. *
  44416. * @sample {highcharts} highcharts/plotoptions/pie-emptyseries/
  44417. * Empty pie series
  44418. *
  44419. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  44420. * @default ${palette.neutralColor20}
  44421. * @apioption plotOptions.pie.color
  44422. */
  44423. /**
  44424. * @product highcharts
  44425. *
  44426. * @private
  44427. */
  44428. clip: false,
  44429. /**
  44430. * @ignore-option
  44431. *
  44432. * @private
  44433. */
  44434. colorByPoint: true,
  44435. /**
  44436. * A series specific or series type specific color set to use instead
  44437. * of the global [colors](#colors).
  44438. *
  44439. * @sample {highcharts} highcharts/demo/pie-monochrome/
  44440. * Set default colors for all pies
  44441. *
  44442. * @type {Array<Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject>}
  44443. * @since 3.0
  44444. * @product highcharts
  44445. * @apioption plotOptions.pie.colors
  44446. */
  44447. /**
  44448. * @declare Highcharts.SeriesPieDataLabelsOptionsObject
  44449. * @extends plotOptions.series.dataLabels
  44450. * @excluding align, allowOverlap, inside, staggerLines, step
  44451. * @private
  44452. */
  44453. dataLabels: {
  44454. /**
  44455. * Alignment method for data labels. Possible values are:
  44456. *
  44457. * - `toPlotEdges`: Each label touches the nearest vertical edge of
  44458. * the plot area.
  44459. *
  44460. * - `connectors`: Connectors have the same x position and the
  44461. * widest label of each half (left & right) touches the nearest
  44462. * vertical edge of the plot area.
  44463. *
  44464. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-alignto-connectors/
  44465. * alignTo: connectors
  44466. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-alignto-plotedges/
  44467. * alignTo: plotEdges
  44468. *
  44469. * @type {string}
  44470. * @since 7.0.0
  44471. * @product highcharts
  44472. * @apioption plotOptions.pie.dataLabels.alignTo
  44473. */
  44474. allowOverlap: true,
  44475. /**
  44476. * The color of the line connecting the data label to the pie slice.
  44477. * The default color is the same as the point's color.
  44478. *
  44479. * In styled mode, the connector stroke is given in the
  44480. * `.highcharts-data-label-connector` class.
  44481. *
  44482. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorcolor/
  44483. * Blue connectors
  44484. * @sample {highcharts} highcharts/css/pie-point/
  44485. * Styled connectors
  44486. *
  44487. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  44488. * @since 2.1
  44489. * @product highcharts
  44490. * @apioption plotOptions.pie.dataLabels.connectorColor
  44491. */
  44492. /**
  44493. * The distance from the data label to the connector. Note that
  44494. * data labels also have a default `padding`, so in order for the
  44495. * connector to touch the text, the `padding` must also be 0.
  44496. *
  44497. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorpadding/
  44498. * No padding
  44499. *
  44500. * @since 2.1
  44501. * @product highcharts
  44502. */
  44503. connectorPadding: 5,
  44504. /**
  44505. * Specifies the method that is used to generate the connector path.
  44506. * Highcharts provides 3 built-in connector shapes: `'fixedOffset'`
  44507. * (default), `'straight'` and `'crookedLine'`. Using
  44508. * `'crookedLine'` has the most sense (in most of the cases) when
  44509. * `'alignTo'` is set.
  44510. *
  44511. * Users can provide their own method by passing a function instead
  44512. * of a String. 3 arguments are passed to the callback:
  44513. *
  44514. * - Object that holds the information about the coordinates of the
  44515. * label (`x` & `y` properties) and how the label is located in
  44516. * relation to the pie (`alignment` property). `alignment` can by
  44517. * one of the following:
  44518. * `'left'` (pie on the left side of the data label),
  44519. * `'right'` (pie on the right side of the data label) or
  44520. * `'center'` (data label overlaps the pie).
  44521. *
  44522. * - Object that holds the information about the position of the
  44523. * connector. Its `touchingSliceAt` porperty tells the position
  44524. * of the place where the connector touches the slice.
  44525. *
  44526. * - Data label options
  44527. *
  44528. * The function has to return an SVG path definition in array form
  44529. * (see the example).
  44530. *
  44531. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorshape-string/
  44532. * connectorShape is a String
  44533. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorshape-function/
  44534. * connectorShape is a function
  44535. *
  44536. * @type {string|Function}
  44537. * @since 7.0.0
  44538. * @product highcharts
  44539. */
  44540. connectorShape: 'fixedOffset',
  44541. /**
  44542. * The width of the line connecting the data label to the pie slice.
  44543. *
  44544. * In styled mode, the connector stroke width is given in the
  44545. * `.highcharts-data-label-connector` class.
  44546. *
  44547. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorwidth-disabled/
  44548. * Disable the connector
  44549. * @sample {highcharts} highcharts/css/pie-point/
  44550. * Styled connectors
  44551. *
  44552. * @type {number}
  44553. * @default 1
  44554. * @since 2.1
  44555. * @product highcharts
  44556. * @apioption plotOptions.pie.dataLabels.connectorWidth
  44557. */
  44558. /**
  44559. * Works only if `connectorShape` is `'crookedLine'`. It defines how
  44560. * far from the vertical plot edge the coonnector path should be
  44561. * crooked.
  44562. *
  44563. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-crookdistance/
  44564. * crookDistance set to 90%
  44565. *
  44566. * @since 7.0.0
  44567. * @product highcharts
  44568. */
  44569. crookDistance: '70%',
  44570. /**
  44571. * The distance of the data label from the pie's edge. Negative
  44572. * numbers put the data label on top of the pie slices. Can also be
  44573. * defined as a percentage of pie's radius. Connectors are only
  44574. * shown for data labels outside the pie.
  44575. *
  44576. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-distance/
  44577. * Data labels on top of the pie
  44578. *
  44579. * @type {number|string}
  44580. * @since 2.1
  44581. * @product highcharts
  44582. */
  44583. distance: 30,
  44584. enabled: true,
  44585. /**
  44586. * A
  44587. * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
  44588. * for the data label. Available variables are the same as for
  44589. * `formatter`.
  44590. *
  44591. * @sample {highcharts} highcharts/plotoptions/series-datalabels-format/
  44592. * Add a unit
  44593. *
  44594. * @type {string}
  44595. * @default undefined
  44596. * @since 3.0
  44597. * @apioption plotOptions.pie.dataLabels.format
  44598. */
  44599. // eslint-disable-next-line valid-jsdoc
  44600. /**
  44601. * Callback JavaScript function to format the data label. Note that
  44602. * if a `format` is defined, the format takes precedence and the
  44603. * formatter is ignored.
  44604. *
  44605. * @type {Highcharts.DataLabelsFormatterCallbackFunction}
  44606. * @default function () { return this.point.isNull ? void 0 : this.point.name; }
  44607. */
  44608. formatter: function () {
  44609. return this.point.isNull ? void 0 : this.point.name;
  44610. },
  44611. /**
  44612. * Whether to render the connector as a soft arc or a line with
  44613. * sharp break. Works only if `connectorShape` equals to
  44614. * `fixedOffset`.
  44615. *
  44616. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-softconnector-true/
  44617. * Soft
  44618. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-softconnector-false/
  44619. * Non soft
  44620. *
  44621. * @since 2.1.7
  44622. * @product highcharts
  44623. */
  44624. softConnector: true,
  44625. /**
  44626. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-overflow
  44627. * Long labels truncated with an ellipsis
  44628. * @sample {highcharts} highcharts/plotoptions/pie-datalabels-overflow-wrap
  44629. * Long labels are wrapped
  44630. *
  44631. * @type {Highcharts.CSSObject}
  44632. * @apioption plotOptions.pie.dataLabels.style
  44633. */
  44634. x: 0
  44635. },
  44636. /**
  44637. * If the total sum of the pie's values is 0, the series is represented
  44638. * as an empty circle . The `fillColor` option defines the color of that
  44639. * circle. Use [pie.borderWidth](#plotOptions.pie.borderWidth) to set
  44640. * the border thickness.
  44641. *
  44642. * @sample {highcharts} highcharts/plotoptions/pie-emptyseries/
  44643. * Empty pie series
  44644. *
  44645. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  44646. * @private
  44647. */
  44648. fillColor: void 0,
  44649. /**
  44650. * The end angle of the pie in degrees where 0 is top and 90 is right.
  44651. * Defaults to `startAngle` plus 360.
  44652. *
  44653. * @sample {highcharts} highcharts/demo/pie-semi-circle/
  44654. * Semi-circle donut
  44655. *
  44656. * @type {number}
  44657. * @since 1.3.6
  44658. * @product highcharts
  44659. * @apioption plotOptions.pie.endAngle
  44660. */
  44661. /**
  44662. * Equivalent to [chart.ignoreHiddenSeries](#chart.ignoreHiddenSeries),
  44663. * this option tells whether the series shall be redrawn as if the
  44664. * hidden point were `null`.
  44665. *
  44666. * The default value changed from `false` to `true` with Highcharts
  44667. * 3.0.
  44668. *
  44669. * @sample {highcharts} highcharts/plotoptions/pie-ignorehiddenpoint/
  44670. * True, the hiddden point is ignored
  44671. *
  44672. * @since 2.3.0
  44673. * @product highcharts
  44674. *
  44675. * @private
  44676. */
  44677. ignoreHiddenPoint: true,
  44678. /**
  44679. * @ignore-option
  44680. *
  44681. * @private
  44682. */
  44683. inactiveOtherPoints: true,
  44684. /**
  44685. * The size of the inner diameter for the pie. A size greater than 0
  44686. * renders a donut chart. Can be a percentage or pixel value.
  44687. * Percentages are relative to the pie size. Pixel values are given as
  44688. * integers.
  44689. *
  44690. *
  44691. * Note: in Highcharts < 4.1.2, the percentage was relative to the plot
  44692. * area, not the pie size.
  44693. *
  44694. * @sample {highcharts} highcharts/plotoptions/pie-innersize-80px/
  44695. * 80px inner size
  44696. * @sample {highcharts} highcharts/plotoptions/pie-innersize-50percent/
  44697. * 50% of the plot area
  44698. * @sample {highcharts} highcharts/demo/3d-pie-donut/
  44699. * 3D donut
  44700. *
  44701. * @type {number|string}
  44702. * @default 0
  44703. * @since 2.0
  44704. * @product highcharts
  44705. * @apioption plotOptions.pie.innerSize
  44706. */
  44707. /**
  44708. * @ignore-option
  44709. *
  44710. * @private
  44711. */
  44712. legendType: 'point',
  44713. /**
  44714. * @ignore-option
  44715. *
  44716. * @private
  44717. */
  44718. marker: null,
  44719. /**
  44720. * The minimum size for a pie in response to auto margins. The pie will
  44721. * try to shrink to make room for data labels in side the plot area,
  44722. * but only to this size.
  44723. *
  44724. * @type {number|string}
  44725. * @default 80
  44726. * @since 3.0
  44727. * @product highcharts
  44728. * @apioption plotOptions.pie.minSize
  44729. */
  44730. /**
  44731. * The diameter of the pie relative to the plot area. Can be a
  44732. * percentage or pixel value. Pixel values are given as integers. The
  44733. * default behaviour (as of 3.0) is to scale to the plot area and give
  44734. * room for data labels within the plot area.
  44735. * [slicedOffset](#plotOptions.pie.slicedOffset) is also included in the
  44736. * default size calculation. As a consequence, the size of the pie may
  44737. * vary when points are updated and data labels more around. In that
  44738. * case it is best to set a fixed value, for example `"75%"`.
  44739. *
  44740. * @sample {highcharts} highcharts/plotoptions/pie-size/
  44741. * Smaller pie
  44742. *
  44743. * @type {number|string|null}
  44744. * @product highcharts
  44745. *
  44746. * @private
  44747. */
  44748. size: null,
  44749. /**
  44750. * Whether to display this particular series or series type in the
  44751. * legend. Since 2.1, pies are not shown in the legend by default.
  44752. *
  44753. * @sample {highcharts} highcharts/plotoptions/series-showinlegend/
  44754. * One series in the legend, one hidden
  44755. *
  44756. * @product highcharts
  44757. *
  44758. * @private
  44759. */
  44760. showInLegend: false,
  44761. /**
  44762. * If a point is sliced, moved out from the center, how many pixels
  44763. * should it be moved?.
  44764. *
  44765. * @sample {highcharts} highcharts/plotoptions/pie-slicedoffset-20/
  44766. * 20px offset
  44767. *
  44768. * @product highcharts
  44769. *
  44770. * @private
  44771. */
  44772. slicedOffset: 10,
  44773. /**
  44774. * The start angle of the pie slices in degrees where 0 is top and 90
  44775. * right.
  44776. *
  44777. * @sample {highcharts} highcharts/plotoptions/pie-startangle-90/
  44778. * Start from right
  44779. *
  44780. * @type {number}
  44781. * @default 0
  44782. * @since 2.3.4
  44783. * @product highcharts
  44784. * @apioption plotOptions.pie.startAngle
  44785. */
  44786. /**
  44787. * Sticky tracking of mouse events. When true, the `mouseOut` event
  44788. * on a series isn't triggered until the mouse moves over another
  44789. * series, or out of the plot area. When false, the `mouseOut` event on
  44790. * a series is triggered when the mouse leaves the area around the
  44791. * series' graph or markers. This also implies the tooltip. When
  44792. * `stickyTracking` is false and `tooltip.shared` is false, the tooltip
  44793. * will be hidden when moving the mouse between series.
  44794. *
  44795. * @product highcharts
  44796. *
  44797. * @private
  44798. */
  44799. stickyTracking: false,
  44800. tooltip: {
  44801. followPointer: true
  44802. },
  44803. /**
  44804. * The color of the border surrounding each slice. When `null`, the
  44805. * border takes the same color as the slice fill. This can be used
  44806. * together with a `borderWidth` to fill drawing gaps created by
  44807. * antialiazing artefacts in borderless pies.
  44808. *
  44809. * In styled mode, the border stroke is given in the `.highcharts-point`
  44810. * class.
  44811. *
  44812. * @sample {highcharts} highcharts/plotoptions/pie-bordercolor-black/
  44813. * Black border
  44814. *
  44815. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  44816. * @default #ffffff
  44817. * @product highcharts
  44818. *
  44819. * @private
  44820. */
  44821. borderColor: palette.backgroundColor,
  44822. /**
  44823. * The width of the border surrounding each slice.
  44824. *
  44825. * When setting the border width to 0, there may be small gaps between
  44826. * the slices due to SVG antialiasing artefacts. To work around this,
  44827. * keep the border width at 0.5 or 1, but set the `borderColor` to
  44828. * `null` instead.
  44829. *
  44830. * In styled mode, the border stroke width is given in the
  44831. * `.highcharts-point` class.
  44832. *
  44833. * @sample {highcharts} highcharts/plotoptions/pie-borderwidth/
  44834. * 3px border
  44835. *
  44836. * @product highcharts
  44837. *
  44838. * @private
  44839. */
  44840. borderWidth: 1,
  44841. /**
  44842. * @ignore-options
  44843. * @private
  44844. */
  44845. lineWidth: void 0,
  44846. states: {
  44847. /**
  44848. * @extends plotOptions.series.states.hover
  44849. * @excluding marker, lineWidth, lineWidthPlus
  44850. * @product highcharts
  44851. */
  44852. hover: {
  44853. /**
  44854. * How much to brighten the point on interaction. Requires the
  44855. * main color to be defined in hex or rgb(a) format.
  44856. *
  44857. * In styled mode, the hover brightness is by default replaced
  44858. * by a fill-opacity given in the `.highcharts-point-hover`
  44859. * class.
  44860. *
  44861. * @sample {highcharts} highcharts/plotoptions/pie-states-hover-brightness/
  44862. * Brightened by 0.5
  44863. *
  44864. * @product highcharts
  44865. */
  44866. brightness: 0.1
  44867. }
  44868. }
  44869. });
  44870. return PieSeries;
  44871. }(Series));
  44872. extend(PieSeries.prototype, {
  44873. axisTypes: [],
  44874. directTouch: true,
  44875. drawGraph: void 0,
  44876. drawLegendSymbol: LegendSymbolMixin.drawRectangle,
  44877. drawTracker: ColumnSeries.prototype.drawTracker,
  44878. getCenter: CenteredSeriesMixin.getCenter,
  44879. getSymbol: noop,
  44880. isCartesian: false,
  44881. noSharedTooltip: true,
  44882. pointAttribs: ColumnSeries.prototype.pointAttribs,
  44883. pointClass: PiePoint,
  44884. requireSorting: false,
  44885. searchPoint: noop,
  44886. trackerGroups: ['group', 'dataLabelsGroup']
  44887. });
  44888. SeriesRegistry.registerSeriesType('pie', PieSeries);
  44889. /* *
  44890. *
  44891. * Default Export
  44892. *
  44893. * */
  44894. /* *
  44895. *
  44896. * API Options
  44897. *
  44898. * */
  44899. /**
  44900. * A `pie` series. If the [type](#series.pie.type) option is not specified,
  44901. * it is inherited from [chart.type](#chart.type).
  44902. *
  44903. * @extends series,plotOptions.pie
  44904. * @excluding cropThreshold, dataParser, dataURL, stack, xAxis, yAxis,
  44905. * dataSorting, step, boostThreshold, boostBlending
  44906. * @product highcharts
  44907. * @apioption series.pie
  44908. */
  44909. /**
  44910. * An array of data points for the series. For the `pie` series type,
  44911. * points can be given in the following ways:
  44912. *
  44913. * 1. An array of numerical values. In this case, the numerical values will be
  44914. * interpreted as `y` options. Example:
  44915. * ```js
  44916. * data: [0, 5, 3, 5]
  44917. * ```
  44918. *
  44919. * 2. An array of objects with named values. The following snippet shows only a
  44920. * few settings, see the complete options set below. If the total number of
  44921. * data points exceeds the series'
  44922. * [turboThreshold](#series.pie.turboThreshold),
  44923. * this option is not available.
  44924. * ```js
  44925. * data: [{
  44926. * y: 1,
  44927. * name: "Point2",
  44928. * color: "#00FF00"
  44929. * }, {
  44930. * y: 7,
  44931. * name: "Point1",
  44932. * color: "#FF00FF"
  44933. * }]
  44934. * ```
  44935. *
  44936. * @sample {highcharts} highcharts/chart/reflow-true/
  44937. * Numerical values
  44938. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  44939. * Arrays of numeric x and y
  44940. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  44941. * Arrays of datetime x and y
  44942. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  44943. * Arrays of point.name and y
  44944. * @sample {highcharts} highcharts/series/data-array-of-objects/
  44945. * Config objects
  44946. *
  44947. * @type {Array<number|Array<string,(number|null)>|null|*>}
  44948. * @extends series.line.data
  44949. * @excluding marker, x
  44950. * @product highcharts
  44951. * @apioption series.pie.data
  44952. */
  44953. /**
  44954. * @type {Highcharts.SeriesPieDataLabelsOptionsObject}
  44955. * @product highcharts
  44956. * @apioption series.pie.data.dataLabels
  44957. */
  44958. /**
  44959. * The sequential index of the data point in the legend.
  44960. *
  44961. * @type {number}
  44962. * @product highcharts
  44963. * @apioption series.pie.data.legendIndex
  44964. */
  44965. /**
  44966. * Whether to display a slice offset from the center.
  44967. *
  44968. * @sample {highcharts} highcharts/point/sliced/
  44969. * One sliced point
  44970. *
  44971. * @type {boolean}
  44972. * @product highcharts
  44973. * @apioption series.pie.data.sliced
  44974. */
  44975. /**
  44976. * @extends plotOptions.pie.dataLabels
  44977. * @excluding align, allowOverlap, inside, staggerLines, step
  44978. * @product highcharts
  44979. * @apioption series.pie.dataLabels
  44980. */
  44981. /**
  44982. * @excluding legendItemClick
  44983. * @product highcharts
  44984. * @apioption series.pie.events
  44985. */
  44986. ''; // placeholder for transpiled doclets above
  44987. return PieSeries;
  44988. });
  44989. _registerModule(_modules, 'Core/Series/DataLabels.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/FormatUtilities.js'], _modules['Core/Globals.js'], _modules['Core/Color/Palette.js'], _modules['Core/Series/Series.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (A, F, H, palette, Series, SeriesRegistry, U) {
  44990. /* *
  44991. *
  44992. * (c) 2010-2021 Torstein Honsi
  44993. *
  44994. * License: www.highcharts.com/license
  44995. *
  44996. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  44997. *
  44998. * */
  44999. var getDeferredAnimation = A.getDeferredAnimation;
  45000. var format = F.format;
  45001. var noop = H.noop;
  45002. var seriesTypes = SeriesRegistry.seriesTypes;
  45003. var arrayMax = U.arrayMax,
  45004. clamp = U.clamp,
  45005. defined = U.defined,
  45006. extend = U.extend,
  45007. fireEvent = U.fireEvent,
  45008. isArray = U.isArray,
  45009. merge = U.merge,
  45010. objectEach = U.objectEach,
  45011. pick = U.pick,
  45012. relativeLength = U.relativeLength,
  45013. splat = U.splat,
  45014. stableSort = U.stableSort;
  45015. /**
  45016. * Callback JavaScript function to format the data label as a string. Note that
  45017. * if a `format` is defined, the format takes precedence and the formatter is
  45018. * ignored.
  45019. *
  45020. * @callback Highcharts.DataLabelsFormatterCallbackFunction
  45021. *
  45022. * @param {Highcharts.PointLabelObject} this
  45023. * Data label context to format
  45024. *
  45025. * @param {Highcharts.DataLabelsOptions} options
  45026. * [API options](/highcharts/plotOptions.series.dataLabels) of the data label
  45027. *
  45028. * @return {number|string|null|undefined}
  45029. * Formatted data label text
  45030. */
  45031. /**
  45032. * Values for handling data labels that flow outside the plot area.
  45033. *
  45034. * @typedef {"allow"|"justify"} Highcharts.DataLabelsOverflowValue
  45035. */
  45036. ''; // detach doclets above
  45037. /* eslint-disable valid-jsdoc */
  45038. /**
  45039. * General distribution algorithm for distributing labels of differing size
  45040. * along a confined length in two dimensions. The algorithm takes an array of
  45041. * objects containing a size, a target and a rank. It will place the labels as
  45042. * close as possible to their targets, skipping the lowest ranked labels if
  45043. * necessary.
  45044. *
  45045. * @private
  45046. * @function Highcharts.distribute
  45047. * @param {Highcharts.DataLabelsBoxArray} boxes
  45048. * @param {number} len
  45049. * @param {number} [maxDistance]
  45050. * @return {void}
  45051. */
  45052. H.distribute = function (boxes, len, maxDistance) {
  45053. var i,
  45054. overlapping = true,
  45055. origBoxes = boxes, // Original array will be altered with added .pos
  45056. restBoxes = [], // The outranked overshoot
  45057. box,
  45058. target,
  45059. total = 0,
  45060. reducedLen = origBoxes.reducedLen || len;
  45061. /**
  45062. * @private
  45063. */
  45064. function sortByTarget(a, b) {
  45065. return a.target - b.target;
  45066. }
  45067. // If the total size exceeds the len, remove those boxes with the lowest
  45068. // rank
  45069. i = boxes.length;
  45070. while (i--) {
  45071. total += boxes[i].size;
  45072. }
  45073. // Sort by rank, then slice away overshoot
  45074. if (total > reducedLen) {
  45075. stableSort(boxes, function (a, b) {
  45076. return (b.rank || 0) - (a.rank || 0);
  45077. });
  45078. i = 0;
  45079. total = 0;
  45080. while (total <= reducedLen) {
  45081. total += boxes[i].size;
  45082. i++;
  45083. }
  45084. restBoxes = boxes.splice(i - 1, boxes.length);
  45085. }
  45086. // Order by target
  45087. stableSort(boxes, sortByTarget);
  45088. // So far we have been mutating the original array. Now
  45089. // create a copy with target arrays
  45090. boxes = boxes.map(function (box) {
  45091. return {
  45092. size: box.size,
  45093. targets: [box.target],
  45094. align: pick(box.align, 0.5)
  45095. };
  45096. });
  45097. while (overlapping) {
  45098. // Initial positions: target centered in box
  45099. i = boxes.length;
  45100. while (i--) {
  45101. box = boxes[i];
  45102. // Composite box, average of targets
  45103. target = (Math.min.apply(0, box.targets) +
  45104. Math.max.apply(0, box.targets)) / 2;
  45105. box.pos = clamp(target - box.size * box.align, 0, len - box.size);
  45106. }
  45107. // Detect overlap and join boxes
  45108. i = boxes.length;
  45109. overlapping = false;
  45110. while (i--) {
  45111. // Overlap
  45112. if (i > 0 &&
  45113. boxes[i - 1].pos + boxes[i - 1].size >
  45114. boxes[i].pos) {
  45115. // Add this size to the previous box
  45116. boxes[i - 1].size += boxes[i].size;
  45117. boxes[i - 1].targets = boxes[i - 1]
  45118. .targets
  45119. .concat(boxes[i].targets);
  45120. boxes[i - 1].align = 0.5;
  45121. // Overlapping right, push left
  45122. if (boxes[i - 1].pos + boxes[i - 1].size > len) {
  45123. boxes[i - 1].pos = len - boxes[i - 1].size;
  45124. }
  45125. boxes.splice(i, 1); // Remove this item
  45126. overlapping = true;
  45127. }
  45128. }
  45129. }
  45130. // Add the rest (hidden boxes)
  45131. origBoxes.push.apply(origBoxes, restBoxes);
  45132. // Now the composite boxes are placed, we need to put the original boxes
  45133. // within them
  45134. i = 0;
  45135. boxes.some(function (box) {
  45136. var posInCompositeBox = 0;
  45137. if (box.targets.some(function () {
  45138. origBoxes[i].pos = box.pos + posInCompositeBox;
  45139. // If the distance between the position and the target exceeds
  45140. // maxDistance, abort the loop and decrease the length in increments
  45141. // of 10% to recursively reduce the number of visible boxes by
  45142. // rank. Once all boxes are within the maxDistance, we're good.
  45143. if (typeof maxDistance !== 'undefined' &&
  45144. Math.abs(origBoxes[i].pos - origBoxes[i].target) > maxDistance) {
  45145. // Reset the positions that are already set
  45146. origBoxes.slice(0, i + 1).forEach(function (box) {
  45147. delete box.pos;
  45148. });
  45149. // Try with a smaller length
  45150. origBoxes.reducedLen =
  45151. (origBoxes.reducedLen || len) - (len * 0.1);
  45152. // Recurse
  45153. if (origBoxes.reducedLen > len * 0.1) {
  45154. H.distribute(origBoxes, len, maxDistance);
  45155. }
  45156. // Exceeded maxDistance => abort
  45157. return true;
  45158. }
  45159. posInCompositeBox += origBoxes[i].size;
  45160. i++;
  45161. })) {
  45162. // Exceeded maxDistance => abort
  45163. return true;
  45164. }
  45165. });
  45166. // Add the rest (hidden) boxes and sort by target
  45167. stableSort(origBoxes, sortByTarget);
  45168. };
  45169. /**
  45170. * Draw the data labels
  45171. *
  45172. * @private
  45173. * @function Highcharts.Series#drawDataLabels
  45174. * @return {void}
  45175. * @fires Highcharts.Series#event:afterDrawDataLabels
  45176. */
  45177. Series.prototype.drawDataLabels = function () {
  45178. var series = this,
  45179. chart = series.chart,
  45180. seriesOptions = series.options,
  45181. seriesDlOptions = seriesOptions.dataLabels,
  45182. points = series.points,
  45183. pointOptions,
  45184. hasRendered = series.hasRendered || 0,
  45185. dataLabelsGroup,
  45186. dataLabelAnim = seriesDlOptions.animation,
  45187. animationConfig = seriesDlOptions.defer ?
  45188. getDeferredAnimation(chart,
  45189. dataLabelAnim,
  45190. series) :
  45191. { defer: 0,
  45192. duration: 0 },
  45193. renderer = chart.renderer;
  45194. /**
  45195. * Handle the dataLabels.filter option.
  45196. * @private
  45197. */
  45198. function applyFilter(point, options) {
  45199. var filter = options.filter,
  45200. op,
  45201. prop,
  45202. val;
  45203. if (filter) {
  45204. op = filter.operator;
  45205. prop = point[filter.property];
  45206. val = filter.value;
  45207. if ((op === '>' && prop > val) ||
  45208. (op === '<' && prop < val) ||
  45209. (op === '>=' && prop >= val) ||
  45210. (op === '<=' && prop <= val) ||
  45211. (op === '==' && prop == val) || // eslint-disable-line eqeqeq
  45212. (op === '===' && prop === val)) {
  45213. return true;
  45214. }
  45215. return false;
  45216. }
  45217. return true;
  45218. }
  45219. /**
  45220. * Merge two objects that can be arrays. If one of them is an array, the
  45221. * other is merged into each element. If both are arrays, each element is
  45222. * merged by index. If neither are arrays, we use normal merge.
  45223. * @private
  45224. */
  45225. function mergeArrays(one, two) {
  45226. var res = [],
  45227. i;
  45228. if (isArray(one) && !isArray(two)) {
  45229. res = one.map(function (el) {
  45230. return merge(el, two);
  45231. });
  45232. }
  45233. else if (isArray(two) && !isArray(one)) {
  45234. res = two.map(function (el) {
  45235. return merge(one, el);
  45236. });
  45237. }
  45238. else if (!isArray(one) && !isArray(two)) {
  45239. res = merge(one, two);
  45240. }
  45241. else {
  45242. i = Math.max(one.length, two.length);
  45243. while (i--) {
  45244. res[i] = merge(one[i], two[i]);
  45245. }
  45246. }
  45247. return res;
  45248. }
  45249. // Merge in plotOptions.dataLabels for series
  45250. seriesDlOptions = mergeArrays(mergeArrays(chart.options.plotOptions &&
  45251. chart.options.plotOptions.series &&
  45252. chart.options.plotOptions.series.dataLabels, chart.options.plotOptions &&
  45253. chart.options.plotOptions[series.type] &&
  45254. chart.options.plotOptions[series.type].dataLabels), seriesDlOptions);
  45255. fireEvent(this, 'drawDataLabels');
  45256. if (isArray(seriesDlOptions) ||
  45257. seriesDlOptions.enabled ||
  45258. series._hasPointLabels) {
  45259. // Create a separate group for the data labels to avoid rotation
  45260. dataLabelsGroup = series.plotGroup('dataLabelsGroup', 'data-labels', !hasRendered ? 'hidden' : 'inherit', // #5133, #10220
  45261. seriesDlOptions.zIndex || 6);
  45262. dataLabelsGroup.attr({ opacity: +hasRendered }); // #3300
  45263. if (!hasRendered) {
  45264. var group = series.dataLabelsGroup;
  45265. if (group) {
  45266. if (series.visible) { // #2597, #3023, #3024
  45267. dataLabelsGroup.show(true);
  45268. }
  45269. group[seriesOptions.animation ? 'animate' : 'attr']({ opacity: 1 }, animationConfig);
  45270. }
  45271. }
  45272. // Make the labels for each point
  45273. points.forEach(function (point) {
  45274. // Merge in series options for the point.
  45275. // @note dataLabelAttribs (like pointAttribs) would eradicate
  45276. // the need for dlOptions, and simplify the section below.
  45277. pointOptions = splat(mergeArrays(seriesDlOptions, point.dlOptions || // dlOptions is used in treemaps
  45278. (point.options && point.options.dataLabels)));
  45279. // Handle each individual data label for this point
  45280. pointOptions.forEach(function (labelOptions, i) {
  45281. // Options for one datalabel
  45282. var labelEnabled = (labelOptions.enabled &&
  45283. // #2282, #4641, #7112, #10049
  45284. (!point.isNull || point.dataLabelOnNull) &&
  45285. applyFilter(point,
  45286. labelOptions)),
  45287. labelConfig,
  45288. formatString,
  45289. labelText,
  45290. style,
  45291. rotation,
  45292. attr,
  45293. dataLabel = point.dataLabels ? point.dataLabels[i] :
  45294. point.dataLabel,
  45295. connector = point.connectors ? point.connectors[i] :
  45296. point.connector,
  45297. labelDistance = pick(labelOptions.distance,
  45298. point.labelDistance),
  45299. isNew = !dataLabel;
  45300. if (labelEnabled) {
  45301. // Create individual options structure that can be extended
  45302. // without affecting others
  45303. labelConfig = point.getLabelConfig();
  45304. formatString = pick(labelOptions[point.formatPrefix + 'Format'], labelOptions.format);
  45305. labelText = defined(formatString) ?
  45306. format(formatString, labelConfig, chart) :
  45307. (labelOptions[point.formatPrefix + 'Formatter'] ||
  45308. labelOptions.formatter).call(labelConfig, labelOptions);
  45309. style = labelOptions.style;
  45310. rotation = labelOptions.rotation;
  45311. if (!chart.styledMode) {
  45312. // Determine the color
  45313. style.color = pick(labelOptions.color, style.color, series.color, palette.neutralColor100);
  45314. // Get automated contrast color
  45315. if (style.color === 'contrast') {
  45316. point.contrastColor = renderer.getContrast((point.color || series.color));
  45317. style.color = (!defined(labelDistance) &&
  45318. labelOptions.inside) ||
  45319. labelDistance < 0 ||
  45320. !!seriesOptions.stacking ?
  45321. point.contrastColor :
  45322. palette.neutralColor100;
  45323. }
  45324. else {
  45325. delete point.contrastColor;
  45326. }
  45327. if (seriesOptions.cursor) {
  45328. style.cursor = seriesOptions.cursor;
  45329. }
  45330. }
  45331. attr = {
  45332. r: labelOptions.borderRadius || 0,
  45333. rotation: rotation,
  45334. padding: labelOptions.padding,
  45335. zIndex: 1
  45336. };
  45337. if (!chart.styledMode) {
  45338. attr.fill = labelOptions.backgroundColor;
  45339. attr.stroke = labelOptions.borderColor;
  45340. attr['stroke-width'] = labelOptions.borderWidth;
  45341. }
  45342. // Remove unused attributes (#947)
  45343. objectEach(attr, function (val, name) {
  45344. if (typeof val === 'undefined') {
  45345. delete attr[name];
  45346. }
  45347. });
  45348. }
  45349. // If the point is outside the plot area, destroy it. #678, #820
  45350. if (dataLabel && (!labelEnabled || !defined(labelText))) {
  45351. point.dataLabel =
  45352. point.dataLabel && point.dataLabel.destroy();
  45353. if (point.dataLabels) {
  45354. // Remove point.dataLabels if this was the last one
  45355. if (point.dataLabels.length === 1) {
  45356. delete point.dataLabels;
  45357. }
  45358. else {
  45359. delete point.dataLabels[i];
  45360. }
  45361. }
  45362. if (!i) {
  45363. delete point.dataLabel;
  45364. }
  45365. if (connector) {
  45366. point.connector = point.connector.destroy();
  45367. if (point.connectors) {
  45368. // Remove point.connectors if this was the last one
  45369. if (point.connectors.length === 1) {
  45370. delete point.connectors;
  45371. }
  45372. else {
  45373. delete point.connectors[i];
  45374. }
  45375. }
  45376. }
  45377. // Individual labels are disabled if the are explicitly disabled
  45378. // in the point options, or if they fall outside the plot area.
  45379. }
  45380. else if (labelEnabled && defined(labelText)) {
  45381. if (!dataLabel) {
  45382. // Create new label element
  45383. point.dataLabels = point.dataLabels || [];
  45384. dataLabel = point.dataLabels[i] = rotation ?
  45385. // Labels don't rotate, use text element
  45386. renderer.text(labelText, 0, -9999, labelOptions.useHTML)
  45387. .addClass('highcharts-data-label') :
  45388. // We can use label
  45389. renderer.label(labelText, 0, -9999, labelOptions.shape, null, null, labelOptions.useHTML, null, 'data-label');
  45390. // Store for backwards compatibility
  45391. if (!i) {
  45392. point.dataLabel = dataLabel;
  45393. }
  45394. dataLabel.addClass(' highcharts-data-label-color-' + point.colorIndex +
  45395. ' ' + (labelOptions.className || '') +
  45396. ( // #3398
  45397. labelOptions.useHTML ?
  45398. ' highcharts-tracker' :
  45399. ''));
  45400. }
  45401. else {
  45402. // Use old element and just update text
  45403. attr.text = labelText;
  45404. }
  45405. // Store data label options for later access
  45406. dataLabel.options = labelOptions;
  45407. dataLabel.attr(attr);
  45408. if (!chart.styledMode) {
  45409. // Styles must be applied before add in order to read
  45410. // text bounding box
  45411. dataLabel.css(style).shadow(labelOptions.shadow);
  45412. }
  45413. if (!dataLabel.added) {
  45414. dataLabel.add(dataLabelsGroup);
  45415. }
  45416. if (labelOptions.textPath && !labelOptions.useHTML) {
  45417. dataLabel.setTextPath((point.getDataLabelPath &&
  45418. point.getDataLabelPath(dataLabel)) || point.graphic, labelOptions.textPath);
  45419. if (point.dataLabelPath &&
  45420. !labelOptions.textPath.enabled) {
  45421. // clean the DOM
  45422. point.dataLabelPath = point.dataLabelPath.destroy();
  45423. }
  45424. }
  45425. // Now the data label is created and placed at 0,0, so we
  45426. // need to align it
  45427. series.alignDataLabel(point, dataLabel, labelOptions, null, isNew);
  45428. }
  45429. });
  45430. });
  45431. }
  45432. fireEvent(this, 'afterDrawDataLabels');
  45433. };
  45434. /**
  45435. * Align each individual data label.
  45436. *
  45437. * @private
  45438. * @function Highcharts.Series#alignDataLabel
  45439. * @param {Highcharts.Point} point
  45440. * @param {Highcharts.SVGElement} dataLabel
  45441. * @param {Highcharts.DataLabelsOptions} options
  45442. * @param {Highcharts.BBoxObject} alignTo
  45443. * @param {boolean} [isNew]
  45444. * @return {void}
  45445. */
  45446. Series.prototype.alignDataLabel = function (point, dataLabel, options, alignTo, isNew) {
  45447. var series = this,
  45448. chart = this.chart,
  45449. inverted = this.isCartesian && chart.inverted,
  45450. enabledDataSorting = this.enabledDataSorting,
  45451. plotX = pick(point.dlBox && point.dlBox.centerX,
  45452. point.plotX, -9999),
  45453. plotY = pick(point.plotY, -9999),
  45454. bBox = dataLabel.getBBox(),
  45455. baseline,
  45456. rotation = options.rotation,
  45457. normRotation,
  45458. negRotation,
  45459. align = options.align,
  45460. rotCorr, // rotation correction
  45461. isInsidePlot = chart.isInsidePlot(plotX,
  45462. Math.round(plotY), {
  45463. inverted: inverted,
  45464. paneCoordinates: true,
  45465. series: series
  45466. }),
  45467. // Math.round for rounding errors (#2683), alignTo to allow column
  45468. // labels (#2700)
  45469. alignAttr, // the final position;
  45470. justify = pick(options.overflow, (enabledDataSorting ? 'none' : 'justify')) === 'justify', visible = this.visible &&
  45471. point.visible !== false &&
  45472. (point.series.forceDL ||
  45473. (enabledDataSorting && !justify) ||
  45474. isInsidePlot ||
  45475. (
  45476. // If the data label is inside the align box, it is enough
  45477. // that parts of the align box is inside the plot area
  45478. // (#12370). When stacking, it is always inside regardless
  45479. // of the option (#15148).
  45480. pick(options.inside, !!this.options.stacking) &&
  45481. alignTo &&
  45482. chart.isInsidePlot(plotX, inverted ?
  45483. alignTo.x + 1 :
  45484. alignTo.y + alignTo.height - 1, {
  45485. inverted: inverted,
  45486. paneCoordinates: true,
  45487. series: series
  45488. }))), setStartPos = function (alignOptions) {
  45489. if (enabledDataSorting && series.xAxis && !justify) {
  45490. series.setDataLabelStartPos(point, dataLabel, isNew, isInsidePlot, alignOptions);
  45491. }
  45492. };
  45493. if (visible) {
  45494. baseline = chart.renderer.fontMetrics(chart.styledMode ? void 0 : options.style.fontSize, dataLabel).b;
  45495. // The alignment box is a singular point
  45496. alignTo = extend({
  45497. x: inverted ? this.yAxis.len - plotY : plotX,
  45498. y: Math.round(inverted ? this.xAxis.len - plotX : plotY),
  45499. width: 0,
  45500. height: 0
  45501. }, alignTo);
  45502. // Add the text size for alignment calculation
  45503. extend(options, {
  45504. width: bBox.width,
  45505. height: bBox.height
  45506. });
  45507. // Allow a hook for changing alignment in the last moment, then do the
  45508. // alignment
  45509. if (rotation) {
  45510. justify = false; // Not supported for rotated text
  45511. rotCorr = chart.renderer.rotCorr(baseline, rotation); // #3723
  45512. alignAttr = {
  45513. x: (alignTo.x +
  45514. (options.x || 0) +
  45515. alignTo.width / 2 +
  45516. rotCorr.x),
  45517. y: (alignTo.y +
  45518. (options.y || 0) +
  45519. { top: 0, middle: 0.5, bottom: 1 }[options.verticalAlign] *
  45520. alignTo.height)
  45521. };
  45522. setStartPos(alignAttr); // data sorting
  45523. dataLabel[isNew ? 'attr' : 'animate'](alignAttr)
  45524. .attr({
  45525. align: align
  45526. });
  45527. // Compensate for the rotated label sticking out on the sides
  45528. normRotation = (rotation + 720) % 360;
  45529. negRotation = normRotation > 180 && normRotation < 360;
  45530. if (align === 'left') {
  45531. alignAttr.y -= negRotation ? bBox.height : 0;
  45532. }
  45533. else if (align === 'center') {
  45534. alignAttr.x -= bBox.width / 2;
  45535. alignAttr.y -= bBox.height / 2;
  45536. }
  45537. else if (align === 'right') {
  45538. alignAttr.x -= bBox.width;
  45539. alignAttr.y -= negRotation ? 0 : bBox.height;
  45540. }
  45541. dataLabel.placed = true;
  45542. dataLabel.alignAttr = alignAttr;
  45543. }
  45544. else {
  45545. setStartPos(alignTo); // data sorting
  45546. dataLabel.align(options, void 0, alignTo);
  45547. alignAttr = dataLabel.alignAttr;
  45548. }
  45549. // Handle justify or crop
  45550. if (justify && alignTo.height >= 0) { // #8830
  45551. this.justifyDataLabel(dataLabel, options, alignAttr, bBox, alignTo, isNew);
  45552. // Now check that the data label is within the plot area
  45553. }
  45554. else if (pick(options.crop, true)) {
  45555. visible =
  45556. chart.isInsidePlot(alignAttr.x, alignAttr.y, {
  45557. paneCoordinates: true,
  45558. series: series
  45559. }) &&
  45560. chart.isInsidePlot(alignAttr.x + bBox.width, alignAttr.y + bBox.height, {
  45561. paneCoordinates: true,
  45562. series: series
  45563. });
  45564. }
  45565. // When we're using a shape, make it possible with a connector or an
  45566. // arrow pointing to thie point
  45567. if (options.shape && !rotation) {
  45568. dataLabel[isNew ? 'attr' : 'animate']({
  45569. anchorX: inverted ?
  45570. chart.plotWidth - point.plotY :
  45571. point.plotX,
  45572. anchorY: inverted ?
  45573. chart.plotHeight - point.plotX :
  45574. point.plotY
  45575. });
  45576. }
  45577. }
  45578. // To use alignAttr property in hideOverlappingLabels
  45579. if (isNew && enabledDataSorting) {
  45580. dataLabel.placed = false;
  45581. }
  45582. // Show or hide based on the final aligned position
  45583. if (!visible && (!enabledDataSorting || justify)) {
  45584. dataLabel.hide(true);
  45585. dataLabel.placed = false; // don't animate back in
  45586. }
  45587. };
  45588. /**
  45589. * Set starting position for data label sorting animation.
  45590. *
  45591. * @private
  45592. * @function Highcharts.Series#setDataLabelStartPos
  45593. * @param {Highcharts.SVGElement} dataLabel
  45594. * @param {Highcharts.ColumnPoint} point
  45595. * @param {boolean | undefined} [isNew]
  45596. * @param {boolean} [isInside]
  45597. * @param {Highcharts.AlignObject} [alignOptions]
  45598. *
  45599. * @return {void}
  45600. */
  45601. Series.prototype.setDataLabelStartPos = function (point, dataLabel, isNew, isInside, alignOptions) {
  45602. var chart = this.chart,
  45603. inverted = chart.inverted,
  45604. xAxis = this.xAxis,
  45605. reversed = xAxis.reversed,
  45606. labelCenter = inverted ? dataLabel.height / 2 : dataLabel.width / 2,
  45607. pointWidth = point.pointWidth,
  45608. halfWidth = pointWidth ? pointWidth / 2 : 0,
  45609. startXPos,
  45610. startYPos;
  45611. startXPos = inverted ?
  45612. alignOptions.x :
  45613. (reversed ?
  45614. -labelCenter - halfWidth :
  45615. xAxis.width - labelCenter + halfWidth);
  45616. startYPos = inverted ?
  45617. (reversed ?
  45618. this.yAxis.height - labelCenter + halfWidth :
  45619. -labelCenter - halfWidth) : alignOptions.y;
  45620. dataLabel.startXPos = startXPos;
  45621. dataLabel.startYPos = startYPos;
  45622. // We need to handle visibility in case of sorting point outside plot area
  45623. if (!isInside) {
  45624. dataLabel
  45625. .attr({ opacity: 1 })
  45626. .animate({ opacity: 0 }, void 0, dataLabel.hide);
  45627. }
  45628. else if (dataLabel.visibility === 'hidden') {
  45629. dataLabel.show();
  45630. dataLabel
  45631. .attr({ opacity: 0 })
  45632. .animate({ opacity: 1 });
  45633. }
  45634. // Save start position on first render, but do not change position
  45635. if (!chart.hasRendered) {
  45636. return;
  45637. }
  45638. // Set start position
  45639. if (isNew) {
  45640. dataLabel.attr({ x: dataLabel.startXPos, y: dataLabel.startYPos });
  45641. }
  45642. dataLabel.placed = true;
  45643. };
  45644. /**
  45645. * If data labels fall partly outside the plot area, align them back in, in a
  45646. * way that doesn't hide the point.
  45647. *
  45648. * @private
  45649. * @function Highcharts.Series#justifyDataLabel
  45650. * @param {Highcharts.SVGElement} dataLabel
  45651. * @param {Highcharts.DataLabelsOptions} options
  45652. * @param {Highcharts.SVGAttributes} alignAttr
  45653. * @param {Highcharts.BBoxObject} bBox
  45654. * @param {Highcharts.BBoxObject} [alignTo]
  45655. * @param {boolean} [isNew]
  45656. * @return {boolean|undefined}
  45657. */
  45658. Series.prototype.justifyDataLabel = function (dataLabel, options, alignAttr, bBox, alignTo, isNew) {
  45659. var chart = this.chart,
  45660. align = options.align,
  45661. verticalAlign = options.verticalAlign,
  45662. off,
  45663. justified,
  45664. padding = dataLabel.box ? 0 : (dataLabel.padding || 0);
  45665. var _a = options.x,
  45666. x = _a === void 0 ? 0 : _a,
  45667. _b = options.y,
  45668. y = _b === void 0 ? 0 : _b;
  45669. // Off left
  45670. off = (alignAttr.x || 0) + padding;
  45671. if (off < 0) {
  45672. if (align === 'right' && x >= 0) {
  45673. options.align = 'left';
  45674. options.inside = true;
  45675. }
  45676. else {
  45677. x -= off;
  45678. }
  45679. justified = true;
  45680. }
  45681. // Off right
  45682. off = (alignAttr.x || 0) + bBox.width - padding;
  45683. if (off > chart.plotWidth) {
  45684. if (align === 'left' && x <= 0) {
  45685. options.align = 'right';
  45686. options.inside = true;
  45687. }
  45688. else {
  45689. x += chart.plotWidth - off;
  45690. }
  45691. justified = true;
  45692. }
  45693. // Off top
  45694. off = alignAttr.y + padding;
  45695. if (off < 0) {
  45696. if (verticalAlign === 'bottom' && y >= 0) {
  45697. options.verticalAlign = 'top';
  45698. options.inside = true;
  45699. }
  45700. else {
  45701. y -= off;
  45702. }
  45703. justified = true;
  45704. }
  45705. // Off bottom
  45706. off = (alignAttr.y || 0) + bBox.height - padding;
  45707. if (off > chart.plotHeight) {
  45708. if (verticalAlign === 'top' && y <= 0) {
  45709. options.verticalAlign = 'bottom';
  45710. options.inside = true;
  45711. }
  45712. else {
  45713. y += chart.plotHeight - off;
  45714. }
  45715. justified = true;
  45716. }
  45717. if (justified) {
  45718. options.x = x;
  45719. options.y = y;
  45720. dataLabel.placed = !isNew;
  45721. dataLabel.align(options, void 0, alignTo);
  45722. }
  45723. return justified;
  45724. };
  45725. if (seriesTypes.pie) {
  45726. seriesTypes.pie.prototype.dataLabelPositioners = {
  45727. // Based on the value computed in Highcharts' distribute algorithm.
  45728. radialDistributionY: function (point) {
  45729. return point.top + point.distributeBox.pos;
  45730. },
  45731. // get the x - use the natural x position for labels near the
  45732. // top and bottom, to prevent the top and botton slice
  45733. // connectors from touching each other on either side
  45734. // Based on the value computed in Highcharts' distribute algorithm.
  45735. radialDistributionX: function (series, point, y, naturalY) {
  45736. return series.getX(y < point.top + 2 || y > point.bottom - 2 ?
  45737. naturalY :
  45738. y, point.half, point);
  45739. },
  45740. // dataLabels.distance determines the x position of the label
  45741. justify: function (point, radius, seriesCenter) {
  45742. return seriesCenter[0] + (point.half ? -1 : 1) *
  45743. (radius + point.labelDistance);
  45744. },
  45745. // Left edges of the left-half labels touch the left edge of the plot
  45746. // area. Right edges of the right-half labels touch the right edge of
  45747. // the plot area.
  45748. alignToPlotEdges: function (dataLabel, half, plotWidth, plotLeft) {
  45749. var dataLabelWidth = dataLabel.getBBox().width;
  45750. return half ? dataLabelWidth + plotLeft :
  45751. plotWidth - dataLabelWidth - plotLeft;
  45752. },
  45753. // Connectors of each side end in the same x position. Labels are
  45754. // aligned to them. Left edge of the widest left-half label touches the
  45755. // left edge of the plot area. Right edge of the widest right-half label
  45756. // touches the right edge of the plot area.
  45757. alignToConnectors: function (points, half, plotWidth, plotLeft) {
  45758. var maxDataLabelWidth = 0,
  45759. dataLabelWidth;
  45760. // find widest data label
  45761. points.forEach(function (point) {
  45762. dataLabelWidth = point.dataLabel.getBBox().width;
  45763. if (dataLabelWidth > maxDataLabelWidth) {
  45764. maxDataLabelWidth = dataLabelWidth;
  45765. }
  45766. });
  45767. return half ? maxDataLabelWidth + plotLeft :
  45768. plotWidth - maxDataLabelWidth - plotLeft;
  45769. }
  45770. };
  45771. /**
  45772. * Override the base drawDataLabels method by pie specific functionality
  45773. *
  45774. * @private
  45775. * @function Highcharts.seriesTypes.pie#drawDataLabels
  45776. * @return {void}
  45777. */
  45778. seriesTypes.pie.prototype.drawDataLabels = function () {
  45779. var series = this,
  45780. data = series.data,
  45781. point,
  45782. chart = series.chart,
  45783. options = series.options.dataLabels || {},
  45784. connectorPadding = options.connectorPadding,
  45785. connectorWidth,
  45786. plotWidth = chart.plotWidth,
  45787. plotHeight = chart.plotHeight,
  45788. plotLeft = chart.plotLeft,
  45789. maxWidth = Math.round(chart.chartWidth / 3),
  45790. connector,
  45791. seriesCenter = series.center,
  45792. radius = seriesCenter[2] / 2,
  45793. centerY = seriesCenter[1],
  45794. dataLabel,
  45795. dataLabelWidth,
  45796. // labelPos,
  45797. labelPosition,
  45798. labelHeight,
  45799. // divide the points into right and left halves for anti collision
  45800. halves = [
  45801. [],
  45802. [] // left
  45803. ],
  45804. x,
  45805. y,
  45806. visibility,
  45807. j,
  45808. overflow = [0, 0, 0, 0], // top, right, bottom, left
  45809. dataLabelPositioners = series.dataLabelPositioners,
  45810. pointDataLabelsOptions;
  45811. // get out if not enabled
  45812. if (!series.visible ||
  45813. (!options.enabled &&
  45814. !series._hasPointLabels)) {
  45815. return;
  45816. }
  45817. // Reset all labels that have been shortened
  45818. data.forEach(function (point) {
  45819. if (point.dataLabel && point.visible && point.dataLabel.shortened) {
  45820. point.dataLabel
  45821. .attr({
  45822. width: 'auto'
  45823. }).css({
  45824. width: 'auto',
  45825. textOverflow: 'clip'
  45826. });
  45827. point.dataLabel.shortened = false;
  45828. }
  45829. });
  45830. // run parent method
  45831. Series.prototype.drawDataLabels.apply(series);
  45832. data.forEach(function (point) {
  45833. if (point.dataLabel) {
  45834. if (point.visible) { // #407, #2510
  45835. // Arrange points for detection collision
  45836. halves[point.half].push(point);
  45837. // Reset positions (#4905)
  45838. point.dataLabel._pos = null;
  45839. // Avoid long labels squeezing the pie size too far down
  45840. if (!defined(options.style.width) &&
  45841. !defined(point.options.dataLabels &&
  45842. point.options.dataLabels.style &&
  45843. point.options.dataLabels.style.width)) {
  45844. if (point.dataLabel.getBBox().width > maxWidth) {
  45845. point.dataLabel.css({
  45846. // Use a fraction of the maxWidth to avoid
  45847. // wrapping close to the end of the string.
  45848. width: Math.round(maxWidth * 0.7) + 'px'
  45849. });
  45850. point.dataLabel.shortened = true;
  45851. }
  45852. }
  45853. }
  45854. else {
  45855. point.dataLabel = point.dataLabel.destroy();
  45856. // Workaround to make pies destroy multiple datalabels
  45857. // correctly. This logic needs rewriting to support multiple
  45858. // datalabels fully.
  45859. if (point.dataLabels && point.dataLabels.length === 1) {
  45860. delete point.dataLabels;
  45861. }
  45862. }
  45863. }
  45864. });
  45865. /* Loop over the points in each half, starting from the top and bottom
  45866. * of the pie to detect overlapping labels.
  45867. */
  45868. halves.forEach(function (points, i) {
  45869. var top,
  45870. bottom,
  45871. length = points.length,
  45872. positions = [],
  45873. naturalY,
  45874. sideOverflow,
  45875. size,
  45876. distributionLength;
  45877. if (!length) {
  45878. return;
  45879. }
  45880. // Sort by angle
  45881. series.sortByAngle(points, i - 0.5);
  45882. // Only do anti-collision when we have dataLabels outside the pie
  45883. // and have connectors. (#856)
  45884. if (series.maxLabelDistance > 0) {
  45885. top = Math.max(0, centerY - radius - series.maxLabelDistance);
  45886. bottom = Math.min(centerY + radius + series.maxLabelDistance, chart.plotHeight);
  45887. points.forEach(function (point) {
  45888. // check if specific points' label is outside the pie
  45889. if (point.labelDistance > 0 && point.dataLabel) {
  45890. // point.top depends on point.labelDistance value
  45891. // Used for calculation of y value in getX method
  45892. point.top = Math.max(0, centerY - radius - point.labelDistance);
  45893. point.bottom = Math.min(centerY + radius + point.labelDistance, chart.plotHeight);
  45894. size = point.dataLabel.getBBox().height || 21;
  45895. // point.positionsIndex is needed for getting index of
  45896. // parameter related to specific point inside positions
  45897. // array - not every point is in positions array.
  45898. point.distributeBox = {
  45899. target: point.labelPosition.natural.y -
  45900. point.top + size / 2,
  45901. size: size,
  45902. rank: point.y
  45903. };
  45904. positions.push(point.distributeBox);
  45905. }
  45906. });
  45907. distributionLength = bottom + size - top;
  45908. H.distribute(positions, distributionLength, distributionLength / 5);
  45909. }
  45910. // Now the used slots are sorted, fill them up sequentially
  45911. for (j = 0; j < length; j++) {
  45912. point = points[j];
  45913. // labelPos = point.labelPos;
  45914. labelPosition = point.labelPosition;
  45915. dataLabel = point.dataLabel;
  45916. visibility = point.visible === false ? 'hidden' : 'inherit';
  45917. naturalY = labelPosition.natural.y;
  45918. y = naturalY;
  45919. if (positions && defined(point.distributeBox)) {
  45920. if (typeof point.distributeBox.pos === 'undefined') {
  45921. visibility = 'hidden';
  45922. }
  45923. else {
  45924. labelHeight = point.distributeBox.size;
  45925. // Find label's y position
  45926. y = dataLabelPositioners
  45927. .radialDistributionY(point);
  45928. }
  45929. }
  45930. // It is needed to delete point.positionIndex for
  45931. // dynamically added points etc.
  45932. delete point.positionIndex; // @todo unused
  45933. // Find label's x position
  45934. // justify is undocumented in the API - preserve support for it
  45935. if (options.justify) {
  45936. x = dataLabelPositioners.justify(point, radius, seriesCenter);
  45937. }
  45938. else {
  45939. switch (options.alignTo) {
  45940. case 'connectors':
  45941. x = dataLabelPositioners.alignToConnectors(points, i, plotWidth, plotLeft);
  45942. break;
  45943. case 'plotEdges':
  45944. x = dataLabelPositioners.alignToPlotEdges(dataLabel, i, plotWidth, plotLeft);
  45945. break;
  45946. default:
  45947. x = dataLabelPositioners.radialDistributionX(series, point, y, naturalY);
  45948. }
  45949. }
  45950. // Record the placement and visibility
  45951. dataLabel._attr = {
  45952. visibility: visibility,
  45953. align: labelPosition.alignment
  45954. };
  45955. pointDataLabelsOptions = point.options.dataLabels || {};
  45956. dataLabel._pos = {
  45957. x: (x +
  45958. pick(pointDataLabelsOptions.x, options.x) + // (#12985)
  45959. ({
  45960. left: connectorPadding,
  45961. right: -connectorPadding
  45962. }[labelPosition.alignment] || 0)),
  45963. // 10 is for the baseline (label vs text)
  45964. y: (y +
  45965. pick(pointDataLabelsOptions.y, options.y) - // (#12985)
  45966. 10)
  45967. };
  45968. // labelPos.x = x;
  45969. // labelPos.y = y;
  45970. labelPosition.final.x = x;
  45971. labelPosition.final.y = y;
  45972. // Detect overflowing data labels
  45973. if (pick(options.crop, true)) {
  45974. dataLabelWidth = dataLabel.getBBox().width;
  45975. sideOverflow = null;
  45976. // Overflow left
  45977. if (x - dataLabelWidth < connectorPadding &&
  45978. i === 1 // left half
  45979. ) {
  45980. sideOverflow = Math.round(dataLabelWidth - x + connectorPadding);
  45981. overflow[3] = Math.max(sideOverflow, overflow[3]);
  45982. // Overflow right
  45983. }
  45984. else if (x + dataLabelWidth > plotWidth - connectorPadding &&
  45985. i === 0 // right half
  45986. ) {
  45987. sideOverflow = Math.round(x + dataLabelWidth - plotWidth + connectorPadding);
  45988. overflow[1] = Math.max(sideOverflow, overflow[1]);
  45989. }
  45990. // Overflow top
  45991. if (y - labelHeight / 2 < 0) {
  45992. overflow[0] = Math.max(Math.round(-y + labelHeight / 2), overflow[0]);
  45993. // Overflow left
  45994. }
  45995. else if (y + labelHeight / 2 > plotHeight) {
  45996. overflow[2] = Math.max(Math.round(y + labelHeight / 2 - plotHeight), overflow[2]);
  45997. }
  45998. dataLabel.sideOverflow = sideOverflow;
  45999. }
  46000. } // for each point
  46001. }); // for each half
  46002. // Do not apply the final placement and draw the connectors until we
  46003. // have verified that labels are not spilling over.
  46004. if (arrayMax(overflow) === 0 ||
  46005. this.verifyDataLabelOverflow(overflow)) {
  46006. // Place the labels in the final position
  46007. this.placeDataLabels();
  46008. this.points.forEach(function (point) {
  46009. // #8864: every connector can have individual options
  46010. pointDataLabelsOptions =
  46011. merge(options, point.options.dataLabels);
  46012. connectorWidth =
  46013. pick(pointDataLabelsOptions.connectorWidth, 1);
  46014. // Draw the connector
  46015. if (connectorWidth) {
  46016. var isNew = void 0;
  46017. connector = point.connector;
  46018. dataLabel = point.dataLabel;
  46019. if (dataLabel &&
  46020. dataLabel._pos &&
  46021. point.visible &&
  46022. point.labelDistance > 0) {
  46023. visibility = dataLabel._attr.visibility;
  46024. isNew = !connector;
  46025. if (isNew) {
  46026. point.connector = connector = chart.renderer
  46027. .path()
  46028. .addClass('highcharts-data-label-connector ' +
  46029. ' highcharts-color-' + point.colorIndex +
  46030. (point.className ?
  46031. ' ' + point.className :
  46032. ''))
  46033. .add(series.dataLabelsGroup);
  46034. if (!chart.styledMode) {
  46035. connector.attr({
  46036. 'stroke-width': connectorWidth,
  46037. 'stroke': (pointDataLabelsOptions.connectorColor ||
  46038. point.color ||
  46039. palette.neutralColor60)
  46040. });
  46041. }
  46042. }
  46043. connector[isNew ? 'attr' : 'animate']({
  46044. d: point.getConnectorPath()
  46045. });
  46046. connector.attr('visibility', visibility);
  46047. }
  46048. else if (connector) {
  46049. point.connector = connector.destroy();
  46050. }
  46051. }
  46052. });
  46053. }
  46054. };
  46055. /**
  46056. * Extendable method for getting the path of the connector between the data
  46057. * label and the pie slice.
  46058. *
  46059. * @private
  46060. * @function Highcharts.seriesTypes.pie#connectorPath
  46061. *
  46062. * @param {*} labelPos
  46063. *
  46064. * @return {Highcharts.SVGPathArray}
  46065. */
  46066. // TODO: depracated - remove it
  46067. /*
  46068. seriesTypes.pie.prototype.connectorPath = function (labelPos) {
  46069. let x = labelPos.x,
  46070. y = labelPos.y;
  46071. return pick(this.options.dataLabels.softConnector, true) ? [
  46072. 'M',
  46073. // end of the string at the label
  46074. x + (labelPos[6] === 'left' ? 5 : -5), y,
  46075. 'C',
  46076. x, y, // first break, next to the label
  46077. 2 * labelPos[2] - labelPos[4], 2 * labelPos[3] - labelPos[5],
  46078. labelPos[2], labelPos[3], // second break
  46079. 'L',
  46080. labelPos[4], labelPos[5] // base
  46081. ] : [
  46082. 'M',
  46083. // end of the string at the label
  46084. x + (labelPos[6] === 'left' ? 5 : -5), y,
  46085. 'L',
  46086. labelPos[2], labelPos[3], // second break
  46087. 'L',
  46088. labelPos[4], labelPos[5] // base
  46089. ];
  46090. };
  46091. */
  46092. /**
  46093. * Perform the final placement of the data labels after we have verified
  46094. * that they fall within the plot area.
  46095. *
  46096. * @private
  46097. * @function Highcharts.seriesTypes.pie#placeDataLabels
  46098. * @return {void}
  46099. */
  46100. seriesTypes.pie.prototype.placeDataLabels = function () {
  46101. this.points.forEach(function (point) {
  46102. var dataLabel = point.dataLabel,
  46103. _pos;
  46104. if (dataLabel && point.visible) {
  46105. _pos = dataLabel._pos;
  46106. if (_pos) {
  46107. // Shorten data labels with ellipsis if they still overflow
  46108. // after the pie has reached minSize (#223).
  46109. if (dataLabel.sideOverflow) {
  46110. dataLabel._attr.width =
  46111. Math.max(dataLabel.getBBox().width -
  46112. dataLabel.sideOverflow, 0);
  46113. dataLabel.css({
  46114. width: dataLabel._attr.width + 'px',
  46115. textOverflow: ((this.options.dataLabels.style || {})
  46116. .textOverflow ||
  46117. 'ellipsis')
  46118. });
  46119. dataLabel.shortened = true;
  46120. }
  46121. dataLabel.attr(dataLabel._attr);
  46122. dataLabel[dataLabel.moved ? 'animate' : 'attr'](_pos);
  46123. dataLabel.moved = true;
  46124. }
  46125. else if (dataLabel) {
  46126. dataLabel.attr({ y: -9999 });
  46127. }
  46128. }
  46129. // Clear for update
  46130. delete point.distributeBox;
  46131. }, this);
  46132. };
  46133. seriesTypes.pie.prototype.alignDataLabel = noop;
  46134. /**
  46135. * Verify whether the data labels are allowed to draw, or we should run more
  46136. * translation and data label positioning to keep them inside the plot area.
  46137. * Returns true when data labels are ready to draw.
  46138. *
  46139. * @private
  46140. * @function Highcharts.seriesTypes.pie#verifyDataLabelOverflow
  46141. * @param {Array<number>} overflow
  46142. * @return {boolean}
  46143. */
  46144. seriesTypes.pie.prototype.verifyDataLabelOverflow = function (overflow) {
  46145. var center = this.center,
  46146. options = this.options,
  46147. centerOption = options.center,
  46148. minSize = options.minSize || 80,
  46149. newSize = minSize,
  46150. // If a size is set, return true and don't try to shrink the pie
  46151. // to fit the labels.
  46152. ret = options.size !== null;
  46153. if (!ret) {
  46154. // Handle horizontal size and center
  46155. if (centerOption[0] !== null) { // Fixed center
  46156. newSize = Math.max(center[2] -
  46157. Math.max(overflow[1], overflow[3]), minSize);
  46158. }
  46159. else { // Auto center
  46160. newSize = Math.max(
  46161. // horizontal overflow
  46162. center[2] - overflow[1] - overflow[3], minSize);
  46163. // horizontal center
  46164. center[0] += (overflow[3] - overflow[1]) / 2;
  46165. }
  46166. // Handle vertical size and center
  46167. if (centerOption[1] !== null) { // Fixed center
  46168. newSize = clamp(newSize, minSize, center[2] - Math.max(overflow[0], overflow[2]));
  46169. }
  46170. else { // Auto center
  46171. newSize = clamp(newSize, minSize,
  46172. // vertical overflow
  46173. center[2] - overflow[0] - overflow[2]);
  46174. // vertical center
  46175. center[1] += (overflow[0] - overflow[2]) / 2;
  46176. }
  46177. // If the size must be decreased, we need to run translate and
  46178. // drawDataLabels again
  46179. if (newSize < center[2]) {
  46180. center[2] = newSize;
  46181. center[3] = Math.min(// #3632
  46182. relativeLength(options.innerSize || 0, newSize), newSize);
  46183. this.translate(center);
  46184. if (this.drawDataLabels) {
  46185. this.drawDataLabels();
  46186. }
  46187. // Else, return true to indicate that the pie and its labels is
  46188. // within the plot area
  46189. }
  46190. else {
  46191. ret = true;
  46192. }
  46193. }
  46194. return ret;
  46195. };
  46196. }
  46197. if (seriesTypes.column) {
  46198. /**
  46199. * Override the basic data label alignment by adjusting for the position of
  46200. * the column.
  46201. *
  46202. * @private
  46203. * @function Highcharts.seriesTypes.column#alignDataLabel
  46204. * @param {Highcharts.Point} point
  46205. * @param {Highcharts.SVGElement} dataLabel
  46206. * @param {Highcharts.DataLabelsOptions} options
  46207. * @param {Highcharts.BBoxObject} alignTo
  46208. * @param {boolean} [isNew]
  46209. * @return {void}
  46210. */
  46211. seriesTypes.column.prototype.alignDataLabel = function (point, dataLabel, options, alignTo, isNew) {
  46212. var inverted = this.chart.inverted,
  46213. series = point.series,
  46214. // data label box for alignment
  46215. dlBox = point.dlBox || point.shapeArgs,
  46216. below = pick(point.below, // range series
  46217. point.plotY >
  46218. pick(this.translatedThreshold,
  46219. series.yAxis.len)),
  46220. // draw it inside the box?
  46221. inside = pick(options.inside, !!this.options.stacking),
  46222. overshoot;
  46223. // Align to the column itself, or the top of it
  46224. if (dlBox) { // Area range uses this method but not alignTo
  46225. alignTo = merge(dlBox);
  46226. if (alignTo.y < 0) {
  46227. alignTo.height += alignTo.y;
  46228. alignTo.y = 0;
  46229. }
  46230. // If parts of the box overshoots outside the plot area, modify the
  46231. // box to center the label inside
  46232. overshoot = alignTo.y + alignTo.height - series.yAxis.len;
  46233. if (overshoot > 0 && overshoot < alignTo.height) {
  46234. alignTo.height -= overshoot;
  46235. }
  46236. if (inverted) {
  46237. alignTo = {
  46238. x: series.yAxis.len - alignTo.y - alignTo.height,
  46239. y: series.xAxis.len - alignTo.x - alignTo.width,
  46240. width: alignTo.height,
  46241. height: alignTo.width
  46242. };
  46243. }
  46244. // Compute the alignment box
  46245. if (!inside) {
  46246. if (inverted) {
  46247. alignTo.x += below ? 0 : alignTo.width;
  46248. alignTo.width = 0;
  46249. }
  46250. else {
  46251. alignTo.y += below ? alignTo.height : 0;
  46252. alignTo.height = 0;
  46253. }
  46254. }
  46255. }
  46256. // When alignment is undefined (typically columns and bars), display the
  46257. // individual point below or above the point depending on the threshold
  46258. options.align = pick(options.align, !inverted || inside ? 'center' : below ? 'right' : 'left');
  46259. options.verticalAlign = pick(options.verticalAlign, inverted || inside ? 'middle' : below ? 'top' : 'bottom');
  46260. // Call the parent method
  46261. Series.prototype.alignDataLabel.call(this, point, dataLabel, options, alignTo, isNew);
  46262. // If label was justified and we have contrast, set it:
  46263. if (options.inside && point.contrastColor) {
  46264. dataLabel.css({
  46265. color: point.contrastColor
  46266. });
  46267. }
  46268. };
  46269. }
  46270. });
  46271. _registerModule(_modules, 'Extensions/OverlappingDataLabels.js', [_modules['Core/Chart/Chart.js'], _modules['Core/Utilities.js']], function (Chart, U) {
  46272. /* *
  46273. *
  46274. * Highcharts module to hide overlapping data labels.
  46275. * This module is included in Highcharts.
  46276. *
  46277. * (c) 2009-2021 Torstein Honsi
  46278. *
  46279. * License: www.highcharts.com/license
  46280. *
  46281. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  46282. *
  46283. * */
  46284. var addEvent = U.addEvent,
  46285. fireEvent = U.fireEvent,
  46286. isArray = U.isArray,
  46287. isNumber = U.isNumber,
  46288. objectEach = U.objectEach,
  46289. pick = U.pick;
  46290. /**
  46291. * Internal type
  46292. * @private
  46293. */
  46294. /* eslint-disable no-invalid-this */
  46295. // Collect potensial overlapping data labels. Stack labels probably don't need
  46296. // to be considered because they are usually accompanied by data labels that lie
  46297. // inside the columns.
  46298. addEvent(Chart, 'render', function collectAndHide() {
  46299. var chart = this,
  46300. labels = [];
  46301. // Consider external label collectors
  46302. (this.labelCollectors || []).forEach(function (collector) {
  46303. labels = labels.concat(collector());
  46304. });
  46305. (this.yAxis || []).forEach(function (yAxis) {
  46306. if (yAxis.stacking &&
  46307. yAxis.options.stackLabels &&
  46308. !yAxis.options.stackLabels.allowOverlap) {
  46309. objectEach(yAxis.stacking.stacks, function (stack) {
  46310. objectEach(stack, function (stackItem) {
  46311. if (stackItem.label &&
  46312. stackItem.label.visibility !== 'hidden' // #15607
  46313. ) {
  46314. labels.push(stackItem.label);
  46315. }
  46316. });
  46317. });
  46318. }
  46319. });
  46320. (this.series || []).forEach(function (series) {
  46321. var dlOptions = series.options.dataLabels;
  46322. if (series.visible &&
  46323. !(dlOptions.enabled === false && !series._hasPointLabels)) { // #3866
  46324. var push = function (points) {
  46325. return points.forEach(function (point) {
  46326. if (point.visible) {
  46327. var dataLabels = (isArray(point.dataLabels) ?
  46328. point.dataLabels :
  46329. (point.dataLabel ? [point.dataLabel] : []));
  46330. dataLabels.forEach(function (label) {
  46331. var options = label.options;
  46332. label.labelrank = pick(options.labelrank, point.labelrank, point.shapeArgs && point.shapeArgs.height); // #4118
  46333. if (!options.allowOverlap) {
  46334. labels.push(label);
  46335. }
  46336. else { // #13449
  46337. label.oldOpacity = label.opacity;
  46338. label.newOpacity = 1;
  46339. hideOrShow(label, chart);
  46340. }
  46341. });
  46342. }
  46343. });
  46344. };
  46345. push(series.nodes || []);
  46346. push(series.points);
  46347. }
  46348. });
  46349. this.hideOverlappingLabels(labels);
  46350. });
  46351. /**
  46352. * Hide overlapping labels. Labels are moved and faded in and out on zoom to
  46353. * provide a smooth visual imression.
  46354. *
  46355. * @private
  46356. * @function Highcharts.Chart#hideOverlappingLabels
  46357. * @param {Array<Highcharts.SVGElement>} labels
  46358. * Rendered data labels
  46359. * @requires modules/overlapping-datalabels
  46360. */
  46361. Chart.prototype.hideOverlappingLabels = function (labels) {
  46362. var chart = this,
  46363. len = labels.length,
  46364. ren = chart.renderer,
  46365. label,
  46366. i,
  46367. j,
  46368. label1,
  46369. label2,
  46370. box1,
  46371. box2,
  46372. isLabelAffected = false,
  46373. isIntersectRect = function (box1,
  46374. box2) {
  46375. return !(box2.x >= box1.x + box1.width ||
  46376. box2.x + box2.width <= box1.x ||
  46377. box2.y >= box1.y + box1.height ||
  46378. box2.y + box2.height <= box1.y);
  46379. },
  46380. // Get the box with its position inside the chart, as opposed to getBBox
  46381. // that only reports the position relative to the parent.
  46382. getAbsoluteBox = function (label) {
  46383. var pos,
  46384. parent,
  46385. bBox,
  46386. // Substract the padding if no background or border (#4333)
  46387. padding = label.box ? 0 : (label.padding || 0),
  46388. lineHeightCorrection = 0,
  46389. xOffset = 0,
  46390. boxWidth,
  46391. alignValue;
  46392. if (label &&
  46393. (!label.alignAttr || label.placed)) {
  46394. pos = label.alignAttr || {
  46395. x: label.attr('x'),
  46396. y: label.attr('y')
  46397. };
  46398. parent = label.parentGroup;
  46399. // Get width and height if pure text nodes (stack labels)
  46400. if (!label.width) {
  46401. bBox = label.getBBox();
  46402. label.width = bBox.width;
  46403. label.height = bBox.height;
  46404. // Labels positions are computed from top left corner, so
  46405. // we need to substract the text height from text nodes too.
  46406. lineHeightCorrection = ren
  46407. .fontMetrics(null, label.element).h;
  46408. }
  46409. boxWidth = label.width - 2 * padding;
  46410. alignValue = {
  46411. left: '0',
  46412. center: '0.5',
  46413. right: '1'
  46414. }[label.alignValue];
  46415. if (alignValue) {
  46416. xOffset = +alignValue * boxWidth;
  46417. }
  46418. else if (isNumber(label.x) && Math.round(label.x) !== label.translateX) {
  46419. xOffset = label.x - label.translateX;
  46420. }
  46421. return {
  46422. x: pos.x + (parent.translateX || 0) + padding -
  46423. (xOffset || 0),
  46424. y: pos.y + (parent.translateY || 0) + padding -
  46425. lineHeightCorrection,
  46426. width: label.width - 2 * padding,
  46427. height: label.height - 2 * padding
  46428. };
  46429. }
  46430. };
  46431. for (i = 0; i < len; i++) {
  46432. label = labels[i];
  46433. if (label) {
  46434. // Mark with initial opacity
  46435. label.oldOpacity = label.opacity;
  46436. label.newOpacity = 1;
  46437. label.absoluteBox = getAbsoluteBox(label);
  46438. }
  46439. }
  46440. // Prevent a situation in a gradually rising slope, that each label will
  46441. // hide the previous one because the previous one always has lower rank.
  46442. labels.sort(function (a, b) {
  46443. return (b.labelrank || 0) - (a.labelrank || 0);
  46444. });
  46445. // Detect overlapping labels
  46446. for (i = 0; i < len; i++) {
  46447. label1 = labels[i];
  46448. box1 = label1 && label1.absoluteBox;
  46449. for (j = i + 1; j < len; ++j) {
  46450. label2 = labels[j];
  46451. box2 = label2 && label2.absoluteBox;
  46452. if (box1 &&
  46453. box2 &&
  46454. label1 !== label2 && // #6465, polar chart with connectEnds
  46455. label1.newOpacity !== 0 &&
  46456. label2.newOpacity !== 0) {
  46457. if (isIntersectRect(box1, box2)) {
  46458. (label1.labelrank < label2.labelrank ? label1 : label2)
  46459. .newOpacity = 0;
  46460. }
  46461. }
  46462. }
  46463. }
  46464. // Hide or show
  46465. labels.forEach(function (label) {
  46466. if (hideOrShow(label, chart)) {
  46467. isLabelAffected = true;
  46468. }
  46469. });
  46470. if (isLabelAffected) {
  46471. fireEvent(chart, 'afterHideAllOverlappingLabels');
  46472. }
  46473. };
  46474. /**
  46475. * Hide or show labels based on opacity.
  46476. *
  46477. * @private
  46478. * @function hideOrShow
  46479. * @param {Highcharts.SVGElement} label
  46480. * The label.
  46481. * @param {Highcharts.Chart} chart
  46482. * The chart that contains the label.
  46483. * @return {boolean}
  46484. */
  46485. function hideOrShow(label, chart) {
  46486. var complete,
  46487. newOpacity,
  46488. isLabelAffected = false;
  46489. if (label) {
  46490. newOpacity = label.newOpacity;
  46491. if (label.oldOpacity !== newOpacity) {
  46492. // Make sure the label is completely hidden to avoid catching
  46493. // clicks (#4362)
  46494. if (label.alignAttr && label.placed) { // data labels
  46495. label[newOpacity ? 'removeClass' : 'addClass']('highcharts-data-label-hidden');
  46496. complete = function () {
  46497. if (!chart.styledMode) {
  46498. label.css({ pointerEvents: newOpacity ? 'auto' : 'none' });
  46499. }
  46500. };
  46501. isLabelAffected = true;
  46502. // Animate or set the opacity
  46503. label.alignAttr.opacity = newOpacity;
  46504. label[label.isOld ? 'animate' : 'attr'](label.alignAttr, null, complete);
  46505. fireEvent(chart, 'afterHideOverlappingLabel');
  46506. }
  46507. else { // other labels, tick labels
  46508. label.attr({
  46509. opacity: newOpacity
  46510. });
  46511. }
  46512. }
  46513. label.isOld = true;
  46514. }
  46515. return isLabelAffected;
  46516. }
  46517. });
  46518. _registerModule(_modules, 'Core/Responsive.js', [_modules['Core/Utilities.js']], function (U) {
  46519. /* *
  46520. *
  46521. * (c) 2010-2021 Torstein Honsi
  46522. *
  46523. * License: www.highcharts.com/license
  46524. *
  46525. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  46526. *
  46527. * */
  46528. var extend = U.extend,
  46529. find = U.find,
  46530. isArray = U.isArray,
  46531. isObject = U.isObject,
  46532. merge = U.merge,
  46533. objectEach = U.objectEach,
  46534. pick = U.pick,
  46535. splat = U.splat,
  46536. uniqueKey = U.uniqueKey;
  46537. /* *
  46538. *
  46539. * Class
  46540. *
  46541. * */
  46542. /* eslint-disable no-invalid-this, valid-jsdoc */
  46543. var ResponsiveChart = /** @class */ (function () {
  46544. function ResponsiveChart() {
  46545. }
  46546. /* *
  46547. *
  46548. * Functions
  46549. *
  46550. * */
  46551. /**
  46552. * Get the current values for a given set of options. Used before we update
  46553. * the chart with a new responsiveness rule.
  46554. *
  46555. * @todo Restore axis options (by id?). The matching of items in collections
  46556. * bears resemblance to the oneToOne matching in Chart.update. Probably we
  46557. * can refactor out that matching and reuse it in both functions.
  46558. *
  46559. * @private
  46560. * @function Highcharts.Chart#currentOptions
  46561. */
  46562. ResponsiveChart.prototype.currentOptions = function (options) {
  46563. var chart = this, ret = {};
  46564. /**
  46565. * Recurse over a set of options and its current values,
  46566. * and store the current values in the ret object.
  46567. */
  46568. function getCurrent(options, curr, ret, depth) {
  46569. var i;
  46570. objectEach(options, function (val, key) {
  46571. if (!depth &&
  46572. chart.collectionsWithUpdate.indexOf(key) > -1 &&
  46573. curr[key]) {
  46574. val = splat(val);
  46575. ret[key] = [];
  46576. // Iterate over collections like series, xAxis or yAxis and
  46577. // map the items by index.
  46578. for (i = 0; i < Math.max(val.length, curr[key].length); i++) {
  46579. // Item exists in current data (#6347)
  46580. if (curr[key][i]) {
  46581. // If the item is missing from the new data, we need
  46582. // to save the whole config structure. Like when
  46583. // responsively updating from a dual axis layout to
  46584. // a single axis and back (#13544).
  46585. if (val[i] === void 0) {
  46586. ret[key][i] = curr[key][i];
  46587. // Otherwise, proceed
  46588. }
  46589. else {
  46590. ret[key][i] = {};
  46591. getCurrent(val[i], curr[key][i], ret[key][i], depth + 1);
  46592. }
  46593. }
  46594. }
  46595. }
  46596. else if (isObject(val)) {
  46597. ret[key] = isArray(val) ? [] : {};
  46598. getCurrent(val, curr[key] || {}, ret[key], depth + 1);
  46599. }
  46600. else if (typeof curr[key] === 'undefined') { // #10286
  46601. ret[key] = null;
  46602. }
  46603. else {
  46604. ret[key] = curr[key];
  46605. }
  46606. });
  46607. }
  46608. getCurrent(options, this.options, ret, 0);
  46609. return ret;
  46610. };
  46611. /**
  46612. * Handle a single responsiveness rule.
  46613. *
  46614. * @private
  46615. * @function Highcharts.Chart#matchResponsiveRule
  46616. * @param {Highcharts.ResponsiveRulesOptions} rule
  46617. * @param {Array<string>} matches
  46618. */
  46619. ResponsiveChart.prototype.matchResponsiveRule = function (rule, matches) {
  46620. var condition = rule.condition,
  46621. fn = condition.callback || function () {
  46622. return (this.chartWidth <= pick(condition.maxWidth,
  46623. Number.MAX_VALUE) &&
  46624. this.chartHeight <=
  46625. pick(condition.maxHeight,
  46626. Number.MAX_VALUE) &&
  46627. this.chartWidth >= pick(condition.minWidth, 0) &&
  46628. this.chartHeight >= pick(condition.minHeight, 0));
  46629. };
  46630. if (fn.call(this)) {
  46631. matches.push(rule._id);
  46632. }
  46633. };
  46634. /**
  46635. * Update the chart based on the current chart/document size and options for
  46636. * responsiveness.
  46637. *
  46638. * @private
  46639. * @function Highcharts.Chart#setResponsive
  46640. * @param {boolean} [redraw=true]
  46641. * @param {boolean} [reset=false]
  46642. * Reset by un-applying all rules. Chart.update resets all rules before
  46643. * applying updated options.
  46644. */
  46645. ResponsiveChart.prototype.setResponsive = function (redraw, reset) {
  46646. var options = this.options.responsive,
  46647. currentResponsive = this.currentResponsive;
  46648. var ruleIds = [],
  46649. undoOptions;
  46650. if (!reset && options && options.rules) {
  46651. options.rules.forEach(function (rule) {
  46652. if (typeof rule._id === 'undefined') {
  46653. rule._id = uniqueKey();
  46654. }
  46655. this.matchResponsiveRule(rule, ruleIds /* , redraw */);
  46656. }, this);
  46657. }
  46658. // Merge matching rules
  46659. var mergedOptions = merge.apply(void 0,
  46660. ruleIds
  46661. .map(function (ruleId) { return find((options || {}).rules || [],
  46662. function (rule) { return (rule._id === ruleId); }); })
  46663. .map(function (rule) { return (rule && rule.chartOptions); }));
  46664. mergedOptions.isResponsiveOptions = true;
  46665. // Stringified key for the rules that currently apply.
  46666. ruleIds = (ruleIds.toString() || void 0);
  46667. var currentRuleIds = currentResponsive && currentResponsive.ruleIds;
  46668. // Changes in what rules apply
  46669. if (ruleIds !== currentRuleIds) {
  46670. // Undo previous rules. Before we apply a new set of rules, we need
  46671. // to roll back completely to base options (#6291).
  46672. if (currentResponsive) {
  46673. this.update(currentResponsive.undoOptions, redraw, true);
  46674. }
  46675. if (ruleIds) {
  46676. // Get undo-options for matching rules
  46677. undoOptions = this.currentOptions(mergedOptions);
  46678. undoOptions.isResponsiveOptions = true;
  46679. this.currentResponsive = {
  46680. ruleIds: ruleIds,
  46681. mergedOptions: mergedOptions,
  46682. undoOptions: undoOptions
  46683. };
  46684. this.update(mergedOptions, redraw, true);
  46685. }
  46686. else {
  46687. this.currentResponsive = void 0;
  46688. }
  46689. }
  46690. };
  46691. return ResponsiveChart;
  46692. }());
  46693. /* *
  46694. *
  46695. * Composition
  46696. *
  46697. * */
  46698. var ResponsiveComposition = /** @class */ (function () {
  46699. function ResponsiveComposition() {
  46700. }
  46701. /* *
  46702. *
  46703. * Static Functions
  46704. *
  46705. * */
  46706. ResponsiveComposition.compose = function (ChartClass) {
  46707. extend(ChartClass.prototype, ResponsiveChart.prototype);
  46708. return ChartClass;
  46709. };
  46710. return ResponsiveComposition;
  46711. }());
  46712. /* *
  46713. *
  46714. * Default Export
  46715. *
  46716. * */
  46717. /* *
  46718. *
  46719. * API Declarations
  46720. *
  46721. * */
  46722. /**
  46723. * A callback function to gain complete control on when the responsive rule
  46724. * applies.
  46725. *
  46726. * @callback Highcharts.ResponsiveCallbackFunction
  46727. *
  46728. * @param {Highcharts.Chart} this
  46729. * Chart context.
  46730. *
  46731. * @return {boolean}
  46732. * Return `true` if it applies.
  46733. */
  46734. (''); // detached doclets above
  46735. /* *
  46736. *
  46737. * API Options
  46738. *
  46739. * */
  46740. /**
  46741. * Allows setting a set of rules to apply for different screen or chart
  46742. * sizes. Each rule specifies additional chart options.
  46743. *
  46744. * @sample {highstock} stock/demo/responsive/
  46745. * Stock chart
  46746. * @sample highcharts/responsive/axis/
  46747. * Axis
  46748. * @sample highcharts/responsive/legend/
  46749. * Legend
  46750. * @sample highcharts/responsive/classname/
  46751. * Class name
  46752. *
  46753. * @since 5.0.0
  46754. * @apioption responsive
  46755. */
  46756. /**
  46757. * A set of rules for responsive settings. The rules are executed from
  46758. * the top down.
  46759. *
  46760. * @sample {highcharts} highcharts/responsive/axis/
  46761. * Axis changes
  46762. * @sample {highstock} highcharts/responsive/axis/
  46763. * Axis changes
  46764. * @sample {highmaps} highcharts/responsive/axis/
  46765. * Axis changes
  46766. *
  46767. * @type {Array<*>}
  46768. * @since 5.0.0
  46769. * @apioption responsive.rules
  46770. */
  46771. /**
  46772. * A full set of chart options to apply as overrides to the general
  46773. * chart options. The chart options are applied when the given rule
  46774. * is active.
  46775. *
  46776. * A special case is configuration objects that take arrays, for example
  46777. * [xAxis](#xAxis), [yAxis](#yAxis) or [series](#series). For these
  46778. * collections, an `id` option is used to map the new option set to
  46779. * an existing object. If an existing object of the same id is not found,
  46780. * the item of the same indexupdated. So for example, setting `chartOptions`
  46781. * with two series items without an `id`, will cause the existing chart's
  46782. * two series to be updated with respective options.
  46783. *
  46784. * @sample {highstock} stock/demo/responsive/
  46785. * Stock chart
  46786. * @sample highcharts/responsive/axis/
  46787. * Axis
  46788. * @sample highcharts/responsive/legend/
  46789. * Legend
  46790. * @sample highcharts/responsive/classname/
  46791. * Class name
  46792. *
  46793. * @type {Highcharts.Options}
  46794. * @since 5.0.0
  46795. * @apioption responsive.rules.chartOptions
  46796. */
  46797. /**
  46798. * Under which conditions the rule applies.
  46799. *
  46800. * @since 5.0.0
  46801. * @apioption responsive.rules.condition
  46802. */
  46803. /**
  46804. * A callback function to gain complete control on when the responsive
  46805. * rule applies. Return `true` if it applies. This opens for checking
  46806. * against other metrics than the chart size, for example the document
  46807. * size or other elements.
  46808. *
  46809. * @type {Highcharts.ResponsiveCallbackFunction}
  46810. * @since 5.0.0
  46811. * @context Highcharts.Chart
  46812. * @apioption responsive.rules.condition.callback
  46813. */
  46814. /**
  46815. * The responsive rule applies if the chart height is less than this.
  46816. *
  46817. * @type {number}
  46818. * @since 5.0.0
  46819. * @apioption responsive.rules.condition.maxHeight
  46820. */
  46821. /**
  46822. * The responsive rule applies if the chart width is less than this.
  46823. *
  46824. * @sample highcharts/responsive/axis/
  46825. * Max width is 500
  46826. *
  46827. * @type {number}
  46828. * @since 5.0.0
  46829. * @apioption responsive.rules.condition.maxWidth
  46830. */
  46831. /**
  46832. * The responsive rule applies if the chart height is greater than this.
  46833. *
  46834. * @type {number}
  46835. * @default 0
  46836. * @since 5.0.0
  46837. * @apioption responsive.rules.condition.minHeight
  46838. */
  46839. /**
  46840. * The responsive rule applies if the chart width is greater than this.
  46841. *
  46842. * @type {number}
  46843. * @default 0
  46844. * @since 5.0.0
  46845. * @apioption responsive.rules.condition.minWidth
  46846. */
  46847. (''); // keeps doclets above in JS file
  46848. return ResponsiveComposition;
  46849. });
  46850. _registerModule(_modules, 'masters/highcharts.src.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js'], _modules['Core/DefaultOptions.js'], _modules['Core/Animation/Fx.js'], _modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Renderer/HTML/AST.js'], _modules['Core/FormatUtilities.js'], _modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Renderer/SVG/SVGRenderer.js'], _modules['Core/Renderer/HTML/HTMLElement.js'], _modules['Core/Renderer/HTML/HTMLRenderer.js'], _modules['Core/Axis/Axis.js'], _modules['Core/Axis/PlotLineOrBand.js'], _modules['Core/Axis/Tick.js'], _modules['Core/Pointer.js'], _modules['Core/MSPointer.js'], _modules['Core/Chart/Chart.js'], _modules['Core/Series/Series.js'], _modules['Core/Responsive.js'], _modules['Core/Color/Color.js'], _modules['Core/Time.js']], function (Highcharts, Utilities, DefaultOptions, Fx, Animation, AST, FormatUtilities, SVGElement, SVGRenderer, HTMLElement, HTMLRenderer, Axis, PlotLineOrBand, Tick, Pointer, MSPointer, Chart, Series, Responsive, Color, Time) {
  46851. var G = Highcharts;
  46852. // Animation
  46853. G.animate = Animation.animate;
  46854. G.animObject = Animation.animObject;
  46855. G.getDeferredAnimation = Animation.getDeferredAnimation;
  46856. G.setAnimation = Animation.setAnimation;
  46857. G.stop = Animation.stop;
  46858. G.timers = Fx.timers;
  46859. // Classes
  46860. G.AST = AST;
  46861. G.Axis = Axis;
  46862. G.Chart = Chart;
  46863. G.chart = Chart.chart;
  46864. G.Fx = Fx;
  46865. G.PlotLineOrBand = PlotLineOrBand;
  46866. G.Pointer = (MSPointer.isRequired() ? MSPointer : Pointer);
  46867. G.Series = Series;
  46868. G.SVGElement = SVGElement;
  46869. G.SVGRenderer = SVGRenderer;
  46870. G.Tick = Tick;
  46871. G.Time = Time;
  46872. // Color
  46873. G.Color = Color;
  46874. G.color = Color.parse;
  46875. // Compositions
  46876. HTMLRenderer.compose(SVGRenderer);
  46877. HTMLElement.compose(SVGElement);
  46878. // DefaultOptions
  46879. G.defaultOptions = DefaultOptions.defaultOptions;
  46880. G.getOptions = DefaultOptions.getOptions;
  46881. G.time = DefaultOptions.defaultTime;
  46882. G.setOptions = DefaultOptions.setOptions;
  46883. // Format Utilities
  46884. G.dateFormat = FormatUtilities.dateFormat;
  46885. G.format = FormatUtilities.format;
  46886. G.numberFormat = FormatUtilities.numberFormat;
  46887. // Utilities
  46888. G.addEvent = Utilities.addEvent;
  46889. G.arrayMax = Utilities.arrayMax;
  46890. G.arrayMin = Utilities.arrayMin;
  46891. G.attr = Utilities.attr;
  46892. G.clearTimeout = Utilities.clearTimeout;
  46893. G.correctFloat = Utilities.correctFloat;
  46894. G.createElement = Utilities.createElement;
  46895. G.css = Utilities.css;
  46896. G.defined = Utilities.defined;
  46897. G.destroyObjectProperties = Utilities.destroyObjectProperties;
  46898. G.discardElement = Utilities.discardElement;
  46899. G.erase = Utilities.erase;
  46900. G.error = Utilities.error;
  46901. G.extend = Utilities.extend;
  46902. G.extendClass = Utilities.extendClass;
  46903. G.find = Utilities.find;
  46904. G.fireEvent = Utilities.fireEvent;
  46905. G.getMagnitude = Utilities.getMagnitude;
  46906. G.getStyle = Utilities.getStyle;
  46907. G.inArray = Utilities.inArray;
  46908. G.isArray = Utilities.isArray;
  46909. G.isClass = Utilities.isClass;
  46910. G.isDOMElement = Utilities.isDOMElement;
  46911. G.isFunction = Utilities.isFunction;
  46912. G.isNumber = Utilities.isNumber;
  46913. G.isObject = Utilities.isObject;
  46914. G.isString = Utilities.isString;
  46915. G.keys = Utilities.keys;
  46916. G.merge = Utilities.merge;
  46917. G.normalizeTickInterval = Utilities.normalizeTickInterval;
  46918. G.objectEach = Utilities.objectEach;
  46919. G.offset = Utilities.offset;
  46920. G.pad = Utilities.pad;
  46921. G.pick = Utilities.pick;
  46922. G.pInt = Utilities.pInt;
  46923. G.relativeLength = Utilities.relativeLength;
  46924. G.removeEvent = Utilities.removeEvent;
  46925. G.splat = Utilities.splat;
  46926. G.stableSort = Utilities.stableSort;
  46927. G.syncTimeout = Utilities.syncTimeout;
  46928. G.timeUnits = Utilities.timeUnits;
  46929. G.uniqueKey = Utilities.uniqueKey;
  46930. G.useSerialIds = Utilities.useSerialIds;
  46931. G.wrap = Utilities.wrap;
  46932. // Compositions
  46933. Responsive.compose(Chart);
  46934. // Default Export
  46935. return G;
  46936. });
  46937. _registerModule(_modules, 'Series/XRange/XRangePoint.js', [_modules['Core/Series/Point.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (Point, SeriesRegistry, U) {
  46938. /* *
  46939. *
  46940. * X-range series module
  46941. *
  46942. * (c) 2010-2021 Torstein Honsi, Lars A. V. Cabrera
  46943. *
  46944. * License: www.highcharts.com/license
  46945. *
  46946. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  46947. *
  46948. * */
  46949. var __extends = (this && this.__extends) || (function () {
  46950. var extendStatics = function (d,
  46951. b) {
  46952. extendStatics = Object.setPrototypeOf ||
  46953. ({ __proto__: [] } instanceof Array && function (d,
  46954. b) { d.__proto__ = b; }) ||
  46955. function (d,
  46956. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  46957. return extendStatics(d, b);
  46958. };
  46959. return function (d, b) {
  46960. extendStatics(d, b);
  46961. function __() { this.constructor = d; }
  46962. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  46963. };
  46964. })();
  46965. var ColumnSeries = SeriesRegistry.seriesTypes.column;
  46966. var extend = U.extend;
  46967. /* *
  46968. *
  46969. * Class
  46970. *
  46971. * */
  46972. var XRangePoint = /** @class */ (function (_super) {
  46973. __extends(XRangePoint, _super);
  46974. function XRangePoint() {
  46975. var _this = _super !== null && _super.apply(this,
  46976. arguments) || this;
  46977. /* *
  46978. *
  46979. * Properties
  46980. *
  46981. * */
  46982. _this.options = void 0;
  46983. _this.series = void 0;
  46984. return _this;
  46985. /* eslint-enable valid-jsdoc */
  46986. }
  46987. /* *
  46988. *
  46989. * Static properties
  46990. *
  46991. * */
  46992. /**
  46993. * Return color of a point based on its category.
  46994. *
  46995. * @private
  46996. * @function getColorByCategory
  46997. *
  46998. * @param {object} series
  46999. * The series which the point belongs to.
  47000. *
  47001. * @param {object} point
  47002. * The point to calculate its color for.
  47003. *
  47004. * @return {object}
  47005. * Returns an object containing the properties color and colorIndex.
  47006. */
  47007. XRangePoint.getColorByCategory = function (series, point) {
  47008. var colors = series.options.colors || series.chart.options.colors,
  47009. colorCount = colors ?
  47010. colors.length :
  47011. series.chart.options.chart.colorCount,
  47012. colorIndex = point.y % colorCount,
  47013. color = colors && colors[colorIndex];
  47014. return {
  47015. colorIndex: colorIndex,
  47016. color: color
  47017. };
  47018. };
  47019. /* *
  47020. *
  47021. * Functions
  47022. *
  47023. * */
  47024. /**
  47025. * The ending X value of the range point.
  47026. * @name Highcharts.Point#x2
  47027. * @type {number|undefined}
  47028. * @requires modules/xrange
  47029. */
  47030. /**
  47031. * Extend applyOptions so that `colorByPoint` for x-range means that one
  47032. * color is applied per Y axis category.
  47033. *
  47034. * @private
  47035. * @function Highcharts.Point#applyOptions
  47036. *
  47037. * @return {Highcharts.Series}
  47038. */
  47039. /* eslint-disable valid-jsdoc */
  47040. /**
  47041. * @private
  47042. */
  47043. XRangePoint.prototype.resolveColor = function () {
  47044. var series = this.series,
  47045. colorByPoint;
  47046. if (series.options.colorByPoint && !this.options.color) {
  47047. colorByPoint = XRangePoint.getColorByCategory(series, this);
  47048. if (!series.chart.styledMode) {
  47049. this.color = colorByPoint.color;
  47050. }
  47051. if (!this.options.colorIndex) {
  47052. this.colorIndex = colorByPoint.colorIndex;
  47053. }
  47054. }
  47055. else if (!this.color) {
  47056. this.color = series.color;
  47057. }
  47058. };
  47059. /**
  47060. * Extend init to have y default to 0.
  47061. *
  47062. * @private
  47063. * @function Highcharts.Point#init
  47064. *
  47065. * @return {Highcharts.Point}
  47066. */
  47067. XRangePoint.prototype.init = function () {
  47068. Point.prototype.init.apply(this, arguments);
  47069. if (!this.y) {
  47070. this.y = 0;
  47071. }
  47072. return this;
  47073. };
  47074. /**
  47075. * @private
  47076. * @function Highcharts.Point#setState
  47077. */
  47078. XRangePoint.prototype.setState = function () {
  47079. Point.prototype.setState.apply(this, arguments);
  47080. this.series.drawPoint(this, this.series.getAnimationVerb());
  47081. };
  47082. /**
  47083. * @private
  47084. * @function Highcharts.Point#getLabelConfig
  47085. *
  47086. * @return {Highcharts.PointLabelObject}
  47087. */
  47088. // Add x2 and yCategory to the available properties for tooltip formats
  47089. XRangePoint.prototype.getLabelConfig = function () {
  47090. var point = this,
  47091. cfg = Point.prototype.getLabelConfig.call(point),
  47092. yCats = point.series.yAxis.categories;
  47093. cfg.x2 = point.x2;
  47094. cfg.yCategory = point.yCategory = yCats && yCats[point.y];
  47095. return cfg;
  47096. };
  47097. /**
  47098. * @private
  47099. * @function Highcharts.Point#isValid
  47100. *
  47101. * @return {boolean}
  47102. */
  47103. XRangePoint.prototype.isValid = function () {
  47104. return typeof this.x === 'number' &&
  47105. typeof this.x2 === 'number';
  47106. };
  47107. return XRangePoint;
  47108. }(ColumnSeries.prototype.pointClass));
  47109. extend(XRangePoint.prototype, {
  47110. tooltipDateKeys: ['x', 'x2']
  47111. });
  47112. /* *
  47113. *
  47114. * Default Export
  47115. *
  47116. * */
  47117. return XRangePoint;
  47118. });
  47119. _registerModule(_modules, 'Series/XRange/XRangeComposition.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Utilities.js']], function (Axis, U) {
  47120. /* *
  47121. *
  47122. * X-range series module
  47123. *
  47124. * (c) 2010-2021 Torstein Honsi, Lars A. V. Cabrera
  47125. *
  47126. * License: www.highcharts.com/license
  47127. *
  47128. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  47129. *
  47130. * */
  47131. /* *
  47132. *
  47133. * Imports
  47134. *
  47135. * */
  47136. /* *
  47137. *
  47138. * Imports
  47139. *
  47140. * */
  47141. var addEvent = U.addEvent,
  47142. pick = U.pick;
  47143. /**
  47144. * Max x2 should be considered in xAxis extremes
  47145. */
  47146. addEvent(Axis, 'afterGetSeriesExtremes', function () {
  47147. var axis = this, // eslint-disable-line no-invalid-this
  47148. axisSeries = axis.series,
  47149. dataMax,
  47150. modMax;
  47151. if (axis.isXAxis) {
  47152. dataMax = pick(axis.dataMax, -Number.MAX_VALUE);
  47153. axisSeries.forEach(function (series) {
  47154. if (series.x2Data) {
  47155. series.x2Data
  47156. .forEach(function (val) {
  47157. if (val > dataMax) {
  47158. dataMax = val;
  47159. modMax = true;
  47160. }
  47161. });
  47162. }
  47163. });
  47164. if (modMax) {
  47165. axis.dataMax = dataMax;
  47166. }
  47167. }
  47168. });
  47169. });
  47170. _registerModule(_modules, 'Series/XRange/XRangeSeries.js', [_modules['Core/Globals.js'], _modules['Core/Color/Color.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js'], _modules['Series/XRange/XRangePoint.js']], function (H, Color, SeriesRegistry, U, XRangePoint) {
  47171. /* *
  47172. *
  47173. * X-range series module
  47174. *
  47175. * (c) 2010-2021 Torstein Honsi, Lars A. V. Cabrera
  47176. *
  47177. * License: www.highcharts.com/license
  47178. *
  47179. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  47180. *
  47181. * */
  47182. var __extends = (this && this.__extends) || (function () {
  47183. var extendStatics = function (d,
  47184. b) {
  47185. extendStatics = Object.setPrototypeOf ||
  47186. ({ __proto__: [] } instanceof Array && function (d,
  47187. b) { d.__proto__ = b; }) ||
  47188. function (d,
  47189. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  47190. return extendStatics(d, b);
  47191. };
  47192. return function (d, b) {
  47193. extendStatics(d, b);
  47194. function __() { this.constructor = d; }
  47195. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  47196. };
  47197. })();
  47198. var color = Color.parse;
  47199. var Series = SeriesRegistry.series,
  47200. ColumnSeries = SeriesRegistry.seriesTypes.column;
  47201. var columnProto = ColumnSeries.prototype;
  47202. var clamp = U.clamp,
  47203. correctFloat = U.correctFloat,
  47204. defined = U.defined,
  47205. extend = U.extend,
  47206. find = U.find,
  47207. isNumber = U.isNumber,
  47208. isObject = U.isObject,
  47209. merge = U.merge,
  47210. pick = U.pick;
  47211. /* *
  47212. * @interface Highcharts.PointOptionsObject in parts/Point.ts
  47213. */ /**
  47214. * The ending X value of the range point.
  47215. * @name Highcharts.PointOptionsObject#x2
  47216. * @type {number|undefined}
  47217. * @requires modules/xrange
  47218. */
  47219. /**
  47220. * @private
  47221. * @class
  47222. * @name Highcharts.seriesTypes.xrange
  47223. *
  47224. * @augments Highcharts.Series
  47225. */
  47226. var XRangeSeries = /** @class */ (function (_super) {
  47227. __extends(XRangeSeries, _super);
  47228. function XRangeSeries() {
  47229. var _this = _super !== null && _super.apply(this,
  47230. arguments) || this;
  47231. /* *
  47232. *
  47233. * Properties
  47234. *
  47235. * */
  47236. _this.data = void 0;
  47237. _this.options = void 0;
  47238. _this.points = void 0;
  47239. return _this;
  47240. /*
  47241. // Override to remove stroke from points. For partial fill.
  47242. pointAttribs: function () {
  47243. let series = this,
  47244. retVal = columnType.prototype.pointAttribs
  47245. .apply(series, arguments);
  47246. //retVal['stroke-width'] = 0;
  47247. return retVal;
  47248. }
  47249. //*/
  47250. /* eslint-enable valid-jsdoc */
  47251. }
  47252. /* *
  47253. *
  47254. * Functions
  47255. *
  47256. * */
  47257. /* eslint-disable valid-jsdoc */
  47258. /**
  47259. * @private
  47260. * @function Highcarts.seriesTypes.xrange#init
  47261. * @return {void}
  47262. */
  47263. XRangeSeries.prototype.init = function () {
  47264. ColumnSeries.prototype.init.apply(this, arguments);
  47265. this.options.stacking = void 0; // #13161
  47266. };
  47267. /**
  47268. * Borrow the column series metrics, but with swapped axes. This gives
  47269. * free access to features like groupPadding, grouping, pointWidth etc.
  47270. *
  47271. * @private
  47272. * @function Highcharts.Series#getColumnMetrics
  47273. *
  47274. * @return {Highcharts.ColumnMetricsObject}
  47275. */
  47276. XRangeSeries.prototype.getColumnMetrics = function () {
  47277. var metrics,
  47278. chart = this.chart;
  47279. /**
  47280. * @private
  47281. */
  47282. function swapAxes() {
  47283. chart.series.forEach(function (s) {
  47284. var xAxis = s.xAxis;
  47285. s.xAxis = s.yAxis;
  47286. s.yAxis = xAxis;
  47287. });
  47288. }
  47289. swapAxes();
  47290. metrics = columnProto.getColumnMetrics.call(this);
  47291. swapAxes();
  47292. return metrics;
  47293. };
  47294. /**
  47295. * Override cropData to show a point where x or x2 is outside visible
  47296. * range, but one of them is inside.
  47297. *
  47298. * @private
  47299. * @function Highcharts.Series#cropData
  47300. *
  47301. * @param {Array<number>} xData
  47302. *
  47303. * @param {Array<number>} yData
  47304. *
  47305. * @param {number} min
  47306. *
  47307. * @param {number} max
  47308. *
  47309. * @param {number} [cropShoulder]
  47310. *
  47311. * @return {*}
  47312. */
  47313. XRangeSeries.prototype.cropData = function (xData, yData, min, max) {
  47314. // Replace xData with x2Data to find the appropriate cropStart
  47315. var cropData = Series.prototype.cropData,
  47316. crop = cropData.call(this,
  47317. this.x2Data,
  47318. yData,
  47319. min,
  47320. max);
  47321. // Re-insert the cropped xData
  47322. crop.xData = xData.slice(crop.start, crop.end);
  47323. return crop;
  47324. };
  47325. /**
  47326. * Finds the index of an existing point that matches the given point
  47327. * options.
  47328. *
  47329. * @private
  47330. * @function Highcharts.Series#findPointIndex
  47331. * @param {object} options The options of the point.
  47332. * @returns {number|undefined} Returns index of a matching point,
  47333. * returns undefined if no match is found.
  47334. */
  47335. XRangeSeries.prototype.findPointIndex = function (options) {
  47336. var _a = this,
  47337. cropped = _a.cropped,
  47338. cropStart = _a.cropStart,
  47339. points = _a.points;
  47340. var id = options.id;
  47341. var pointIndex;
  47342. if (id) {
  47343. var point = find(points,
  47344. function (point) {
  47345. return point.id === id;
  47346. });
  47347. pointIndex = point ? point.index : void 0;
  47348. }
  47349. if (typeof pointIndex === 'undefined') {
  47350. var point = find(points,
  47351. function (point) {
  47352. return (point.x === options.x &&
  47353. point.x2 === options.x2 &&
  47354. !point.touched);
  47355. });
  47356. pointIndex = point ? point.index : void 0;
  47357. }
  47358. // Reduce pointIndex if data is cropped
  47359. if (cropped &&
  47360. isNumber(pointIndex) &&
  47361. isNumber(cropStart) &&
  47362. pointIndex >= cropStart) {
  47363. pointIndex -= cropStart;
  47364. }
  47365. return pointIndex;
  47366. };
  47367. /**
  47368. * @private
  47369. * @function Highcharts.Series#translatePoint
  47370. *
  47371. * @param {Highcharts.Point} point
  47372. */
  47373. XRangeSeries.prototype.translatePoint = function (point) {
  47374. var series = this,
  47375. xAxis = series.xAxis,
  47376. yAxis = series.yAxis,
  47377. metrics = series.columnMetrics,
  47378. options = series.options,
  47379. minPointLength = options.minPointLength || 0,
  47380. oldColWidth = (point.shapeArgs && point.shapeArgs.width || 0) / 2,
  47381. seriesXOffset = series.pointXOffset = metrics.offset,
  47382. plotX = point.plotX,
  47383. posX = pick(point.x2,
  47384. point.x + (point.len || 0)),
  47385. plotX2 = xAxis.translate(posX, 0, 0, 0, 1),
  47386. length = Math.abs(plotX2 - plotX),
  47387. widthDifference,
  47388. partialFill,
  47389. inverted = this.chart.inverted,
  47390. borderWidth = pick(options.borderWidth, 1),
  47391. crisper = borderWidth % 2 / 2,
  47392. yOffset = metrics.offset,
  47393. pointHeight = Math.round(metrics.width),
  47394. dlLeft,
  47395. dlRight,
  47396. dlWidth,
  47397. clipRectWidth,
  47398. tooltipYOffset;
  47399. if (minPointLength) {
  47400. widthDifference = minPointLength - length;
  47401. if (widthDifference < 0) {
  47402. widthDifference = 0;
  47403. }
  47404. plotX -= widthDifference / 2;
  47405. plotX2 += widthDifference / 2;
  47406. }
  47407. plotX = Math.max(plotX, -10);
  47408. plotX2 = clamp(plotX2, -10, xAxis.len + 10);
  47409. // Handle individual pointWidth
  47410. if (defined(point.options.pointWidth)) {
  47411. yOffset -= ((Math.ceil(point.options.pointWidth) - pointHeight) / 2);
  47412. pointHeight = Math.ceil(point.options.pointWidth);
  47413. }
  47414. // Apply pointPlacement to the Y axis
  47415. if (options.pointPlacement &&
  47416. isNumber(point.plotY) &&
  47417. yAxis.categories) {
  47418. point.plotY = yAxis.translate(point.y, 0, 1, 0, 1, options.pointPlacement);
  47419. }
  47420. var shapeArgs = {
  47421. x: Math.floor(Math.min(plotX,
  47422. plotX2)) + crisper,
  47423. y: Math.floor(point.plotY + yOffset) + crisper,
  47424. width: Math.round(Math.abs(plotX2 - plotX)),
  47425. height: pointHeight,
  47426. r: series.options.borderRadius
  47427. };
  47428. point.shapeArgs = shapeArgs;
  47429. // Move tooltip to default position
  47430. if (!inverted) {
  47431. point.tooltipPos[0] -= oldColWidth +
  47432. seriesXOffset -
  47433. shapeArgs.width / 2;
  47434. }
  47435. else {
  47436. point.tooltipPos[1] += seriesXOffset +
  47437. oldColWidth;
  47438. }
  47439. // Align data labels inside the shape and inside the plot area
  47440. dlLeft = shapeArgs.x;
  47441. dlRight = dlLeft + shapeArgs.width;
  47442. if (dlLeft < 0 || dlRight > xAxis.len) {
  47443. dlLeft = clamp(dlLeft, 0, xAxis.len);
  47444. dlRight = clamp(dlRight, 0, xAxis.len);
  47445. dlWidth = dlRight - dlLeft;
  47446. point.dlBox = merge(shapeArgs, {
  47447. x: dlLeft,
  47448. width: dlRight - dlLeft,
  47449. centerX: dlWidth ? dlWidth / 2 : null
  47450. });
  47451. }
  47452. else {
  47453. point.dlBox = null;
  47454. }
  47455. // Tooltip position
  47456. var tooltipPos = point.tooltipPos;
  47457. var xIndex = !inverted ? 0 : 1;
  47458. var yIndex = !inverted ? 1 : 0;
  47459. tooltipYOffset = series.columnMetrics ?
  47460. series.columnMetrics.offset : -metrics.width / 2;
  47461. // Centering tooltip position (#14147)
  47462. if (!inverted) {
  47463. tooltipPos[xIndex] += (xAxis.reversed ? -1 : 0) * shapeArgs.width;
  47464. }
  47465. else {
  47466. tooltipPos[xIndex] += shapeArgs.width / 2;
  47467. }
  47468. tooltipPos[yIndex] = clamp(tooltipPos[yIndex] + ((inverted ? -1 : 1) * tooltipYOffset), 0, yAxis.len - 1);
  47469. // Add a partShapeArgs to the point, based on the shapeArgs property
  47470. partialFill = point.partialFill;
  47471. if (partialFill) {
  47472. // Get the partial fill amount
  47473. if (isObject(partialFill)) {
  47474. partialFill = partialFill.amount;
  47475. }
  47476. // If it was not a number, assume 0
  47477. if (!isNumber(partialFill)) {
  47478. partialFill = 0;
  47479. }
  47480. point.partShapeArgs = merge(shapeArgs, {
  47481. r: series.options.borderRadius
  47482. });
  47483. clipRectWidth = Math.max(Math.round(length * partialFill + point.plotX -
  47484. plotX), 0);
  47485. point.clipRectArgs = {
  47486. x: xAxis.reversed ? // #10717
  47487. shapeArgs.x + length - clipRectWidth :
  47488. shapeArgs.x,
  47489. y: shapeArgs.y,
  47490. width: clipRectWidth,
  47491. height: shapeArgs.height
  47492. };
  47493. }
  47494. };
  47495. /**
  47496. * @private
  47497. * @function Highcharts.Series#translate
  47498. */
  47499. XRangeSeries.prototype.translate = function () {
  47500. columnProto.translate.apply(this, arguments);
  47501. this.points.forEach(function (point) {
  47502. this.translatePoint(point);
  47503. }, this);
  47504. };
  47505. /**
  47506. * Draws a single point in the series. Needed for partial fill.
  47507. *
  47508. * This override turns point.graphic into a group containing the
  47509. * original graphic and an overlay displaying the partial fill.
  47510. *
  47511. * @private
  47512. * @function Highcharts.Series#drawPoint
  47513. *
  47514. * @param {Highcharts.Point} point
  47515. * An instance of Point in the series.
  47516. *
  47517. * @param {"animate"|"attr"} verb
  47518. * 'animate' (animates changes) or 'attr' (sets options)
  47519. */
  47520. XRangeSeries.prototype.drawPoint = function (point, verb) {
  47521. var series = this,
  47522. seriesOpts = series.options,
  47523. renderer = series.chart.renderer,
  47524. graphic = point.graphic,
  47525. type = point.shapeType,
  47526. shapeArgs = point.shapeArgs,
  47527. partShapeArgs = point.partShapeArgs,
  47528. clipRectArgs = point.clipRectArgs,
  47529. pfOptions = point.partialFill,
  47530. cutOff = seriesOpts.stacking && !seriesOpts.borderRadius,
  47531. pointState = point.state,
  47532. stateOpts = (seriesOpts.states[pointState || 'normal'] ||
  47533. {}),
  47534. pointStateVerb = typeof pointState === 'undefined' ?
  47535. 'attr' : verb,
  47536. pointAttr = series.pointAttribs(point,
  47537. pointState),
  47538. animation = pick(series.chart.options.chart.animation,
  47539. stateOpts.animation),
  47540. fill;
  47541. if (!point.isNull && point.visible !== false) {
  47542. // Original graphic
  47543. if (graphic) { // update
  47544. graphic.rect[verb](shapeArgs);
  47545. }
  47546. else {
  47547. point.graphic = graphic = renderer.g('point')
  47548. .addClass(point.getClassName())
  47549. .add(point.group || series.group);
  47550. graphic.rect = renderer[type](merge(shapeArgs))
  47551. .addClass(point.getClassName())
  47552. .addClass('highcharts-partfill-original')
  47553. .add(graphic);
  47554. }
  47555. // Partial fill graphic
  47556. if (partShapeArgs) {
  47557. if (graphic.partRect) {
  47558. graphic.partRect[verb](merge(partShapeArgs));
  47559. graphic.partialClipRect[verb](merge(clipRectArgs));
  47560. }
  47561. else {
  47562. graphic.partialClipRect = renderer.clipRect(clipRectArgs.x, clipRectArgs.y, clipRectArgs.width, clipRectArgs.height);
  47563. graphic.partRect =
  47564. renderer[type](partShapeArgs)
  47565. .addClass('highcharts-partfill-overlay')
  47566. .add(graphic)
  47567. .clip(graphic.partialClipRect);
  47568. }
  47569. }
  47570. // Presentational
  47571. if (!series.chart.styledMode) {
  47572. graphic
  47573. .rect[verb](pointAttr, animation)
  47574. .shadow(seriesOpts.shadow, null, cutOff);
  47575. if (partShapeArgs) {
  47576. // Ensure pfOptions is an object
  47577. if (!isObject(pfOptions)) {
  47578. pfOptions = {};
  47579. }
  47580. if (isObject(seriesOpts.partialFill)) {
  47581. pfOptions = merge(seriesOpts.partialFill, pfOptions);
  47582. }
  47583. fill = (pfOptions.fill ||
  47584. color(pointAttr.fill).brighten(-0.3).get() ||
  47585. color(point.color || series.color)
  47586. .brighten(-0.3).get());
  47587. pointAttr.fill = fill;
  47588. graphic
  47589. .partRect[pointStateVerb](pointAttr, animation)
  47590. .shadow(seriesOpts.shadow, null, cutOff);
  47591. }
  47592. }
  47593. }
  47594. else if (graphic) {
  47595. point.graphic = graphic.destroy(); // #1269
  47596. }
  47597. };
  47598. /**
  47599. * @private
  47600. * @function Highcharts.Series#drawPoints
  47601. */
  47602. XRangeSeries.prototype.drawPoints = function () {
  47603. var series = this,
  47604. verb = series.getAnimationVerb();
  47605. // Draw the columns
  47606. series.points.forEach(function (point) {
  47607. series.drawPoint(point, verb);
  47608. });
  47609. };
  47610. /**
  47611. * Returns "animate", or "attr" if the number of points is above the
  47612. * animation limit.
  47613. *
  47614. * @private
  47615. * @function Highcharts.Series#getAnimationVerb
  47616. *
  47617. * @return {string}
  47618. */
  47619. XRangeSeries.prototype.getAnimationVerb = function () {
  47620. return (this.chart.pointCount < (this.options.animationLimit || 250) ?
  47621. 'animate' :
  47622. 'attr');
  47623. };
  47624. /**
  47625. * @private
  47626. * @function Highcharts.XRangeSeries#isPointInside
  47627. */
  47628. XRangeSeries.prototype.isPointInside = function (point) {
  47629. var shapeArgs = point.shapeArgs,
  47630. plotX = point.plotX,
  47631. plotY = point.plotY;
  47632. if (!shapeArgs) {
  47633. return _super.prototype.isPointInside.apply(this, arguments);
  47634. }
  47635. var isInside = typeof plotX !== 'undefined' &&
  47636. typeof plotY !== 'undefined' &&
  47637. plotY >= 0 &&
  47638. plotY <= this.yAxis.len &&
  47639. (shapeArgs.x || 0) + (shapeArgs.width || 0) >= 0 &&
  47640. plotX <= this.xAxis.len;
  47641. return isInside;
  47642. };
  47643. /* *
  47644. *
  47645. * Static properties
  47646. *
  47647. * */
  47648. /**
  47649. * The X-range series displays ranges on the X axis, typically time
  47650. * intervals with a start and end date.
  47651. *
  47652. * @sample {highcharts} highcharts/demo/x-range/
  47653. * X-range
  47654. * @sample {highcharts} highcharts/css/x-range/
  47655. * Styled mode X-range
  47656. * @sample {highcharts} highcharts/chart/inverted-xrange/
  47657. * Inverted X-range
  47658. *
  47659. * @extends plotOptions.column
  47660. * @since 6.0.0
  47661. * @product highcharts highstock gantt
  47662. * @excluding boostThreshold, crisp, cropThreshold, depth, edgeColor,
  47663. * edgeWidth, findNearestPointBy, getExtremesFromAll,
  47664. * negativeColor, pointInterval, pointIntervalUnit,
  47665. * pointPlacement, pointRange, pointStart, softThreshold,
  47666. * stacking, threshold, data, dataSorting, boostBlending
  47667. * @requires modules/xrange
  47668. * @optionparent plotOptions.xrange
  47669. */
  47670. XRangeSeries.defaultOptions = merge(ColumnSeries.defaultOptions, {
  47671. /**
  47672. * A partial fill for each point, typically used to visualize how much
  47673. * of a task is performed. The partial fill object can be set either on
  47674. * series or point level.
  47675. *
  47676. * @sample {highcharts} highcharts/demo/x-range
  47677. * X-range with partial fill
  47678. *
  47679. * @product highcharts highstock gantt
  47680. * @apioption plotOptions.xrange.partialFill
  47681. */
  47682. /**
  47683. * The fill color to be used for partial fills. Defaults to a darker
  47684. * shade of the point color.
  47685. *
  47686. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  47687. * @product highcharts highstock gantt
  47688. * @apioption plotOptions.xrange.partialFill.fill
  47689. */
  47690. /**
  47691. * A partial fill for each point, typically used to visualize how much
  47692. * of a task is performed. See [completed](series.gantt.data.completed).
  47693. *
  47694. * @sample gantt/demo/progress-indicator
  47695. * Gantt with progress indicator
  47696. *
  47697. * @product gantt
  47698. * @apioption plotOptions.gantt.partialFill
  47699. */
  47700. /**
  47701. * In an X-range series, this option makes all points of the same Y-axis
  47702. * category the same color.
  47703. */
  47704. colorByPoint: true,
  47705. dataLabels: {
  47706. formatter: function () {
  47707. var point = this.point,
  47708. amount = point.partialFill;
  47709. if (isObject(amount)) {
  47710. amount = amount.amount;
  47711. }
  47712. if (isNumber(amount) && amount > 0) {
  47713. return correctFloat(amount * 100) + '%';
  47714. }
  47715. },
  47716. inside: true,
  47717. verticalAlign: 'middle'
  47718. },
  47719. tooltip: {
  47720. headerFormat: '<span style="font-size: 10px">{point.x} - {point.x2}</span><br/>',
  47721. pointFormat: '<span style="color:{point.color}">\u25CF</span> {series.name}: <b>{point.yCategory}</b><br/>'
  47722. },
  47723. borderRadius: 3,
  47724. pointRange: 0
  47725. });
  47726. return XRangeSeries;
  47727. }(ColumnSeries));
  47728. extend(XRangeSeries.prototype, {
  47729. type: 'xrange',
  47730. parallelArrays: ['x', 'x2', 'y'],
  47731. requireSorting: false,
  47732. animate: Series.prototype.animate,
  47733. cropShoulder: 1,
  47734. getExtremesFromAll: true,
  47735. autoIncrement: H.noop,
  47736. buildKDTree: H.noop,
  47737. pointClass: XRangePoint
  47738. });
  47739. SeriesRegistry.registerSeriesType('xrange', XRangeSeries);
  47740. /* *
  47741. *
  47742. * Default Export
  47743. *
  47744. * */
  47745. /* *
  47746. *
  47747. * API Options
  47748. *
  47749. * */
  47750. /**
  47751. * An `xrange` series. If the [type](#series.xrange.type) option is not
  47752. * specified, it is inherited from [chart.type](#chart.type).
  47753. *
  47754. * @extends series,plotOptions.xrange
  47755. * @excluding boostThreshold, crisp, cropThreshold, depth, edgeColor, edgeWidth,
  47756. * findNearestPointBy, getExtremesFromAll, negativeColor,
  47757. * pointInterval, pointIntervalUnit, pointPlacement, pointRange,
  47758. * pointStart, softThreshold, stacking, threshold, dataSorting,
  47759. * boostBlending
  47760. * @product highcharts highstock gantt
  47761. * @requires modules/xrange
  47762. * @apioption series.xrange
  47763. */
  47764. /**
  47765. * An array of data points for the series. For the `xrange` series type,
  47766. * points can be given in the following ways:
  47767. *
  47768. * 1. An array of objects with named values. The objects are point configuration
  47769. * objects as seen below.
  47770. * ```js
  47771. * data: [{
  47772. * x: Date.UTC(2017, 0, 1),
  47773. * x2: Date.UTC(2017, 0, 3),
  47774. * name: "Test",
  47775. * y: 0,
  47776. * color: "#00FF00"
  47777. * }, {
  47778. * x: Date.UTC(2017, 0, 4),
  47779. * x2: Date.UTC(2017, 0, 5),
  47780. * name: "Deploy",
  47781. * y: 1,
  47782. * color: "#FF0000"
  47783. * }]
  47784. * ```
  47785. *
  47786. * @sample {highcharts} highcharts/series/data-array-of-objects/
  47787. * Config objects
  47788. *
  47789. * @declare Highcharts.XrangePointOptionsObject
  47790. * @type {Array<*>}
  47791. * @extends series.line.data
  47792. * @product highcharts highstock gantt
  47793. * @apioption series.xrange.data
  47794. */
  47795. /**
  47796. * The starting X value of the range point.
  47797. *
  47798. * @sample {highcharts} highcharts/demo/x-range
  47799. * X-range
  47800. *
  47801. * @type {number}
  47802. * @product highcharts highstock gantt
  47803. * @apioption series.xrange.data.x
  47804. */
  47805. /**
  47806. * The ending X value of the range point.
  47807. *
  47808. * @sample {highcharts} highcharts/demo/x-range
  47809. * X-range
  47810. *
  47811. * @type {number}
  47812. * @product highcharts highstock gantt
  47813. * @apioption series.xrange.data.x2
  47814. */
  47815. /**
  47816. * The Y value of the range point.
  47817. *
  47818. * @sample {highcharts} highcharts/demo/x-range
  47819. * X-range
  47820. *
  47821. * @type {number}
  47822. * @product highcharts highstock gantt
  47823. * @apioption series.xrange.data.y
  47824. */
  47825. /**
  47826. * A partial fill for each point, typically used to visualize how much of
  47827. * a task is performed. The partial fill object can be set either on series
  47828. * or point level.
  47829. *
  47830. * @sample {highcharts} highcharts/demo/x-range
  47831. * X-range with partial fill
  47832. *
  47833. * @declare Highcharts.XrangePointPartialFillOptionsObject
  47834. * @product highcharts highstock gantt
  47835. * @apioption series.xrange.data.partialFill
  47836. */
  47837. /**
  47838. * The amount of the X-range point to be filled. Values can be 0-1 and are
  47839. * converted to percentages in the default data label formatter.
  47840. *
  47841. * @type {number}
  47842. * @product highcharts highstock gantt
  47843. * @apioption series.xrange.data.partialFill.amount
  47844. */
  47845. /**
  47846. * The fill color to be used for partial fills. Defaults to a darker shade
  47847. * of the point color.
  47848. *
  47849. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  47850. * @product highcharts highstock gantt
  47851. * @apioption series.xrange.data.partialFill.fill
  47852. */
  47853. ''; // adds doclets above to transpiled file
  47854. return XRangeSeries;
  47855. });
  47856. _registerModule(_modules, 'Series/Gantt/GanttPoint.js', [_modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (SeriesRegistry, U) {
  47857. /* *
  47858. *
  47859. * (c) 2016-2021 Highsoft AS
  47860. *
  47861. * Author: Lars A. V. Cabrera
  47862. *
  47863. * License: www.highcharts.com/license
  47864. *
  47865. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  47866. *
  47867. * */
  47868. var __extends = (this && this.__extends) || (function () {
  47869. var extendStatics = function (d,
  47870. b) {
  47871. extendStatics = Object.setPrototypeOf ||
  47872. ({ __proto__: [] } instanceof Array && function (d,
  47873. b) { d.__proto__ = b; }) ||
  47874. function (d,
  47875. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  47876. return extendStatics(d, b);
  47877. };
  47878. return function (d, b) {
  47879. extendStatics(d, b);
  47880. function __() { this.constructor = d; }
  47881. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  47882. };
  47883. })();
  47884. var XRangePoint = SeriesRegistry.seriesTypes.xrange.prototype.pointClass;
  47885. var pick = U.pick;
  47886. /* *
  47887. *
  47888. * Class
  47889. *
  47890. * */
  47891. var GanttPoint = /** @class */ (function (_super) {
  47892. __extends(GanttPoint, _super);
  47893. function GanttPoint() {
  47894. /* *
  47895. *
  47896. * Static Functions
  47897. *
  47898. * */
  47899. var _this = _super !== null && _super.apply(this,
  47900. arguments) || this;
  47901. _this.options = void 0;
  47902. _this.series = void 0;
  47903. return _this;
  47904. /* eslint-enable valid-jsdoc */
  47905. }
  47906. /* eslint-disable valid-jsdoc */
  47907. /**
  47908. * @private
  47909. */
  47910. GanttPoint.setGanttPointAliases = function (options) {
  47911. /**
  47912. * Add a value to options if the value exists.
  47913. * @private
  47914. */
  47915. function addIfExists(prop, val) {
  47916. if (typeof val !== 'undefined') {
  47917. options[prop] = val;
  47918. }
  47919. }
  47920. addIfExists('x', pick(options.start, options.x));
  47921. addIfExists('x2', pick(options.end, options.x2));
  47922. addIfExists('partialFill', pick(options.completed, options.partialFill));
  47923. };
  47924. /* *
  47925. *
  47926. * Functions
  47927. *
  47928. * */
  47929. /* eslint-disable valid-jsdoc */
  47930. /**
  47931. * Applies the options containing the x and y data and possible some
  47932. * extra properties. This is called on point init or from point.update.
  47933. *
  47934. * @private
  47935. * @function Highcharts.Point#applyOptions
  47936. *
  47937. * @param {object} options
  47938. * The point options
  47939. *
  47940. * @param {number} x
  47941. * The x value
  47942. *
  47943. * @return {Highcharts.Point}
  47944. * The Point instance
  47945. */
  47946. GanttPoint.prototype.applyOptions = function (options, x) {
  47947. var point = this,
  47948. ganttPoint;
  47949. ganttPoint = _super.prototype.applyOptions.call(point, options, x);
  47950. GanttPoint.setGanttPointAliases(ganttPoint);
  47951. return ganttPoint;
  47952. };
  47953. GanttPoint.prototype.isValid = function () {
  47954. return ((typeof this.start === 'number' ||
  47955. typeof this.x === 'number') &&
  47956. (typeof this.end === 'number' ||
  47957. typeof this.x2 === 'number' ||
  47958. this.milestone));
  47959. };
  47960. return GanttPoint;
  47961. }(XRangePoint));
  47962. /* *
  47963. *
  47964. * Default Export
  47965. *
  47966. * */
  47967. return GanttPoint;
  47968. });
  47969. _registerModule(_modules, 'Core/Axis/BrokenAxis.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Series/Series.js'], _modules['Extensions/Stacking.js'], _modules['Core/Utilities.js']], function (Axis, Series, StackItem, U) {
  47970. /* *
  47971. *
  47972. * (c) 2009-2021 Torstein Honsi
  47973. *
  47974. * License: www.highcharts.com/license
  47975. *
  47976. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  47977. *
  47978. * */
  47979. var addEvent = U.addEvent,
  47980. find = U.find,
  47981. fireEvent = U.fireEvent,
  47982. isArray = U.isArray,
  47983. isNumber = U.isNumber,
  47984. pick = U.pick;
  47985. /**
  47986. * Axis with support of broken data rows.
  47987. * @private
  47988. * @class
  47989. */
  47990. var BrokenAxis;
  47991. (function (BrokenAxis) {
  47992. /* *
  47993. *
  47994. * Functions
  47995. *
  47996. * */
  47997. /* eslint-disable valid-jsdoc */
  47998. /**
  47999. * Adds support for broken axes.
  48000. * @private
  48001. */
  48002. function compose(AxisClass, SeriesClass) {
  48003. if (AxisClass.keepProps.indexOf('brokenAxis') === -1) {
  48004. AxisClass.keepProps.push('brokenAxis');
  48005. var seriesProto = Series.prototype;
  48006. seriesProto.drawBreaks = seriesDrawBreaks;
  48007. seriesProto.gappedPath = seriesGappedPath;
  48008. addEvent(AxisClass, 'init', onInit);
  48009. addEvent(AxisClass, 'afterInit', onAfterInit);
  48010. addEvent(AxisClass, 'afterSetTickPositions', onAfterSetTickPositions);
  48011. addEvent(AxisClass, 'afterSetOptions', onAfterSetOptions);
  48012. addEvent(SeriesClass, 'afterGeneratePoints', onSeriesAfterGeneratePoints);
  48013. addEvent(SeriesClass, 'afterRender', onSeriesAfterRender);
  48014. }
  48015. return AxisClass;
  48016. }
  48017. BrokenAxis.compose = compose;
  48018. /**
  48019. * @private
  48020. */
  48021. function onAfterInit() {
  48022. if (typeof this.brokenAxis !== 'undefined') {
  48023. this.brokenAxis.setBreaks(this.options.breaks, false);
  48024. }
  48025. }
  48026. /**
  48027. * Force Axis to be not-ordinal when breaks are defined.
  48028. * @private
  48029. */
  48030. function onAfterSetOptions() {
  48031. var axis = this;
  48032. if (axis.brokenAxis && axis.brokenAxis.hasBreaks) {
  48033. axis.options.ordinal = false;
  48034. }
  48035. }
  48036. /**
  48037. * @private
  48038. */
  48039. function onAfterSetTickPositions() {
  48040. var axis = this,
  48041. brokenAxis = axis.brokenAxis;
  48042. if (brokenAxis &&
  48043. brokenAxis.hasBreaks) {
  48044. var tickPositions = axis.tickPositions,
  48045. info = axis.tickPositions.info,
  48046. newPositions = [];
  48047. for (var i = 0; i < tickPositions.length; i++) {
  48048. if (!brokenAxis.isInAnyBreak(tickPositions[i])) {
  48049. newPositions.push(tickPositions[i]);
  48050. }
  48051. }
  48052. axis.tickPositions = newPositions;
  48053. axis.tickPositions.info = info;
  48054. }
  48055. }
  48056. /**
  48057. * @private
  48058. */
  48059. function onInit() {
  48060. var axis = this;
  48061. if (!axis.brokenAxis) {
  48062. axis.brokenAxis = new Additions(axis);
  48063. }
  48064. }
  48065. /**
  48066. * @private
  48067. */
  48068. function onSeriesAfterGeneratePoints() {
  48069. var _a = this,
  48070. isDirty = _a.isDirty,
  48071. connectNulls = _a.options.connectNulls,
  48072. points = _a.points,
  48073. xAxis = _a.xAxis,
  48074. yAxis = _a.yAxis;
  48075. // Set, or reset visibility of the points. Axis.setBreaks marks
  48076. // the series as isDirty
  48077. if (isDirty) {
  48078. var i = points.length;
  48079. while (i--) {
  48080. var point = points[i];
  48081. // Respect nulls inside the break (#4275)
  48082. var nullGap = point.y === null && connectNulls === false;
  48083. var isPointInBreak = (!nullGap && ((xAxis &&
  48084. xAxis.brokenAxis &&
  48085. xAxis.brokenAxis.isInAnyBreak(point.x,
  48086. true)) || (yAxis &&
  48087. yAxis.brokenAxis &&
  48088. yAxis.brokenAxis.isInAnyBreak(point.y,
  48089. true))));
  48090. // Set point.visible if in any break.
  48091. // If not in break, reset visible to original value.
  48092. point.visible = isPointInBreak ?
  48093. false :
  48094. point.options.visible !== false;
  48095. }
  48096. }
  48097. }
  48098. /**
  48099. * @private
  48100. */
  48101. function onSeriesAfterRender() {
  48102. this.drawBreaks(this.xAxis, ['x']);
  48103. this.drawBreaks(this.yAxis, pick(this.pointArrayMap, ['y']));
  48104. }
  48105. /**
  48106. * @private
  48107. */
  48108. function seriesDrawBreaks(axis, keys) {
  48109. var series = this,
  48110. points = series.points;
  48111. var breaks,
  48112. threshold,
  48113. eventName,
  48114. y;
  48115. if (axis && // #5950
  48116. axis.brokenAxis &&
  48117. axis.brokenAxis.hasBreaks) {
  48118. var brokenAxis_1 = axis.brokenAxis;
  48119. keys.forEach(function (key) {
  48120. breaks = brokenAxis_1 && brokenAxis_1.breakArray || [];
  48121. threshold = axis.isXAxis ?
  48122. axis.min :
  48123. pick(series.options.threshold, axis.min);
  48124. points.forEach(function (point) {
  48125. y = pick(point['stack' + key.toUpperCase()], point[key]);
  48126. breaks.forEach(function (brk) {
  48127. if (isNumber(threshold) && isNumber(y)) {
  48128. eventName = false;
  48129. if ((threshold < brk.from && y > brk.to) ||
  48130. (threshold > brk.from && y < brk.from)) {
  48131. eventName = 'pointBreak';
  48132. }
  48133. else if ((threshold < brk.from && y > brk.from && y < brk.to) ||
  48134. (threshold > brk.from && y > brk.to && y < brk.from)) {
  48135. eventName = 'pointInBreak';
  48136. }
  48137. if (eventName) {
  48138. fireEvent(axis, eventName, { point: point, brk: brk });
  48139. }
  48140. }
  48141. });
  48142. });
  48143. });
  48144. }
  48145. }
  48146. /**
  48147. * Extend getGraphPath by identifying gaps in the data so that we
  48148. * can draw a gap in the line or area. This was moved from ordinal
  48149. * axis module to broken axis module as of #5045.
  48150. *
  48151. * @private
  48152. * @function Highcharts.Series#gappedPath
  48153. *
  48154. * @return {Highcharts.SVGPathArray}
  48155. * Gapped path
  48156. */
  48157. function seriesGappedPath() {
  48158. var currentDataGrouping = this.currentDataGrouping,
  48159. groupingSize = currentDataGrouping && currentDataGrouping.gapSize,
  48160. points = this.points.slice(),
  48161. yAxis = this.yAxis;
  48162. var gapSize = this.options.gapSize,
  48163. i = points.length - 1,
  48164. stack;
  48165. /**
  48166. * Defines when to display a gap in the graph, together with the
  48167. * [gapUnit](plotOptions.series.gapUnit) option.
  48168. *
  48169. * In case when `dataGrouping` is enabled, points can be grouped
  48170. * into a larger time span. This can make the grouped points to
  48171. * have a greater distance than the absolute value of `gapSize`
  48172. * property, which will result in disappearing graph completely.
  48173. * To prevent this situation the mentioned distance between
  48174. * grouped points is used instead of previously defined
  48175. * `gapSize`.
  48176. *
  48177. * In practice, this option is most often used to visualize gaps
  48178. * in time series. In a stock chart, intraday data is available
  48179. * for daytime hours, while gaps will appear in nights and
  48180. * weekends.
  48181. *
  48182. * @see [gapUnit](plotOptions.series.gapUnit)
  48183. * @see [xAxis.breaks](#xAxis.breaks)
  48184. *
  48185. * @sample {highstock} stock/plotoptions/series-gapsize/
  48186. * Setting the gap size to 2 introduces gaps for weekends in
  48187. * daily datasets.
  48188. *
  48189. * @type {number}
  48190. * @default 0
  48191. * @product highstock
  48192. * @requires modules/broken-axis
  48193. * @apioption plotOptions.series.gapSize
  48194. */
  48195. /**
  48196. * Together with [gapSize](plotOptions.series.gapSize), this
  48197. * option defines where to draw gaps in the graph.
  48198. *
  48199. * When the `gapUnit` is `"relative"` (default), a gap size of 5
  48200. * means that if the distance between two points is greater than
  48201. * 5 times that of the two closest points, the graph will be
  48202. * broken.
  48203. *
  48204. * When the `gapUnit` is `"value"`, the gap is based on absolute
  48205. * axis values, which on a datetime axis is milliseconds. This
  48206. * also applies to the navigator series that inherits gap
  48207. * options from the base series.
  48208. *
  48209. * @see [gapSize](plotOptions.series.gapSize)
  48210. *
  48211. * @type {string}
  48212. * @default relative
  48213. * @since 5.0.13
  48214. * @product highstock
  48215. * @validvalue ["relative", "value"]
  48216. * @requires modules/broken-axis
  48217. * @apioption plotOptions.series.gapUnit
  48218. */
  48219. if (gapSize && i > 0) { // #5008
  48220. // Gap unit is relative
  48221. if (this.options.gapUnit !== 'value') {
  48222. gapSize *= this.basePointRange;
  48223. }
  48224. // Setting a new gapSize in case dataGrouping is enabled
  48225. // (#7686)
  48226. if (groupingSize &&
  48227. groupingSize > gapSize &&
  48228. // Except when DG is forced (e.g. from other series)
  48229. // and has lower granularity than actual points (#11351)
  48230. groupingSize >= this.basePointRange) {
  48231. gapSize = groupingSize;
  48232. }
  48233. // extension for ordinal breaks
  48234. var current = void 0,
  48235. next = void 0;
  48236. while (i--) {
  48237. // Reassign next if it is not visible
  48238. if (!(next && next.visible !== false)) {
  48239. next = points[i + 1];
  48240. }
  48241. current = points[i];
  48242. // Skip iteration if one of the points is not visible
  48243. if (next.visible === false || current.visible === false) {
  48244. continue;
  48245. }
  48246. if (next.x - current.x > gapSize) {
  48247. var xRange = (current.x + next.x) / 2;
  48248. points.splice(// insert after this one
  48249. i + 1, 0, {
  48250. isNull: true,
  48251. x: xRange
  48252. });
  48253. // For stacked chart generate empty stack items,
  48254. // #6546
  48255. if (yAxis.stacking && this.options.stacking) {
  48256. stack = yAxis.stacking.stacks[this.stackKey][xRange] =
  48257. new StackItem(yAxis, yAxis.options
  48258. .stackLabels, false, xRange, this.stack);
  48259. stack.total = 0;
  48260. }
  48261. }
  48262. // Assign current to next for the upcoming iteration
  48263. next = current;
  48264. }
  48265. }
  48266. // Call base method
  48267. return this.getGraphPath(points);
  48268. }
  48269. /* *
  48270. *
  48271. * Class
  48272. *
  48273. * */
  48274. /**
  48275. * Provides support for broken axes.
  48276. * @private
  48277. * @class
  48278. */
  48279. var Additions = /** @class */ (function () {
  48280. /* *
  48281. *
  48282. * Constructors
  48283. *
  48284. * */
  48285. function Additions(axis) {
  48286. this.hasBreaks = false;
  48287. this.axis = axis;
  48288. }
  48289. /* *
  48290. *
  48291. * Static Functions
  48292. *
  48293. * */
  48294. /**
  48295. * @private
  48296. */
  48297. Additions.isInBreak = function (brk, val) {
  48298. var repeat = brk.repeat || Infinity,
  48299. from = brk.from,
  48300. length = brk.to - brk.from,
  48301. test = (val >= from ?
  48302. (val - from) % repeat :
  48303. repeat - ((from - val) % repeat));
  48304. var ret;
  48305. if (!brk.inclusive) {
  48306. ret = test < length && test !== 0;
  48307. }
  48308. else {
  48309. ret = test <= length;
  48310. }
  48311. return ret;
  48312. };
  48313. /**
  48314. * @private
  48315. */
  48316. Additions.lin2Val = function (val) {
  48317. var axis = this;
  48318. var brokenAxis = axis.brokenAxis;
  48319. var breakArray = brokenAxis && brokenAxis.breakArray;
  48320. if (!breakArray || !isNumber(val)) {
  48321. return val;
  48322. }
  48323. var nval = val,
  48324. brk,
  48325. i;
  48326. for (i = 0; i < breakArray.length; i++) {
  48327. brk = breakArray[i];
  48328. if (brk.from >= nval) {
  48329. break;
  48330. }
  48331. else if (brk.to < nval) {
  48332. nval += brk.len;
  48333. }
  48334. else if (Additions.isInBreak(brk, nval)) {
  48335. nval += brk.len;
  48336. }
  48337. }
  48338. return nval;
  48339. };
  48340. /**
  48341. * @private
  48342. */
  48343. Additions.val2Lin = function (val) {
  48344. var axis = this;
  48345. var brokenAxis = axis.brokenAxis;
  48346. var breakArray = brokenAxis && brokenAxis.breakArray;
  48347. if (!breakArray || !isNumber(val)) {
  48348. return val;
  48349. }
  48350. var nval = val,
  48351. brk,
  48352. i;
  48353. for (i = 0; i < breakArray.length; i++) {
  48354. brk = breakArray[i];
  48355. if (brk.to <= val) {
  48356. nval -= brk.len;
  48357. }
  48358. else if (brk.from >= val) {
  48359. break;
  48360. }
  48361. else if (Additions.isInBreak(brk, val)) {
  48362. nval -= (val - brk.from);
  48363. break;
  48364. }
  48365. }
  48366. return nval;
  48367. };
  48368. /* *
  48369. *
  48370. * Functions
  48371. *
  48372. * */
  48373. /**
  48374. * Returns the first break found where the x is larger then break.from
  48375. * and smaller then break.to.
  48376. *
  48377. * @param {number} x
  48378. * The number which should be within a break.
  48379. *
  48380. * @param {Array<Highcharts.XAxisBreaksOptions>} breaks
  48381. * The array of breaks to search within.
  48382. *
  48383. * @return {Highcharts.XAxisBreaksOptions|undefined}
  48384. * Returns the first break found that matches, returns false if no break
  48385. * is found.
  48386. */
  48387. Additions.prototype.findBreakAt = function (x, breaks) {
  48388. return find(breaks, function (b) {
  48389. return b.from < x && x < b.to;
  48390. });
  48391. };
  48392. /**
  48393. * @private
  48394. */
  48395. Additions.prototype.isInAnyBreak = function (val, testKeep) {
  48396. var brokenAxis = this,
  48397. axis = brokenAxis.axis,
  48398. breaks = axis.options.breaks || [];
  48399. var i = breaks.length,
  48400. inbrk,
  48401. keep,
  48402. ret;
  48403. if (i && isNumber(val)) {
  48404. while (i--) {
  48405. if (Additions.isInBreak(breaks[i], val)) {
  48406. inbrk = true;
  48407. if (!keep) {
  48408. keep = pick(breaks[i].showPoints, !axis.isXAxis);
  48409. }
  48410. }
  48411. }
  48412. if (inbrk && testKeep) {
  48413. ret = inbrk && !keep;
  48414. }
  48415. else {
  48416. ret = inbrk;
  48417. }
  48418. }
  48419. return ret;
  48420. };
  48421. /**
  48422. * Dynamically set or unset breaks in an axis. This function in lighter
  48423. * than usin Axis.update, and it also preserves animation.
  48424. *
  48425. * @private
  48426. * @function Highcharts.Axis#setBreaks
  48427. *
  48428. * @param {Array<Highcharts.XAxisBreaksOptions>} [breaks]
  48429. * The breaks to add. When `undefined` it removes existing breaks.
  48430. *
  48431. * @param {boolean} [redraw=true]
  48432. * Whether to redraw the chart immediately.
  48433. */
  48434. Additions.prototype.setBreaks = function (breaks, redraw) {
  48435. var brokenAxis = this;
  48436. var axis = brokenAxis.axis;
  48437. var hasBreaks = (isArray(breaks) && !!breaks.length);
  48438. axis.isDirty = brokenAxis.hasBreaks !== hasBreaks;
  48439. brokenAxis.hasBreaks = hasBreaks;
  48440. axis.options.breaks = axis.userOptions.breaks = breaks;
  48441. axis.forceRedraw = true; // Force recalculation in setScale
  48442. // Recalculate series related to the axis.
  48443. axis.series.forEach(function (series) {
  48444. series.isDirty = true;
  48445. });
  48446. if (!hasBreaks && axis.val2lin === Additions.val2Lin) {
  48447. // Revert to prototype functions
  48448. delete axis.val2lin;
  48449. delete axis.lin2val;
  48450. }
  48451. if (hasBreaks) {
  48452. axis.userOptions.ordinal = false;
  48453. axis.lin2val = Additions.lin2Val;
  48454. axis.val2lin = Additions.val2Lin;
  48455. axis.setExtremes = function (newMin, newMax, redraw, animation, eventArguments) {
  48456. // If trying to set extremes inside a break, extend min to
  48457. // after, and max to before the break ( #3857 )
  48458. if (brokenAxis.hasBreaks) {
  48459. var breaks_1 = (this.options.breaks || []);
  48460. var axisBreak = void 0;
  48461. while ((axisBreak = brokenAxis.findBreakAt(newMin, breaks_1))) {
  48462. newMin = axisBreak.to;
  48463. }
  48464. while ((axisBreak = brokenAxis.findBreakAt(newMax, breaks_1))) {
  48465. newMax = axisBreak.from;
  48466. }
  48467. // If both min and max is within the same break.
  48468. if (newMax < newMin) {
  48469. newMax = newMin;
  48470. }
  48471. }
  48472. Axis.prototype.setExtremes.call(this, newMin, newMax, redraw, animation, eventArguments);
  48473. };
  48474. axis.setAxisTranslation = function () {
  48475. Axis.prototype.setAxisTranslation.call(this);
  48476. brokenAxis.unitLength = void 0;
  48477. if (brokenAxis.hasBreaks) {
  48478. var breaks_2 = axis.options.breaks || [],
  48479. // Temporary one:
  48480. breakArrayT_1 = [],
  48481. breakArray_1 = [],
  48482. pointRangePadding = pick(axis.pointRangePadding, 0);
  48483. var length_1 = 0,
  48484. inBrk_1,
  48485. repeat_1,
  48486. min_1 = axis.userMin || axis.min,
  48487. max_1 = axis.userMax || axis.max,
  48488. start_1,
  48489. i_1;
  48490. // Min & max check (#4247)
  48491. breaks_2.forEach(function (brk) {
  48492. repeat_1 = brk.repeat || Infinity;
  48493. if (isNumber(min_1) && isNumber(max_1)) {
  48494. if (Additions.isInBreak(brk, min_1)) {
  48495. min_1 += (brk.to % repeat_1) - (min_1 % repeat_1);
  48496. }
  48497. if (Additions.isInBreak(brk, max_1)) {
  48498. max_1 -= (max_1 % repeat_1) - (brk.from % repeat_1);
  48499. }
  48500. }
  48501. });
  48502. // Construct an array holding all breaks in the axis
  48503. breaks_2.forEach(function (brk) {
  48504. start_1 = brk.from;
  48505. repeat_1 = brk.repeat || Infinity;
  48506. if (isNumber(min_1) && isNumber(max_1)) {
  48507. while (start_1 - repeat_1 > min_1) {
  48508. start_1 -= repeat_1;
  48509. }
  48510. while (start_1 < min_1) {
  48511. start_1 += repeat_1;
  48512. }
  48513. for (i_1 = start_1; i_1 < max_1; i_1 += repeat_1) {
  48514. breakArrayT_1.push({
  48515. value: i_1,
  48516. move: 'in'
  48517. });
  48518. breakArrayT_1.push({
  48519. value: i_1 + brk.to - brk.from,
  48520. move: 'out',
  48521. size: brk.breakSize
  48522. });
  48523. }
  48524. }
  48525. });
  48526. breakArrayT_1.sort(function (a, b) {
  48527. return ((a.value === b.value) ?
  48528. ((a.move === 'in' ? 0 : 1) -
  48529. (b.move === 'in' ? 0 : 1)) :
  48530. a.value - b.value);
  48531. });
  48532. // Simplify the breaks
  48533. inBrk_1 = 0;
  48534. start_1 = min_1;
  48535. breakArrayT_1.forEach(function (brk) {
  48536. inBrk_1 += (brk.move === 'in' ? 1 : -1);
  48537. if (inBrk_1 === 1 && brk.move === 'in') {
  48538. start_1 = brk.value;
  48539. }
  48540. if (inBrk_1 === 0 && isNumber(start_1)) {
  48541. breakArray_1.push({
  48542. from: start_1,
  48543. to: brk.value,
  48544. len: brk.value - start_1 - (brk.size || 0)
  48545. });
  48546. length_1 += brk.value - start_1 - (brk.size || 0);
  48547. }
  48548. });
  48549. brokenAxis.breakArray = breakArray_1;
  48550. // Used with staticScale, and below the actual axis
  48551. // length, when breaks are substracted.
  48552. if (isNumber(min_1) && isNumber(max_1) && isNumber(axis.min)) {
  48553. brokenAxis.unitLength = max_1 - min_1 - length_1 +
  48554. pointRangePadding;
  48555. fireEvent(axis, 'afterBreaks');
  48556. if (axis.staticScale) {
  48557. axis.transA = axis.staticScale;
  48558. }
  48559. else if (brokenAxis.unitLength) {
  48560. axis.transA *=
  48561. (max_1 - axis.min + pointRangePadding) /
  48562. brokenAxis.unitLength;
  48563. }
  48564. if (pointRangePadding) {
  48565. axis.minPixelPadding =
  48566. axis.transA * (axis.minPointOffset || 0);
  48567. }
  48568. axis.min = min_1;
  48569. axis.max = max_1;
  48570. }
  48571. }
  48572. };
  48573. }
  48574. if (pick(redraw, true)) {
  48575. axis.chart.redraw();
  48576. }
  48577. };
  48578. return Additions;
  48579. }());
  48580. BrokenAxis.Additions = Additions;
  48581. })(BrokenAxis || (BrokenAxis = {}));
  48582. /* *
  48583. *
  48584. * Default Export
  48585. *
  48586. * */
  48587. return BrokenAxis;
  48588. });
  48589. _registerModule(_modules, 'Core/Axis/GridAxis.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Axis/AxisDefaults.js'], _modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (Axis, AxisDefaults, H, U) {
  48590. /* *
  48591. *
  48592. * (c) 2016 Highsoft AS
  48593. * Authors: Lars A. V. Cabrera
  48594. *
  48595. * License: www.highcharts.com/license
  48596. *
  48597. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  48598. *
  48599. * */
  48600. var dateFormats = H.dateFormats;
  48601. var addEvent = U.addEvent,
  48602. defined = U.defined,
  48603. erase = U.erase,
  48604. find = U.find,
  48605. isArray = U.isArray,
  48606. isNumber = U.isNumber,
  48607. merge = U.merge,
  48608. pick = U.pick,
  48609. timeUnits = U.timeUnits,
  48610. wrap = U.wrap;
  48611. /* *
  48612. *
  48613. * Functions
  48614. *
  48615. * */
  48616. /* eslint-disable require-jsdoc */
  48617. function argsToArray(args) {
  48618. return Array.prototype.slice.call(args, 1);
  48619. }
  48620. function isObject(x) {
  48621. // Always use strict mode
  48622. return U.isObject(x, true);
  48623. }
  48624. function applyGridOptions(axis) {
  48625. var options = axis.options;
  48626. // Center-align by default
  48627. /*
  48628. if (!options.labels) {
  48629. options.labels = {};
  48630. }
  48631. */
  48632. options.labels.align = pick(options.labels.align, 'center');
  48633. // @todo: Check against tickLabelPlacement between/on etc
  48634. /* Prevents adding the last tick label if the axis is not a category
  48635. axis.
  48636. Since numeric labels are normally placed at starts and ends of a
  48637. range of value, and this module makes the label point at the value,
  48638. an "extra" label would appear. */
  48639. if (!axis.categories) {
  48640. options.showLastLabel = false;
  48641. }
  48642. // Prevents rotation of labels when squished, as rotating them would not
  48643. // help.
  48644. axis.labelRotation = 0;
  48645. options.labels.rotation = 0;
  48646. }
  48647. /**
  48648. * Axis with grid support.
  48649. * @private
  48650. */
  48651. var GridAxis;
  48652. (function (GridAxis) {
  48653. /* *
  48654. *
  48655. * Declarations
  48656. *
  48657. * */
  48658. /**
  48659. * Enum for which side the axis is on. Maps to axis.side.
  48660. * @private
  48661. */
  48662. var Side;
  48663. (function (Side) {
  48664. Side[Side["top"] = 0] = "top";
  48665. Side[Side["right"] = 1] = "right";
  48666. Side[Side["bottom"] = 2] = "bottom";
  48667. Side[Side["left"] = 3] = "left";
  48668. })(Side = GridAxis.Side || (GridAxis.Side = {}));
  48669. /* *
  48670. *
  48671. * Functions
  48672. *
  48673. * */
  48674. /* eslint-disable valid-jsdoc */
  48675. /**
  48676. * Extends axis class with grid support.
  48677. * @private
  48678. */
  48679. function compose(AxisClass, ChartClass, TickClass) {
  48680. if (AxisClass.keepProps.indexOf('grid') === -1) {
  48681. AxisClass.keepProps.push('grid');
  48682. AxisClass.prototype.getMaxLabelDimensions = getMaxLabelDimensions;
  48683. wrap(AxisClass.prototype, 'unsquish', wrapUnsquish);
  48684. // Add event handlers
  48685. addEvent(AxisClass, 'init', onInit);
  48686. addEvent(AxisClass, 'afterGetOffset', onAfterGetOffset);
  48687. addEvent(AxisClass, 'afterGetTitlePosition', onAfterGetTitlePosition);
  48688. addEvent(AxisClass, 'afterInit', onAfterInit);
  48689. addEvent(AxisClass, 'afterRender', onAfterRender);
  48690. addEvent(AxisClass, 'afterSetAxisTranslation', onAfterSetAxisTranslation);
  48691. addEvent(AxisClass, 'afterSetOptions', onAfterSetOptions);
  48692. addEvent(AxisClass, 'afterSetOptions', onAfterSetOptions2);
  48693. addEvent(AxisClass, 'afterSetScale', onAfterSetScale);
  48694. addEvent(AxisClass, 'afterTickSize', onAfterTickSize);
  48695. addEvent(AxisClass, 'trimTicks', onTrimTicks);
  48696. addEvent(AxisClass, 'destroy', onDestroy);
  48697. }
  48698. addEvent(ChartClass, 'afterSetChartSize', onChartAfterSetChartSize);
  48699. addEvent(TickClass, 'afterGetLabelPosition', onTickAfterGetLabelPosition);
  48700. addEvent(TickClass, 'labelFormat', onTickLabelFormat);
  48701. return AxisClass;
  48702. }
  48703. GridAxis.compose = compose;
  48704. /**
  48705. * Get the largest label width and height.
  48706. *
  48707. * @private
  48708. * @function Highcharts.Axis#getMaxLabelDimensions
  48709. *
  48710. * @param {Highcharts.Dictionary<Highcharts.Tick>} ticks
  48711. * All the ticks on one axis.
  48712. *
  48713. * @param {Array<number|string>} tickPositions
  48714. * All the tick positions on one axis.
  48715. *
  48716. * @return {Highcharts.SizeObject}
  48717. * Object containing the properties height and width.
  48718. *
  48719. * @todo Move this to the generic axis implementation, as it is used there.
  48720. */
  48721. function getMaxLabelDimensions(ticks, tickPositions) {
  48722. var dimensions = {
  48723. width: 0,
  48724. height: 0
  48725. };
  48726. tickPositions.forEach(function (pos) {
  48727. var tick = ticks[pos];
  48728. var labelHeight = 0,
  48729. labelWidth = 0,
  48730. label;
  48731. if (isObject(tick)) {
  48732. label = isObject(tick.label) ? tick.label : {};
  48733. // Find width and height of label
  48734. labelHeight = label.getBBox ? label.getBBox().height : 0;
  48735. if (label.textStr && !isNumber(label.textPxLength)) {
  48736. label.textPxLength = label.getBBox().width;
  48737. }
  48738. labelWidth = isNumber(label.textPxLength) ?
  48739. // Math.round ensures crisp lines
  48740. Math.round(label.textPxLength) :
  48741. 0;
  48742. if (label.textStr) {
  48743. // Set the tickWidth same as the label width after ellipsis
  48744. // applied #10281
  48745. labelWidth = Math.round(label.getBBox().width);
  48746. }
  48747. // Update the result if width and/or height are larger
  48748. dimensions.height = Math.max(labelHeight, dimensions.height);
  48749. dimensions.width = Math.max(labelWidth, dimensions.width);
  48750. }
  48751. });
  48752. // For tree grid, add indentation
  48753. if (this.options.type === 'treegrid' &&
  48754. this.treeGrid &&
  48755. this.treeGrid.mapOfPosToGridNode) {
  48756. var treeDepth = this.treeGrid.mapOfPosToGridNode[-1].height || 0;
  48757. dimensions.width += this.options.labels.indentation * (treeDepth - 1);
  48758. }
  48759. return dimensions;
  48760. }
  48761. /**
  48762. * Handle columns and getOffset.
  48763. * @private
  48764. */
  48765. function onAfterGetOffset() {
  48766. var grid = this.grid;
  48767. (grid && grid.columns || []).forEach(function (column) {
  48768. column.getOffset();
  48769. });
  48770. }
  48771. /**
  48772. * @private
  48773. */
  48774. function onAfterGetTitlePosition(e) {
  48775. var axis = this;
  48776. var options = axis.options;
  48777. var gridOptions = options.grid || {};
  48778. if (gridOptions.enabled === true) {
  48779. // compute anchor points for each of the title align options
  48780. var axisTitle = axis.axisTitle,
  48781. axisHeight = axis.height,
  48782. horiz = axis.horiz,
  48783. axisLeft = axis.left,
  48784. offset = axis.offset,
  48785. opposite = axis.opposite,
  48786. options_1 = axis.options,
  48787. axisTop = axis.top,
  48788. axisWidth = axis.width;
  48789. var tickSize = axis.tickSize();
  48790. var titleWidth = axisTitle && axisTitle.getBBox().width;
  48791. var xOption = options_1.title.x;
  48792. var yOption = options_1.title.y;
  48793. var titleMargin = pick(options_1.title.margin,
  48794. horiz ? 5 : 10);
  48795. var titleFontSize = axis.chart.renderer.fontMetrics(options_1.title.style.fontSize,
  48796. axisTitle).f;
  48797. var crispCorr = tickSize ? tickSize[0] / 2 : 0;
  48798. // TODO account for alignment
  48799. // the position in the perpendicular direction of the axis
  48800. var offAxis = ((horiz ? axisTop + axisHeight : axisLeft) +
  48801. (horiz ? 1 : -1) * // horizontal axis reverses the margin
  48802. (opposite ? -1 : 1) * // so does opposite axes
  48803. crispCorr +
  48804. (axis.side === GridAxis.Side.bottom ? titleFontSize : 0));
  48805. e.titlePosition.x = horiz ?
  48806. axisLeft - (titleWidth || 0) / 2 - titleMargin + xOption :
  48807. offAxis + (opposite ? axisWidth : 0) + offset + xOption;
  48808. e.titlePosition.y = horiz ?
  48809. (offAxis -
  48810. (opposite ? axisHeight : 0) +
  48811. (opposite ? titleFontSize : -titleFontSize) / 2 +
  48812. offset +
  48813. yOption) :
  48814. axisTop - titleMargin + yOption;
  48815. }
  48816. }
  48817. /**
  48818. * @private
  48819. */
  48820. function onAfterInit() {
  48821. var axis = this;
  48822. var chart = axis.chart,
  48823. _a = axis.options.grid,
  48824. gridOptions = _a === void 0 ? {} : _a,
  48825. userOptions = axis.userOptions;
  48826. if (gridOptions.enabled) {
  48827. applyGridOptions(axis);
  48828. }
  48829. if (gridOptions.columns) {
  48830. var columns = axis.grid.columns = [];
  48831. var columnIndex = axis.grid.columnIndex = 0;
  48832. // Handle columns, each column is a grid axis
  48833. while (++columnIndex < gridOptions.columns.length) {
  48834. var columnOptions = merge(userOptions,
  48835. gridOptions.columns[gridOptions.columns.length - columnIndex - 1], {
  48836. linkedTo: 0,
  48837. // Force to behave like category axis
  48838. type: 'category',
  48839. // Disable by default the scrollbar on the grid axis
  48840. scrollbar: {
  48841. enabled: false
  48842. }
  48843. });
  48844. delete columnOptions.grid.columns; // Prevent recursion
  48845. var column = new Axis(axis.chart,
  48846. columnOptions);
  48847. column.grid.isColumn = true;
  48848. column.grid.columnIndex = columnIndex;
  48849. // Remove column axis from chart axes array, and place it
  48850. // in the columns array.
  48851. erase(chart.axes, column);
  48852. erase(chart[axis.coll], column);
  48853. columns.push(column);
  48854. }
  48855. }
  48856. }
  48857. /**
  48858. * Draw an extra line on the far side of the outermost axis,
  48859. * creating floor/roof/wall of a grid. And some padding.
  48860. * ```
  48861. * Make this:
  48862. * (axis.min) __________________________ (axis.max)
  48863. * | | | | |
  48864. * Into this:
  48865. * (axis.min) __________________________ (axis.max)
  48866. * ___|____|____|____|____|__
  48867. * ```
  48868. * @private
  48869. */
  48870. function onAfterRender() {
  48871. var axis = this,
  48872. grid = axis.grid,
  48873. options = axis.options,
  48874. gridOptions = options.grid || {};
  48875. if (gridOptions.enabled === true) {
  48876. var min = axis.min || 0,
  48877. max = axis.max || 0;
  48878. // @todo acutual label padding (top, bottom, left, right)
  48879. axis.maxLabelDimensions = axis.getMaxLabelDimensions(axis.ticks, axis.tickPositions);
  48880. // Remove right wall before rendering if updating
  48881. if (axis.rightWall) {
  48882. axis.rightWall.destroy();
  48883. }
  48884. /*
  48885. Draw an extra axis line on outer axes
  48886. >
  48887. Make this: |______|______|______|___
  48888. > _________________________
  48889. Into this: |______|______|______|__|
  48890. */
  48891. if (axis.grid && axis.grid.isOuterAxis() && axis.axisLine) {
  48892. var lineWidth = options.lineWidth;
  48893. if (lineWidth) {
  48894. var linePath = axis.getLinePath(lineWidth),
  48895. startPoint = linePath[0],
  48896. endPoint = linePath[1],
  48897. // Negate distance if top or left axis
  48898. // Subtract 1px to draw the line at the end of the tick
  48899. tickLength = (axis.tickSize('tick') || [1])[0],
  48900. distance = (tickLength - 1) * ((axis.side === GridAxis.Side.top ||
  48901. axis.side === GridAxis.Side.left) ? -1 : 1);
  48902. // If axis is horizontal, reposition line path vertically
  48903. if (startPoint[0] === 'M' && endPoint[0] === 'L') {
  48904. if (axis.horiz) {
  48905. startPoint[2] += distance;
  48906. endPoint[2] += distance;
  48907. }
  48908. else {
  48909. startPoint[1] += distance;
  48910. endPoint[1] += distance;
  48911. }
  48912. }
  48913. // If it doesn't exist, add an upper and lower border
  48914. // for the vertical grid axis.
  48915. if (!axis.horiz && axis.chart.marginRight) {
  48916. var upperBorderStartPoint = startPoint,
  48917. upperBorderEndPoint = [
  48918. 'L',
  48919. axis.left,
  48920. startPoint[2] || 0
  48921. ],
  48922. upperBorderPath = [upperBorderStartPoint,
  48923. upperBorderEndPoint],
  48924. lowerBorderEndPoint = [
  48925. 'L',
  48926. axis.chart.chartWidth - axis.chart.marginRight,
  48927. axis.toPixels(max + axis.tickmarkOffset)
  48928. ],
  48929. lowerBorderStartPoint = [
  48930. 'M',
  48931. endPoint[1] || 0,
  48932. axis.toPixels(max + axis.tickmarkOffset)
  48933. ],
  48934. lowerBorderPath = [lowerBorderStartPoint,
  48935. lowerBorderEndPoint];
  48936. if (!axis.grid.upperBorder && min % 1 !== 0) {
  48937. axis.grid.upperBorder = axis.grid.renderBorder(upperBorderPath);
  48938. }
  48939. if (axis.grid.upperBorder) {
  48940. axis.grid.upperBorder.attr({
  48941. stroke: options.lineColor,
  48942. 'stroke-width': options.lineWidth
  48943. });
  48944. axis.grid.upperBorder.animate({
  48945. d: upperBorderPath
  48946. });
  48947. }
  48948. if (!axis.grid.lowerBorder && max % 1 !== 0) {
  48949. axis.grid.lowerBorder = axis.grid.renderBorder(lowerBorderPath);
  48950. }
  48951. if (axis.grid.lowerBorder) {
  48952. axis.grid.lowerBorder.attr({
  48953. stroke: options.lineColor,
  48954. 'stroke-width': options.lineWidth
  48955. });
  48956. axis.grid.lowerBorder.animate({
  48957. d: lowerBorderPath
  48958. });
  48959. }
  48960. }
  48961. // Render an extra line parallel to the existing axes,
  48962. // to close the grid.
  48963. if (!axis.grid.axisLineExtra) {
  48964. axis.grid.axisLineExtra = axis.grid.renderBorder(linePath);
  48965. }
  48966. else {
  48967. axis.grid.axisLineExtra.attr({
  48968. stroke: options.lineColor,
  48969. 'stroke-width': options.lineWidth
  48970. });
  48971. axis.grid.axisLineExtra.animate({
  48972. d: linePath
  48973. });
  48974. }
  48975. // show or hide the line depending on
  48976. // options.showEmpty
  48977. axis.axisLine[axis.showAxis ? 'show' : 'hide'](true);
  48978. }
  48979. }
  48980. (grid && grid.columns || []).forEach(function (column) {
  48981. column.render();
  48982. });
  48983. // Manipulate the tick mark visibility
  48984. // based on the axis.max- allows smooth scrolling.
  48985. if (!axis.horiz &&
  48986. axis.chart.hasRendered &&
  48987. (axis.scrollbar ||
  48988. (axis.linkedParent && axis.linkedParent.scrollbar))) {
  48989. var tickmarkOffset = axis.tickmarkOffset,
  48990. lastTick = axis.tickPositions[axis.tickPositions.length - 1],
  48991. firstTick = axis.tickPositions[0];
  48992. // Hide/show firts tick label.
  48993. var label = axis.ticks[firstTick].label;
  48994. if (label) {
  48995. if (min - firstTick > tickmarkOffset) {
  48996. label.hide();
  48997. }
  48998. else {
  48999. label.show();
  49000. }
  49001. }
  49002. // Hide/show last tick mark/label.
  49003. label = axis.ticks[lastTick].label;
  49004. if (label) {
  49005. if (lastTick - max > tickmarkOffset) {
  49006. label.hide();
  49007. }
  49008. else {
  49009. label.show();
  49010. }
  49011. }
  49012. var mark = axis.ticks[lastTick].mark;
  49013. if (mark) {
  49014. if (lastTick - max < tickmarkOffset && lastTick - max > 0 && axis.ticks[lastTick].isLast) {
  49015. mark.hide();
  49016. }
  49017. else if (axis.ticks[lastTick - 1]) {
  49018. mark.show();
  49019. }
  49020. }
  49021. }
  49022. }
  49023. }
  49024. /**
  49025. * @private
  49026. */
  49027. function onAfterSetAxisTranslation() {
  49028. var axis = this;
  49029. var tickInfo = axis.tickPositions && axis.tickPositions.info;
  49030. var options = axis.options;
  49031. var gridOptions = options.grid || {};
  49032. var userLabels = axis.userOptions.labels || {};
  49033. // Fire this only for the Gantt type chart, #14868.
  49034. if (gridOptions.enabled) {
  49035. if (axis.horiz) {
  49036. axis.series.forEach(function (series) {
  49037. series.options.pointRange = 0;
  49038. });
  49039. // Lower level time ticks, like hours or minutes, represent
  49040. // points in time and not ranges. These should be aligned
  49041. // left in the grid cell by default. The same applies to
  49042. // years of higher order.
  49043. if (tickInfo &&
  49044. options.dateTimeLabelFormats &&
  49045. options.labels &&
  49046. !defined(userLabels.align) &&
  49047. (options.dateTimeLabelFormats[tickInfo.unitName].range === false ||
  49048. tickInfo.count > 1 // years
  49049. )) {
  49050. options.labels.align = 'left';
  49051. if (!defined(userLabels.x)) {
  49052. options.labels.x = 3;
  49053. }
  49054. }
  49055. }
  49056. else {
  49057. // Don't trim ticks which not in min/max range but
  49058. // they are still in the min/max plus tickInterval.
  49059. if (this.options.type !== 'treegrid' &&
  49060. axis.grid &&
  49061. axis.grid.columns) {
  49062. this.minPointOffset = this.tickInterval;
  49063. }
  49064. }
  49065. }
  49066. }
  49067. /**
  49068. * Creates a left and right wall on horizontal axes:
  49069. * - Places leftmost tick at the start of the axis, to create a left
  49070. * wall
  49071. * - Ensures that the rightmost tick is at the end of the axis, to
  49072. * create a right wall.
  49073. * @private
  49074. */
  49075. function onAfterSetOptions(e) {
  49076. var options = this.options,
  49077. userOptions = e.userOptions,
  49078. gridOptions = ((options && isObject(options.grid)) ? options.grid : {});
  49079. var gridAxisOptions;
  49080. if (gridOptions.enabled === true) {
  49081. // Merge the user options into default grid axis options so
  49082. // that when a user option is set, it takes presedence.
  49083. gridAxisOptions = merge(true, {
  49084. className: ('highcharts-grid-axis ' + (userOptions.className || '')),
  49085. dateTimeLabelFormats: {
  49086. hour: {
  49087. list: ['%H:%M', '%H']
  49088. },
  49089. day: {
  49090. list: ['%A, %e. %B', '%a, %e. %b', '%E']
  49091. },
  49092. week: {
  49093. list: ['Week %W', 'W%W']
  49094. },
  49095. month: {
  49096. list: ['%B', '%b', '%o']
  49097. }
  49098. },
  49099. grid: {
  49100. borderWidth: 1
  49101. },
  49102. labels: {
  49103. padding: 2,
  49104. style: {
  49105. fontSize: '13px'
  49106. }
  49107. },
  49108. margin: 0,
  49109. title: {
  49110. text: null,
  49111. reserveSpace: false,
  49112. rotation: 0
  49113. },
  49114. // In a grid axis, only allow one unit of certain types,
  49115. // for example we shouln't have one grid cell spanning
  49116. // two days.
  49117. units: [[
  49118. 'millisecond',
  49119. [1, 10, 100]
  49120. ], [
  49121. 'second',
  49122. [1, 10]
  49123. ], [
  49124. 'minute',
  49125. [1, 5, 15]
  49126. ], [
  49127. 'hour',
  49128. [1, 6]
  49129. ], [
  49130. 'day',
  49131. [1]
  49132. ], [
  49133. 'week',
  49134. [1]
  49135. ], [
  49136. 'month',
  49137. [1]
  49138. ], [
  49139. 'year',
  49140. null
  49141. ]]
  49142. }, userOptions);
  49143. // X-axis specific options
  49144. if (this.coll === 'xAxis') {
  49145. // For linked axes, tickPixelInterval is used only if
  49146. // the tickPositioner below doesn't run or returns
  49147. // undefined (like multiple years)
  49148. if (defined(userOptions.linkedTo) &&
  49149. !defined(userOptions.tickPixelInterval)) {
  49150. gridAxisOptions.tickPixelInterval = 350;
  49151. }
  49152. // For the secondary grid axis, use the primary axis'
  49153. // tick intervals and return ticks one level higher.
  49154. if (
  49155. // Check for tick pixel interval in options
  49156. !defined(userOptions.tickPixelInterval) &&
  49157. // Only for linked axes
  49158. defined(userOptions.linkedTo) &&
  49159. !defined(userOptions.tickPositioner) &&
  49160. !defined(userOptions.tickInterval)) {
  49161. gridAxisOptions.tickPositioner = function (min, max) {
  49162. var parentInfo = (this.linkedParent &&
  49163. this.linkedParent.tickPositions &&
  49164. this.linkedParent.tickPositions.info);
  49165. if (parentInfo) {
  49166. var units = (gridAxisOptions.units || []);
  49167. var unitIdx = void 0,
  49168. count = void 0,
  49169. unitName = void 0;
  49170. for (var i = 0; i < units.length; i++) {
  49171. if (units[i][0] ===
  49172. parentInfo.unitName) {
  49173. unitIdx = i;
  49174. break;
  49175. }
  49176. }
  49177. // Get the first allowed count on the next
  49178. // unit.
  49179. if (units[unitIdx + 1]) {
  49180. unitName = units[unitIdx + 1][0];
  49181. count =
  49182. (units[unitIdx + 1][1] || [1])[0];
  49183. // In case the base X axis shows years, make
  49184. // the secondary axis show ten times the
  49185. // years (#11427)
  49186. }
  49187. else if (parentInfo.unitName === 'year') {
  49188. unitName = 'year';
  49189. count = parentInfo.count * 10;
  49190. }
  49191. var unitRange = timeUnits[unitName];
  49192. this.tickInterval = unitRange * count;
  49193. return this.getTimeTicks({
  49194. unitRange: unitRange,
  49195. count: count,
  49196. unitName: unitName
  49197. }, min, max, this.options.startOfWeek);
  49198. }
  49199. };
  49200. }
  49201. }
  49202. // Now merge the combined options into the axis options
  49203. merge(true, this.options, gridAxisOptions);
  49204. if (this.horiz) {
  49205. /* _________________________
  49206. Make this: ___|_____|_____|_____|__|
  49207. ^ ^
  49208. _________________________
  49209. Into this: |_____|_____|_____|_____|
  49210. ^ ^ */
  49211. options.minPadding = pick(userOptions.minPadding, 0);
  49212. options.maxPadding = pick(userOptions.maxPadding, 0);
  49213. }
  49214. // If borderWidth is set, then use its value for tick and
  49215. // line width.
  49216. if (isNumber(options.grid.borderWidth)) {
  49217. options.tickWidth = options.lineWidth =
  49218. gridOptions.borderWidth;
  49219. }
  49220. }
  49221. }
  49222. /**
  49223. * @private
  49224. */
  49225. function onAfterSetOptions2(e) {
  49226. var axis = this;
  49227. var userOptions = e.userOptions;
  49228. var gridOptions = userOptions && userOptions.grid || {};
  49229. var columns = gridOptions.columns;
  49230. // Add column options to the parent axis. Children has their column
  49231. // options set on init in onGridAxisAfterInit.
  49232. if (gridOptions.enabled && columns) {
  49233. merge(true, axis.options, columns[columns.length - 1]);
  49234. }
  49235. }
  49236. /**
  49237. * Handle columns and setScale.
  49238. * @private
  49239. */
  49240. function onAfterSetScale() {
  49241. var axis = this;
  49242. (axis.grid.columns || []).forEach(function (column) {
  49243. column.setScale();
  49244. });
  49245. }
  49246. /**
  49247. * Draw vertical axis ticks extra long to create cell floors and roofs.
  49248. * Overrides the tickLength for vertical axes.
  49249. * @private
  49250. */
  49251. function onAfterTickSize(e) {
  49252. var defaultLeftAxisOptions = AxisDefaults.defaultLeftAxisOptions;
  49253. var _a = this,
  49254. horiz = _a.horiz,
  49255. maxLabelDimensions = _a.maxLabelDimensions,
  49256. _b = _a.options.grid,
  49257. gridOptions = _b === void 0 ? {} : _b;
  49258. if (gridOptions.enabled && maxLabelDimensions) {
  49259. var labelPadding = (Math.abs(defaultLeftAxisOptions.labels.x) * 2);
  49260. var distance = horiz ?
  49261. gridOptions.cellHeight || labelPadding + maxLabelDimensions.height :
  49262. labelPadding + maxLabelDimensions.width;
  49263. if (isArray(e.tickSize)) {
  49264. e.tickSize[0] = distance;
  49265. }
  49266. else {
  49267. e.tickSize = [distance, 0];
  49268. }
  49269. }
  49270. }
  49271. /**
  49272. * @private
  49273. */
  49274. function onChartAfterSetChartSize() {
  49275. this.axes.forEach(function (axis) {
  49276. (axis.grid && axis.grid.columns || []).forEach(function (column) {
  49277. column.setAxisSize();
  49278. column.setAxisTranslation();
  49279. });
  49280. });
  49281. }
  49282. /**
  49283. * @private
  49284. */
  49285. function onDestroy(e) {
  49286. var grid = this.grid;
  49287. (grid.columns || []).forEach(function (column) {
  49288. column.destroy(e.keepEvents);
  49289. });
  49290. grid.columns = void 0;
  49291. }
  49292. /**
  49293. * Wraps axis init to draw cell walls on vertical axes.
  49294. * @private
  49295. */
  49296. function onInit(e) {
  49297. var axis = this;
  49298. var userOptions = e.userOptions || {};
  49299. var gridOptions = userOptions.grid || {};
  49300. if (gridOptions.enabled && defined(gridOptions.borderColor)) {
  49301. userOptions.tickColor = userOptions.lineColor = gridOptions.borderColor;
  49302. }
  49303. if (!axis.grid) {
  49304. axis.grid = new Additions(axis);
  49305. }
  49306. }
  49307. /**
  49308. * Center tick labels in cells.
  49309. * @private
  49310. */
  49311. function onTickAfterGetLabelPosition(e) {
  49312. var tick = this,
  49313. label = tick.label,
  49314. axis = tick.axis,
  49315. reversed = axis.reversed,
  49316. chart = axis.chart,
  49317. options = axis.options,
  49318. gridOptions = options.grid || {},
  49319. labelOpts = axis.options.labels,
  49320. align = labelOpts.align,
  49321. // verticalAlign is currently not supported for axis.labels.
  49322. verticalAlign = 'middle', // labelOpts.verticalAlign,
  49323. side = GridAxis.Side[axis.side],
  49324. tickmarkOffset = e.tickmarkOffset,
  49325. tickPositions = axis.tickPositions,
  49326. tickPos = tick.pos - tickmarkOffset,
  49327. nextTickPos = (isNumber(tickPositions[e.index + 1]) ?
  49328. tickPositions[e.index + 1] - tickmarkOffset :
  49329. (axis.max || 0) + tickmarkOffset),
  49330. tickSize = axis.tickSize('tick'),
  49331. tickWidth = tickSize ? tickSize[0] : 0,
  49332. crispCorr = tickSize ? tickSize[1] / 2 : 0;
  49333. var labelHeight,
  49334. lblMetrics,
  49335. lines,
  49336. bottom,
  49337. top,
  49338. left,
  49339. right;
  49340. // Only center tick labels in grid axes
  49341. if (gridOptions.enabled === true) {
  49342. // Calculate top and bottom positions of the cell.
  49343. if (side === 'top') {
  49344. bottom = axis.top + axis.offset;
  49345. top = bottom - tickWidth;
  49346. }
  49347. else if (side === 'bottom') {
  49348. top = chart.chartHeight - axis.bottom + axis.offset;
  49349. bottom = top + tickWidth;
  49350. }
  49351. else {
  49352. bottom = axis.top + axis.len - (axis.translate(reversed ? nextTickPos : tickPos) || 0);
  49353. top = axis.top + axis.len - (axis.translate(reversed ? tickPos : nextTickPos) || 0);
  49354. }
  49355. // Calculate left and right positions of the cell.
  49356. if (side === 'right') {
  49357. left = chart.chartWidth - axis.right + axis.offset;
  49358. right = left + tickWidth;
  49359. }
  49360. else if (side === 'left') {
  49361. right = axis.left + axis.offset;
  49362. left = right - tickWidth;
  49363. }
  49364. else {
  49365. left = Math.round(axis.left + (axis.translate(reversed ? nextTickPos : tickPos) || 0)) - crispCorr;
  49366. right = Math.min(// #15742
  49367. Math.round(axis.left + (axis.translate(reversed ? tickPos : nextTickPos) || 0)) - crispCorr, axis.left + axis.len);
  49368. }
  49369. tick.slotWidth = right - left;
  49370. // Calculate the positioning of the label based on
  49371. // alignment.
  49372. e.pos.x = (align === 'left' ?
  49373. left :
  49374. align === 'right' ?
  49375. right :
  49376. left + ((right - left) / 2) // default to center
  49377. );
  49378. e.pos.y = (verticalAlign === 'top' ?
  49379. top :
  49380. verticalAlign === 'bottom' ?
  49381. bottom :
  49382. top + ((bottom - top) / 2) // default to middle
  49383. );
  49384. lblMetrics = chart.renderer.fontMetrics(labelOpts.style.fontSize, label && label.element);
  49385. labelHeight = label ? label.getBBox().height : 0;
  49386. // Adjustment to y position to align the label correctly.
  49387. // Would be better to have a setter or similar for this.
  49388. if (!labelOpts.useHTML) {
  49389. lines = Math.round(labelHeight / lblMetrics.h);
  49390. e.pos.y += (
  49391. // Center the label
  49392. // TODO: why does this actually center the label?
  49393. ((lblMetrics.b - (lblMetrics.h - lblMetrics.f)) / 2) +
  49394. // Adjust for height of additional lines.
  49395. -(((lines - 1) * lblMetrics.h) / 2));
  49396. }
  49397. else {
  49398. e.pos.y += (
  49399. // Readjust yCorr in htmlUpdateTransform
  49400. lblMetrics.b +
  49401. // Adjust for height of html label
  49402. -(labelHeight / 2));
  49403. }
  49404. e.pos.x += (axis.horiz && labelOpts.x) || 0;
  49405. }
  49406. }
  49407. /**
  49408. * @private
  49409. */
  49410. function onTickLabelFormat(ctx) {
  49411. var axis = ctx.axis,
  49412. value = ctx.value;
  49413. if (axis.options.grid &&
  49414. axis.options.grid.enabled) {
  49415. var tickPos = axis.tickPositions;
  49416. var series = (axis.linkedParent || axis).series[0];
  49417. var isFirst = value === tickPos[0];
  49418. var isLast = value === tickPos[tickPos.length - 1];
  49419. var point = series && find(series.options.data,
  49420. function (p) {
  49421. return p[axis.isXAxis ? 'x' : 'y'] === value;
  49422. });
  49423. var pointCopy = void 0;
  49424. if (point && series.is('gantt')) {
  49425. // For the Gantt set point aliases to the pointCopy
  49426. // to do not change the original point
  49427. pointCopy = merge(point);
  49428. H.seriesTypes.gantt.prototype.pointClass
  49429. .setGanttPointAliases(pointCopy);
  49430. }
  49431. // Make additional properties available for the
  49432. // formatter
  49433. ctx.isFirst = isFirst;
  49434. ctx.isLast = isLast;
  49435. ctx.point = pointCopy;
  49436. }
  49437. }
  49438. /**
  49439. * Makes tick labels which are usually ignored in a linked axis
  49440. * displayed if they are within range of linkedParent.min.
  49441. * ```
  49442. * _____________________________
  49443. * | | | | |
  49444. * Make this: | | 2 | 3 | 4 |
  49445. * |___|_______|_______|_______|
  49446. * ^
  49447. * _____________________________
  49448. * | | | | |
  49449. * Into this: | 1 | 2 | 3 | 4 |
  49450. * |___|_______|_______|_______|
  49451. * ^
  49452. * ```
  49453. * @private
  49454. * @todo Does this function do what the drawing says? Seems to affect
  49455. * ticks and not the labels directly?
  49456. */
  49457. function onTrimTicks() {
  49458. var axis = this;
  49459. var options = axis.options;
  49460. var gridOptions = options.grid || {};
  49461. var categoryAxis = axis.categories;
  49462. var tickPositions = axis.tickPositions;
  49463. var firstPos = tickPositions[0];
  49464. var lastPos = tickPositions[tickPositions.length - 1];
  49465. var linkedMin = axis.linkedParent && axis.linkedParent.min;
  49466. var linkedMax = axis.linkedParent && axis.linkedParent.max;
  49467. var min = linkedMin || axis.min;
  49468. var max = linkedMax || axis.max;
  49469. var tickInterval = axis.tickInterval;
  49470. var endMoreThanMin = (firstPos < min &&
  49471. firstPos + tickInterval > min);
  49472. var startLessThanMax = (lastPos > max &&
  49473. lastPos - tickInterval < max);
  49474. if (gridOptions.enabled === true &&
  49475. !categoryAxis &&
  49476. (axis.horiz || axis.isLinked)) {
  49477. if (endMoreThanMin && !options.startOnTick) {
  49478. tickPositions[0] = min;
  49479. }
  49480. if (startLessThanMax && !options.endOnTick) {
  49481. tickPositions[tickPositions.length - 1] = max;
  49482. }
  49483. }
  49484. }
  49485. /**
  49486. * Avoid altering tickInterval when reserving space.
  49487. * @private
  49488. */
  49489. function wrapUnsquish(proceed) {
  49490. var axis = this;
  49491. var _a = axis.options.grid,
  49492. gridOptions = _a === void 0 ? {} : _a;
  49493. if (gridOptions.enabled === true && axis.categories) {
  49494. return axis.tickInterval;
  49495. }
  49496. return proceed.apply(axis, argsToArray(arguments));
  49497. }
  49498. /* *
  49499. *
  49500. * Class
  49501. *
  49502. * */
  49503. /**
  49504. * Additions for grid axes.
  49505. * @private
  49506. * @class
  49507. */
  49508. var Additions = /** @class */ (function () {
  49509. /* *
  49510. *
  49511. * Constructors
  49512. *
  49513. * */
  49514. function Additions(axis) {
  49515. this.axis = axis;
  49516. }
  49517. /* *
  49518. *
  49519. * Functions
  49520. *
  49521. * */
  49522. /**
  49523. * Checks if an axis is the outer axis in its dimension. Since
  49524. * axes are placed outwards in order, the axis with the highest
  49525. * index is the outermost axis.
  49526. *
  49527. * Example: If there are multiple x-axes at the top of the chart,
  49528. * this function returns true if the axis supplied is the last
  49529. * of the x-axes.
  49530. *
  49531. * @private
  49532. *
  49533. * @return {boolean}
  49534. * True if the axis is the outermost axis in its dimension; false if
  49535. * not.
  49536. */
  49537. Additions.prototype.isOuterAxis = function () {
  49538. var axis = this.axis;
  49539. var chart = axis.chart;
  49540. var columnIndex = axis.grid.columnIndex;
  49541. var columns = (axis.linkedParent && axis.linkedParent.grid.columns ||
  49542. axis.grid.columns);
  49543. var parentAxis = columnIndex ? axis.linkedParent : axis;
  49544. var thisIndex = -1,
  49545. lastIndex = 0;
  49546. chart[axis.coll].forEach(function (otherAxis, index) {
  49547. if (otherAxis.side === axis.side && !otherAxis.options.isInternal) {
  49548. lastIndex = index;
  49549. if (otherAxis === parentAxis) {
  49550. // Get the index of the axis in question
  49551. thisIndex = index;
  49552. }
  49553. }
  49554. });
  49555. return (lastIndex === thisIndex &&
  49556. (isNumber(columnIndex) ? columns.length === columnIndex : true));
  49557. };
  49558. /**
  49559. * Add extra border based on the provided path.
  49560. * *
  49561. * @private
  49562. *
  49563. * @param {SVGPath} path
  49564. * The path of the border.
  49565. *
  49566. * @return {Highcharts.SVGElement}
  49567. */
  49568. Additions.prototype.renderBorder = function (path) {
  49569. var axis = this.axis,
  49570. renderer = axis.chart.renderer,
  49571. options = axis.options,
  49572. extraBorderLine = renderer.path(path)
  49573. .addClass('highcharts-axis-line')
  49574. .add(axis.axisBorder);
  49575. if (!renderer.styledMode) {
  49576. extraBorderLine.attr({
  49577. stroke: options.lineColor,
  49578. 'stroke-width': options.lineWidth,
  49579. zIndex: 7
  49580. });
  49581. }
  49582. return extraBorderLine;
  49583. };
  49584. return Additions;
  49585. }());
  49586. GridAxis.Additions = Additions;
  49587. })(GridAxis || (GridAxis = {}));
  49588. /* *
  49589. *
  49590. * Registry
  49591. *
  49592. * */
  49593. // First letter of the day of the week, e.g. 'M' for 'Monday'.
  49594. dateFormats.E = function (timestamp) {
  49595. return this.dateFormat('%a', timestamp, true).charAt(0);
  49596. };
  49597. // Adds week date format
  49598. dateFormats.W = function (timestamp) {
  49599. var d = new this.Date(timestamp);
  49600. var firstDay = (this.get('Day',
  49601. d) + 6) % 7;
  49602. var thursday = new this.Date(d.valueOf());
  49603. this.set('Date', thursday, this.get('Date', d) - firstDay + 3);
  49604. var firstThursday = new this.Date(this.get('FullYear',
  49605. thursday), 0, 1);
  49606. if (this.get('Day', firstThursday) !== 4) {
  49607. this.set('Month', d, 0);
  49608. this.set('Date', d, 1 + (11 - this.get('Day', firstThursday)) % 7);
  49609. }
  49610. return (1 +
  49611. Math.floor((thursday.valueOf() - firstThursday.valueOf()) / 604800000)).toString();
  49612. };
  49613. /* *
  49614. *
  49615. * Default Export
  49616. *
  49617. * */
  49618. /* *
  49619. *
  49620. * API Options
  49621. *
  49622. * */
  49623. /**
  49624. * @productdesc {gantt}
  49625. * For grid axes (like in Gantt charts),
  49626. * it is possible to declare as a list to provide different
  49627. * formats depending on available space.
  49628. *
  49629. * Defaults to:
  49630. * ```js
  49631. * {
  49632. * hour: { list: ['%H:%M', '%H'] },
  49633. * day: { list: ['%A, %e. %B', '%a, %e. %b', '%E'] },
  49634. * week: { list: ['Week %W', 'W%W'] },
  49635. * month: { list: ['%B', '%b', '%o'] }
  49636. * }
  49637. * ```
  49638. *
  49639. * @sample {gantt} gantt/grid-axis/date-time-label-formats
  49640. * Gantt chart with custom axis date format.
  49641. *
  49642. * @apioption xAxis.dateTimeLabelFormats
  49643. */
  49644. /**
  49645. * Set grid options for the axis labels. Requires Highcharts Gantt.
  49646. *
  49647. * @since 6.2.0
  49648. * @product gantt
  49649. * @apioption xAxis.grid
  49650. */
  49651. /**
  49652. * Enable grid on the axis labels. Defaults to true for Gantt charts.
  49653. *
  49654. * @type {boolean}
  49655. * @default true
  49656. * @since 6.2.0
  49657. * @product gantt
  49658. * @apioption xAxis.grid.enabled
  49659. */
  49660. /**
  49661. * Set specific options for each column (or row for horizontal axes) in the
  49662. * grid. Each extra column/row is its own axis, and the axis options can be set
  49663. * here.
  49664. *
  49665. * @sample gantt/demo/left-axis-table
  49666. * Left axis as a table
  49667. *
  49668. * @type {Array<Highcharts.XAxisOptions>}
  49669. * @apioption xAxis.grid.columns
  49670. */
  49671. /**
  49672. * Set border color for the label grid lines.
  49673. *
  49674. * @type {Highcharts.ColorString}
  49675. * @apioption xAxis.grid.borderColor
  49676. */
  49677. /**
  49678. * Set border width of the label grid lines.
  49679. *
  49680. * @type {number}
  49681. * @default 1
  49682. * @apioption xAxis.grid.borderWidth
  49683. */
  49684. /**
  49685. * Set cell height for grid axis labels. By default this is calculated from font
  49686. * size. This option only applies to horizontal axes.
  49687. *
  49688. * @sample gantt/grid-axis/cellheight
  49689. * Gant chart with custom cell height
  49690. * @type {number}
  49691. * @apioption xAxis.grid.cellHeight
  49692. */
  49693. ''; // keeps doclets above in JS file
  49694. return GridAxis;
  49695. });
  49696. _registerModule(_modules, 'Gantt/Tree.js', [_modules['Core/Utilities.js']], function (U) {
  49697. /* *
  49698. *
  49699. * (c) 2016-2021 Highsoft AS
  49700. *
  49701. * Authors: Jon Arild Nygard
  49702. *
  49703. * License: www.highcharts.com/license
  49704. *
  49705. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  49706. *
  49707. * */
  49708. /* eslint no-console: 0 */
  49709. var extend = U.extend,
  49710. isNumber = U.isNumber,
  49711. pick = U.pick;
  49712. /**
  49713. * Creates an object map from parent id to childrens index.
  49714. *
  49715. * @private
  49716. * @function Highcharts.Tree#getListOfParents
  49717. *
  49718. * @param {Array<*>} data
  49719. * List of points set in options. `Array.parent` is parent id of point.
  49720. *
  49721. * @param {Array<string>} ids
  49722. * List of all point ids.
  49723. *
  49724. * @return {Highcharts.Dictionary<Array<*>>}
  49725. * Map from parent id to children index in data
  49726. */
  49727. var getListOfParents = function (data,
  49728. ids) {
  49729. var listOfParents = data.reduce(function (prev,
  49730. curr) {
  49731. var parent = pick(curr.parent, '');
  49732. if (typeof prev[parent] === 'undefined') {
  49733. prev[parent] = [];
  49734. }
  49735. prev[parent].push(curr);
  49736. return prev;
  49737. }, {}), parents = Object.keys(listOfParents);
  49738. // If parent does not exist, hoist parent to root of tree.
  49739. parents.forEach(function (parent, list) {
  49740. var children = listOfParents[parent];
  49741. if ((parent !== '') && (ids.indexOf(parent) === -1)) {
  49742. children.forEach(function (child) {
  49743. list[''].push(child);
  49744. });
  49745. delete list[parent];
  49746. }
  49747. });
  49748. return listOfParents;
  49749. };
  49750. var getNode = function (id,
  49751. parent,
  49752. level,
  49753. data,
  49754. mapOfIdToChildren,
  49755. options) {
  49756. var descendants = 0,
  49757. height = 0,
  49758. after = options && options.after,
  49759. before = options && options.before,
  49760. node = {
  49761. data: data,
  49762. depth: level - 1,
  49763. id: id,
  49764. level: level,
  49765. parent: parent
  49766. },
  49767. start,
  49768. end,
  49769. children;
  49770. // Allow custom logic before the children has been created.
  49771. if (typeof before === 'function') {
  49772. before(node, options);
  49773. }
  49774. // Call getNode recursively on the children. Calulate the height of the
  49775. // node, and the number of descendants.
  49776. children = ((mapOfIdToChildren[id] || [])).map(function (child) {
  49777. var node = getNode(child.id,
  49778. id, (level + 1),
  49779. child,
  49780. mapOfIdToChildren,
  49781. options),
  49782. childStart = child.start,
  49783. childEnd = (child.milestone === true ?
  49784. childStart :
  49785. child.end);
  49786. // Start should be the lowest child.start.
  49787. start = ((!isNumber(start) || childStart < start) ?
  49788. childStart :
  49789. start);
  49790. // End should be the largest child.end.
  49791. // If child is milestone, then use start as end.
  49792. end = ((!isNumber(end) || childEnd > end) ?
  49793. childEnd :
  49794. end);
  49795. descendants = descendants + 1 + node.descendants;
  49796. height = Math.max(node.height + 1, height);
  49797. return node;
  49798. });
  49799. // Calculate start and end for point if it is not already explicitly set.
  49800. if (data) {
  49801. data.start = pick(data.start, start);
  49802. data.end = pick(data.end, end);
  49803. }
  49804. extend(node, {
  49805. children: children,
  49806. descendants: descendants,
  49807. height: height
  49808. });
  49809. // Allow custom logic after the children has been created.
  49810. if (typeof after === 'function') {
  49811. after(node, options);
  49812. }
  49813. return node;
  49814. };
  49815. var getTree = function (data,
  49816. options) {
  49817. var ids = data.map(function (d) {
  49818. return d.id;
  49819. }), mapOfIdToChildren = getListOfParents(data, ids);
  49820. return getNode('', null, 1, null, mapOfIdToChildren, options);
  49821. };
  49822. var Tree = {
  49823. getListOfParents: getListOfParents,
  49824. getNode: getNode,
  49825. getTree: getTree
  49826. };
  49827. return Tree;
  49828. });
  49829. _registerModule(_modules, 'Core/Axis/TreeGridTick.js', [_modules['Core/Color/Palette.js'], _modules['Core/Utilities.js']], function (palette, U) {
  49830. /* *
  49831. *
  49832. * (c) 2016 Highsoft AS
  49833. * Authors: Jon Arild Nygard
  49834. *
  49835. * License: www.highcharts.com/license
  49836. *
  49837. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  49838. *
  49839. * */
  49840. var addEvent = U.addEvent,
  49841. isObject = U.isObject,
  49842. isNumber = U.isNumber,
  49843. pick = U.pick,
  49844. wrap = U.wrap;
  49845. /* eslint-disable no-invalid-this, valid-jsdoc */
  49846. /**
  49847. * @private
  49848. */
  49849. var TreeGridTick;
  49850. (function (TreeGridTick) {
  49851. /* *
  49852. *
  49853. * Interfaces
  49854. *
  49855. * */
  49856. /* *
  49857. *
  49858. * Variables
  49859. *
  49860. * */
  49861. var applied = false;
  49862. /* *
  49863. *
  49864. * Functions
  49865. *
  49866. * */
  49867. /**
  49868. * @private
  49869. */
  49870. function compose(TickClass) {
  49871. if (!applied) {
  49872. addEvent(TickClass, 'init', onInit);
  49873. wrap(TickClass.prototype, 'getLabelPosition', wrapGetLabelPosition);
  49874. wrap(TickClass.prototype, 'renderLabel', wrapRenderLabel);
  49875. // backwards compatibility
  49876. TickClass.prototype.collapse = function (redraw) {
  49877. this.treeGrid.collapse(redraw);
  49878. };
  49879. TickClass.prototype.expand = function (redraw) {
  49880. this.treeGrid.expand(redraw);
  49881. };
  49882. TickClass.prototype.toggleCollapse = function (redraw) {
  49883. this.treeGrid.toggleCollapse(redraw);
  49884. };
  49885. applied = true;
  49886. }
  49887. }
  49888. TreeGridTick.compose = compose;
  49889. /**
  49890. * @private
  49891. */
  49892. function onInit() {
  49893. var tick = this;
  49894. if (!tick.treeGrid) {
  49895. tick.treeGrid = new Additions(tick);
  49896. }
  49897. }
  49898. /**
  49899. * @private
  49900. */
  49901. function onTickHover(label) {
  49902. label.addClass('highcharts-treegrid-node-active');
  49903. if (!label.renderer.styledMode) {
  49904. label.css({
  49905. textDecoration: 'underline'
  49906. });
  49907. }
  49908. }
  49909. /**
  49910. * @private
  49911. */
  49912. function onTickHoverExit(label, options) {
  49913. var css = isObject(options.style) ? options.style : {};
  49914. label.removeClass('highcharts-treegrid-node-active');
  49915. if (!label.renderer.styledMode) {
  49916. label.css({ textDecoration: css.textDecoration });
  49917. }
  49918. }
  49919. /**
  49920. * @private
  49921. */
  49922. function renderLabelIcon(tick, params) {
  49923. var treeGrid = tick.treeGrid,
  49924. isNew = !treeGrid.labelIcon,
  49925. renderer = params.renderer,
  49926. labelBox = params.xy,
  49927. options = params.options,
  49928. width = options.width || 0,
  49929. height = options.height || 0,
  49930. iconCenter = {
  49931. x: labelBox.x - (width / 2) - (options.padding || 0),
  49932. y: labelBox.y - (height / 2)
  49933. },
  49934. rotation = params.collapsed ? 90 : 180,
  49935. shouldRender = params.show && isNumber(iconCenter.y);
  49936. var icon = treeGrid.labelIcon;
  49937. if (!icon) {
  49938. treeGrid.labelIcon = icon = renderer
  49939. .path(renderer.symbols[options.type](options.x || 0, options.y || 0, width, height))
  49940. .addClass('highcharts-label-icon')
  49941. .add(params.group);
  49942. }
  49943. // Set the new position, and show or hide
  49944. icon.attr({ y: shouldRender ? 0 : -9999 }); // #14904, #1338
  49945. // Presentational attributes
  49946. if (!renderer.styledMode) {
  49947. icon
  49948. .attr({
  49949. cursor: 'pointer',
  49950. 'fill': pick(params.color, palette.neutralColor60),
  49951. 'stroke-width': 1,
  49952. stroke: options.lineColor,
  49953. strokeWidth: options.lineWidth || 0
  49954. });
  49955. }
  49956. // Update the icon positions
  49957. icon[isNew ? 'attr' : 'animate']({
  49958. translateX: iconCenter.x,
  49959. translateY: iconCenter.y,
  49960. rotation: rotation
  49961. });
  49962. }
  49963. /**
  49964. * @private
  49965. */
  49966. function wrapGetLabelPosition(proceed, x, y, label, horiz, labelOptions, tickmarkOffset, index, step) {
  49967. var tick = this,
  49968. lbOptions = pick(tick.options && tick.options.labels,
  49969. labelOptions),
  49970. pos = tick.pos,
  49971. axis = tick.axis,
  49972. options = axis.options,
  49973. isTreeGrid = options.type === 'treegrid',
  49974. result = proceed.apply(tick,
  49975. [x,
  49976. y,
  49977. label,
  49978. horiz,
  49979. lbOptions,
  49980. tickmarkOffset,
  49981. index,
  49982. step]);
  49983. var symbolOptions,
  49984. indentation,
  49985. mapOfPosToGridNode,
  49986. node,
  49987. level;
  49988. if (isTreeGrid) {
  49989. symbolOptions = (lbOptions && isObject(lbOptions.symbol, true) ?
  49990. lbOptions.symbol :
  49991. {});
  49992. indentation = (lbOptions && isNumber(lbOptions.indentation) ?
  49993. lbOptions.indentation :
  49994. 0);
  49995. mapOfPosToGridNode = axis.treeGrid.mapOfPosToGridNode;
  49996. node = mapOfPosToGridNode && mapOfPosToGridNode[pos];
  49997. level = (node && node.depth) || 1;
  49998. result.x += (
  49999. // Add space for symbols
  50000. ((symbolOptions.width || 0) +
  50001. ((symbolOptions.padding || 0) * 2)) +
  50002. // Apply indentation
  50003. ((level - 1) * indentation));
  50004. }
  50005. return result;
  50006. }
  50007. /**
  50008. * @private
  50009. */
  50010. function wrapRenderLabel(proceed) {
  50011. var tick = this, pos = tick.pos, axis = tick.axis, label = tick.label, mapOfPosToGridNode = axis.treeGrid.mapOfPosToGridNode, options = axis.options, labelOptions = pick(tick.options && tick.options.labels, options && options.labels), symbolOptions = (labelOptions && isObject(labelOptions.symbol, true) ?
  50012. labelOptions.symbol :
  50013. {}), node = mapOfPosToGridNode && mapOfPosToGridNode[pos], level = node && node.depth, isTreeGrid = options.type === 'treegrid', shouldRender = axis.tickPositions.indexOf(pos) > -1, prefixClassName = 'highcharts-treegrid-node-', styledMode = axis.chart.styledMode;
  50014. var collapsed,
  50015. addClassName,
  50016. removeClassName;
  50017. if (isTreeGrid && node) {
  50018. // Add class name for hierarchical styling.
  50019. if (label &&
  50020. label.element) {
  50021. label.addClass(prefixClassName + 'level-' + level);
  50022. }
  50023. }
  50024. proceed.apply(tick, Array.prototype.slice.call(arguments, 1));
  50025. if (isTreeGrid &&
  50026. label &&
  50027. label.element &&
  50028. node &&
  50029. node.descendants &&
  50030. node.descendants > 0) {
  50031. collapsed = axis.treeGrid.isCollapsed(node);
  50032. renderLabelIcon(tick, {
  50033. color: !styledMode && label.styles && label.styles.color || '',
  50034. collapsed: collapsed,
  50035. group: label.parentGroup,
  50036. options: symbolOptions,
  50037. renderer: label.renderer,
  50038. show: shouldRender,
  50039. xy: label.xy
  50040. });
  50041. // Add class name for the node.
  50042. addClassName = prefixClassName +
  50043. (collapsed ? 'collapsed' : 'expanded');
  50044. removeClassName = prefixClassName +
  50045. (collapsed ? 'expanded' : 'collapsed');
  50046. label
  50047. .addClass(addClassName)
  50048. .removeClass(removeClassName);
  50049. if (!styledMode) {
  50050. label.css({
  50051. cursor: 'pointer'
  50052. });
  50053. }
  50054. // Add events to both label text and icon
  50055. [label, tick.treeGrid.labelIcon].forEach(function (object) {
  50056. if (object && !object.attachedTreeGridEvents) {
  50057. // On hover
  50058. addEvent(object.element, 'mouseover', function () {
  50059. onTickHover(label);
  50060. });
  50061. // On hover out
  50062. addEvent(object.element, 'mouseout', function () {
  50063. onTickHoverExit(label, labelOptions);
  50064. });
  50065. addEvent(object.element, 'click', function () {
  50066. tick.treeGrid.toggleCollapse();
  50067. });
  50068. object.attachedTreeGridEvents = true;
  50069. }
  50070. });
  50071. }
  50072. }
  50073. /* *
  50074. *
  50075. * Classes
  50076. *
  50077. * */
  50078. /**
  50079. * @private
  50080. * @class
  50081. */
  50082. var Additions = /** @class */ (function () {
  50083. /* *
  50084. *
  50085. * Constructors
  50086. *
  50087. * */
  50088. /**
  50089. * @private
  50090. */
  50091. function Additions(tick) {
  50092. this.tick = tick;
  50093. }
  50094. /* *
  50095. *
  50096. * Functions
  50097. *
  50098. * */
  50099. /**
  50100. * Collapse the grid cell. Used when axis is of type treegrid.
  50101. *
  50102. * @see gantt/treegrid-axis/collapsed-dynamically/demo.js
  50103. *
  50104. * @private
  50105. * @function Highcharts.Tick#collapse
  50106. *
  50107. * @param {boolean} [redraw=true]
  50108. * Whether to redraw the chart or wait for an explicit call to
  50109. * {@link Highcharts.Chart#redraw}
  50110. */
  50111. Additions.prototype.collapse = function (redraw) {
  50112. var tick = this.tick,
  50113. axis = tick.axis,
  50114. brokenAxis = axis.brokenAxis;
  50115. if (brokenAxis &&
  50116. axis.treeGrid.mapOfPosToGridNode) {
  50117. var pos = tick.pos,
  50118. node = axis.treeGrid.mapOfPosToGridNode[pos],
  50119. breaks = axis.treeGrid.collapse(node);
  50120. brokenAxis.setBreaks(breaks, pick(redraw, true));
  50121. }
  50122. };
  50123. /**
  50124. * Expand the grid cell. Used when axis is of type treegrid.
  50125. *
  50126. * @see gantt/treegrid-axis/collapsed-dynamically/demo.js
  50127. *
  50128. * @private
  50129. * @function Highcharts.Tick#expand
  50130. *
  50131. * @param {boolean} [redraw=true]
  50132. * Whether to redraw the chart or wait for an explicit call to
  50133. * {@link Highcharts.Chart#redraw}
  50134. */
  50135. Additions.prototype.expand = function (redraw) {
  50136. var tick = this.tick,
  50137. axis = tick.axis,
  50138. brokenAxis = axis.brokenAxis;
  50139. if (brokenAxis &&
  50140. axis.treeGrid.mapOfPosToGridNode) {
  50141. var pos = tick.pos,
  50142. node = axis.treeGrid.mapOfPosToGridNode[pos],
  50143. breaks = axis.treeGrid.expand(node);
  50144. brokenAxis.setBreaks(breaks, pick(redraw, true));
  50145. }
  50146. };
  50147. /**
  50148. * Toggle the collapse/expand state of the grid cell. Used when axis is
  50149. * of type treegrid.
  50150. *
  50151. * @see gantt/treegrid-axis/collapsed-dynamically/demo.js
  50152. *
  50153. * @private
  50154. * @function Highcharts.Tick#toggleCollapse
  50155. *
  50156. * @param {boolean} [redraw=true]
  50157. * Whether to redraw the chart or wait for an explicit call to
  50158. * {@link Highcharts.Chart#redraw}
  50159. */
  50160. Additions.prototype.toggleCollapse = function (redraw) {
  50161. var tick = this.tick,
  50162. axis = tick.axis,
  50163. brokenAxis = axis.brokenAxis;
  50164. if (brokenAxis &&
  50165. axis.treeGrid.mapOfPosToGridNode) {
  50166. var pos = tick.pos,
  50167. node = axis.treeGrid.mapOfPosToGridNode[pos],
  50168. breaks = axis.treeGrid.toggleCollapse(node);
  50169. brokenAxis.setBreaks(breaks, pick(redraw, true));
  50170. }
  50171. };
  50172. return Additions;
  50173. }());
  50174. TreeGridTick.Additions = Additions;
  50175. })(TreeGridTick || (TreeGridTick = {}));
  50176. return TreeGridTick;
  50177. });
  50178. _registerModule(_modules, 'Mixins/TreeSeries.js', [_modules['Core/Color/Color.js'], _modules['Core/Utilities.js']], function (Color, U) {
  50179. /* *
  50180. *
  50181. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  50182. *
  50183. * */
  50184. var extend = U.extend,
  50185. isArray = U.isArray,
  50186. isNumber = U.isNumber,
  50187. isObject = U.isObject,
  50188. merge = U.merge,
  50189. pick = U.pick;
  50190. var isBoolean = function (x) {
  50191. return typeof x === 'boolean';
  50192. }, isFn = function (x) {
  50193. return typeof x === 'function';
  50194. };
  50195. /* eslint-disable valid-jsdoc */
  50196. /**
  50197. * @todo Combine buildTree and buildNode with setTreeValues
  50198. * @todo Remove logic from Treemap and make it utilize this mixin.
  50199. * @private
  50200. */
  50201. var setTreeValues = function setTreeValues(tree,
  50202. options) {
  50203. var before = options.before,
  50204. idRoot = options.idRoot,
  50205. mapIdToNode = options.mapIdToNode,
  50206. nodeRoot = mapIdToNode[idRoot],
  50207. levelIsConstant = (isBoolean(options.levelIsConstant) ?
  50208. options.levelIsConstant :
  50209. true),
  50210. points = options.points,
  50211. point = points[tree.i],
  50212. optionsPoint = point && point.options || {},
  50213. childrenTotal = 0,
  50214. children = [],
  50215. value;
  50216. tree.levelDynamic = tree.level - (levelIsConstant ? 0 : nodeRoot.level);
  50217. tree.name = pick(point && point.name, '');
  50218. tree.visible = (idRoot === tree.id ||
  50219. (isBoolean(options.visible) ? options.visible : false));
  50220. if (isFn(before)) {
  50221. tree = before(tree, options);
  50222. }
  50223. // First give the children some values
  50224. tree.children.forEach(function (child, i) {
  50225. var newOptions = extend({},
  50226. options);
  50227. extend(newOptions, {
  50228. index: i,
  50229. siblings: tree.children.length,
  50230. visible: tree.visible
  50231. });
  50232. child = setTreeValues(child, newOptions);
  50233. children.push(child);
  50234. if (child.visible) {
  50235. childrenTotal += child.val;
  50236. }
  50237. });
  50238. tree.visible = childrenTotal > 0 || tree.visible;
  50239. // Set the values
  50240. value = pick(optionsPoint.value, childrenTotal);
  50241. tree.children = children;
  50242. tree.childrenTotal = childrenTotal;
  50243. tree.isLeaf = tree.visible && !childrenTotal;
  50244. tree.val = value;
  50245. return tree;
  50246. };
  50247. /**
  50248. * @private
  50249. */
  50250. var getColor = function getColor(node,
  50251. options) {
  50252. var index = options.index,
  50253. mapOptionsToLevel = options.mapOptionsToLevel,
  50254. parentColor = options.parentColor,
  50255. parentColorIndex = options.parentColorIndex,
  50256. series = options.series,
  50257. colors = options.colors,
  50258. siblings = options.siblings,
  50259. points = series.points,
  50260. getColorByPoint,
  50261. chartOptionsChart = series.chart.options.chart,
  50262. point,
  50263. level,
  50264. colorByPoint,
  50265. colorIndexByPoint,
  50266. color,
  50267. colorIndex;
  50268. /**
  50269. * @private
  50270. */
  50271. function variation(color) {
  50272. var colorVariation = level && level.colorVariation;
  50273. if (colorVariation) {
  50274. if (colorVariation.key === 'brightness') {
  50275. return Color.parse(color).brighten(colorVariation.to * (index / siblings)).get();
  50276. }
  50277. }
  50278. return color;
  50279. }
  50280. if (node) {
  50281. point = points[node.i];
  50282. level = mapOptionsToLevel[node.level] || {};
  50283. getColorByPoint = point && level.colorByPoint;
  50284. if (getColorByPoint) {
  50285. colorIndexByPoint = point.index % (colors ?
  50286. colors.length :
  50287. chartOptionsChart.colorCount);
  50288. colorByPoint = colors && colors[colorIndexByPoint];
  50289. }
  50290. // Select either point color, level color or inherited color.
  50291. if (!series.chart.styledMode) {
  50292. color = pick(point && point.options.color, level && level.color, colorByPoint, parentColor && variation(parentColor), series.color);
  50293. }
  50294. colorIndex = pick(point && point.options.colorIndex, level && level.colorIndex, colorIndexByPoint, parentColorIndex, options.colorIndex);
  50295. }
  50296. return {
  50297. color: color,
  50298. colorIndex: colorIndex
  50299. };
  50300. };
  50301. /**
  50302. * Creates a map from level number to its given options.
  50303. *
  50304. * @private
  50305. * @function getLevelOptions
  50306. * @param {object} params
  50307. * Object containing parameters.
  50308. * - `defaults` Object containing default options. The default options
  50309. * are merged with the userOptions to get the final options for a
  50310. * specific level.
  50311. * - `from` The lowest level number.
  50312. * - `levels` User options from series.levels.
  50313. * - `to` The highest level number.
  50314. * @return {Highcharts.Dictionary<object>|null}
  50315. * Returns a map from level number to its given options.
  50316. */
  50317. var getLevelOptions = function getLevelOptions(params) {
  50318. var result = null,
  50319. defaults,
  50320. converted,
  50321. i,
  50322. from,
  50323. to,
  50324. levels;
  50325. if (isObject(params)) {
  50326. result = {};
  50327. from = isNumber(params.from) ? params.from : 1;
  50328. levels = params.levels;
  50329. converted = {};
  50330. defaults = isObject(params.defaults) ? params.defaults : {};
  50331. if (isArray(levels)) {
  50332. converted = levels.reduce(function (obj, item) {
  50333. var level,
  50334. levelIsConstant,
  50335. options;
  50336. if (isObject(item) && isNumber(item.level)) {
  50337. options = merge({}, item);
  50338. levelIsConstant = (isBoolean(options.levelIsConstant) ?
  50339. options.levelIsConstant :
  50340. defaults.levelIsConstant);
  50341. // Delete redundant properties.
  50342. delete options.levelIsConstant;
  50343. delete options.level;
  50344. // Calculate which level these options apply to.
  50345. level = item.level + (levelIsConstant ? 0 : from - 1);
  50346. if (isObject(obj[level])) {
  50347. extend(obj[level], options);
  50348. }
  50349. else {
  50350. obj[level] = options;
  50351. }
  50352. }
  50353. return obj;
  50354. }, {});
  50355. }
  50356. to = isNumber(params.to) ? params.to : 1;
  50357. for (i = 0; i <= to; i++) {
  50358. result[i] = merge({}, defaults, isObject(converted[i]) ? converted[i] : {});
  50359. }
  50360. }
  50361. return result;
  50362. };
  50363. /**
  50364. * Update the rootId property on the series. Also makes sure that it is
  50365. * accessible to exporting.
  50366. *
  50367. * @private
  50368. * @function updateRootId
  50369. *
  50370. * @param {object} series
  50371. * The series to operate on.
  50372. *
  50373. * @return {string}
  50374. * Returns the resulting rootId after update.
  50375. */
  50376. var updateRootId = function (series) {
  50377. var rootId,
  50378. options;
  50379. if (isObject(series)) {
  50380. // Get the series options.
  50381. options = isObject(series.options) ? series.options : {};
  50382. // Calculate the rootId.
  50383. rootId = pick(series.rootNode, options.rootId, '');
  50384. // Set rootId on series.userOptions to pick it up in exporting.
  50385. if (isObject(series.userOptions)) {
  50386. series.userOptions.rootId = rootId;
  50387. }
  50388. // Set rootId on series to pick it up on next update.
  50389. series.rootNode = rootId;
  50390. }
  50391. return rootId;
  50392. };
  50393. var result = {
  50394. getColor: getColor,
  50395. getLevelOptions: getLevelOptions,
  50396. setTreeValues: setTreeValues,
  50397. updateRootId: updateRootId
  50398. };
  50399. return result;
  50400. });
  50401. _registerModule(_modules, 'Core/Axis/TreeGridAxis.js', [_modules['Core/Axis/BrokenAxis.js'], _modules['Core/Axis/GridAxis.js'], _modules['Gantt/Tree.js'], _modules['Core/Axis/TreeGridTick.js'], _modules['Mixins/TreeSeries.js'], _modules['Core/Utilities.js']], function (BrokenAxis, GridAxis, Tree, TreeGridTick, mixinTreeSeries, U) {
  50402. /* *
  50403. *
  50404. * (c) 2016 Highsoft AS
  50405. * Authors: Jon Arild Nygard
  50406. *
  50407. * License: www.highcharts.com/license
  50408. *
  50409. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  50410. *
  50411. * */
  50412. var getLevelOptions = mixinTreeSeries.getLevelOptions;
  50413. var addEvent = U.addEvent,
  50414. find = U.find,
  50415. fireEvent = U.fireEvent,
  50416. isArray = U.isArray,
  50417. isObject = U.isObject,
  50418. isString = U.isString,
  50419. merge = U.merge,
  50420. pick = U.pick,
  50421. wrap = U.wrap;
  50422. /**
  50423. * @private
  50424. */
  50425. var TreeGridAxis;
  50426. (function (TreeGridAxis) {
  50427. /* *
  50428. *
  50429. * Declarations
  50430. *
  50431. * */
  50432. /* *
  50433. *
  50434. * Variables
  50435. *
  50436. * */
  50437. var TickConstructor;
  50438. /* *
  50439. *
  50440. * Functions
  50441. *
  50442. * */
  50443. /**
  50444. * @private
  50445. */
  50446. function compose(AxisClass, ChartClass, SeriesClass, TickClass) {
  50447. if (AxisClass.keepProps.indexOf('treeGrid') === -1) {
  50448. AxisClass.keepProps.push('treeGrid');
  50449. TickConstructor = TickClass;
  50450. wrap(AxisClass.prototype, 'generateTick', wrapGenerateTick);
  50451. wrap(AxisClass.prototype, 'init', wrapInit);
  50452. wrap(AxisClass.prototype, 'setTickInterval', wrapSetTickInterval);
  50453. // Make utility functions available for testing.
  50454. AxisClass.prototype.utils = {
  50455. getNode: Tree.getNode
  50456. };
  50457. GridAxis.compose(AxisClass, ChartClass, TickClass);
  50458. BrokenAxis.compose(AxisClass, SeriesClass);
  50459. TreeGridTick.compose(TickClass);
  50460. }
  50461. return AxisClass;
  50462. }
  50463. TreeGridAxis.compose = compose;
  50464. /**
  50465. * @private
  50466. */
  50467. function getBreakFromNode(node, max) {
  50468. var to = node.collapseEnd || 0;
  50469. var from = node.collapseStart || 0;
  50470. // In broken-axis, the axis.max is minimized until it is not within a
  50471. // break. Therefore, if break.to is larger than axis.max, the axis.to
  50472. // should not add the 0.5 axis.tickMarkOffset, to avoid adding a break
  50473. // larger than axis.max.
  50474. // TODO consider simplifying broken-axis and this might solve itself
  50475. if (to >= max) {
  50476. from -= 0.5;
  50477. }
  50478. return {
  50479. from: from,
  50480. to: to,
  50481. showPoints: false
  50482. };
  50483. }
  50484. /**
  50485. * Creates a tree structure of the data, and the treegrid. Calculates
  50486. * categories, and y-values of points based on the tree.
  50487. *
  50488. * @private
  50489. * @function getTreeGridFromData
  50490. *
  50491. * @param {Array<Highcharts.GanttPointOptions>} data
  50492. * All the data points to display in the axis.
  50493. *
  50494. * @param {boolean} uniqueNames
  50495. * Wether or not the data node with the same name should share grid cell. If
  50496. * true they do share cell. False by default.
  50497. *
  50498. * @param {number} numberOfSeries
  50499. *
  50500. * @return {object}
  50501. * Returns an object containing categories, mapOfIdToNode,
  50502. * mapOfPosToGridNode, and tree.
  50503. *
  50504. * @todo There should be only one point per line.
  50505. * @todo It should be optional to have one category per point, or merge
  50506. * cells
  50507. * @todo Add unit-tests.
  50508. */
  50509. function getTreeGridFromData(data, uniqueNames, numberOfSeries) {
  50510. var categories = [],
  50511. collapsedNodes = [],
  50512. mapOfIdToNode = {},
  50513. uniqueNamesEnabled = typeof uniqueNames === 'boolean' ? uniqueNames : false;
  50514. var mapOfPosToGridNode = {},
  50515. posIterator = -1;
  50516. // Build the tree from the series data.
  50517. var treeParams = {
  50518. // After the children has been created.
  50519. after: function (node) {
  50520. var gridNode = mapOfPosToGridNode[node.pos];
  50521. var height = 0,
  50522. descendants = 0;
  50523. gridNode.children.forEach(function (child) {
  50524. descendants += (child.descendants || 0) + 1;
  50525. height = Math.max((child.height || 0) + 1, height);
  50526. });
  50527. gridNode.descendants = descendants;
  50528. gridNode.height = height;
  50529. if (gridNode.collapsed) {
  50530. collapsedNodes.push(gridNode);
  50531. }
  50532. },
  50533. // Before the children has been created.
  50534. before: function (node) {
  50535. var data = isObject(node.data,
  50536. true) ? node.data : {},
  50537. name = isString(data.name) ? data.name : '',
  50538. parentNode = mapOfIdToNode[node.parent],
  50539. parentGridNode = (isObject(parentNode,
  50540. true) ?
  50541. mapOfPosToGridNode[parentNode.pos] :
  50542. null),
  50543. hasSameName = function (x) {
  50544. return x.name === name;
  50545. };
  50546. var gridNode,
  50547. pos;
  50548. // If not unique names, look for sibling node with the same name
  50549. if (uniqueNamesEnabled &&
  50550. isObject(parentGridNode, true) &&
  50551. !!(gridNode = find(parentGridNode.children, hasSameName))) {
  50552. // If there is a gridNode with the same name, reuse position
  50553. pos = gridNode.pos;
  50554. // Add data node to list of nodes in the grid node.
  50555. gridNode.nodes.push(node);
  50556. }
  50557. else {
  50558. // If it is a new grid node, increment position.
  50559. pos = posIterator++;
  50560. }
  50561. // Add new grid node to map.
  50562. if (!mapOfPosToGridNode[pos]) {
  50563. mapOfPosToGridNode[pos] = gridNode = {
  50564. depth: parentGridNode ? parentGridNode.depth + 1 : 0,
  50565. name: name,
  50566. id: data.id,
  50567. nodes: [node],
  50568. children: [],
  50569. pos: pos
  50570. };
  50571. // If not root, then add name to categories.
  50572. if (pos !== -1) {
  50573. categories.push(name);
  50574. }
  50575. // Add name to list of children.
  50576. if (isObject(parentGridNode, true)) {
  50577. parentGridNode.children.push(gridNode);
  50578. }
  50579. }
  50580. // Add data node to map
  50581. if (isString(node.id)) {
  50582. mapOfIdToNode[node.id] = node;
  50583. }
  50584. // If one of the points are collapsed, then start the grid node
  50585. // in collapsed state.
  50586. if (gridNode &&
  50587. data.collapsed === true) {
  50588. gridNode.collapsed = true;
  50589. }
  50590. // Assign pos to data node
  50591. node.pos = pos;
  50592. }
  50593. };
  50594. var updateYValuesAndTickPos = function (map,
  50595. numberOfSeries) {
  50596. var setValues = function (gridNode,
  50597. start,
  50598. result) {
  50599. var nodes = gridNode.nodes,
  50600. padding = 0.5;
  50601. var end = start + (start === -1 ? 0 : numberOfSeries - 1);
  50602. var diff = (end - start) / 2,
  50603. pos = start + diff;
  50604. nodes.forEach(function (node) {
  50605. var data = node.data;
  50606. if (isObject(data, true)) {
  50607. // Update point
  50608. data.y = start + (data.seriesIndex || 0);
  50609. // Remove the property once used
  50610. delete data.seriesIndex;
  50611. }
  50612. node.pos = pos;
  50613. });
  50614. result[pos] = gridNode;
  50615. gridNode.pos = pos;
  50616. gridNode.tickmarkOffset = diff + padding;
  50617. gridNode.collapseStart = end + padding;
  50618. gridNode.children.forEach(function (child) {
  50619. setValues(child, end + 1, result);
  50620. end = (child.collapseEnd || 0) - padding;
  50621. });
  50622. // Set collapseEnd to the end of the last child node.
  50623. gridNode.collapseEnd = end + padding;
  50624. return result;
  50625. };
  50626. return setValues(map['-1'], -1, {});
  50627. };
  50628. // Create tree from data
  50629. var tree = Tree.getTree(data,
  50630. treeParams);
  50631. // Update y values of data, and set calculate tick positions.
  50632. mapOfPosToGridNode = updateYValuesAndTickPos(mapOfPosToGridNode, numberOfSeries);
  50633. // Return the resulting data.
  50634. return {
  50635. categories: categories,
  50636. mapOfIdToNode: mapOfIdToNode,
  50637. mapOfPosToGridNode: mapOfPosToGridNode,
  50638. collapsedNodes: collapsedNodes,
  50639. tree: tree
  50640. };
  50641. }
  50642. /**
  50643. * Builds the tree of categories and calculates its positions.
  50644. * @private
  50645. * @param {object} e Event object
  50646. * @param {object} e.target The chart instance which the event was fired on.
  50647. * @param {object[]} e.target.axes The axes of the chart.
  50648. */
  50649. function onBeforeRender(e) {
  50650. var chart = e.target,
  50651. axes = chart.axes;
  50652. axes.filter(function (axis) {
  50653. return axis.options.type === 'treegrid';
  50654. }).forEach(function (axis) {
  50655. var options = axis.options || {},
  50656. labelOptions = options.labels,
  50657. uniqueNames = options.uniqueNames,
  50658. max = options.max,
  50659. // Check whether any of series is rendering for the first
  50660. // time, visibility has changed, or its data is dirty, and
  50661. // only then update. #10570, #10580
  50662. // Also check if mapOfPosToGridNode exists. #10887
  50663. isDirty = (!axis.treeGrid.mapOfPosToGridNode ||
  50664. axis.series.some(function (series) {
  50665. return !series.hasRendered ||
  50666. series.isDirtyData ||
  50667. series.isDirty;
  50668. }));
  50669. var numberOfSeries = 0,
  50670. data,
  50671. treeGrid;
  50672. if (isDirty) {
  50673. // Concatenate data from all series assigned to this axis.
  50674. data = axis.series.reduce(function (arr, s) {
  50675. if (s.visible) {
  50676. // Push all data to array
  50677. (s.options.data || []).forEach(function (data) {
  50678. // For using keys - rebuild the data structure
  50679. if (s.options.keys && s.options.keys.length) {
  50680. data = s.pointClass.prototype.optionsToObject.call({ series: s }, data);
  50681. s.pointClass.setGanttPointAliases(data);
  50682. }
  50683. if (isObject(data, true)) {
  50684. // Set series index on data. Removed again
  50685. // after use.
  50686. data.seriesIndex = numberOfSeries;
  50687. arr.push(data);
  50688. }
  50689. });
  50690. // Increment series index
  50691. if (uniqueNames === true) {
  50692. numberOfSeries++;
  50693. }
  50694. }
  50695. return arr;
  50696. }, []);
  50697. // If max is higher than set data - add a
  50698. // dummy data to render categories #10779
  50699. if (max && data.length < max) {
  50700. for (var i = data.length; i <= max; i++) {
  50701. data.push({
  50702. // Use the zero-width character
  50703. // to avoid conflict with uniqueNames
  50704. name: i + '\u200B'
  50705. });
  50706. }
  50707. }
  50708. // setScale is fired after all the series is initialized,
  50709. // which is an ideal time to update the axis.categories.
  50710. treeGrid = getTreeGridFromData(data, uniqueNames || false, (uniqueNames === true) ? numberOfSeries : 1);
  50711. // Assign values to the axis.
  50712. axis.categories = treeGrid.categories;
  50713. axis.treeGrid.mapOfPosToGridNode = treeGrid.mapOfPosToGridNode;
  50714. axis.hasNames = true;
  50715. axis.treeGrid.tree = treeGrid.tree;
  50716. // Update yData now that we have calculated the y values
  50717. axis.series.forEach(function (series) {
  50718. var axisData = (series.options.data || []).map(function (d) {
  50719. if (isArray(d) && series.options.keys && series.options.keys.length) {
  50720. // Get the axisData from the data array used to
  50721. // build the treeGrid where has been modified
  50722. data.forEach(function (point) {
  50723. if (d.indexOf(point.x) >= 0 && d.indexOf(point.x2) >= 0) {
  50724. d = point;
  50725. }
  50726. });
  50727. }
  50728. return isObject(d, true) ? merge(d) : d;
  50729. });
  50730. // Avoid destroying points when series is not visible
  50731. if (series.visible) {
  50732. series.setData(axisData, false);
  50733. }
  50734. });
  50735. // Calculate the label options for each level in the tree.
  50736. axis.treeGrid.mapOptionsToLevel =
  50737. getLevelOptions({
  50738. defaults: labelOptions,
  50739. from: 1,
  50740. levels: labelOptions && labelOptions.levels,
  50741. to: axis.treeGrid.tree && axis.treeGrid.tree.height
  50742. });
  50743. // Setting initial collapsed nodes
  50744. if (e.type === 'beforeRender') {
  50745. axis.treeGrid.collapsedNodes = treeGrid.collapsedNodes;
  50746. }
  50747. }
  50748. });
  50749. }
  50750. /**
  50751. * Generates a tick for initial positioning.
  50752. *
  50753. * @private
  50754. * @function Highcharts.GridAxis#generateTick
  50755. *
  50756. * @param {Function} proceed
  50757. * The original generateTick function.
  50758. *
  50759. * @param {number} pos
  50760. * The tick position in axis values.
  50761. */
  50762. function wrapGenerateTick(proceed, pos) {
  50763. var axis = this,
  50764. mapOptionsToLevel = axis.treeGrid.mapOptionsToLevel || {},
  50765. isTreeGrid = axis.options.type === 'treegrid',
  50766. ticks = axis.ticks;
  50767. var tick = ticks[pos],
  50768. levelOptions,
  50769. options,
  50770. gridNode;
  50771. if (isTreeGrid &&
  50772. axis.treeGrid.mapOfPosToGridNode) {
  50773. gridNode = axis.treeGrid.mapOfPosToGridNode[pos];
  50774. levelOptions = mapOptionsToLevel[gridNode.depth];
  50775. if (levelOptions) {
  50776. options = {
  50777. labels: levelOptions
  50778. };
  50779. }
  50780. if (!tick &&
  50781. TickConstructor) {
  50782. ticks[pos] = tick =
  50783. new TickConstructor(axis, pos, void 0, void 0, {
  50784. category: gridNode.name,
  50785. tickmarkOffset: gridNode.tickmarkOffset,
  50786. options: options
  50787. });
  50788. }
  50789. else {
  50790. // update labels depending on tick interval
  50791. tick.parameters.category = gridNode.name;
  50792. tick.options = options;
  50793. tick.addLabel();
  50794. }
  50795. }
  50796. else {
  50797. proceed.apply(axis, Array.prototype.slice.call(arguments, 1));
  50798. }
  50799. }
  50800. /**
  50801. * @private
  50802. */
  50803. function wrapInit(proceed, chart, userOptions) {
  50804. var axis = this,
  50805. isTreeGrid = userOptions.type === 'treegrid';
  50806. if (!axis.treeGrid) {
  50807. axis.treeGrid = new Additions(axis);
  50808. }
  50809. // Set default and forced options for TreeGrid
  50810. if (isTreeGrid) {
  50811. // Add event for updating the categories of a treegrid.
  50812. // NOTE Preferably these events should be set on the axis.
  50813. addEvent(chart, 'beforeRender', onBeforeRender);
  50814. addEvent(chart, 'beforeRedraw', onBeforeRender);
  50815. // Add new collapsed nodes on addseries
  50816. addEvent(chart, 'addSeries', function (e) {
  50817. if (e.options.data) {
  50818. var treeGrid = getTreeGridFromData(e.options.data,
  50819. userOptions.uniqueNames || false, 1);
  50820. axis.treeGrid.collapsedNodes = (axis.treeGrid.collapsedNodes || []).concat(treeGrid.collapsedNodes);
  50821. }
  50822. });
  50823. // Collapse all nodes in axis.treegrid.collapsednodes
  50824. // where collapsed equals true.
  50825. addEvent(axis, 'foundExtremes', function () {
  50826. if (axis.treeGrid.collapsedNodes) {
  50827. axis.treeGrid.collapsedNodes.forEach(function (node) {
  50828. var breaks = axis.treeGrid.collapse(node);
  50829. if (axis.brokenAxis) {
  50830. axis.brokenAxis.setBreaks(breaks, false);
  50831. // remove the node from the axis collapsedNodes
  50832. if (axis.treeGrid.collapsedNodes) {
  50833. axis.treeGrid.collapsedNodes = axis.treeGrid.collapsedNodes.filter(function (n) {
  50834. return node.collapseStart !== n.collapseStart ||
  50835. node.collapseEnd !== n.collapseEnd;
  50836. });
  50837. }
  50838. }
  50839. });
  50840. }
  50841. });
  50842. // If staticScale is not defined on the yAxis
  50843. // and chart height is set, set axis.isDirty
  50844. // to ensure collapsing works (#12012)
  50845. addEvent(axis, 'afterBreaks', function () {
  50846. if (axis.coll === 'yAxis' &&
  50847. !axis.staticScale &&
  50848. axis.chart.options.chart.height) {
  50849. axis.isDirty = true;
  50850. }
  50851. });
  50852. userOptions = merge({
  50853. // Default options
  50854. grid: {
  50855. enabled: true
  50856. },
  50857. // TODO: add support for align in treegrid.
  50858. labels: {
  50859. align: 'left',
  50860. /**
  50861. * Set options on specific levels in a tree grid axis. Takes
  50862. * precedence over labels options.
  50863. *
  50864. * @sample {gantt} gantt/treegrid-axis/labels-levels
  50865. * Levels on TreeGrid Labels
  50866. *
  50867. * @type {Array<*>}
  50868. * @product gantt
  50869. * @apioption yAxis.labels.levels
  50870. *
  50871. * @private
  50872. */
  50873. levels: [{
  50874. /**
  50875. * Specify the level which the options within this object
  50876. * applies to.
  50877. *
  50878. * @type {number}
  50879. * @product gantt
  50880. * @apioption yAxis.labels.levels.level
  50881. *
  50882. * @private
  50883. */
  50884. level: void 0
  50885. }, {
  50886. level: 1,
  50887. /**
  50888. * @type {Highcharts.CSSObject}
  50889. * @product gantt
  50890. * @apioption yAxis.labels.levels.style
  50891. *
  50892. * @private
  50893. */
  50894. style: {
  50895. /** @ignore-option */
  50896. fontWeight: 'bold'
  50897. }
  50898. }],
  50899. /**
  50900. * The symbol for the collapse and expand icon in a
  50901. * treegrid.
  50902. *
  50903. * @product gantt
  50904. * @optionparent yAxis.labels.symbol
  50905. *
  50906. * @private
  50907. */
  50908. symbol: {
  50909. /**
  50910. * The symbol type. Points to a definition function in
  50911. * the `Highcharts.Renderer.symbols` collection.
  50912. *
  50913. * @type {Highcharts.SymbolKeyValue}
  50914. *
  50915. * @private
  50916. */
  50917. type: 'triangle',
  50918. x: -5,
  50919. y: -5,
  50920. height: 10,
  50921. width: 10,
  50922. padding: 5
  50923. }
  50924. },
  50925. uniqueNames: false
  50926. }, userOptions, {
  50927. // Forced options
  50928. reversed: true,
  50929. // grid.columns is not supported in treegrid
  50930. grid: {
  50931. columns: void 0
  50932. }
  50933. });
  50934. }
  50935. // Now apply the original function with the original arguments,
  50936. // which are sliced off this function's arguments
  50937. proceed.apply(axis, [chart, userOptions]);
  50938. if (isTreeGrid) {
  50939. axis.hasNames = true;
  50940. axis.options.showLastLabel = true;
  50941. }
  50942. }
  50943. /**
  50944. * Set the tick positions, tickInterval, axis min and max.
  50945. *
  50946. * @private
  50947. * @function Highcharts.GridAxis#setTickInterval
  50948. *
  50949. * @param {Function} proceed
  50950. * The original setTickInterval function.
  50951. */
  50952. function wrapSetTickInterval(proceed) {
  50953. var axis = this,
  50954. options = axis.options,
  50955. isTreeGrid = options.type === 'treegrid';
  50956. if (isTreeGrid) {
  50957. axis.min = pick(axis.userMin, options.min, axis.dataMin);
  50958. axis.max = pick(axis.userMax, options.max, axis.dataMax);
  50959. fireEvent(axis, 'foundExtremes');
  50960. // setAxisTranslation modifies the min and max according to
  50961. // axis breaks.
  50962. axis.setAxisTranslation();
  50963. axis.tickmarkOffset = 0.5;
  50964. axis.tickInterval = 1;
  50965. axis.tickPositions = axis.treeGrid.mapOfPosToGridNode ?
  50966. axis.treeGrid.getTickPositions() :
  50967. [];
  50968. }
  50969. else {
  50970. proceed.apply(axis, Array.prototype.slice.call(arguments, 1));
  50971. }
  50972. }
  50973. /* *
  50974. *
  50975. * Classes
  50976. *
  50977. * */
  50978. /**
  50979. * @private
  50980. * @class
  50981. */
  50982. var Additions = /** @class */ (function () {
  50983. /* *
  50984. *
  50985. * Constructors
  50986. *
  50987. * */
  50988. /**
  50989. * @private
  50990. */
  50991. function Additions(axis) {
  50992. this.axis = axis;
  50993. }
  50994. /* *
  50995. *
  50996. * Functions
  50997. *
  50998. * */
  50999. /**
  51000. * Set the collapse status.
  51001. *
  51002. * @private
  51003. *
  51004. * @param {Highcharts.Axis} axis
  51005. * The axis to check against.
  51006. *
  51007. * @param {Highcharts.GridNode} node
  51008. * The node to collapse.
  51009. */
  51010. Additions.prototype.setCollapsedStatus = function (node) {
  51011. var axis = this.axis,
  51012. chart = axis.chart;
  51013. axis.series.forEach(function (series) {
  51014. var data = series.options.data;
  51015. if (node.id && data) {
  51016. var point = chart.get(node.id),
  51017. dataPoint = data[series.data.indexOf(point)];
  51018. if (point && dataPoint) {
  51019. point.collapsed = node.collapsed;
  51020. dataPoint.collapsed = node.collapsed;
  51021. }
  51022. }
  51023. });
  51024. };
  51025. /**
  51026. * Calculates the new axis breaks to collapse a node.
  51027. *
  51028. * @private
  51029. *
  51030. * @param {Highcharts.Axis} axis
  51031. * The axis to check against.
  51032. *
  51033. * @param {Highcharts.GridNode} node
  51034. * The node to collapse.
  51035. *
  51036. * @param {number} pos
  51037. * The tick position to collapse.
  51038. *
  51039. * @return {Array<object>}
  51040. * Returns an array of the new breaks for the axis.
  51041. */
  51042. Additions.prototype.collapse = function (node) {
  51043. var axis = this.axis,
  51044. breaks = (axis.options.breaks || []),
  51045. obj = getBreakFromNode(node,
  51046. axis.max);
  51047. breaks.push(obj);
  51048. // Change the collapsed flag #13838
  51049. node.collapsed = true;
  51050. axis.treeGrid.setCollapsedStatus(node);
  51051. return breaks;
  51052. };
  51053. /**
  51054. * Calculates the new axis breaks to expand a node.
  51055. *
  51056. * @private
  51057. *
  51058. * @param {Highcharts.Axis} axis
  51059. * The axis to check against.
  51060. *
  51061. * @param {Highcharts.GridNode} node
  51062. * The node to expand.
  51063. *
  51064. * @param {number} pos
  51065. * The tick position to expand.
  51066. *
  51067. * @return {Array<object>}
  51068. * Returns an array of the new breaks for the axis.
  51069. */
  51070. Additions.prototype.expand = function (node) {
  51071. var axis = this.axis,
  51072. breaks = (axis.options.breaks || []),
  51073. obj = getBreakFromNode(node,
  51074. axis.max);
  51075. // Change the collapsed flag #13838
  51076. node.collapsed = false;
  51077. axis.treeGrid.setCollapsedStatus(node);
  51078. // Remove the break from the axis breaks array.
  51079. return breaks.reduce(function (arr, b) {
  51080. if (b.to !== obj.to || b.from !== obj.from) {
  51081. arr.push(b);
  51082. }
  51083. return arr;
  51084. }, []);
  51085. };
  51086. /**
  51087. * Creates a list of positions for the ticks on the axis. Filters out
  51088. * positions that are outside min and max, or is inside an axis break.
  51089. *
  51090. * @private
  51091. *
  51092. * @return {Array<number>}
  51093. * List of positions.
  51094. */
  51095. Additions.prototype.getTickPositions = function () {
  51096. var axis = this.axis,
  51097. roundedMin = Math.floor(axis.min / axis.tickInterval) * axis.tickInterval,
  51098. roundedMax = Math.ceil(axis.max / axis.tickInterval) * axis.tickInterval;
  51099. return Object.keys(axis.treeGrid.mapOfPosToGridNode || {}).reduce(function (arr, key) {
  51100. var pos = +key;
  51101. if (pos >= roundedMin &&
  51102. pos <= roundedMax &&
  51103. !(axis.brokenAxis && axis.brokenAxis.isInAnyBreak(pos))) {
  51104. arr.push(pos);
  51105. }
  51106. return arr;
  51107. }, []);
  51108. };
  51109. /**
  51110. * Check if a node is collapsed.
  51111. *
  51112. * @private
  51113. *
  51114. * @param {Highcharts.Axis} axis
  51115. * The axis to check against.
  51116. *
  51117. * @param {object} node
  51118. * The node to check if is collapsed.
  51119. *
  51120. * @param {number} pos
  51121. * The tick position to collapse.
  51122. *
  51123. * @return {boolean}
  51124. * Returns true if collapsed, false if expanded.
  51125. */
  51126. Additions.prototype.isCollapsed = function (node) {
  51127. var axis = this.axis,
  51128. breaks = (axis.options.breaks || []),
  51129. obj = getBreakFromNode(node,
  51130. axis.max);
  51131. return breaks.some(function (b) {
  51132. return b.from === obj.from && b.to === obj.to;
  51133. });
  51134. };
  51135. /**
  51136. * Calculates the new axis breaks after toggling the collapse/expand
  51137. * state of a node. If it is collapsed it will be expanded, and if it is
  51138. * exapended it will be collapsed.
  51139. *
  51140. * @private
  51141. *
  51142. * @param {Highcharts.Axis} axis
  51143. * The axis to check against.
  51144. *
  51145. * @param {Highcharts.GridNode} node
  51146. * The node to toggle.
  51147. *
  51148. * @return {Array<object>}
  51149. * Returns an array of the new breaks for the axis.
  51150. */
  51151. Additions.prototype.toggleCollapse = function (node) {
  51152. return (this.isCollapsed(node) ?
  51153. this.expand(node) :
  51154. this.collapse(node));
  51155. };
  51156. return Additions;
  51157. }());
  51158. TreeGridAxis.Additions = Additions;
  51159. })(TreeGridAxis || (TreeGridAxis = {}));
  51160. return TreeGridAxis;
  51161. });
  51162. _registerModule(_modules, 'Extensions/CurrentDateIndication.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Color/Palette.js'], _modules['Core/Axis/PlotLineOrBand.js'], _modules['Core/Utilities.js']], function (Axis, Palette, PlotLineOrBand, U) {
  51163. /* *
  51164. *
  51165. * (c) 2016-2021 Highsoft AS
  51166. *
  51167. * Author: Lars A. V. Cabrera
  51168. *
  51169. * License: www.highcharts.com/license
  51170. *
  51171. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  51172. *
  51173. * */
  51174. var addEvent = U.addEvent,
  51175. merge = U.merge,
  51176. wrap = U.wrap;
  51177. /**
  51178. * Show an indicator on the axis for the current date and time. Can be a
  51179. * boolean or a configuration object similar to
  51180. * [xAxis.plotLines](#xAxis.plotLines).
  51181. *
  51182. * @sample gantt/current-date-indicator/demo
  51183. * Current date indicator enabled
  51184. * @sample gantt/current-date-indicator/object-config
  51185. * Current date indicator with custom options
  51186. *
  51187. * @declare Highcharts.CurrentDateIndicatorOptions
  51188. * @type {boolean|CurrentDateIndicatorOptions}
  51189. * @default true
  51190. * @extends xAxis.plotLines
  51191. * @excluding value
  51192. * @product gantt
  51193. * @apioption xAxis.currentDateIndicator
  51194. */
  51195. var defaultOptions = {
  51196. color: Palette.highlightColor20,
  51197. width: 2,
  51198. /**
  51199. * @declare Highcharts.AxisCurrentDateIndicatorLabelOptions
  51200. */
  51201. label: {
  51202. /**
  51203. * Format of the label. This options is passed as the fist argument to
  51204. * [dateFormat](/class-reference/Highcharts#.dateFormat) function.
  51205. *
  51206. * @type {string}
  51207. * @default %a, %b %d %Y, %H:%M
  51208. * @product gantt
  51209. * @apioption xAxis.currentDateIndicator.label.format
  51210. */
  51211. format: '%a, %b %d %Y, %H:%M',
  51212. formatter: function (value, format) {
  51213. return this.axis.chart.time.dateFormat(format || '', value);
  51214. },
  51215. rotation: 0,
  51216. /**
  51217. * @type {Highcharts.CSSObject}
  51218. */
  51219. style: {
  51220. /** @internal */
  51221. fontSize: '10px'
  51222. }
  51223. }
  51224. };
  51225. /* eslint-disable no-invalid-this */
  51226. addEvent(Axis, 'afterSetOptions', function () {
  51227. var options = this.options,
  51228. cdiOptions = options.currentDateIndicator;
  51229. if (cdiOptions) {
  51230. var plotLineOptions = typeof cdiOptions === 'object' ?
  51231. merge(defaultOptions,
  51232. cdiOptions) :
  51233. merge(defaultOptions);
  51234. plotLineOptions.value = Date.now();
  51235. plotLineOptions.className = 'highcharts-current-date-indicator';
  51236. if (!options.plotLines) {
  51237. options.plotLines = [];
  51238. }
  51239. options.plotLines.push(plotLineOptions);
  51240. }
  51241. });
  51242. addEvent(PlotLineOrBand, 'render', function () {
  51243. // If the label already exists, update its text
  51244. if (this.label) {
  51245. this.label.attr({
  51246. text: this.getLabelText(this.options.label)
  51247. });
  51248. }
  51249. });
  51250. wrap(PlotLineOrBand.prototype, 'getLabelText', function (defaultMethod, defaultLabelOptions) {
  51251. var options = this.options;
  51252. if (options &&
  51253. options.className &&
  51254. options.className.indexOf('highcharts-current-date-indicator') !== -1 &&
  51255. options.label &&
  51256. typeof options.label.formatter === 'function') {
  51257. options.value = Date.now();
  51258. return options.label.formatter
  51259. .call(this, options.value, options.label.format);
  51260. }
  51261. return defaultMethod.call(this, defaultLabelOptions);
  51262. });
  51263. });
  51264. _registerModule(_modules, 'Extensions/StaticScale.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Chart/Chart.js'], _modules['Core/Utilities.js']], function (Axis, Chart, U) {
  51265. /* *
  51266. *
  51267. * (c) 2016-2021 Torstein Honsi, Lars Cabrera
  51268. *
  51269. * License: www.highcharts.com/license
  51270. *
  51271. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  51272. *
  51273. * */
  51274. var addEvent = U.addEvent,
  51275. defined = U.defined,
  51276. isNumber = U.isNumber,
  51277. pick = U.pick;
  51278. /* eslint-disable no-invalid-this */
  51279. /**
  51280. * For vertical axes only. Setting the static scale ensures that each tick unit
  51281. * is translated into a fixed pixel height. For example, setting the static
  51282. * scale to 24 results in each Y axis category taking up 24 pixels, and the
  51283. * height of the chart adjusts. Adding or removing items will make the chart
  51284. * resize.
  51285. *
  51286. * @sample gantt/xrange-series/demo/
  51287. * X-range series with static scale
  51288. *
  51289. * @type {number}
  51290. * @default 50
  51291. * @since 6.2.0
  51292. * @product gantt
  51293. * @apioption yAxis.staticScale
  51294. */
  51295. addEvent(Axis, 'afterSetOptions', function () {
  51296. var chartOptions = this.chart.options.chart;
  51297. if (!this.horiz &&
  51298. isNumber(this.options.staticScale) &&
  51299. (!chartOptions.height ||
  51300. (chartOptions.scrollablePlotArea &&
  51301. chartOptions.scrollablePlotArea.minHeight))) {
  51302. this.staticScale = this.options.staticScale;
  51303. }
  51304. });
  51305. Chart.prototype.adjustHeight = function () {
  51306. if (this.redrawTrigger !== 'adjustHeight') {
  51307. (this.axes || []).forEach(function (axis) {
  51308. var chart = axis.chart,
  51309. animate = !!chart.initiatedScale &&
  51310. chart.options.animation,
  51311. staticScale = axis.options.staticScale,
  51312. height,
  51313. diff;
  51314. if (axis.staticScale && defined(axis.min)) {
  51315. height = pick(axis.brokenAxis && axis.brokenAxis.unitLength, axis.max + axis.tickInterval - axis.min) * staticScale;
  51316. // Minimum height is 1 x staticScale.
  51317. height = Math.max(height, staticScale);
  51318. diff = height - chart.plotHeight;
  51319. if (!chart.scrollablePixelsY && Math.abs(diff) >= 1) {
  51320. chart.plotHeight = height;
  51321. chart.redrawTrigger = 'adjustHeight';
  51322. chart.setSize(void 0, chart.chartHeight + diff, animate);
  51323. }
  51324. // Make sure clip rects have the right height before initial
  51325. // animation.
  51326. axis.series.forEach(function (series) {
  51327. var clipRect = series.sharedClipKey &&
  51328. chart.sharedClips[series.sharedClipKey];
  51329. if (clipRect) {
  51330. clipRect.attr(chart.inverted ? {
  51331. width: chart.plotHeight
  51332. } : {
  51333. height: chart.plotHeight
  51334. });
  51335. }
  51336. });
  51337. }
  51338. });
  51339. this.initiatedScale = true;
  51340. }
  51341. this.redrawTrigger = null;
  51342. };
  51343. addEvent(Chart, 'render', Chart.prototype.adjustHeight);
  51344. });
  51345. _registerModule(_modules, 'Extensions/ArrowSymbols.js', [_modules['Core/Renderer/SVG/SVGRenderer.js']], function (SVGRenderer) {
  51346. /* *
  51347. *
  51348. * (c) 2017 Highsoft AS
  51349. * Authors: Lars A. V. Cabrera
  51350. *
  51351. * License: www.highcharts.com/license
  51352. *
  51353. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  51354. *
  51355. * */
  51356. var symbols = SVGRenderer.prototype.symbols;
  51357. /* *
  51358. *
  51359. * Functions
  51360. *
  51361. * */
  51362. /**
  51363. * Creates an arrow symbol. Like a triangle, except not filled.
  51364. * ```
  51365. * o
  51366. * o
  51367. * o
  51368. * o
  51369. * o
  51370. * o
  51371. * o
  51372. * ```
  51373. *
  51374. * @private
  51375. * @function
  51376. *
  51377. * @param {number} x
  51378. * x position of the arrow
  51379. *
  51380. * @param {number} y
  51381. * y position of the arrow
  51382. *
  51383. * @param {number} w
  51384. * width of the arrow
  51385. *
  51386. * @param {number} h
  51387. * height of the arrow
  51388. *
  51389. * @return {Highcharts.SVGPathArray}
  51390. * Path array
  51391. */
  51392. function arrow(x, y, w, h) {
  51393. return [
  51394. ['M', x, y + h / 2],
  51395. ['L', x + w, y],
  51396. ['L', x, y + h / 2],
  51397. ['L', x + w, y + h]
  51398. ];
  51399. }
  51400. /**
  51401. * Creates a half-width arrow symbol. Like a triangle, except not filled.
  51402. * ```
  51403. * o
  51404. * o
  51405. * o
  51406. * o
  51407. * o
  51408. * ```
  51409. *
  51410. * @private
  51411. * @function
  51412. *
  51413. * @param {number} x
  51414. * x position of the arrow
  51415. *
  51416. * @param {number} y
  51417. * y position of the arrow
  51418. *
  51419. * @param {number} w
  51420. * width of the arrow
  51421. *
  51422. * @param {number} h
  51423. * height of the arrow
  51424. *
  51425. * @return {Highcharts.SVGPathArray}
  51426. * Path array
  51427. */
  51428. function arrowHalf(x, y, w, h) {
  51429. return arrow(x, y, w / 2, h);
  51430. }
  51431. /**
  51432. * Creates a left-oriented triangle.
  51433. * ```
  51434. * o
  51435. * ooooooo
  51436. * ooooooooooooo
  51437. * ooooooo
  51438. * o
  51439. * ```
  51440. *
  51441. * @private
  51442. * @function
  51443. *
  51444. * @param {number} x
  51445. * x position of the triangle
  51446. *
  51447. * @param {number} y
  51448. * y position of the triangle
  51449. *
  51450. * @param {number} w
  51451. * width of the triangle
  51452. *
  51453. * @param {number} h
  51454. * height of the triangle
  51455. *
  51456. * @return {Highcharts.SVGPathArray}
  51457. * Path array
  51458. */
  51459. function triangleLeft(x, y, w, h) {
  51460. return [
  51461. ['M', x + w, y],
  51462. ['L', x, y + h / 2],
  51463. ['L', x + w, y + h],
  51464. ['Z']
  51465. ];
  51466. }
  51467. /**
  51468. * Creates a half-width, left-oriented triangle.
  51469. * ```
  51470. * o
  51471. * oooo
  51472. * ooooooo
  51473. * oooo
  51474. * o
  51475. * ```
  51476. *
  51477. * @private
  51478. * @function
  51479. *
  51480. * @param {number} x
  51481. * x position of the triangle
  51482. *
  51483. * @param {number} y
  51484. * y position of the triangle
  51485. *
  51486. * @param {number} w
  51487. * width of the triangle
  51488. *
  51489. * @param {number} h
  51490. * height of the triangle
  51491. *
  51492. * @return {Highcharts.SVGPathArray}
  51493. * Path array
  51494. */
  51495. function triangleLeftHalf(x, y, w, h) {
  51496. return triangleLeft(x, y, w / 2, h);
  51497. }
  51498. symbols.arrow = arrow;
  51499. symbols['arrow-filled'] = triangleLeft;
  51500. symbols['arrow-filled-half'] = triangleLeftHalf;
  51501. symbols['arrow-half'] = arrowHalf;
  51502. symbols['triangle-left'] = triangleLeft;
  51503. symbols['triangle-left-half'] = triangleLeftHalf;
  51504. /* *
  51505. *
  51506. * Default Export
  51507. *
  51508. * */
  51509. return symbols;
  51510. });
  51511. _registerModule(_modules, 'Gantt/Connection.js', [_modules['Core/Globals.js'], _modules['Core/DefaultOptions.js'], _modules['Core/Series/Point.js'], _modules['Core/Utilities.js']], function (H, D, Point, U) {
  51512. /* *
  51513. *
  51514. * (c) 2016 Highsoft AS
  51515. * Authors: Øystein Moseng, Lars A. V. Cabrera
  51516. *
  51517. * License: www.highcharts.com/license
  51518. *
  51519. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  51520. *
  51521. * */
  51522. /**
  51523. * The default pathfinder algorithm to use for a chart. It is possible to define
  51524. * your own algorithms by adding them to the
  51525. * `Highcharts.Pathfinder.prototype.algorithms`
  51526. * object before the chart has been created.
  51527. *
  51528. * The default algorithms are as follows:
  51529. *
  51530. * `straight`: Draws a straight line between the connecting
  51531. * points. Does not avoid other points when drawing.
  51532. *
  51533. * `simpleConnect`: Finds a path between the points using right angles
  51534. * only. Takes only starting/ending points into
  51535. * account, and will not avoid other points.
  51536. *
  51537. * `fastAvoid`: Finds a path between the points using right angles
  51538. * only. Will attempt to avoid other points, but its
  51539. * focus is performance over accuracy. Works well with
  51540. * less dense datasets.
  51541. *
  51542. * @typedef {"fastAvoid"|"simpleConnect"|"straight"|string} Highcharts.PathfinderTypeValue
  51543. */
  51544. ''; // detach doclets above
  51545. var defaultOptions = D.defaultOptions;
  51546. var addEvent = U.addEvent,
  51547. defined = U.defined,
  51548. error = U.error,
  51549. extend = U.extend,
  51550. merge = U.merge,
  51551. objectEach = U.objectEach,
  51552. pick = U.pick,
  51553. splat = U.splat;
  51554. var deg2rad = H.deg2rad,
  51555. max = Math.max,
  51556. min = Math.min;
  51557. /*
  51558. @todo:
  51559. - Document how to write your own algorithms
  51560. - Consider adding a Point.pathTo method that wraps creating a connection
  51561. and rendering it
  51562. */
  51563. // Set default Pathfinder options
  51564. extend(defaultOptions, {
  51565. /**
  51566. * The Pathfinder module allows you to define connections between any two
  51567. * points, represented as lines - optionally with markers for the start
  51568. * and/or end points. Multiple algorithms are available for calculating how
  51569. * the connecting lines are drawn.
  51570. *
  51571. * Connector functionality requires Highcharts Gantt to be loaded. In Gantt
  51572. * charts, the connectors are used to draw dependencies between tasks.
  51573. *
  51574. * @see [dependency](series.gantt.data.dependency)
  51575. *
  51576. * @sample gantt/pathfinder/demo
  51577. * Pathfinder connections
  51578. *
  51579. * @declare Highcharts.ConnectorsOptions
  51580. * @product gantt
  51581. * @optionparent connectors
  51582. */
  51583. connectors: {
  51584. /**
  51585. * Enable connectors for this chart. Requires Highcharts Gantt.
  51586. *
  51587. * @type {boolean}
  51588. * @default true
  51589. * @since 6.2.0
  51590. * @apioption connectors.enabled
  51591. */
  51592. /**
  51593. * Set the default dash style for this chart's connecting lines.
  51594. *
  51595. * @type {string}
  51596. * @default solid
  51597. * @since 6.2.0
  51598. * @apioption connectors.dashStyle
  51599. */
  51600. /**
  51601. * Set the default color for this chart's Pathfinder connecting lines.
  51602. * Defaults to the color of the point being connected.
  51603. *
  51604. * @type {Highcharts.ColorString}
  51605. * @since 6.2.0
  51606. * @apioption connectors.lineColor
  51607. */
  51608. /**
  51609. * Set the default pathfinder margin to use, in pixels. Some Pathfinder
  51610. * algorithms attempt to avoid obstacles, such as other points in the
  51611. * chart. These algorithms use this margin to determine how close lines
  51612. * can be to an obstacle. The default is to compute this automatically
  51613. * from the size of the obstacles in the chart.
  51614. *
  51615. * To draw connecting lines close to existing points, set this to a low
  51616. * number. For more space around existing points, set this number
  51617. * higher.
  51618. *
  51619. * @sample gantt/pathfinder/algorithm-margin
  51620. * Small algorithmMargin
  51621. *
  51622. * @type {number}
  51623. * @since 6.2.0
  51624. * @apioption connectors.algorithmMargin
  51625. */
  51626. /**
  51627. * Set the default pathfinder algorithm to use for this chart. It is
  51628. * possible to define your own algorithms by adding them to the
  51629. * Highcharts.Pathfinder.prototype.algorithms object before the chart
  51630. * has been created.
  51631. *
  51632. * The default algorithms are as follows:
  51633. *
  51634. * `straight`: Draws a straight line between the connecting
  51635. * points. Does not avoid other points when drawing.
  51636. *
  51637. * `simpleConnect`: Finds a path between the points using right angles
  51638. * only. Takes only starting/ending points into
  51639. * account, and will not avoid other points.
  51640. *
  51641. * `fastAvoid`: Finds a path between the points using right angles
  51642. * only. Will attempt to avoid other points, but its
  51643. * focus is performance over accuracy. Works well with
  51644. * less dense datasets.
  51645. *
  51646. * Default value: `straight` is used as default for most series types,
  51647. * while `simpleConnect` is used as default for Gantt series, to show
  51648. * dependencies between points.
  51649. *
  51650. * @sample gantt/pathfinder/demo
  51651. * Different types used
  51652. *
  51653. * @type {Highcharts.PathfinderTypeValue}
  51654. * @default undefined
  51655. * @since 6.2.0
  51656. */
  51657. type: 'straight',
  51658. /**
  51659. * Set the default pixel width for this chart's Pathfinder connecting
  51660. * lines.
  51661. *
  51662. * @since 6.2.0
  51663. */
  51664. lineWidth: 1,
  51665. /**
  51666. * Marker options for this chart's Pathfinder connectors. Note that
  51667. * this option is overridden by the `startMarker` and `endMarker`
  51668. * options.
  51669. *
  51670. * @declare Highcharts.ConnectorsMarkerOptions
  51671. * @since 6.2.0
  51672. */
  51673. marker: {
  51674. /**
  51675. * Set the radius of the connector markers. The default is
  51676. * automatically computed based on the algorithmMargin setting.
  51677. *
  51678. * Setting marker.width and marker.height will override this
  51679. * setting.
  51680. *
  51681. * @type {number}
  51682. * @since 6.2.0
  51683. * @apioption connectors.marker.radius
  51684. */
  51685. /**
  51686. * Set the width of the connector markers. If not supplied, this
  51687. * is inferred from the marker radius.
  51688. *
  51689. * @type {number}
  51690. * @since 6.2.0
  51691. * @apioption connectors.marker.width
  51692. */
  51693. /**
  51694. * Set the height of the connector markers. If not supplied, this
  51695. * is inferred from the marker radius.
  51696. *
  51697. * @type {number}
  51698. * @since 6.2.0
  51699. * @apioption connectors.marker.height
  51700. */
  51701. /**
  51702. * Set the color of the connector markers. By default this is the
  51703. * same as the connector color.
  51704. *
  51705. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  51706. * @since 6.2.0
  51707. * @apioption connectors.marker.color
  51708. */
  51709. /**
  51710. * Set the line/border color of the connector markers. By default
  51711. * this is the same as the marker color.
  51712. *
  51713. * @type {Highcharts.ColorString}
  51714. * @since 6.2.0
  51715. * @apioption connectors.marker.lineColor
  51716. */
  51717. /**
  51718. * Enable markers for the connectors.
  51719. */
  51720. enabled: false,
  51721. /**
  51722. * Horizontal alignment of the markers relative to the points.
  51723. *
  51724. * @type {Highcharts.AlignValue}
  51725. */
  51726. align: 'center',
  51727. /**
  51728. * Vertical alignment of the markers relative to the points.
  51729. *
  51730. * @type {Highcharts.VerticalAlignValue}
  51731. */
  51732. verticalAlign: 'middle',
  51733. /**
  51734. * Whether or not to draw the markers inside the points.
  51735. */
  51736. inside: false,
  51737. /**
  51738. * Set the line/border width of the pathfinder markers.
  51739. */
  51740. lineWidth: 1
  51741. },
  51742. /**
  51743. * Marker options specific to the start markers for this chart's
  51744. * Pathfinder connectors. Overrides the generic marker options.
  51745. *
  51746. * @declare Highcharts.ConnectorsStartMarkerOptions
  51747. * @extends connectors.marker
  51748. * @since 6.2.0
  51749. */
  51750. startMarker: {
  51751. /**
  51752. * Set the symbol of the connector start markers.
  51753. */
  51754. symbol: 'diamond'
  51755. },
  51756. /**
  51757. * Marker options specific to the end markers for this chart's
  51758. * Pathfinder connectors. Overrides the generic marker options.
  51759. *
  51760. * @declare Highcharts.ConnectorsEndMarkerOptions
  51761. * @extends connectors.marker
  51762. * @since 6.2.0
  51763. */
  51764. endMarker: {
  51765. /**
  51766. * Set the symbol of the connector end markers.
  51767. */
  51768. symbol: 'arrow-filled'
  51769. }
  51770. }
  51771. });
  51772. /**
  51773. * Override Pathfinder connector options for a series. Requires Highcharts Gantt
  51774. * to be loaded.
  51775. *
  51776. * @declare Highcharts.SeriesConnectorsOptionsObject
  51777. * @extends connectors
  51778. * @since 6.2.0
  51779. * @excluding enabled, algorithmMargin
  51780. * @product gantt
  51781. * @apioption plotOptions.series.connectors
  51782. */
  51783. /**
  51784. * Connect to a point. This option can be either a string, referring to the ID
  51785. * of another point, or an object, or an array of either. If the option is an
  51786. * array, each element defines a connection.
  51787. *
  51788. * @sample gantt/pathfinder/demo
  51789. * Different connection types
  51790. *
  51791. * @declare Highcharts.XrangePointConnectorsOptionsObject
  51792. * @type {string|Array<string|*>|*}
  51793. * @extends plotOptions.series.connectors
  51794. * @since 6.2.0
  51795. * @excluding enabled
  51796. * @product gantt
  51797. * @requires highcharts-gantt
  51798. * @apioption series.xrange.data.connect
  51799. */
  51800. /**
  51801. * The ID of the point to connect to.
  51802. *
  51803. * @type {string}
  51804. * @since 6.2.0
  51805. * @product gantt
  51806. * @apioption series.xrange.data.connect.to
  51807. */
  51808. /**
  51809. * Get point bounding box using plotX/plotY and shapeArgs. If using
  51810. * graphic.getBBox() directly, the bbox will be affected by animation.
  51811. *
  51812. * @private
  51813. * @function
  51814. *
  51815. * @param {Highcharts.Point} point
  51816. * The point to get BB of.
  51817. *
  51818. * @return {Highcharts.Dictionary<number>|null}
  51819. * Result xMax, xMin, yMax, yMin.
  51820. */
  51821. function getPointBB(point) {
  51822. var shapeArgs = point.shapeArgs,
  51823. bb;
  51824. // Prefer using shapeArgs (columns)
  51825. if (shapeArgs) {
  51826. return {
  51827. xMin: shapeArgs.x || 0,
  51828. xMax: (shapeArgs.x || 0) + (shapeArgs.width || 0),
  51829. yMin: shapeArgs.y || 0,
  51830. yMax: (shapeArgs.y || 0) + (shapeArgs.height || 0)
  51831. };
  51832. }
  51833. // Otherwise use plotX/plotY and bb
  51834. bb = point.graphic && point.graphic.getBBox();
  51835. return bb ? {
  51836. xMin: point.plotX - bb.width / 2,
  51837. xMax: point.plotX + bb.width / 2,
  51838. yMin: point.plotY - bb.height / 2,
  51839. yMax: point.plotY + bb.height / 2
  51840. } : null;
  51841. }
  51842. /**
  51843. * Calculate margin to place around obstacles for the pathfinder in pixels.
  51844. * Returns a minimum of 1 pixel margin.
  51845. *
  51846. * @private
  51847. * @function
  51848. *
  51849. * @param {Array<object>} obstacles
  51850. * Obstacles to calculate margin from.
  51851. *
  51852. * @return {number}
  51853. * The calculated margin in pixels. At least 1.
  51854. */
  51855. function calculateObstacleMargin(obstacles) {
  51856. var len = obstacles.length,
  51857. i = 0,
  51858. j,
  51859. obstacleDistance,
  51860. distances = [],
  51861. // Compute smallest distance between two rectangles
  51862. distance = function (a,
  51863. b,
  51864. bbMargin) {
  51865. // Count the distance even if we are slightly off
  51866. var margin = pick(bbMargin, 10),
  51867. yOverlap = a.yMax + margin > b.yMin - margin &&
  51868. a.yMin - margin < b.yMax + margin,
  51869. xOverlap = a.xMax + margin > b.xMin - margin &&
  51870. a.xMin - margin < b.xMax + margin,
  51871. xDistance = yOverlap ? (a.xMin > b.xMax ? a.xMin - b.xMax : b.xMin - a.xMax) : Infinity,
  51872. yDistance = xOverlap ? (a.yMin > b.yMax ? a.yMin - b.yMax : b.yMin - a.yMax) : Infinity;
  51873. // If the rectangles collide, try recomputing with smaller margin.
  51874. // If they collide anyway, discard the obstacle.
  51875. if (xOverlap && yOverlap) {
  51876. return (margin ?
  51877. distance(a, b, Math.floor(margin / 2)) :
  51878. Infinity);
  51879. }
  51880. return min(xDistance, yDistance);
  51881. };
  51882. // Go over all obstacles and compare them to the others.
  51883. for (; i < len; ++i) {
  51884. // Compare to all obstacles ahead. We will already have compared this
  51885. // obstacle to the ones before.
  51886. for (j = i + 1; j < len; ++j) {
  51887. obstacleDistance = distance(obstacles[i], obstacles[j]);
  51888. // TODO: Magic number 80
  51889. if (obstacleDistance < 80) { // Ignore large distances
  51890. distances.push(obstacleDistance);
  51891. }
  51892. }
  51893. }
  51894. // Ensure we always have at least one value, even in very spaceous charts
  51895. distances.push(80);
  51896. return max(Math.floor(distances.sort(function (a, b) {
  51897. return (a - b);
  51898. })[
  51899. // Discard first 10% of the relevant distances, and then grab
  51900. // the smallest one.
  51901. Math.floor(distances.length / 10)] / 2 - 1 // Divide the distance by 2 and subtract 1.
  51902. ), 1 // 1 is the minimum margin
  51903. );
  51904. }
  51905. /* eslint-disable no-invalid-this, valid-jsdoc */
  51906. /**
  51907. * The Connection class. Used internally to represent a connection between two
  51908. * points.
  51909. *
  51910. * @private
  51911. * @class
  51912. * @name Highcharts.Connection
  51913. *
  51914. * @param {Highcharts.Point} from
  51915. * Connection runs from this Point.
  51916. *
  51917. * @param {Highcharts.Point} to
  51918. * Connection runs to this Point.
  51919. *
  51920. * @param {Highcharts.ConnectorsOptions} [options]
  51921. * Connection options.
  51922. */
  51923. var Connection = /** @class */ (function () {
  51924. function Connection(from, to, options) {
  51925. /* *
  51926. *
  51927. * Properties
  51928. *
  51929. * */
  51930. this.chart = void 0;
  51931. this.fromPoint = void 0;
  51932. this.graphics = void 0;
  51933. this.pathfinder = void 0;
  51934. this.toPoint = void 0;
  51935. this.init(from, to, options);
  51936. }
  51937. /**
  51938. * Initialize the Connection object. Used as constructor only.
  51939. *
  51940. * @function Highcharts.Connection#init
  51941. *
  51942. * @param {Highcharts.Point} from
  51943. * Connection runs from this Point.
  51944. *
  51945. * @param {Highcharts.Point} to
  51946. * Connection runs to this Point.
  51947. *
  51948. * @param {Highcharts.ConnectorsOptions} [options]
  51949. * Connection options.
  51950. */
  51951. Connection.prototype.init = function (from, to, options) {
  51952. this.fromPoint = from;
  51953. this.toPoint = to;
  51954. this.options = options;
  51955. this.chart = from.series.chart;
  51956. this.pathfinder = this.chart.pathfinder;
  51957. };
  51958. /**
  51959. * Add (or update) this connection's path on chart. Stores reference to the
  51960. * created element on this.graphics.path.
  51961. *
  51962. * @function Highcharts.Connection#renderPath
  51963. *
  51964. * @param {Highcharts.SVGPathArray} path
  51965. * Path to render, in array format. E.g. ['M', 0, 0, 'L', 10, 10]
  51966. *
  51967. * @param {Highcharts.SVGAttributes} [attribs]
  51968. * SVG attributes for the path.
  51969. *
  51970. * @param {Partial<Highcharts.AnimationOptionsObject>} [animation]
  51971. * Animation options for the rendering.
  51972. */
  51973. Connection.prototype.renderPath = function (path, attribs, animation) {
  51974. var connection = this,
  51975. chart = this.chart,
  51976. styledMode = chart.styledMode,
  51977. pathfinder = chart.pathfinder,
  51978. animate = !chart.options.chart.forExport && animation !== false,
  51979. pathGraphic = connection.graphics && connection.graphics.path,
  51980. anim;
  51981. // Add the SVG element of the pathfinder group if it doesn't exist
  51982. if (!pathfinder.group) {
  51983. pathfinder.group = chart.renderer.g()
  51984. .addClass('highcharts-pathfinder-group')
  51985. .attr({ zIndex: -1 })
  51986. .add(chart.seriesGroup);
  51987. }
  51988. // Shift the group to compensate for plot area.
  51989. // Note: Do this always (even when redrawing a path) to avoid issues
  51990. // when updating chart in a way that changes plot metrics.
  51991. pathfinder.group.translate(chart.plotLeft, chart.plotTop);
  51992. // Create path if does not exist
  51993. if (!(pathGraphic && pathGraphic.renderer)) {
  51994. pathGraphic = chart.renderer.path()
  51995. .add(pathfinder.group);
  51996. if (!styledMode) {
  51997. pathGraphic.attr({
  51998. opacity: 0
  51999. });
  52000. }
  52001. }
  52002. // Set path attribs and animate to the new path
  52003. pathGraphic.attr(attribs);
  52004. anim = { d: path };
  52005. if (!styledMode) {
  52006. anim.opacity = 1;
  52007. }
  52008. pathGraphic[animate ? 'animate' : 'attr'](anim, animation);
  52009. // Store reference on connection
  52010. this.graphics = this.graphics || {};
  52011. this.graphics.path = pathGraphic;
  52012. };
  52013. /**
  52014. * Calculate and add marker graphics for connection to the chart. The
  52015. * created/updated elements are stored on this.graphics.start and
  52016. * this.graphics.end.
  52017. *
  52018. * @function Highcharts.Connection#addMarker
  52019. *
  52020. * @param {string} type
  52021. * Marker type, either 'start' or 'end'.
  52022. *
  52023. * @param {Highcharts.ConnectorsMarkerOptions} options
  52024. * All options for this marker. Not calculated or merged with other
  52025. * options.
  52026. *
  52027. * @param {Highcharts.SVGPathArray} path
  52028. * Connection path in array format. This is used to calculate the
  52029. * rotation angle of the markers.
  52030. */
  52031. Connection.prototype.addMarker = function (type, options, path) {
  52032. var connection = this,
  52033. chart = connection.fromPoint.series.chart,
  52034. pathfinder = chart.pathfinder,
  52035. renderer = chart.renderer,
  52036. point = (type === 'start' ?
  52037. connection.fromPoint :
  52038. connection.toPoint),
  52039. anchor = point.getPathfinderAnchorPoint(options),
  52040. markerVector,
  52041. radians,
  52042. rotation,
  52043. box,
  52044. width,
  52045. height,
  52046. pathVector,
  52047. segment;
  52048. if (!options.enabled) {
  52049. return;
  52050. }
  52051. // Last vector before start/end of path, used to get angle
  52052. if (type === 'start') {
  52053. segment = path[1];
  52054. }
  52055. else { // 'end'
  52056. segment = path[path.length - 2];
  52057. }
  52058. if (segment && segment[0] === 'M' || segment[0] === 'L') {
  52059. pathVector = {
  52060. x: segment[1],
  52061. y: segment[2]
  52062. };
  52063. // Get angle between pathVector and anchor point and use it to
  52064. // create marker position.
  52065. radians = point.getRadiansToVector(pathVector, anchor);
  52066. markerVector = point.getMarkerVector(radians, options.radius, anchor);
  52067. // Rotation of marker is calculated from angle between pathVector
  52068. // and markerVector.
  52069. // (Note:
  52070. // Used to recalculate radians between markerVector and pathVector,
  52071. // but this should be the same as between pathVector and anchor.)
  52072. rotation = -radians / deg2rad;
  52073. if (options.width && options.height) {
  52074. width = options.width;
  52075. height = options.height;
  52076. }
  52077. else {
  52078. width = height = options.radius * 2;
  52079. }
  52080. // Add graphics object if it does not exist
  52081. connection.graphics = connection.graphics || {};
  52082. box = {
  52083. x: markerVector.x - (width / 2),
  52084. y: markerVector.y - (height / 2),
  52085. width: width,
  52086. height: height,
  52087. rotation: rotation,
  52088. rotationOriginX: markerVector.x,
  52089. rotationOriginY: markerVector.y
  52090. };
  52091. if (!connection.graphics[type]) {
  52092. // Create new marker element
  52093. connection.graphics[type] = renderer
  52094. .symbol(options.symbol)
  52095. .addClass('highcharts-point-connecting-path-' + type + '-marker')
  52096. .attr(box)
  52097. .add(pathfinder.group);
  52098. if (!renderer.styledMode) {
  52099. connection.graphics[type].attr({
  52100. fill: options.color || connection.fromPoint.color,
  52101. stroke: options.lineColor,
  52102. 'stroke-width': options.lineWidth,
  52103. opacity: 0
  52104. })
  52105. .animate({
  52106. opacity: 1
  52107. }, point.series.options.animation);
  52108. }
  52109. }
  52110. else {
  52111. connection.graphics[type].animate(box);
  52112. }
  52113. }
  52114. };
  52115. /**
  52116. * Calculate and return connection path.
  52117. * Note: Recalculates chart obstacles on demand if they aren't calculated.
  52118. *
  52119. * @function Highcharts.Connection#getPath
  52120. *
  52121. * @param {Highcharts.ConnectorsOptions} options
  52122. * Connector options. Not calculated or merged with other options.
  52123. *
  52124. * @return {object|undefined}
  52125. * Calculated SVG path data in array format.
  52126. */
  52127. Connection.prototype.getPath = function (options) {
  52128. var pathfinder = this.pathfinder,
  52129. chart = this.chart,
  52130. algorithm = pathfinder.algorithms[options.type],
  52131. chartObstacles = pathfinder.chartObstacles;
  52132. if (typeof algorithm !== 'function') {
  52133. error('"' + options.type + '" is not a Pathfinder algorithm.');
  52134. return {
  52135. path: [],
  52136. obstacles: []
  52137. };
  52138. }
  52139. // This function calculates obstacles on demand if they don't exist
  52140. if (algorithm.requiresObstacles && !chartObstacles) {
  52141. chartObstacles =
  52142. pathfinder.chartObstacles =
  52143. pathfinder.getChartObstacles(options);
  52144. // If the algorithmMargin was computed, store the result in default
  52145. // options.
  52146. chart.options.connectors.algorithmMargin =
  52147. options.algorithmMargin;
  52148. // Cache some metrics too
  52149. pathfinder.chartObstacleMetrics =
  52150. pathfinder.getObstacleMetrics(chartObstacles);
  52151. }
  52152. // Get the SVG path
  52153. return algorithm(
  52154. // From
  52155. this.fromPoint.getPathfinderAnchorPoint(options.startMarker),
  52156. // To
  52157. this.toPoint.getPathfinderAnchorPoint(options.endMarker), merge({
  52158. chartObstacles: chartObstacles,
  52159. lineObstacles: pathfinder.lineObstacles || [],
  52160. obstacleMetrics: pathfinder.chartObstacleMetrics,
  52161. hardBounds: {
  52162. xMin: 0,
  52163. xMax: chart.plotWidth,
  52164. yMin: 0,
  52165. yMax: chart.plotHeight
  52166. },
  52167. obstacleOptions: {
  52168. margin: options.algorithmMargin
  52169. },
  52170. startDirectionX: pathfinder.getAlgorithmStartDirection(options.startMarker)
  52171. }, options));
  52172. };
  52173. /**
  52174. * (re)Calculate and (re)draw the connection.
  52175. *
  52176. * @function Highcharts.Connection#render
  52177. */
  52178. Connection.prototype.render = function () {
  52179. var connection = this,
  52180. fromPoint = connection.fromPoint,
  52181. series = fromPoint.series,
  52182. chart = series.chart,
  52183. pathfinder = chart.pathfinder,
  52184. pathResult,
  52185. path,
  52186. options = merge(chart.options.connectors,
  52187. series.options.connectors,
  52188. fromPoint.options.connectors,
  52189. connection.options),
  52190. attribs = {};
  52191. // Set path attribs
  52192. if (!chart.styledMode) {
  52193. attribs.stroke = options.lineColor || fromPoint.color;
  52194. attribs['stroke-width'] = options.lineWidth;
  52195. if (options.dashStyle) {
  52196. attribs.dashstyle = options.dashStyle;
  52197. }
  52198. }
  52199. attribs['class'] = // eslint-disable-line dot-notation
  52200. 'highcharts-point-connecting-path ' +
  52201. 'highcharts-color-' + fromPoint.colorIndex;
  52202. options = merge(attribs, options);
  52203. // Set common marker options
  52204. if (!defined(options.marker.radius)) {
  52205. options.marker.radius = min(max(Math.ceil((options.algorithmMargin || 8) / 2) - 1, 1), 5);
  52206. }
  52207. // Get the path
  52208. pathResult = connection.getPath(options);
  52209. path = pathResult.path;
  52210. // Always update obstacle storage with obstacles from this path.
  52211. // We don't know if future calls will need this for their algorithm.
  52212. if (pathResult.obstacles) {
  52213. pathfinder.lineObstacles =
  52214. pathfinder.lineObstacles || [];
  52215. pathfinder.lineObstacles =
  52216. pathfinder.lineObstacles.concat(pathResult.obstacles);
  52217. }
  52218. // Add the calculated path to the pathfinder group
  52219. connection.renderPath(path, attribs, series.options.animation);
  52220. // Render the markers
  52221. connection.addMarker('start', merge(options.marker, options.startMarker), path);
  52222. connection.addMarker('end', merge(options.marker, options.endMarker), path);
  52223. };
  52224. /**
  52225. * Destroy connection by destroying the added graphics elements.
  52226. *
  52227. * @function Highcharts.Connection#destroy
  52228. */
  52229. Connection.prototype.destroy = function () {
  52230. if (this.graphics) {
  52231. objectEach(this.graphics, function (val) {
  52232. val.destroy();
  52233. });
  52234. delete this.graphics;
  52235. }
  52236. };
  52237. return Connection;
  52238. }());
  52239. // Add to Highcharts namespace
  52240. H.Connection = Connection;
  52241. // Add pathfinding capabilities to Points
  52242. extend(Point.prototype, /** @lends Point.prototype */ {
  52243. /**
  52244. * Get coordinates of anchor point for pathfinder connection.
  52245. *
  52246. * @private
  52247. * @function Highcharts.Point#getPathfinderAnchorPoint
  52248. *
  52249. * @param {Highcharts.ConnectorsMarkerOptions} markerOptions
  52250. * Connection options for position on point.
  52251. *
  52252. * @return {Highcharts.PositionObject}
  52253. * An object with x/y properties for the position. Coordinates are
  52254. * in plot values, not relative to point.
  52255. */
  52256. getPathfinderAnchorPoint: function (markerOptions) {
  52257. var bb = getPointBB(this),
  52258. x,
  52259. y;
  52260. switch (markerOptions.align) { // eslint-disable-line default-case
  52261. case 'right':
  52262. x = 'xMax';
  52263. break;
  52264. case 'left':
  52265. x = 'xMin';
  52266. }
  52267. switch (markerOptions.verticalAlign) { // eslint-disable-line default-case
  52268. case 'top':
  52269. y = 'yMin';
  52270. break;
  52271. case 'bottom':
  52272. y = 'yMax';
  52273. }
  52274. return {
  52275. x: x ? bb[x] : (bb.xMin + bb.xMax) / 2,
  52276. y: y ? bb[y] : (bb.yMin + bb.yMax) / 2
  52277. };
  52278. },
  52279. /**
  52280. * Utility to get the angle from one point to another.
  52281. *
  52282. * @private
  52283. * @function Highcharts.Point#getRadiansToVector
  52284. *
  52285. * @param {Highcharts.PositionObject} v1
  52286. * The first vector, as an object with x/y properties.
  52287. *
  52288. * @param {Highcharts.PositionObject} v2
  52289. * The second vector, as an object with x/y properties.
  52290. *
  52291. * @return {number}
  52292. * The angle in degrees
  52293. */
  52294. getRadiansToVector: function (v1, v2) {
  52295. var box;
  52296. if (!defined(v2)) {
  52297. box = getPointBB(this);
  52298. if (box) {
  52299. v2 = {
  52300. x: (box.xMin + box.xMax) / 2,
  52301. y: (box.yMin + box.yMax) / 2
  52302. };
  52303. }
  52304. }
  52305. return Math.atan2(v2.y - v1.y, v1.x - v2.x);
  52306. },
  52307. /**
  52308. * Utility to get the position of the marker, based on the path angle and
  52309. * the marker's radius.
  52310. *
  52311. * @private
  52312. * @function Highcharts.Point#getMarkerVector
  52313. *
  52314. * @param {number} radians
  52315. * The angle in radians from the point center to another vector.
  52316. *
  52317. * @param {number} markerRadius
  52318. * The radius of the marker, to calculate the additional distance to
  52319. * the center of the marker.
  52320. *
  52321. * @param {object} anchor
  52322. * The anchor point of the path and marker as an object with x/y
  52323. * properties.
  52324. *
  52325. * @return {object}
  52326. * The marker vector as an object with x/y properties.
  52327. */
  52328. getMarkerVector: function (radians, markerRadius, anchor) {
  52329. var twoPI = Math.PI * 2.0,
  52330. theta = radians,
  52331. bb = getPointBB(this),
  52332. rectWidth = bb.xMax - bb.xMin,
  52333. rectHeight = bb.yMax - bb.yMin,
  52334. rAtan = Math.atan2(rectHeight,
  52335. rectWidth),
  52336. tanTheta = 1,
  52337. leftOrRightRegion = false,
  52338. rectHalfWidth = rectWidth / 2.0,
  52339. rectHalfHeight = rectHeight / 2.0,
  52340. rectHorizontalCenter = bb.xMin + rectHalfWidth,
  52341. rectVerticalCenter = bb.yMin + rectHalfHeight,
  52342. edgePoint = {
  52343. x: rectHorizontalCenter,
  52344. y: rectVerticalCenter
  52345. },
  52346. xFactor = 1,
  52347. yFactor = 1;
  52348. while (theta < -Math.PI) {
  52349. theta += twoPI;
  52350. }
  52351. while (theta > Math.PI) {
  52352. theta -= twoPI;
  52353. }
  52354. tanTheta = Math.tan(theta);
  52355. if ((theta > -rAtan) && (theta <= rAtan)) {
  52356. // Right side
  52357. yFactor = -1;
  52358. leftOrRightRegion = true;
  52359. }
  52360. else if (theta > rAtan && theta <= (Math.PI - rAtan)) {
  52361. // Top side
  52362. yFactor = -1;
  52363. }
  52364. else if (theta > (Math.PI - rAtan) || theta <= -(Math.PI - rAtan)) {
  52365. // Left side
  52366. xFactor = -1;
  52367. leftOrRightRegion = true;
  52368. }
  52369. else {
  52370. // Bottom side
  52371. xFactor = -1;
  52372. }
  52373. // Correct the edgePoint according to the placement of the marker
  52374. if (leftOrRightRegion) {
  52375. edgePoint.x += xFactor * (rectHalfWidth);
  52376. edgePoint.y += yFactor * (rectHalfWidth) * tanTheta;
  52377. }
  52378. else {
  52379. edgePoint.x += xFactor * (rectHeight / (2.0 * tanTheta));
  52380. edgePoint.y += yFactor * (rectHalfHeight);
  52381. }
  52382. if (anchor.x !== rectHorizontalCenter) {
  52383. edgePoint.x = anchor.x;
  52384. }
  52385. if (anchor.y !== rectVerticalCenter) {
  52386. edgePoint.y = anchor.y;
  52387. }
  52388. return {
  52389. x: edgePoint.x + (markerRadius * Math.cos(theta)),
  52390. y: edgePoint.y - (markerRadius * Math.sin(theta))
  52391. };
  52392. }
  52393. });
  52394. /**
  52395. * Warn if using legacy options. Copy the options over. Note that this will
  52396. * still break if using the legacy options in chart.update, addSeries etc.
  52397. * @private
  52398. */
  52399. function warnLegacy(chart) {
  52400. if (chart.options.pathfinder ||
  52401. chart.series.reduce(function (acc, series) {
  52402. if (series.options) {
  52403. merge(true, (series.options.connectors = series.options.connectors ||
  52404. {}), series.options.pathfinder);
  52405. }
  52406. return acc || series.options && series.options.pathfinder;
  52407. }, false)) {
  52408. merge(true, (chart.options.connectors = chart.options.connectors || {}), chart.options.pathfinder);
  52409. error('WARNING: Pathfinder options have been renamed. ' +
  52410. 'Use "chart.connectors" or "series.connectors" instead.');
  52411. }
  52412. }
  52413. return Connection;
  52414. });
  52415. _registerModule(_modules, 'Gantt/PathfinderAlgorithms.js', [_modules['Core/Utilities.js']], function (U) {
  52416. /* *
  52417. *
  52418. * (c) 2016 Highsoft AS
  52419. * Author: Øystein Moseng
  52420. *
  52421. * License: www.highcharts.com/license
  52422. *
  52423. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  52424. *
  52425. * */
  52426. var extend = U.extend,
  52427. pick = U.pick;
  52428. var min = Math.min,
  52429. max = Math.max,
  52430. abs = Math.abs;
  52431. /**
  52432. * Get index of last obstacle before xMin. Employs a type of binary search, and
  52433. * thus requires that obstacles are sorted by xMin value.
  52434. *
  52435. * @private
  52436. * @function findLastObstacleBefore
  52437. *
  52438. * @param {Array<object>} obstacles
  52439. * Array of obstacles to search in.
  52440. *
  52441. * @param {number} xMin
  52442. * The xMin threshold.
  52443. *
  52444. * @param {number} [startIx]
  52445. * Starting index to search from. Must be within array range.
  52446. *
  52447. * @return {number}
  52448. * The index of the last obstacle element before xMin.
  52449. */
  52450. function findLastObstacleBefore(obstacles, xMin, startIx) {
  52451. var left = startIx || 0, // left limit
  52452. right = obstacles.length - 1, // right limit
  52453. min = xMin - 0.0000001, // Make sure we include all obstacles at xMin
  52454. cursor,
  52455. cmp;
  52456. while (left <= right) {
  52457. cursor = (right + left) >> 1;
  52458. cmp = min - obstacles[cursor].xMin;
  52459. if (cmp > 0) {
  52460. left = cursor + 1;
  52461. }
  52462. else if (cmp < 0) {
  52463. right = cursor - 1;
  52464. }
  52465. else {
  52466. return cursor;
  52467. }
  52468. }
  52469. return left > 0 ? left - 1 : 0;
  52470. }
  52471. /**
  52472. * Test if a point lays within an obstacle.
  52473. *
  52474. * @private
  52475. * @function pointWithinObstacle
  52476. *
  52477. * @param {object} obstacle
  52478. * Obstacle to test.
  52479. *
  52480. * @param {Highcharts.Point} point
  52481. * Point with x/y props.
  52482. *
  52483. * @return {boolean}
  52484. * Whether point is within the obstacle or not.
  52485. */
  52486. function pointWithinObstacle(obstacle, point) {
  52487. return (point.x <= obstacle.xMax &&
  52488. point.x >= obstacle.xMin &&
  52489. point.y <= obstacle.yMax &&
  52490. point.y >= obstacle.yMin);
  52491. }
  52492. /**
  52493. * Find the index of an obstacle that wraps around a point.
  52494. * Returns -1 if not found.
  52495. *
  52496. * @private
  52497. * @function findObstacleFromPoint
  52498. *
  52499. * @param {Array<object>} obstacles
  52500. * Obstacles to test.
  52501. *
  52502. * @param {Highcharts.Point} point
  52503. * Point with x/y props.
  52504. *
  52505. * @return {number}
  52506. * Ix of the obstacle in the array, or -1 if not found.
  52507. */
  52508. function findObstacleFromPoint(obstacles, point) {
  52509. var i = findLastObstacleBefore(obstacles,
  52510. point.x + 1) + 1;
  52511. while (i--) {
  52512. if (obstacles[i].xMax >= point.x &&
  52513. // optimization using lazy evaluation
  52514. pointWithinObstacle(obstacles[i], point)) {
  52515. return i;
  52516. }
  52517. }
  52518. return -1;
  52519. }
  52520. /**
  52521. * Get SVG path array from array of line segments.
  52522. *
  52523. * @private
  52524. * @function pathFromSegments
  52525. *
  52526. * @param {Array<object>} segments
  52527. * The segments to build the path from.
  52528. *
  52529. * @return {Highcharts.SVGPathArray}
  52530. * SVG path array as accepted by the SVG Renderer.
  52531. */
  52532. function pathFromSegments(segments) {
  52533. var path = [];
  52534. if (segments.length) {
  52535. path.push(['M', segments[0].start.x, segments[0].start.y]);
  52536. for (var i = 0; i < segments.length; ++i) {
  52537. path.push(['L', segments[i].end.x, segments[i].end.y]);
  52538. }
  52539. }
  52540. return path;
  52541. }
  52542. /**
  52543. * Limits obstacle max/mins in all directions to bounds. Modifies input
  52544. * obstacle.
  52545. *
  52546. * @private
  52547. * @function limitObstacleToBounds
  52548. *
  52549. * @param {object} obstacle
  52550. * Obstacle to limit.
  52551. *
  52552. * @param {object} bounds
  52553. * Bounds to use as limit.
  52554. *
  52555. * @return {void}
  52556. */
  52557. function limitObstacleToBounds(obstacle, bounds) {
  52558. obstacle.yMin = max(obstacle.yMin, bounds.yMin);
  52559. obstacle.yMax = min(obstacle.yMax, bounds.yMax);
  52560. obstacle.xMin = max(obstacle.xMin, bounds.xMin);
  52561. obstacle.xMax = min(obstacle.xMax, bounds.xMax);
  52562. }
  52563. /**
  52564. * Get an SVG path from a starting coordinate to an ending coordinate.
  52565. * Draws a straight line.
  52566. *
  52567. * @function Highcharts.Pathfinder.algorithms.straight
  52568. *
  52569. * @param {Highcharts.PositionObject} start
  52570. * Starting coordinate, object with x/y props.
  52571. *
  52572. * @param {Highcharts.PositionObject} end
  52573. * Ending coordinate, object with x/y props.
  52574. *
  52575. * @return {object}
  52576. * An object with the SVG path in Array form as accepted by the SVG
  52577. * renderer, as well as an array of new obstacles making up this
  52578. * path.
  52579. */
  52580. function straight(start, end) {
  52581. return {
  52582. path: [
  52583. ['M', start.x, start.y],
  52584. ['L', end.x, end.y]
  52585. ],
  52586. obstacles: [{ start: start, end: end }]
  52587. };
  52588. }
  52589. /**
  52590. * Find a path from a starting coordinate to an ending coordinate, using
  52591. * right angles only, and taking only starting/ending obstacle into
  52592. * consideration.
  52593. *
  52594. * @function Highcharts.Pathfinder.algorithms.simpleConnect
  52595. *
  52596. * @param {Highcharts.PositionObject} start
  52597. * Starting coordinate, object with x/y props.
  52598. *
  52599. * @param {Highcharts.PositionObject} end
  52600. * Ending coordinate, object with x/y props.
  52601. *
  52602. * @param {object} options
  52603. * Options for the algorithm:
  52604. * - chartObstacles: Array of chart obstacles to avoid
  52605. * - startDirectionX: Optional. True if starting in the X direction.
  52606. * If not provided, the algorithm starts in the direction that is
  52607. * the furthest between start/end.
  52608. *
  52609. * @return {object}
  52610. * An object with the SVG path in Array form as accepted by the SVG
  52611. * renderer, as well as an array of new obstacles making up this
  52612. * path.
  52613. */
  52614. var simpleConnect = function (start,
  52615. end,
  52616. options) {
  52617. var segments = [],
  52618. endSegment,
  52619. dir = pick(options.startDirectionX,
  52620. abs(end.x - start.x) > abs(end.y - start.y)) ? 'x' : 'y',
  52621. chartObstacles = options.chartObstacles,
  52622. startObstacleIx = findObstacleFromPoint(chartObstacles,
  52623. start),
  52624. endObstacleIx = findObstacleFromPoint(chartObstacles,
  52625. end),
  52626. startObstacle,
  52627. endObstacle,
  52628. prevWaypoint,
  52629. waypoint,
  52630. waypoint2,
  52631. useMax,
  52632. endPoint;
  52633. // eslint-disable-next-line valid-jsdoc
  52634. /**
  52635. * Return a clone of a point with a property set from a target object,
  52636. * optionally with an offset
  52637. * @private
  52638. */
  52639. function copyFromPoint(from, fromKey, to, toKey, offset) {
  52640. var point = {
  52641. x: from.x,
  52642. y: from.y
  52643. };
  52644. point[fromKey] = to[toKey || fromKey] + (offset || 0);
  52645. return point;
  52646. }
  52647. // eslint-disable-next-line valid-jsdoc
  52648. /**
  52649. * Return waypoint outside obstacle.
  52650. * @private
  52651. */
  52652. function getMeOut(obstacle, point, direction) {
  52653. var useMax = abs(point[direction] - obstacle[direction + 'Min']) >
  52654. abs(point[direction] - obstacle[direction + 'Max']);
  52655. return copyFromPoint(point, direction, obstacle, direction + (useMax ? 'Max' : 'Min'), useMax ? 1 : -1);
  52656. }
  52657. // Pull out end point
  52658. if (endObstacleIx > -1) {
  52659. endObstacle = chartObstacles[endObstacleIx];
  52660. waypoint = getMeOut(endObstacle, end, dir);
  52661. endSegment = {
  52662. start: waypoint,
  52663. end: end
  52664. };
  52665. endPoint = waypoint;
  52666. }
  52667. else {
  52668. endPoint = end;
  52669. }
  52670. // If an obstacle envelops the start point, add a segment to get out,
  52671. // and around it.
  52672. if (startObstacleIx > -1) {
  52673. startObstacle = chartObstacles[startObstacleIx];
  52674. waypoint = getMeOut(startObstacle, start, dir);
  52675. segments.push({
  52676. start: start,
  52677. end: waypoint
  52678. });
  52679. // If we are going back again, switch direction to get around start
  52680. // obstacle.
  52681. if (
  52682. // Going towards max from start:
  52683. waypoint[dir] >= start[dir] ===
  52684. // Going towards min to end:
  52685. waypoint[dir] >= endPoint[dir]) {
  52686. dir = dir === 'y' ? 'x' : 'y';
  52687. useMax = start[dir] < end[dir];
  52688. segments.push({
  52689. start: waypoint,
  52690. end: copyFromPoint(waypoint, dir, startObstacle, dir + (useMax ? 'Max' : 'Min'), useMax ? 1 : -1)
  52691. });
  52692. // Switch direction again
  52693. dir = dir === 'y' ? 'x' : 'y';
  52694. }
  52695. }
  52696. // We are around the start obstacle. Go towards the end in one
  52697. // direction.
  52698. prevWaypoint = segments.length ?
  52699. segments[segments.length - 1].end :
  52700. start;
  52701. waypoint = copyFromPoint(prevWaypoint, dir, endPoint);
  52702. segments.push({
  52703. start: prevWaypoint,
  52704. end: waypoint
  52705. });
  52706. // Final run to end point in the other direction
  52707. dir = dir === 'y' ? 'x' : 'y';
  52708. waypoint2 = copyFromPoint(waypoint, dir, endPoint);
  52709. segments.push({
  52710. start: waypoint,
  52711. end: waypoint2
  52712. });
  52713. // Finally add the endSegment
  52714. segments.push(endSegment);
  52715. return {
  52716. path: pathFromSegments(segments),
  52717. obstacles: segments
  52718. };
  52719. };
  52720. simpleConnect.requiresObstacles = true;
  52721. /**
  52722. * Find a path from a starting coordinate to an ending coordinate, taking
  52723. * obstacles into consideration. Might not always find the optimal path,
  52724. * but is fast, and usually good enough.
  52725. *
  52726. * @function Highcharts.Pathfinder.algorithms.fastAvoid
  52727. *
  52728. * @param {Highcharts.PositionObject} start
  52729. * Starting coordinate, object with x/y props.
  52730. *
  52731. * @param {Highcharts.PositionObject} end
  52732. * Ending coordinate, object with x/y props.
  52733. *
  52734. * @param {object} options
  52735. * Options for the algorithm.
  52736. * - chartObstacles: Array of chart obstacles to avoid
  52737. * - lineObstacles: Array of line obstacles to jump over
  52738. * - obstacleMetrics: Object with metrics of chartObstacles cached
  52739. * - hardBounds: Hard boundaries to not cross
  52740. * - obstacleOptions: Options for the obstacles, including margin
  52741. * - startDirectionX: Optional. True if starting in the X direction.
  52742. * If not provided, the algorithm starts in the
  52743. * direction that is the furthest between
  52744. * start/end.
  52745. *
  52746. * @return {object}
  52747. * An object with the SVG path in Array form as accepted by the SVG
  52748. * renderer, as well as an array of new obstacles making up this
  52749. * path.
  52750. */
  52751. var fastAvoid = function (start,
  52752. end,
  52753. options) {
  52754. /*
  52755. Algorithm rules/description
  52756. - Find initial direction
  52757. - Determine soft/hard max for each direction.
  52758. - Move along initial direction until obstacle.
  52759. - Change direction.
  52760. - If hitting obstacle,
  52761. first try to change length of previous line
  52762. before changing direction again.
  52763. Soft min/max x = start/destination x +/- widest obstacle + margin
  52764. Soft min/max y = start/destination y +/- tallest obstacle + margin
  52765. @todo:
  52766. - Make retrospective,
  52767. try changing prev segment to reduce
  52768. corners
  52769. - Fix logic for breaking out of end-points - not always picking
  52770. the best direction currently
  52771. - When going around the end obstacle we should not always go the
  52772. shortest route,
  52773. rather pick the one closer to the end point
  52774. */
  52775. var dirIsX = pick(options.startDirectionX,
  52776. abs(end.x - start.x) > abs(end.y - start.y)),
  52777. dir = dirIsX ? 'x' : 'y',
  52778. segments,
  52779. useMax,
  52780. extractedEndPoint,
  52781. endSegments = [],
  52782. forceObstacleBreak = false, // Used in clearPathTo to keep track of
  52783. // when to force break through an obstacle.
  52784. // Boundaries to stay within. If beyond soft boundary, prefer to
  52785. // change direction ASAP. If at hard max, always change immediately.
  52786. metrics = options.obstacleMetrics,
  52787. softMinX = min(start.x,
  52788. end.x) - metrics.maxWidth - 10,
  52789. softMaxX = max(start.x,
  52790. end.x) + metrics.maxWidth + 10,
  52791. softMinY = min(start.y,
  52792. end.y) - metrics.maxHeight - 10,
  52793. softMaxY = max(start.y,
  52794. end.y) + metrics.maxHeight + 10,
  52795. // Obstacles
  52796. chartObstacles = options.chartObstacles,
  52797. startObstacleIx = findLastObstacleBefore(chartObstacles,
  52798. softMinX),
  52799. endObstacleIx = findLastObstacleBefore(chartObstacles,
  52800. softMaxX);
  52801. // eslint-disable-next-line valid-jsdoc
  52802. /**
  52803. * How far can you go between two points before hitting an obstacle?
  52804. * Does not work for diagonal lines (because it doesn't have to).
  52805. * @private
  52806. */
  52807. function pivotPoint(fromPoint, toPoint, directionIsX) {
  52808. var firstPoint,
  52809. lastPoint,
  52810. highestPoint,
  52811. lowestPoint,
  52812. i,
  52813. searchDirection = fromPoint.x < toPoint.x ? 1 : -1;
  52814. if (fromPoint.x < toPoint.x) {
  52815. firstPoint = fromPoint;
  52816. lastPoint = toPoint;
  52817. }
  52818. else {
  52819. firstPoint = toPoint;
  52820. lastPoint = fromPoint;
  52821. }
  52822. if (fromPoint.y < toPoint.y) {
  52823. lowestPoint = fromPoint;
  52824. highestPoint = toPoint;
  52825. }
  52826. else {
  52827. lowestPoint = toPoint;
  52828. highestPoint = fromPoint;
  52829. }
  52830. // Go through obstacle range in reverse if toPoint is before
  52831. // fromPoint in the X-dimension.
  52832. i = searchDirection < 0 ?
  52833. // Searching backwards, start at last obstacle before last point
  52834. min(findLastObstacleBefore(chartObstacles, lastPoint.x), chartObstacles.length - 1) :
  52835. // Forwards. Since we're not sorted by xMax, we have to look
  52836. // at all obstacles.
  52837. 0;
  52838. // Go through obstacles in this X range
  52839. while (chartObstacles[i] && (searchDirection > 0 && chartObstacles[i].xMin <= lastPoint.x ||
  52840. searchDirection < 0 && chartObstacles[i].xMax >= firstPoint.x)) {
  52841. // If this obstacle is between from and to points in a straight
  52842. // line, pivot at the intersection.
  52843. if (chartObstacles[i].xMin <= lastPoint.x &&
  52844. chartObstacles[i].xMax >= firstPoint.x &&
  52845. chartObstacles[i].yMin <= highestPoint.y &&
  52846. chartObstacles[i].yMax >= lowestPoint.y) {
  52847. if (directionIsX) {
  52848. return {
  52849. y: fromPoint.y,
  52850. x: fromPoint.x < toPoint.x ?
  52851. chartObstacles[i].xMin - 1 :
  52852. chartObstacles[i].xMax + 1,
  52853. obstacle: chartObstacles[i]
  52854. };
  52855. }
  52856. // else ...
  52857. return {
  52858. x: fromPoint.x,
  52859. y: fromPoint.y < toPoint.y ?
  52860. chartObstacles[i].yMin - 1 :
  52861. chartObstacles[i].yMax + 1,
  52862. obstacle: chartObstacles[i]
  52863. };
  52864. }
  52865. i += searchDirection;
  52866. }
  52867. return toPoint;
  52868. }
  52869. /**
  52870. * Decide in which direction to dodge or get out of an obstacle.
  52871. * Considers desired direction, which way is shortest, soft and hard
  52872. * bounds.
  52873. *
  52874. * (? Returns a string, either xMin, xMax, yMin or yMax.)
  52875. *
  52876. * @private
  52877. * @function
  52878. *
  52879. * @param {object} obstacle
  52880. * Obstacle to dodge/escape.
  52881. *
  52882. * @param {object} fromPoint
  52883. * Point with x/y props that's dodging/escaping.
  52884. *
  52885. * @param {object} toPoint
  52886. * Goal point.
  52887. *
  52888. * @param {boolean} dirIsX
  52889. * Dodge in X dimension.
  52890. *
  52891. * @param {object} bounds
  52892. * Hard and soft boundaries.
  52893. *
  52894. * @return {boolean}
  52895. * Use max or not.
  52896. */
  52897. function getDodgeDirection(obstacle, fromPoint, toPoint, dirIsX, bounds) {
  52898. var softBounds = bounds.soft, hardBounds = bounds.hard, dir = dirIsX ? 'x' : 'y', toPointMax = { x: fromPoint.x, y: fromPoint.y }, toPointMin = { x: fromPoint.x, y: fromPoint.y }, minPivot, maxPivot, maxOutOfSoftBounds = obstacle[dir + 'Max'] >=
  52899. softBounds[dir + 'Max'], minOutOfSoftBounds = obstacle[dir + 'Min'] <=
  52900. softBounds[dir + 'Min'], maxOutOfHardBounds = obstacle[dir + 'Max'] >=
  52901. hardBounds[dir + 'Max'], minOutOfHardBounds = obstacle[dir + 'Min'] <=
  52902. hardBounds[dir + 'Min'],
  52903. // Find out if we should prefer one direction over the other if
  52904. // we can choose freely
  52905. minDistance = abs(obstacle[dir + 'Min'] - fromPoint[dir]), maxDistance = abs(obstacle[dir + 'Max'] - fromPoint[dir]),
  52906. // If it's a small difference, pick the one leading towards dest
  52907. // point. Otherwise pick the shortest distance
  52908. useMax = abs(minDistance - maxDistance) < 10 ?
  52909. fromPoint[dir] < toPoint[dir] :
  52910. maxDistance < minDistance;
  52911. // Check if we hit any obstacles trying to go around in either
  52912. // direction.
  52913. toPointMin[dir] = obstacle[dir + 'Min'];
  52914. toPointMax[dir] = obstacle[dir + 'Max'];
  52915. minPivot = pivotPoint(fromPoint, toPointMin, dirIsX)[dir] !==
  52916. toPointMin[dir];
  52917. maxPivot = pivotPoint(fromPoint, toPointMax, dirIsX)[dir] !==
  52918. toPointMax[dir];
  52919. useMax = minPivot ?
  52920. (maxPivot ? useMax : true) :
  52921. (maxPivot ? false : useMax);
  52922. // useMax now contains our preferred choice, bounds not taken into
  52923. // account. If both or neither direction is out of bounds we want to
  52924. // use this.
  52925. // Deal with soft bounds
  52926. useMax = minOutOfSoftBounds ?
  52927. (maxOutOfSoftBounds ? useMax : true) : // Out on min
  52928. (maxOutOfSoftBounds ? false : useMax); // Not out on min
  52929. // Deal with hard bounds
  52930. useMax = minOutOfHardBounds ?
  52931. (maxOutOfHardBounds ? useMax : true) : // Out on min
  52932. (maxOutOfHardBounds ? false : useMax); // Not out on min
  52933. return useMax;
  52934. }
  52935. // eslint-disable-next-line valid-jsdoc
  52936. /**
  52937. * Find a clear path between point.
  52938. * @private
  52939. */
  52940. function clearPathTo(fromPoint, toPoint, dirIsX) {
  52941. // Don't waste time if we've hit goal
  52942. if (fromPoint.x === toPoint.x && fromPoint.y === toPoint.y) {
  52943. return [];
  52944. }
  52945. var dir = dirIsX ? 'x' : 'y',
  52946. pivot,
  52947. segments,
  52948. waypoint,
  52949. waypointUseMax,
  52950. envelopingObstacle,
  52951. secondEnvelopingObstacle,
  52952. envelopWaypoint,
  52953. obstacleMargin = options.obstacleOptions.margin,
  52954. bounds = {
  52955. soft: {
  52956. xMin: softMinX,
  52957. xMax: softMaxX,
  52958. yMin: softMinY,
  52959. yMax: softMaxY
  52960. },
  52961. hard: options.hardBounds
  52962. };
  52963. // If fromPoint is inside an obstacle we have a problem. Break out
  52964. // by just going to the outside of this obstacle. We prefer to go to
  52965. // the nearest edge in the chosen direction.
  52966. envelopingObstacle =
  52967. findObstacleFromPoint(chartObstacles, fromPoint);
  52968. if (envelopingObstacle > -1) {
  52969. envelopingObstacle = chartObstacles[envelopingObstacle];
  52970. waypointUseMax = getDodgeDirection(envelopingObstacle, fromPoint, toPoint, dirIsX, bounds);
  52971. // Cut obstacle to hard bounds to make sure we stay within
  52972. limitObstacleToBounds(envelopingObstacle, options.hardBounds);
  52973. envelopWaypoint = dirIsX ? {
  52974. y: fromPoint.y,
  52975. x: envelopingObstacle[waypointUseMax ? 'xMax' : 'xMin'] +
  52976. (waypointUseMax ? 1 : -1)
  52977. } : {
  52978. x: fromPoint.x,
  52979. y: envelopingObstacle[waypointUseMax ? 'yMax' : 'yMin'] +
  52980. (waypointUseMax ? 1 : -1)
  52981. };
  52982. // If we crashed into another obstacle doing this, we put the
  52983. // waypoint between them instead
  52984. secondEnvelopingObstacle = findObstacleFromPoint(chartObstacles, envelopWaypoint);
  52985. if (secondEnvelopingObstacle > -1) {
  52986. secondEnvelopingObstacle = chartObstacles[secondEnvelopingObstacle];
  52987. // Cut obstacle to hard bounds
  52988. limitObstacleToBounds(secondEnvelopingObstacle, options.hardBounds);
  52989. // Modify waypoint to lay between obstacles
  52990. envelopWaypoint[dir] = waypointUseMax ? max(envelopingObstacle[dir + 'Max'] - obstacleMargin + 1, (secondEnvelopingObstacle[dir + 'Min'] +
  52991. envelopingObstacle[dir + 'Max']) / 2) :
  52992. min((envelopingObstacle[dir + 'Min'] + obstacleMargin - 1), ((secondEnvelopingObstacle[dir + 'Max'] +
  52993. envelopingObstacle[dir + 'Min']) / 2));
  52994. // We are not going anywhere. If this happens for the first
  52995. // time, do nothing. Otherwise, try to go to the extreme of
  52996. // the obstacle pair in the current direction.
  52997. if (fromPoint.x === envelopWaypoint.x &&
  52998. fromPoint.y === envelopWaypoint.y) {
  52999. if (forceObstacleBreak) {
  53000. envelopWaypoint[dir] = waypointUseMax ?
  53001. max(envelopingObstacle[dir + 'Max'], secondEnvelopingObstacle[dir + 'Max']) + 1 :
  53002. min(envelopingObstacle[dir + 'Min'], secondEnvelopingObstacle[dir + 'Min']) - 1;
  53003. }
  53004. // Toggle on if off, and the opposite
  53005. forceObstacleBreak = !forceObstacleBreak;
  53006. }
  53007. else {
  53008. // This point is not identical to previous.
  53009. // Clear break trigger.
  53010. forceObstacleBreak = false;
  53011. }
  53012. }
  53013. segments = [{
  53014. start: fromPoint,
  53015. end: envelopWaypoint
  53016. }];
  53017. }
  53018. else { // If not enveloping, use standard pivot calculation
  53019. pivot = pivotPoint(fromPoint, {
  53020. x: dirIsX ? toPoint.x : fromPoint.x,
  53021. y: dirIsX ? fromPoint.y : toPoint.y
  53022. }, dirIsX);
  53023. segments = [{
  53024. start: fromPoint,
  53025. end: {
  53026. x: pivot.x,
  53027. y: pivot.y
  53028. }
  53029. }];
  53030. // Pivot before goal, use a waypoint to dodge obstacle
  53031. if (pivot[dirIsX ? 'x' : 'y'] !== toPoint[dirIsX ? 'x' : 'y']) {
  53032. // Find direction of waypoint
  53033. waypointUseMax = getDodgeDirection(pivot.obstacle, pivot, toPoint, !dirIsX, bounds);
  53034. // Cut waypoint to hard bounds
  53035. limitObstacleToBounds(pivot.obstacle, options.hardBounds);
  53036. waypoint = {
  53037. x: dirIsX ?
  53038. pivot.x :
  53039. pivot.obstacle[waypointUseMax ? 'xMax' : 'xMin'] +
  53040. (waypointUseMax ? 1 : -1),
  53041. y: dirIsX ?
  53042. pivot.obstacle[waypointUseMax ? 'yMax' : 'yMin'] +
  53043. (waypointUseMax ? 1 : -1) :
  53044. pivot.y
  53045. };
  53046. // We're changing direction here, store that to make sure we
  53047. // also change direction when adding the last segment array
  53048. // after handling waypoint.
  53049. dirIsX = !dirIsX;
  53050. segments = segments.concat(clearPathTo({
  53051. x: pivot.x,
  53052. y: pivot.y
  53053. }, waypoint, dirIsX));
  53054. }
  53055. }
  53056. // Get segments for the other direction too
  53057. // Recursion is our friend
  53058. segments = segments.concat(clearPathTo(segments[segments.length - 1].end, toPoint, !dirIsX));
  53059. return segments;
  53060. }
  53061. // eslint-disable-next-line valid-jsdoc
  53062. /**
  53063. * Extract point to outside of obstacle in whichever direction is
  53064. * closest. Returns new point outside obstacle.
  53065. * @private
  53066. */
  53067. function extractFromObstacle(obstacle, point, goalPoint) {
  53068. var dirIsX = min(obstacle.xMax - point.x,
  53069. point.x - obstacle.xMin) <
  53070. min(obstacle.yMax - point.y,
  53071. point.y - obstacle.yMin),
  53072. bounds = {
  53073. soft: options.hardBounds,
  53074. hard: options.hardBounds
  53075. },
  53076. useMax = getDodgeDirection(obstacle,
  53077. point,
  53078. goalPoint,
  53079. dirIsX,
  53080. bounds);
  53081. return dirIsX ? {
  53082. y: point.y,
  53083. x: obstacle[useMax ? 'xMax' : 'xMin'] + (useMax ? 1 : -1)
  53084. } : {
  53085. x: point.x,
  53086. y: obstacle[useMax ? 'yMax' : 'yMin'] + (useMax ? 1 : -1)
  53087. };
  53088. }
  53089. // Cut the obstacle array to soft bounds for optimization in large
  53090. // datasets.
  53091. chartObstacles =
  53092. chartObstacles.slice(startObstacleIx, endObstacleIx + 1);
  53093. // If an obstacle envelops the end point, move it out of there and add
  53094. // a little segment to where it was.
  53095. if ((endObstacleIx = findObstacleFromPoint(chartObstacles, end)) > -1) {
  53096. extractedEndPoint = extractFromObstacle(chartObstacles[endObstacleIx], end, start);
  53097. endSegments.push({
  53098. end: end,
  53099. start: extractedEndPoint
  53100. });
  53101. end = extractedEndPoint;
  53102. }
  53103. // If it's still inside one or more obstacles, get out of there by
  53104. // force-moving towards the start point.
  53105. while ((endObstacleIx = findObstacleFromPoint(chartObstacles, end)) > -1) {
  53106. useMax = end[dir] - start[dir] < 0;
  53107. extractedEndPoint = {
  53108. x: end.x,
  53109. y: end.y
  53110. };
  53111. extractedEndPoint[dir] = chartObstacles[endObstacleIx][useMax ? dir + 'Max' : dir + 'Min'] + (useMax ? 1 : -1);
  53112. endSegments.push({
  53113. end: end,
  53114. start: extractedEndPoint
  53115. });
  53116. end = extractedEndPoint;
  53117. }
  53118. // Find the path
  53119. segments = clearPathTo(start, end, dirIsX);
  53120. // Add the end-point segments
  53121. segments = segments.concat(endSegments.reverse());
  53122. return {
  53123. path: pathFromSegments(segments),
  53124. obstacles: segments
  53125. };
  53126. };
  53127. fastAvoid.requiresObstacles = true;
  53128. // Define the available pathfinding algorithms.
  53129. // Algorithms take up to 3 arguments: starting point, ending point, and an
  53130. // options object.
  53131. var algorithms = {
  53132. fastAvoid: fastAvoid,
  53133. straight: straight,
  53134. simpleConnect: simpleConnect
  53135. };
  53136. return algorithms;
  53137. });
  53138. _registerModule(_modules, 'Gantt/Pathfinder.js', [_modules['Gantt/Connection.js'], _modules['Core/Chart/Chart.js'], _modules['Core/Globals.js'], _modules['Core/DefaultOptions.js'], _modules['Core/Series/Point.js'], _modules['Core/Utilities.js'], _modules['Gantt/PathfinderAlgorithms.js']], function (Connection, Chart, H, D, Point, U, pathfinderAlgorithms) {
  53139. /* *
  53140. *
  53141. * (c) 2016 Highsoft AS
  53142. * Authors: Øystein Moseng, Lars A. V. Cabrera
  53143. *
  53144. * License: www.highcharts.com/license
  53145. *
  53146. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  53147. *
  53148. * */
  53149. /**
  53150. * The default pathfinder algorithm to use for a chart. It is possible to define
  53151. * your own algorithms by adding them to the
  53152. * `Highcharts.Pathfinder.prototype.algorithms`
  53153. * object before the chart has been created.
  53154. *
  53155. * The default algorithms are as follows:
  53156. *
  53157. * `straight`: Draws a straight line between the connecting
  53158. * points. Does not avoid other points when drawing.
  53159. *
  53160. * `simpleConnect`: Finds a path between the points using right angles
  53161. * only. Takes only starting/ending points into
  53162. * account, and will not avoid other points.
  53163. *
  53164. * `fastAvoid`: Finds a path between the points using right angles
  53165. * only. Will attempt to avoid other points, but its
  53166. * focus is performance over accuracy. Works well with
  53167. * less dense datasets.
  53168. *
  53169. * @typedef {"fastAvoid"|"simpleConnect"|"straight"|string} Highcharts.PathfinderTypeValue
  53170. */
  53171. ''; // detach doclets above
  53172. var defaultOptions = D.defaultOptions;
  53173. var addEvent = U.addEvent,
  53174. defined = U.defined,
  53175. error = U.error,
  53176. extend = U.extend,
  53177. merge = U.merge,
  53178. objectEach = U.objectEach,
  53179. pick = U.pick,
  53180. splat = U.splat;
  53181. var deg2rad = H.deg2rad,
  53182. max = Math.max,
  53183. min = Math.min;
  53184. /*
  53185. @todo:
  53186. - Document how to write your own algorithms
  53187. - Consider adding a Point.pathTo method that wraps creating a connection
  53188. and rendering it
  53189. */
  53190. // Set default Pathfinder options
  53191. extend(defaultOptions, {
  53192. /**
  53193. * The Pathfinder module allows you to define connections between any two
  53194. * points, represented as lines - optionally with markers for the start
  53195. * and/or end points. Multiple algorithms are available for calculating how
  53196. * the connecting lines are drawn.
  53197. *
  53198. * Connector functionality requires Highcharts Gantt to be loaded. In Gantt
  53199. * charts, the connectors are used to draw dependencies between tasks.
  53200. *
  53201. * @see [dependency](series.gantt.data.dependency)
  53202. *
  53203. * @sample gantt/pathfinder/demo
  53204. * Pathfinder connections
  53205. *
  53206. * @declare Highcharts.ConnectorsOptions
  53207. * @product gantt
  53208. * @optionparent connectors
  53209. */
  53210. connectors: {
  53211. /**
  53212. * Enable connectors for this chart. Requires Highcharts Gantt.
  53213. *
  53214. * @type {boolean}
  53215. * @default true
  53216. * @since 6.2.0
  53217. * @apioption connectors.enabled
  53218. */
  53219. /**
  53220. * Set the default dash style for this chart's connecting lines.
  53221. *
  53222. * @type {string}
  53223. * @default solid
  53224. * @since 6.2.0
  53225. * @apioption connectors.dashStyle
  53226. */
  53227. /**
  53228. * Set the default color for this chart's Pathfinder connecting lines.
  53229. * Defaults to the color of the point being connected.
  53230. *
  53231. * @type {Highcharts.ColorString}
  53232. * @since 6.2.0
  53233. * @apioption connectors.lineColor
  53234. */
  53235. /**
  53236. * Set the default pathfinder margin to use, in pixels. Some Pathfinder
  53237. * algorithms attempt to avoid obstacles, such as other points in the
  53238. * chart. These algorithms use this margin to determine how close lines
  53239. * can be to an obstacle. The default is to compute this automatically
  53240. * from the size of the obstacles in the chart.
  53241. *
  53242. * To draw connecting lines close to existing points, set this to a low
  53243. * number. For more space around existing points, set this number
  53244. * higher.
  53245. *
  53246. * @sample gantt/pathfinder/algorithm-margin
  53247. * Small algorithmMargin
  53248. *
  53249. * @type {number}
  53250. * @since 6.2.0
  53251. * @apioption connectors.algorithmMargin
  53252. */
  53253. /**
  53254. * Set the default pathfinder algorithm to use for this chart. It is
  53255. * possible to define your own algorithms by adding them to the
  53256. * Highcharts.Pathfinder.prototype.algorithms object before the chart
  53257. * has been created.
  53258. *
  53259. * The default algorithms are as follows:
  53260. *
  53261. * `straight`: Draws a straight line between the connecting
  53262. * points. Does not avoid other points when drawing.
  53263. *
  53264. * `simpleConnect`: Finds a path between the points using right angles
  53265. * only. Takes only starting/ending points into
  53266. * account, and will not avoid other points.
  53267. *
  53268. * `fastAvoid`: Finds a path between the points using right angles
  53269. * only. Will attempt to avoid other points, but its
  53270. * focus is performance over accuracy. Works well with
  53271. * less dense datasets.
  53272. *
  53273. * Default value: `straight` is used as default for most series types,
  53274. * while `simpleConnect` is used as default for Gantt series, to show
  53275. * dependencies between points.
  53276. *
  53277. * @sample gantt/pathfinder/demo
  53278. * Different types used
  53279. *
  53280. * @type {Highcharts.PathfinderTypeValue}
  53281. * @default undefined
  53282. * @since 6.2.0
  53283. */
  53284. type: 'straight',
  53285. /**
  53286. * Set the default pixel width for this chart's Pathfinder connecting
  53287. * lines.
  53288. *
  53289. * @since 6.2.0
  53290. */
  53291. lineWidth: 1,
  53292. /**
  53293. * Marker options for this chart's Pathfinder connectors. Note that
  53294. * this option is overridden by the `startMarker` and `endMarker`
  53295. * options.
  53296. *
  53297. * @declare Highcharts.ConnectorsMarkerOptions
  53298. * @since 6.2.0
  53299. */
  53300. marker: {
  53301. /**
  53302. * Set the radius of the connector markers. The default is
  53303. * automatically computed based on the algorithmMargin setting.
  53304. *
  53305. * Setting marker.width and marker.height will override this
  53306. * setting.
  53307. *
  53308. * @type {number}
  53309. * @since 6.2.0
  53310. * @apioption connectors.marker.radius
  53311. */
  53312. /**
  53313. * Set the width of the connector markers. If not supplied, this
  53314. * is inferred from the marker radius.
  53315. *
  53316. * @type {number}
  53317. * @since 6.2.0
  53318. * @apioption connectors.marker.width
  53319. */
  53320. /**
  53321. * Set the height of the connector markers. If not supplied, this
  53322. * is inferred from the marker radius.
  53323. *
  53324. * @type {number}
  53325. * @since 6.2.0
  53326. * @apioption connectors.marker.height
  53327. */
  53328. /**
  53329. * Set the color of the connector markers. By default this is the
  53330. * same as the connector color.
  53331. *
  53332. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  53333. * @since 6.2.0
  53334. * @apioption connectors.marker.color
  53335. */
  53336. /**
  53337. * Set the line/border color of the connector markers. By default
  53338. * this is the same as the marker color.
  53339. *
  53340. * @type {Highcharts.ColorString}
  53341. * @since 6.2.0
  53342. * @apioption connectors.marker.lineColor
  53343. */
  53344. /**
  53345. * Enable markers for the connectors.
  53346. */
  53347. enabled: false,
  53348. /**
  53349. * Horizontal alignment of the markers relative to the points.
  53350. *
  53351. * @type {Highcharts.AlignValue}
  53352. */
  53353. align: 'center',
  53354. /**
  53355. * Vertical alignment of the markers relative to the points.
  53356. *
  53357. * @type {Highcharts.VerticalAlignValue}
  53358. */
  53359. verticalAlign: 'middle',
  53360. /**
  53361. * Whether or not to draw the markers inside the points.
  53362. */
  53363. inside: false,
  53364. /**
  53365. * Set the line/border width of the pathfinder markers.
  53366. */
  53367. lineWidth: 1
  53368. },
  53369. /**
  53370. * Marker options specific to the start markers for this chart's
  53371. * Pathfinder connectors. Overrides the generic marker options.
  53372. *
  53373. * @declare Highcharts.ConnectorsStartMarkerOptions
  53374. * @extends connectors.marker
  53375. * @since 6.2.0
  53376. */
  53377. startMarker: {
  53378. /**
  53379. * Set the symbol of the connector start markers.
  53380. */
  53381. symbol: 'diamond'
  53382. },
  53383. /**
  53384. * Marker options specific to the end markers for this chart's
  53385. * Pathfinder connectors. Overrides the generic marker options.
  53386. *
  53387. * @declare Highcharts.ConnectorsEndMarkerOptions
  53388. * @extends connectors.marker
  53389. * @since 6.2.0
  53390. */
  53391. endMarker: {
  53392. /**
  53393. * Set the symbol of the connector end markers.
  53394. */
  53395. symbol: 'arrow-filled'
  53396. }
  53397. }
  53398. });
  53399. /**
  53400. * Override Pathfinder connector options for a series. Requires Highcharts Gantt
  53401. * to be loaded.
  53402. *
  53403. * @declare Highcharts.SeriesConnectorsOptionsObject
  53404. * @extends connectors
  53405. * @since 6.2.0
  53406. * @excluding enabled, algorithmMargin
  53407. * @product gantt
  53408. * @apioption plotOptions.series.connectors
  53409. */
  53410. /**
  53411. * Connect to a point. This option can be either a string, referring to the ID
  53412. * of another point, or an object, or an array of either. If the option is an
  53413. * array, each element defines a connection.
  53414. *
  53415. * @sample gantt/pathfinder/demo
  53416. * Different connection types
  53417. *
  53418. * @declare Highcharts.XrangePointConnectorsOptionsObject
  53419. * @type {string|Array<string|*>|*}
  53420. * @extends plotOptions.series.connectors
  53421. * @since 6.2.0
  53422. * @excluding enabled
  53423. * @product gantt
  53424. * @requires highcharts-gantt
  53425. * @apioption series.xrange.data.connect
  53426. */
  53427. /**
  53428. * The ID of the point to connect to.
  53429. *
  53430. * @type {string}
  53431. * @since 6.2.0
  53432. * @product gantt
  53433. * @apioption series.xrange.data.connect.to
  53434. */
  53435. /**
  53436. * Get point bounding box using plotX/plotY and shapeArgs. If using
  53437. * graphic.getBBox() directly, the bbox will be affected by animation.
  53438. *
  53439. * @private
  53440. * @function
  53441. *
  53442. * @param {Highcharts.Point} point
  53443. * The point to get BB of.
  53444. *
  53445. * @return {Highcharts.Dictionary<number>|null}
  53446. * Result xMax, xMin, yMax, yMin.
  53447. */
  53448. function getPointBB(point) {
  53449. var shapeArgs = point.shapeArgs,
  53450. bb;
  53451. // Prefer using shapeArgs (columns)
  53452. if (shapeArgs) {
  53453. return {
  53454. xMin: shapeArgs.x || 0,
  53455. xMax: (shapeArgs.x || 0) + (shapeArgs.width || 0),
  53456. yMin: shapeArgs.y || 0,
  53457. yMax: (shapeArgs.y || 0) + (shapeArgs.height || 0)
  53458. };
  53459. }
  53460. // Otherwise use plotX/plotY and bb
  53461. bb = point.graphic && point.graphic.getBBox();
  53462. return bb ? {
  53463. xMin: point.plotX - bb.width / 2,
  53464. xMax: point.plotX + bb.width / 2,
  53465. yMin: point.plotY - bb.height / 2,
  53466. yMax: point.plotY + bb.height / 2
  53467. } : null;
  53468. }
  53469. /**
  53470. * Calculate margin to place around obstacles for the pathfinder in pixels.
  53471. * Returns a minimum of 1 pixel margin.
  53472. *
  53473. * @private
  53474. * @function
  53475. *
  53476. * @param {Array<object>} obstacles
  53477. * Obstacles to calculate margin from.
  53478. *
  53479. * @return {number}
  53480. * The calculated margin in pixels. At least 1.
  53481. */
  53482. function calculateObstacleMargin(obstacles) {
  53483. var len = obstacles.length,
  53484. i = 0,
  53485. j,
  53486. obstacleDistance,
  53487. distances = [],
  53488. // Compute smallest distance between two rectangles
  53489. distance = function (a,
  53490. b,
  53491. bbMargin) {
  53492. // Count the distance even if we are slightly off
  53493. var margin = pick(bbMargin, 10),
  53494. yOverlap = a.yMax + margin > b.yMin - margin &&
  53495. a.yMin - margin < b.yMax + margin,
  53496. xOverlap = a.xMax + margin > b.xMin - margin &&
  53497. a.xMin - margin < b.xMax + margin,
  53498. xDistance = yOverlap ? (a.xMin > b.xMax ? a.xMin - b.xMax : b.xMin - a.xMax) : Infinity,
  53499. yDistance = xOverlap ? (a.yMin > b.yMax ? a.yMin - b.yMax : b.yMin - a.yMax) : Infinity;
  53500. // If the rectangles collide, try recomputing with smaller margin.
  53501. // If they collide anyway, discard the obstacle.
  53502. if (xOverlap && yOverlap) {
  53503. return (margin ?
  53504. distance(a, b, Math.floor(margin / 2)) :
  53505. Infinity);
  53506. }
  53507. return min(xDistance, yDistance);
  53508. };
  53509. // Go over all obstacles and compare them to the others.
  53510. for (; i < len; ++i) {
  53511. // Compare to all obstacles ahead. We will already have compared this
  53512. // obstacle to the ones before.
  53513. for (j = i + 1; j < len; ++j) {
  53514. obstacleDistance = distance(obstacles[i], obstacles[j]);
  53515. // TODO: Magic number 80
  53516. if (obstacleDistance < 80) { // Ignore large distances
  53517. distances.push(obstacleDistance);
  53518. }
  53519. }
  53520. }
  53521. // Ensure we always have at least one value, even in very spaceous charts
  53522. distances.push(80);
  53523. return max(Math.floor(distances.sort(function (a, b) {
  53524. return (a - b);
  53525. })[
  53526. // Discard first 10% of the relevant distances, and then grab
  53527. // the smallest one.
  53528. Math.floor(distances.length / 10)] / 2 - 1 // Divide the distance by 2 and subtract 1.
  53529. ), 1 // 1 is the minimum margin
  53530. );
  53531. }
  53532. /* eslint-disable no-invalid-this, valid-jsdoc */
  53533. /**
  53534. * The Pathfinder class.
  53535. *
  53536. * @private
  53537. * @class
  53538. * @name Highcharts.Pathfinder
  53539. *
  53540. * @param {Highcharts.Chart} chart
  53541. * The chart to operate on.
  53542. */
  53543. var Pathfinder = /** @class */ (function () {
  53544. function Pathfinder(chart) {
  53545. /* *
  53546. *
  53547. * Properties
  53548. *
  53549. * */
  53550. this.chart = void 0;
  53551. this.chartObstacles = void 0;
  53552. this.chartObstacleMetrics = void 0;
  53553. this.connections = void 0;
  53554. this.group = void 0;
  53555. this.lineObstacles = void 0;
  53556. this.init(chart);
  53557. }
  53558. /**
  53559. * @name Highcharts.Pathfinder#algorithms
  53560. * @type {Highcharts.Dictionary<Function>}
  53561. */
  53562. /**
  53563. * Initialize the Pathfinder object.
  53564. *
  53565. * @function Highcharts.Pathfinder#init
  53566. *
  53567. * @param {Highcharts.Chart} chart
  53568. * The chart context.
  53569. */
  53570. Pathfinder.prototype.init = function (chart) {
  53571. // Initialize pathfinder with chart context
  53572. this.chart = chart;
  53573. // Init connection reference list
  53574. this.connections = [];
  53575. // Recalculate paths/obstacles on chart redraw
  53576. addEvent(chart, 'redraw', function () {
  53577. this.pathfinder.update();
  53578. });
  53579. };
  53580. /**
  53581. * Update Pathfinder connections from scratch.
  53582. *
  53583. * @function Highcharts.Pathfinder#update
  53584. *
  53585. * @param {boolean} [deferRender]
  53586. * Whether or not to defer rendering of connections until
  53587. * series.afterAnimate event has fired. Used on first render.
  53588. */
  53589. Pathfinder.prototype.update = function (deferRender) {
  53590. var chart = this.chart,
  53591. pathfinder = this,
  53592. oldConnections = pathfinder.connections;
  53593. // Rebuild pathfinder connections from options
  53594. pathfinder.connections = [];
  53595. chart.series.forEach(function (series) {
  53596. if (series.visible && !series.options.isInternal) {
  53597. series.points.forEach(function (point) {
  53598. var ganttPointOptions = point.options;
  53599. // For Gantt series the connect could be
  53600. // defined as a dependency
  53601. if (ganttPointOptions && ganttPointOptions.dependency) {
  53602. ganttPointOptions.connect = ganttPointOptions.dependency;
  53603. }
  53604. var to,
  53605. connects = (point.options &&
  53606. point.options.connect &&
  53607. splat(point.options.connect));
  53608. if (point.visible && point.isInside !== false && connects) {
  53609. connects.forEach(function (connect) {
  53610. to = chart.get(typeof connect === 'string' ?
  53611. connect : connect.to);
  53612. if (to instanceof Point &&
  53613. to.series.visible &&
  53614. to.visible &&
  53615. to.isInside !== false) {
  53616. // Add new connection
  53617. pathfinder.connections.push(new Connection(point, // from
  53618. to, typeof connect === 'string' ?
  53619. {} :
  53620. connect));
  53621. }
  53622. });
  53623. }
  53624. });
  53625. }
  53626. });
  53627. // Clear connections that should not be updated, and move old info over
  53628. // to new connections.
  53629. for (var j = 0, k = void 0, found = void 0, lenOld = oldConnections.length, lenNew = pathfinder.connections.length; j < lenOld; ++j) {
  53630. found = false;
  53631. for (k = 0; k < lenNew; ++k) {
  53632. if (oldConnections[j].fromPoint ===
  53633. pathfinder.connections[k].fromPoint &&
  53634. oldConnections[j].toPoint ===
  53635. pathfinder.connections[k].toPoint) {
  53636. pathfinder.connections[k].graphics =
  53637. oldConnections[j].graphics;
  53638. found = true;
  53639. break;
  53640. }
  53641. }
  53642. if (!found) {
  53643. oldConnections[j].destroy();
  53644. }
  53645. }
  53646. // Clear obstacles to force recalculation. This must be done on every
  53647. // redraw in case positions have changed. Recalculation is handled in
  53648. // Connection.getPath on demand.
  53649. delete this.chartObstacles;
  53650. delete this.lineObstacles;
  53651. // Draw the pending connections
  53652. pathfinder.renderConnections(deferRender);
  53653. };
  53654. /**
  53655. * Draw the chart's connecting paths.
  53656. *
  53657. * @function Highcharts.Pathfinder#renderConnections
  53658. *
  53659. * @param {boolean} [deferRender]
  53660. * Whether or not to defer render until series animation is finished.
  53661. * Used on first render.
  53662. */
  53663. Pathfinder.prototype.renderConnections = function (deferRender) {
  53664. if (deferRender) {
  53665. // Render after series are done animating
  53666. this.chart.series.forEach(function (series) {
  53667. var render = function () {
  53668. // Find pathfinder connections belonging to this series
  53669. // that haven't rendered, and render them now.
  53670. var pathfinder = series.chart.pathfinder,
  53671. conns = pathfinder && pathfinder.connections || [];
  53672. conns.forEach(function (connection) {
  53673. if (connection.fromPoint &&
  53674. connection.fromPoint.series === series) {
  53675. connection.render();
  53676. }
  53677. });
  53678. if (series.pathfinderRemoveRenderEvent) {
  53679. series.pathfinderRemoveRenderEvent();
  53680. delete series.pathfinderRemoveRenderEvent;
  53681. }
  53682. };
  53683. if (series.options.animation === false) {
  53684. render();
  53685. }
  53686. else {
  53687. series.pathfinderRemoveRenderEvent = addEvent(series, 'afterAnimate', render);
  53688. }
  53689. });
  53690. }
  53691. else {
  53692. // Go through connections and render them
  53693. this.connections.forEach(function (connection) {
  53694. connection.render();
  53695. });
  53696. }
  53697. };
  53698. /**
  53699. * Get obstacles for the points in the chart. Does not include connecting
  53700. * lines from Pathfinder. Applies algorithmMargin to the obstacles.
  53701. *
  53702. * @function Highcharts.Pathfinder#getChartObstacles
  53703. *
  53704. * @param {object} options
  53705. * Options for the calculation. Currenlty only
  53706. * options.algorithmMargin.
  53707. *
  53708. * @return {Array<object>}
  53709. * An array of calculated obstacles. Each obstacle is defined as an
  53710. * object with xMin, xMax, yMin and yMax properties.
  53711. */
  53712. Pathfinder.prototype.getChartObstacles = function (options) {
  53713. var obstacles = [],
  53714. series = this.chart.series,
  53715. margin = pick(options.algorithmMargin, 0),
  53716. calculatedMargin;
  53717. for (var i = 0, sLen = series.length; i < sLen; ++i) {
  53718. if (series[i].visible && !series[i].options.isInternal) {
  53719. for (var j = 0, pLen = series[i].points.length, bb = void 0, point = void 0; j < pLen; ++j) {
  53720. point = series[i].points[j];
  53721. if (point.visible) {
  53722. bb = getPointBB(point);
  53723. if (bb) {
  53724. obstacles.push({
  53725. xMin: bb.xMin - margin,
  53726. xMax: bb.xMax + margin,
  53727. yMin: bb.yMin - margin,
  53728. yMax: bb.yMax + margin
  53729. });
  53730. }
  53731. }
  53732. }
  53733. }
  53734. }
  53735. // Sort obstacles by xMin for optimization
  53736. obstacles = obstacles.sort(function (a, b) {
  53737. return a.xMin - b.xMin;
  53738. });
  53739. // Add auto-calculated margin if the option is not defined
  53740. if (!defined(options.algorithmMargin)) {
  53741. calculatedMargin =
  53742. options.algorithmMargin =
  53743. calculateObstacleMargin(obstacles);
  53744. obstacles.forEach(function (obstacle) {
  53745. obstacle.xMin -= calculatedMargin;
  53746. obstacle.xMax += calculatedMargin;
  53747. obstacle.yMin -= calculatedMargin;
  53748. obstacle.yMax += calculatedMargin;
  53749. });
  53750. }
  53751. return obstacles;
  53752. };
  53753. /**
  53754. * Utility function to get metrics for obstacles:
  53755. * - Widest obstacle width
  53756. * - Tallest obstacle height
  53757. *
  53758. * @function Highcharts.Pathfinder#getObstacleMetrics
  53759. *
  53760. * @param {Array<object>} obstacles
  53761. * An array of obstacles to inspect.
  53762. *
  53763. * @return {object}
  53764. * The calculated metrics, as an object with maxHeight and maxWidth
  53765. * properties.
  53766. */
  53767. Pathfinder.prototype.getObstacleMetrics = function (obstacles) {
  53768. var maxWidth = 0,
  53769. maxHeight = 0,
  53770. width,
  53771. height,
  53772. i = obstacles.length;
  53773. while (i--) {
  53774. width = obstacles[i].xMax - obstacles[i].xMin;
  53775. height = obstacles[i].yMax - obstacles[i].yMin;
  53776. if (maxWidth < width) {
  53777. maxWidth = width;
  53778. }
  53779. if (maxHeight < height) {
  53780. maxHeight = height;
  53781. }
  53782. }
  53783. return {
  53784. maxHeight: maxHeight,
  53785. maxWidth: maxWidth
  53786. };
  53787. };
  53788. /**
  53789. * Utility to get which direction to start the pathfinding algorithm
  53790. * (X vs Y), calculated from a set of marker options.
  53791. *
  53792. * @function Highcharts.Pathfinder#getAlgorithmStartDirection
  53793. *
  53794. * @param {Highcharts.ConnectorsMarkerOptions} markerOptions
  53795. * Marker options to calculate from.
  53796. *
  53797. * @return {boolean}
  53798. * Returns true for X, false for Y, and undefined for autocalculate.
  53799. */
  53800. Pathfinder.prototype.getAlgorithmStartDirection = function (markerOptions) {
  53801. var xCenter = markerOptions.align !== 'left' &&
  53802. markerOptions.align !== 'right', yCenter = markerOptions.verticalAlign !== 'top' &&
  53803. markerOptions.verticalAlign !== 'bottom', undef;
  53804. return xCenter ?
  53805. (yCenter ? undef : false) : // x is centered
  53806. (yCenter ? true : undef); // x is off-center
  53807. };
  53808. return Pathfinder;
  53809. }());
  53810. Pathfinder.prototype.algorithms = pathfinderAlgorithms;
  53811. // Add to Highcharts namespace
  53812. H.Pathfinder = Pathfinder;
  53813. // Add pathfinding capabilities to Points
  53814. extend(Point.prototype, /** @lends Point.prototype */ {
  53815. /**
  53816. * Get coordinates of anchor point for pathfinder connection.
  53817. *
  53818. * @private
  53819. * @function Highcharts.Point#getPathfinderAnchorPoint
  53820. *
  53821. * @param {Highcharts.ConnectorsMarkerOptions} markerOptions
  53822. * Connection options for position on point.
  53823. *
  53824. * @return {Highcharts.PositionObject}
  53825. * An object with x/y properties for the position. Coordinates are
  53826. * in plot values, not relative to point.
  53827. */
  53828. getPathfinderAnchorPoint: function (markerOptions) {
  53829. var bb = getPointBB(this),
  53830. x,
  53831. y;
  53832. switch (markerOptions.align) { // eslint-disable-line default-case
  53833. case 'right':
  53834. x = 'xMax';
  53835. break;
  53836. case 'left':
  53837. x = 'xMin';
  53838. }
  53839. switch (markerOptions.verticalAlign) { // eslint-disable-line default-case
  53840. case 'top':
  53841. y = 'yMin';
  53842. break;
  53843. case 'bottom':
  53844. y = 'yMax';
  53845. }
  53846. return {
  53847. x: x ? bb[x] : (bb.xMin + bb.xMax) / 2,
  53848. y: y ? bb[y] : (bb.yMin + bb.yMax) / 2
  53849. };
  53850. },
  53851. /**
  53852. * Utility to get the angle from one point to another.
  53853. *
  53854. * @private
  53855. * @function Highcharts.Point#getRadiansToVector
  53856. *
  53857. * @param {Highcharts.PositionObject} v1
  53858. * The first vector, as an object with x/y properties.
  53859. *
  53860. * @param {Highcharts.PositionObject} v2
  53861. * The second vector, as an object with x/y properties.
  53862. *
  53863. * @return {number}
  53864. * The angle in degrees
  53865. */
  53866. getRadiansToVector: function (v1, v2) {
  53867. var box;
  53868. if (!defined(v2)) {
  53869. box = getPointBB(this);
  53870. if (box) {
  53871. v2 = {
  53872. x: (box.xMin + box.xMax) / 2,
  53873. y: (box.yMin + box.yMax) / 2
  53874. };
  53875. }
  53876. }
  53877. return Math.atan2(v2.y - v1.y, v1.x - v2.x);
  53878. },
  53879. /**
  53880. * Utility to get the position of the marker, based on the path angle and
  53881. * the marker's radius.
  53882. *
  53883. * @private
  53884. * @function Highcharts.Point#getMarkerVector
  53885. *
  53886. * @param {number} radians
  53887. * The angle in radians from the point center to another vector.
  53888. *
  53889. * @param {number} markerRadius
  53890. * The radius of the marker, to calculate the additional distance to
  53891. * the center of the marker.
  53892. *
  53893. * @param {object} anchor
  53894. * The anchor point of the path and marker as an object with x/y
  53895. * properties.
  53896. *
  53897. * @return {object}
  53898. * The marker vector as an object with x/y properties.
  53899. */
  53900. getMarkerVector: function (radians, markerRadius, anchor) {
  53901. var twoPI = Math.PI * 2.0,
  53902. theta = radians,
  53903. bb = getPointBB(this),
  53904. rectWidth = bb.xMax - bb.xMin,
  53905. rectHeight = bb.yMax - bb.yMin,
  53906. rAtan = Math.atan2(rectHeight,
  53907. rectWidth),
  53908. tanTheta = 1,
  53909. leftOrRightRegion = false,
  53910. rectHalfWidth = rectWidth / 2.0,
  53911. rectHalfHeight = rectHeight / 2.0,
  53912. rectHorizontalCenter = bb.xMin + rectHalfWidth,
  53913. rectVerticalCenter = bb.yMin + rectHalfHeight,
  53914. edgePoint = {
  53915. x: rectHorizontalCenter,
  53916. y: rectVerticalCenter
  53917. },
  53918. xFactor = 1,
  53919. yFactor = 1;
  53920. while (theta < -Math.PI) {
  53921. theta += twoPI;
  53922. }
  53923. while (theta > Math.PI) {
  53924. theta -= twoPI;
  53925. }
  53926. tanTheta = Math.tan(theta);
  53927. if ((theta > -rAtan) && (theta <= rAtan)) {
  53928. // Right side
  53929. yFactor = -1;
  53930. leftOrRightRegion = true;
  53931. }
  53932. else if (theta > rAtan && theta <= (Math.PI - rAtan)) {
  53933. // Top side
  53934. yFactor = -1;
  53935. }
  53936. else if (theta > (Math.PI - rAtan) || theta <= -(Math.PI - rAtan)) {
  53937. // Left side
  53938. xFactor = -1;
  53939. leftOrRightRegion = true;
  53940. }
  53941. else {
  53942. // Bottom side
  53943. xFactor = -1;
  53944. }
  53945. // Correct the edgePoint according to the placement of the marker
  53946. if (leftOrRightRegion) {
  53947. edgePoint.x += xFactor * (rectHalfWidth);
  53948. edgePoint.y += yFactor * (rectHalfWidth) * tanTheta;
  53949. }
  53950. else {
  53951. edgePoint.x += xFactor * (rectHeight / (2.0 * tanTheta));
  53952. edgePoint.y += yFactor * (rectHalfHeight);
  53953. }
  53954. if (anchor.x !== rectHorizontalCenter) {
  53955. edgePoint.x = anchor.x;
  53956. }
  53957. if (anchor.y !== rectVerticalCenter) {
  53958. edgePoint.y = anchor.y;
  53959. }
  53960. return {
  53961. x: edgePoint.x + (markerRadius * Math.cos(theta)),
  53962. y: edgePoint.y - (markerRadius * Math.sin(theta))
  53963. };
  53964. }
  53965. });
  53966. /**
  53967. * Warn if using legacy options. Copy the options over. Note that this will
  53968. * still break if using the legacy options in chart.update, addSeries etc.
  53969. * @private
  53970. */
  53971. function warnLegacy(chart) {
  53972. if (chart.options.pathfinder ||
  53973. chart.series.reduce(function (acc, series) {
  53974. if (series.options) {
  53975. merge(true, (series.options.connectors = series.options.connectors ||
  53976. {}), series.options.pathfinder);
  53977. }
  53978. return acc || series.options && series.options.pathfinder;
  53979. }, false)) {
  53980. merge(true, (chart.options.connectors = chart.options.connectors || {}), chart.options.pathfinder);
  53981. error('WARNING: Pathfinder options have been renamed. ' +
  53982. 'Use "chart.connectors" or "series.connectors" instead.');
  53983. }
  53984. }
  53985. // Initialize Pathfinder for charts
  53986. Chart.prototype.callbacks.push(function (chart) {
  53987. var options = chart.options;
  53988. if (options.connectors.enabled !== false) {
  53989. warnLegacy(chart);
  53990. this.pathfinder = new Pathfinder(this);
  53991. this.pathfinder.update(true); // First draw, defer render
  53992. }
  53993. });
  53994. return Pathfinder;
  53995. });
  53996. _registerModule(_modules, 'Series/Gantt/GanttSeries.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Chart/Chart.js'], _modules['Series/Gantt/GanttPoint.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Axis/Tick.js'], _modules['Core/Utilities.js'], _modules['Core/Axis/TreeGridAxis.js']], function (Axis, Chart, GanttPoint, SeriesRegistry, Tick, U, TreeGridAxis) {
  53997. /* *
  53998. *
  53999. * (c) 2016-2021 Highsoft AS
  54000. *
  54001. * Author: Lars A. V. Cabrera
  54002. *
  54003. * License: www.highcharts.com/license
  54004. *
  54005. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  54006. *
  54007. * */
  54008. var __extends = (this && this.__extends) || (function () {
  54009. var extendStatics = function (d,
  54010. b) {
  54011. extendStatics = Object.setPrototypeOf ||
  54012. ({ __proto__: [] } instanceof Array && function (d,
  54013. b) { d.__proto__ = b; }) ||
  54014. function (d,
  54015. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  54016. return extendStatics(d, b);
  54017. };
  54018. return function (d, b) {
  54019. extendStatics(d, b);
  54020. function __() { this.constructor = d; }
  54021. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  54022. };
  54023. })();
  54024. var Series = SeriesRegistry.series,
  54025. XRangeSeries = SeriesRegistry.seriesTypes.xrange;
  54026. var extend = U.extend,
  54027. isNumber = U.isNumber,
  54028. merge = U.merge,
  54029. splat = U.splat;
  54030. TreeGridAxis.compose(Axis, Chart, Series, Tick);
  54031. /* *
  54032. *
  54033. * Class
  54034. *
  54035. * */
  54036. /**
  54037. * @private
  54038. * @class
  54039. * @name Highcharts.seriesTypes.gantt
  54040. *
  54041. * @augments Highcharts.Series
  54042. */
  54043. var GanttSeries = /** @class */ (function (_super) {
  54044. __extends(GanttSeries, _super);
  54045. function GanttSeries() {
  54046. var _this = _super !== null && _super.apply(this,
  54047. arguments) || this;
  54048. /* *
  54049. *
  54050. * Properties
  54051. *
  54052. * */
  54053. _this.data = void 0;
  54054. _this.options = void 0;
  54055. _this.points = void 0;
  54056. return _this;
  54057. /* eslint-enable valid-jsdoc */
  54058. }
  54059. /* *
  54060. *
  54061. * Functions
  54062. *
  54063. * */
  54064. /* eslint-disable valid-jsdoc */
  54065. /**
  54066. * Draws a single point in the series.
  54067. *
  54068. * This override draws the point as a diamond if point.options.milestone
  54069. * is true, and uses the original drawPoint() if it is false or not set.
  54070. *
  54071. * @requires highcharts-gantt
  54072. *
  54073. * @private
  54074. * @function Highcharts.seriesTypes.gantt#drawPoint
  54075. *
  54076. * @param {Highcharts.Point} point
  54077. * An instance of Point in the series
  54078. *
  54079. * @param {"animate"|"attr"} verb
  54080. * 'animate' (animates changes) or 'attr' (sets options)
  54081. */
  54082. GanttSeries.prototype.drawPoint = function (point, verb) {
  54083. var series = this,
  54084. seriesOpts = series.options,
  54085. renderer = series.chart.renderer,
  54086. shapeArgs = point.shapeArgs,
  54087. plotY = point.plotY,
  54088. graphic = point.graphic,
  54089. state = point.selected && 'select',
  54090. cutOff = seriesOpts.stacking && !seriesOpts.borderRadius,
  54091. diamondShape;
  54092. if (point.options.milestone) {
  54093. if (isNumber(plotY) && point.y !== null && point.visible !== false) {
  54094. diamondShape = renderer.symbols.diamond(shapeArgs.x || 0, shapeArgs.y || 0, shapeArgs.width || 0, shapeArgs.height || 0);
  54095. if (graphic) {
  54096. graphic[verb]({
  54097. d: diamondShape
  54098. });
  54099. }
  54100. else {
  54101. point.graphic = graphic = renderer.path(diamondShape)
  54102. .addClass(point.getClassName(), true)
  54103. .add(point.group || series.group);
  54104. }
  54105. // Presentational
  54106. if (!series.chart.styledMode) {
  54107. point.graphic
  54108. .attr(series.pointAttribs(point, state))
  54109. .shadow(seriesOpts.shadow, null, cutOff);
  54110. }
  54111. }
  54112. else if (graphic) {
  54113. point.graphic = graphic.destroy(); // #1269
  54114. }
  54115. }
  54116. else {
  54117. XRangeSeries.prototype.drawPoint.call(series, point, verb);
  54118. }
  54119. };
  54120. /**
  54121. * Handle milestones, as they have no x2.
  54122. * @private
  54123. */
  54124. GanttSeries.prototype.translatePoint = function (point) {
  54125. var series = this,
  54126. shapeArgs,
  54127. size;
  54128. XRangeSeries.prototype.translatePoint.call(series, point);
  54129. if (point.options.milestone) {
  54130. shapeArgs = point.shapeArgs;
  54131. size = shapeArgs.height || 0;
  54132. point.shapeArgs = {
  54133. x: (shapeArgs.x || 0) - (size / 2),
  54134. y: shapeArgs.y,
  54135. width: size,
  54136. height: size
  54137. };
  54138. }
  54139. };
  54140. /**
  54141. * A `gantt` series. If the [type](#series.gantt.type) option is not specified,
  54142. * it is inherited from [chart.type](#chart.type).
  54143. *
  54144. * @extends plotOptions.xrange
  54145. * @product gantt
  54146. * @requires highcharts-gantt
  54147. * @optionparent plotOptions.gantt
  54148. */
  54149. GanttSeries.defaultOptions = merge(XRangeSeries.defaultOptions, {
  54150. // options - default options merged with parent
  54151. grouping: false,
  54152. dataLabels: {
  54153. enabled: true
  54154. },
  54155. tooltip: {
  54156. headerFormat: '<span style="font-size: 10px">{series.name}</span><br/>',
  54157. pointFormat: null,
  54158. pointFormatter: function () {
  54159. var point = this,
  54160. series = point.series,
  54161. tooltip = series.chart.tooltip,
  54162. xAxis = series.xAxis,
  54163. formats = series.tooltipOptions.dateTimeLabelFormats,
  54164. startOfWeek = xAxis.options.startOfWeek,
  54165. ttOptions = series.tooltipOptions,
  54166. format = ttOptions.xDateFormat,
  54167. start,
  54168. end,
  54169. milestone = point.options.milestone,
  54170. retVal = '<b>' + (point.name || point.yCategory) + '</b>';
  54171. if (ttOptions.pointFormat) {
  54172. return point.tooltipFormatter(ttOptions.pointFormat);
  54173. }
  54174. if (!format) {
  54175. format = splat(tooltip.getDateFormat(xAxis.closestPointRange, point.start, startOfWeek, formats))[0];
  54176. }
  54177. start = series.chart.time.dateFormat(format, point.start);
  54178. end = series.chart.time.dateFormat(format, point.end);
  54179. retVal += '<br/>';
  54180. if (!milestone) {
  54181. retVal += 'Start: ' + start + '<br/>';
  54182. retVal += 'End: ' + end + '<br/>';
  54183. }
  54184. else {
  54185. retVal += start + '<br/>';
  54186. }
  54187. return retVal;
  54188. }
  54189. },
  54190. connectors: {
  54191. type: 'simpleConnect',
  54192. /**
  54193. * @declare Highcharts.ConnectorsAnimationOptionsObject
  54194. */
  54195. animation: {
  54196. reversed: true // Dependencies go from child to parent
  54197. },
  54198. startMarker: {
  54199. enabled: true,
  54200. symbol: 'arrow-filled',
  54201. radius: 4,
  54202. fill: '#fa0',
  54203. align: 'left'
  54204. },
  54205. endMarker: {
  54206. enabled: false,
  54207. align: 'right'
  54208. }
  54209. }
  54210. });
  54211. return GanttSeries;
  54212. }(XRangeSeries));
  54213. extend(GanttSeries.prototype, {
  54214. // Keyboard navigation, don't use nearest vertical mode
  54215. keyboardMoveVertical: false,
  54216. pointArrayMap: ['start', 'end', 'y'],
  54217. pointClass: GanttPoint,
  54218. setData: Series.prototype.setData
  54219. });
  54220. SeriesRegistry.registerSeriesType('gantt', GanttSeries);
  54221. /* *
  54222. *
  54223. * Default Export
  54224. *
  54225. * */
  54226. /* *
  54227. *
  54228. * API Options
  54229. *
  54230. * */
  54231. /**
  54232. * A `gantt` series.
  54233. *
  54234. * @extends series,plotOptions.gantt
  54235. * @excluding boostThreshold, connectors, dashStyle, findNearestPointBy,
  54236. * getExtremesFromAll, marker, negativeColor, pointInterval,
  54237. * pointIntervalUnit, pointPlacement, pointStart
  54238. * @product gantt
  54239. * @requires highcharts-gantt
  54240. * @apioption series.gantt
  54241. */
  54242. /**
  54243. * Data for a Gantt series.
  54244. *
  54245. * @declare Highcharts.GanttPointOptionsObject
  54246. * @type {Array<*>}
  54247. * @extends series.xrange.data
  54248. * @excluding className, connect, dataLabels, events,
  54249. * partialFill, selected, x, x2
  54250. * @product gantt
  54251. * @apioption series.gantt.data
  54252. */
  54253. /**
  54254. * Whether the grid node belonging to this point should start as collapsed. Used
  54255. * in axes of type treegrid.
  54256. *
  54257. * @sample {gantt} gantt/treegrid-axis/collapsed/
  54258. * Start as collapsed
  54259. *
  54260. * @type {boolean}
  54261. * @default false
  54262. * @product gantt
  54263. * @apioption series.gantt.data.collapsed
  54264. */
  54265. /**
  54266. * The start time of a task.
  54267. *
  54268. * @type {number}
  54269. * @product gantt
  54270. * @apioption series.gantt.data.start
  54271. */
  54272. /**
  54273. * The end time of a task.
  54274. *
  54275. * @type {number}
  54276. * @product gantt
  54277. * @apioption series.gantt.data.end
  54278. */
  54279. /**
  54280. * The Y value of a task.
  54281. *
  54282. * @type {number}
  54283. * @product gantt
  54284. * @apioption series.gantt.data.y
  54285. */
  54286. /**
  54287. * The name of a task. If a `treegrid` y-axis is used (default in Gantt charts),
  54288. * this will be picked up automatically, and used to calculate the y-value.
  54289. *
  54290. * @type {string}
  54291. * @product gantt
  54292. * @apioption series.gantt.data.name
  54293. */
  54294. /**
  54295. * Progress indicator, how much of the task completed. If it is a number, the
  54296. * `fill` will be applied automatically.
  54297. *
  54298. * @sample {gantt} gantt/demo/progress-indicator
  54299. * Progress indicator
  54300. *
  54301. * @type {number|*}
  54302. * @extends series.xrange.data.partialFill
  54303. * @product gantt
  54304. * @apioption series.gantt.data.completed
  54305. */
  54306. /**
  54307. * The amount of the progress indicator, ranging from 0 (not started) to 1
  54308. * (finished).
  54309. *
  54310. * @type {number}
  54311. * @default 0
  54312. * @apioption series.gantt.data.completed.amount
  54313. */
  54314. /**
  54315. * The fill of the progress indicator. Defaults to a darkened variety of the
  54316. * main color.
  54317. *
  54318. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  54319. * @apioption series.gantt.data.completed.fill
  54320. */
  54321. /**
  54322. * The ID of the point (task) that this point depends on in Gantt charts.
  54323. * Aliases [connect](series.xrange.data.connect). Can also be an object,
  54324. * specifying further connecting [options](series.gantt.connectors) between the
  54325. * points. Multiple connections can be specified by providing an array.
  54326. *
  54327. * @sample gantt/demo/project-management
  54328. * Dependencies
  54329. * @sample gantt/pathfinder/demo
  54330. * Different connection types
  54331. *
  54332. * @type {string|Array<string|*>|*}
  54333. * @extends series.xrange.data.connect
  54334. * @since 6.2.0
  54335. * @product gantt
  54336. * @apioption series.gantt.data.dependency
  54337. */
  54338. /**
  54339. * Whether this point is a milestone. If so, only the `start` option is handled,
  54340. * while `end` is ignored.
  54341. *
  54342. * @sample gantt/gantt/milestones
  54343. * Milestones
  54344. *
  54345. * @type {boolean}
  54346. * @since 6.2.0
  54347. * @product gantt
  54348. * @apioption series.gantt.data.milestone
  54349. */
  54350. /**
  54351. * The ID of the parent point (task) of this point in Gantt charts.
  54352. *
  54353. * @sample gantt/demo/subtasks
  54354. * Gantt chart with subtasks
  54355. *
  54356. * @type {string}
  54357. * @since 6.2.0
  54358. * @product gantt
  54359. * @apioption series.gantt.data.parent
  54360. */
  54361. /**
  54362. * @excluding afterAnimate
  54363. * @apioption series.gantt.events
  54364. */
  54365. ''; // adds doclets above to the transpiled file
  54366. return GanttSeries;
  54367. });
  54368. _registerModule(_modules, 'Core/Chart/GanttChart.js', [_modules['Core/Chart/Chart.js'], _modules['Core/DefaultOptions.js'], _modules['Core/Utilities.js']], function (Chart, D, U) {
  54369. /* *
  54370. *
  54371. * (c) 2016-2021 Highsoft AS
  54372. *
  54373. * Author: Lars A. V. Cabrera
  54374. *
  54375. * License: www.highcharts.com/license
  54376. *
  54377. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  54378. *
  54379. * */
  54380. var __extends = (this && this.__extends) || (function () {
  54381. var extendStatics = function (d,
  54382. b) {
  54383. extendStatics = Object.setPrototypeOf ||
  54384. ({ __proto__: [] } instanceof Array && function (d,
  54385. b) { d.__proto__ = b; }) ||
  54386. function (d,
  54387. b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  54388. return extendStatics(d, b);
  54389. };
  54390. return function (d, b) {
  54391. extendStatics(d, b);
  54392. function __() { this.constructor = d; }
  54393. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  54394. };
  54395. })();
  54396. var getOptions = D.getOptions;
  54397. var isArray = U.isArray,
  54398. merge = U.merge,
  54399. splat = U.splat;
  54400. /* *
  54401. *
  54402. * Class
  54403. *
  54404. * */
  54405. /**
  54406. * Gantt-optimized chart. Use {@link Highcharts.Chart|Chart} for common charts.
  54407. *
  54408. * @requires modules/gantt
  54409. *
  54410. * @class
  54411. * @name Highcharts.GanttChart
  54412. * @extends Highcharts.Chart
  54413. */
  54414. var GanttChart = /** @class */ (function (_super) {
  54415. __extends(GanttChart, _super);
  54416. function GanttChart() {
  54417. return _super !== null && _super.apply(this, arguments) || this;
  54418. }
  54419. /**
  54420. * Initializes the chart. The constructor's arguments are passed on
  54421. * directly.
  54422. *
  54423. * @function Highcharts.GanttChart#init
  54424. *
  54425. * @param {Highcharts.Options} userOptions
  54426. * Custom options.
  54427. *
  54428. * @param {Function} [callback]
  54429. * Function to run when the chart has loaded and and all external
  54430. * images are loaded.
  54431. *
  54432. * @return {void}
  54433. *
  54434. * @fires Highcharts.GanttChart#event:init
  54435. * @fires Highcharts.GanttChart#event:afterInit
  54436. */
  54437. GanttChart.prototype.init = function (userOptions, callback) {
  54438. var defaultOptions = getOptions(),
  54439. xAxisOptions = userOptions.xAxis,
  54440. yAxisOptions = userOptions.yAxis;
  54441. var defaultLinkedTo;
  54442. // Avoid doing these twice
  54443. userOptions.xAxis = userOptions.yAxis = void 0;
  54444. var options = merge(true, {
  54445. chart: {
  54446. type: 'gantt'
  54447. },
  54448. title: {
  54449. text: null
  54450. },
  54451. legend: {
  54452. enabled: false
  54453. },
  54454. navigator: {
  54455. series: { type: 'gantt' },
  54456. // Bars were clipped, #14060.
  54457. yAxis: {
  54458. type: 'category'
  54459. }
  54460. }
  54461. },
  54462. userOptions, // user's options
  54463. // forced options
  54464. {
  54465. isGantt: true
  54466. });
  54467. userOptions.xAxis = xAxisOptions;
  54468. userOptions.yAxis = yAxisOptions;
  54469. // apply X axis options to both single and multi x axes
  54470. // If user hasn't defined axes as array, make it into an array and add a
  54471. // second axis by default.
  54472. options.xAxis = (!isArray(userOptions.xAxis) ?
  54473. [userOptions.xAxis || {}, {}] :
  54474. userOptions.xAxis).map(function (xAxisOptions, i) {
  54475. if (i === 1) { // Second xAxis
  54476. defaultLinkedTo = 0;
  54477. }
  54478. return merge(defaultOptions.xAxis, {
  54479. grid: {
  54480. enabled: true
  54481. },
  54482. opposite: true,
  54483. linkedTo: defaultLinkedTo
  54484. }, xAxisOptions, // user options
  54485. {
  54486. type: 'datetime'
  54487. });
  54488. });
  54489. // apply Y axis options to both single and multi y axes
  54490. options.yAxis = (splat(userOptions.yAxis || {})).map(function (yAxisOptions) {
  54491. return merge(defaultOptions.yAxis, // #3802
  54492. {
  54493. grid: {
  54494. enabled: true
  54495. },
  54496. staticScale: 50,
  54497. reversed: true,
  54498. // Set default type treegrid, but only if 'categories' is
  54499. // undefined
  54500. type: yAxisOptions.categories ? yAxisOptions.type : 'treegrid'
  54501. }, yAxisOptions // user options
  54502. );
  54503. });
  54504. _super.prototype.init.call(this, options, callback);
  54505. };
  54506. return GanttChart;
  54507. }(Chart));
  54508. /* eslint-disable valid-jsdoc */
  54509. (function (GanttChart) {
  54510. /**
  54511. * The factory function for creating new gantt charts. Creates a new {@link
  54512. * Highcharts.GanttChart|GanttChart} object with different default options
  54513. * than the basic Chart.
  54514. *
  54515. * @example
  54516. * // Render a chart in to div#container
  54517. * let chart = Highcharts.ganttChart('container', {
  54518. * title: {
  54519. * text: 'My chart'
  54520. * },
  54521. * series: [{
  54522. * data: ...
  54523. * }]
  54524. * });
  54525. *
  54526. * @function Highcharts.ganttChart
  54527. *
  54528. * @param {string|Highcharts.HTMLDOMElement} renderTo
  54529. * The DOM element to render to, or its id.
  54530. *
  54531. * @param {Highcharts.Options} options
  54532. * The chart options structure.
  54533. *
  54534. * @param {Highcharts.ChartCallbackFunction} [callback]
  54535. * Function to run when the chart has loaded and and all external
  54536. * images are loaded. Defining a
  54537. * [chart.events.load](https://api.highcharts.com/highcharts/chart.events.load)
  54538. * handler is equivalent.
  54539. *
  54540. * @return {Highcharts.GanttChart}
  54541. * Returns the Chart object.
  54542. */
  54543. function ganttChart(a, b, c) {
  54544. return new GanttChart(a, b, c);
  54545. }
  54546. GanttChart.ganttChart = ganttChart;
  54547. })(GanttChart || (GanttChart = {}));
  54548. return GanttChart;
  54549. });
  54550. _registerModule(_modules, 'Core/Axis/ScrollbarAxis.js', [_modules['Core/Utilities.js']], function (U) {
  54551. /* *
  54552. *
  54553. * (c) 2010-2021 Torstein Honsi
  54554. *
  54555. * License: www.highcharts.com/license
  54556. *
  54557. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  54558. *
  54559. * */
  54560. var addEvent = U.addEvent,
  54561. defined = U.defined,
  54562. pick = U.pick;
  54563. /* *
  54564. *
  54565. * Composition
  54566. *
  54567. * */
  54568. /* eslint-disable no-invalid-this, valid-jsdoc */
  54569. /**
  54570. * Creates scrollbars if enabled.
  54571. * @private
  54572. */
  54573. var ScrollbarAxis = /** @class */ (function () {
  54574. function ScrollbarAxis() {
  54575. }
  54576. /**
  54577. * Attaches to axis events to create scrollbars if enabled.
  54578. *
  54579. * @private
  54580. *
  54581. * @param AxisClass
  54582. * Axis class to extend.
  54583. *
  54584. * @param ScrollbarClass
  54585. * Scrollbar class to use.
  54586. */
  54587. ScrollbarAxis.compose = function (AxisClass, ScrollbarClass) {
  54588. var getExtremes = function (axis) {
  54589. var axisMin = pick(axis.options && axis.options.min, axis.min);
  54590. var axisMax = pick(axis.options && axis.options.max,
  54591. axis.max);
  54592. return {
  54593. axisMin: axisMin,
  54594. axisMax: axisMax,
  54595. scrollMin: defined(axis.dataMin) ?
  54596. Math.min(axisMin, axis.min, axis.dataMin, pick(axis.threshold, Infinity)) : axisMin,
  54597. scrollMax: defined(axis.dataMax) ?
  54598. Math.max(axisMax, axis.max, axis.dataMax, pick(axis.threshold, -Infinity)) : axisMax
  54599. };
  54600. };
  54601. // Wrap axis initialization and create scrollbar if enabled:
  54602. addEvent(AxisClass, 'afterInit', function () {
  54603. var axis = this;
  54604. if (axis.options &&
  54605. axis.options.scrollbar &&
  54606. axis.options.scrollbar.enabled) {
  54607. // Predefined options:
  54608. axis.options.scrollbar.vertical = !axis.horiz;
  54609. axis.options.startOnTick = axis.options.endOnTick = false;
  54610. axis.scrollbar = new ScrollbarClass(axis.chart.renderer, axis.options.scrollbar, axis.chart);
  54611. addEvent(axis.scrollbar, 'changed', function (e) {
  54612. var _a = getExtremes(axis),
  54613. axisMin = _a.axisMin,
  54614. axisMax = _a.axisMax,
  54615. unitedMin = _a.scrollMin,
  54616. unitedMax = _a.scrollMax,
  54617. range = unitedMax - unitedMin,
  54618. to,
  54619. from;
  54620. // #12834, scroll when show/hide series, wrong extremes
  54621. if (!defined(axisMin) || !defined(axisMax)) {
  54622. return;
  54623. }
  54624. if ((axis.horiz && !axis.reversed) ||
  54625. (!axis.horiz && axis.reversed)) {
  54626. to = unitedMin + range * this.to;
  54627. from = unitedMin + range * this.from;
  54628. }
  54629. else {
  54630. // y-values in browser are reversed, but this also
  54631. // applies for reversed horizontal axis:
  54632. to = unitedMin + range * (1 - this.from);
  54633. from = unitedMin + range * (1 - this.to);
  54634. }
  54635. if (this.shouldUpdateExtremes(e.DOMType)) {
  54636. axis.setExtremes(from, to, true, e.DOMType !== 'mousemove' && e.DOMType !== 'touchmove', e);
  54637. }
  54638. else {
  54639. // When live redraw is disabled, don't change extremes
  54640. // Only change the position of the scollbar thumb
  54641. this.setRange(this.from, this.to);
  54642. }
  54643. });
  54644. }
  54645. });
  54646. // Wrap rendering axis, and update scrollbar if one is created:
  54647. addEvent(AxisClass, 'afterRender', function () {
  54648. var axis = this,
  54649. _a = getExtremes(axis),
  54650. scrollMin = _a.scrollMin,
  54651. scrollMax = _a.scrollMax,
  54652. scrollbar = axis.scrollbar,
  54653. offset = axis.axisTitleMargin + (axis.titleOffset || 0),
  54654. scrollbarsOffsets = axis.chart.scrollbarsOffsets,
  54655. axisMargin = axis.options.margin || 0,
  54656. offsetsIndex,
  54657. from,
  54658. to;
  54659. if (scrollbar) {
  54660. if (axis.horiz) {
  54661. // Reserve space for labels/title
  54662. if (!axis.opposite) {
  54663. scrollbarsOffsets[1] += offset;
  54664. }
  54665. scrollbar.position(axis.left, axis.top + axis.height + 2 + scrollbarsOffsets[1] -
  54666. (axis.opposite ? axisMargin : 0), axis.width, axis.height);
  54667. // Next scrollbar should reserve space for margin (if set)
  54668. if (!axis.opposite) {
  54669. scrollbarsOffsets[1] += axisMargin;
  54670. }
  54671. offsetsIndex = 1;
  54672. }
  54673. else {
  54674. // Reserve space for labels/title
  54675. if (axis.opposite) {
  54676. scrollbarsOffsets[0] += offset;
  54677. }
  54678. scrollbar.position(axis.left + axis.width + 2 + scrollbarsOffsets[0] -
  54679. (axis.opposite ? 0 : axisMargin), axis.top, axis.width, axis.height);
  54680. // Next scrollbar should reserve space for margin (if set)
  54681. if (axis.opposite) {
  54682. scrollbarsOffsets[0] += axisMargin;
  54683. }
  54684. offsetsIndex = 0;
  54685. }
  54686. scrollbarsOffsets[offsetsIndex] += scrollbar.size +
  54687. scrollbar.options.margin;
  54688. if (isNaN(scrollMin) ||
  54689. isNaN(scrollMax) ||
  54690. !defined(axis.min) ||
  54691. !defined(axis.max) ||
  54692. axis.min === axis.max // #10733
  54693. ) {
  54694. // default action: when extremes are the same or there is
  54695. // not extremes on the axis, but scrollbar exists, make it
  54696. // full size
  54697. scrollbar.setRange(0, 1);
  54698. }
  54699. else {
  54700. from =
  54701. (axis.min - scrollMin) / (scrollMax - scrollMin);
  54702. to =
  54703. (axis.max - scrollMin) / (scrollMax - scrollMin);
  54704. if ((axis.horiz && !axis.reversed) ||
  54705. (!axis.horiz && axis.reversed)) {
  54706. scrollbar.setRange(from, to);
  54707. }
  54708. else {
  54709. // inverse vertical axis
  54710. scrollbar.setRange(1 - to, 1 - from);
  54711. }
  54712. }
  54713. }
  54714. });
  54715. // Make space for a scrollbar:
  54716. addEvent(AxisClass, 'afterGetOffset', function () {
  54717. var axis = this,
  54718. index = axis.horiz ? 2 : 1,
  54719. scrollbar = axis.scrollbar;
  54720. if (scrollbar) {
  54721. axis.chart.scrollbarsOffsets = [0, 0]; // reset scrollbars offsets
  54722. axis.chart.axisOffset[index] +=
  54723. scrollbar.size + scrollbar.options.margin;
  54724. }
  54725. });
  54726. return AxisClass;
  54727. };
  54728. return ScrollbarAxis;
  54729. }());
  54730. return ScrollbarAxis;
  54731. });
  54732. _registerModule(_modules, 'Core/ScrollbarDefaults.js', [_modules['Core/Globals.js'], _modules['Core/Color/Palette.js']], function (H, Palette) {
  54733. /* *
  54734. *
  54735. * (c) 2010-2021 Torstein Honsi
  54736. *
  54737. * License: www.highcharts.com/license
  54738. *
  54739. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  54740. *
  54741. * */
  54742. var isTouchDevice = H.isTouchDevice;
  54743. /* *
  54744. *
  54745. * Constant
  54746. *
  54747. * */
  54748. /**
  54749. *
  54750. * The scrollbar is a means of panning over the X axis of a stock chart.
  54751. * Scrollbars can also be applied to other types of axes.
  54752. *
  54753. * Another approach to scrollable charts is the [chart.scrollablePlotArea](
  54754. * https://api.highcharts.com/highcharts/chart.scrollablePlotArea) option that
  54755. * is especially suitable for simpler cartesian charts on mobile.
  54756. *
  54757. * In styled mode, all the presentational options for the
  54758. * scrollbar are replaced by the classes `.highcharts-scrollbar-thumb`,
  54759. * `.highcharts-scrollbar-arrow`, `.highcharts-scrollbar-button`,
  54760. * `.highcharts-scrollbar-rifles` and `.highcharts-scrollbar-track`.
  54761. *
  54762. * @sample stock/yaxis/inverted-bar-scrollbar/
  54763. * A scrollbar on a simple bar chart
  54764. *
  54765. * @product highstock gantt
  54766. * @optionparent scrollbar
  54767. *
  54768. * @private
  54769. */
  54770. var ScrollbarDefaults = {
  54771. /**
  54772. * The height of the scrollbar. The height also applies to the width
  54773. * of the scroll arrows so that they are always squares. Defaults to
  54774. * 20 for touch devices and 14 for mouse devices.
  54775. *
  54776. * @sample stock/scrollbar/height/
  54777. * A 30px scrollbar
  54778. *
  54779. * @type {number}
  54780. * @default 20/14
  54781. */
  54782. height: isTouchDevice ? 20 : 14,
  54783. /**
  54784. * The border rounding radius of the bar.
  54785. *
  54786. * @sample stock/scrollbar/style/
  54787. * Scrollbar styling
  54788. */
  54789. barBorderRadius: 0,
  54790. /**
  54791. * The corner radius of the scrollbar buttons.
  54792. *
  54793. * @sample stock/scrollbar/style/
  54794. * Scrollbar styling
  54795. */
  54796. buttonBorderRadius: 0,
  54797. /**
  54798. * Enable or disable the scrollbar.
  54799. *
  54800. * @sample stock/scrollbar/enabled/
  54801. * Disable the scrollbar,
  54802. only use navigator
  54803. *
  54804. * @type {boolean}
  54805. * @default true
  54806. * @apioption scrollbar.enabled
  54807. */
  54808. /**
  54809. * Whether to redraw the main chart as the scrollbar or the navigator
  54810. * zoomed window is moved. Defaults to `true` for modern browsers and
  54811. * `false` for legacy IE browsers as well as mobile devices.
  54812. *
  54813. * @sample stock/scrollbar/liveredraw
  54814. * Setting live redraw to false
  54815. *
  54816. * @type {boolean}
  54817. * @since 1.3
  54818. */
  54819. liveRedraw: void 0,
  54820. /**
  54821. * The margin between the scrollbar and its axis when the scrollbar is
  54822. * applied directly to an axis.
  54823. */
  54824. margin: 10,
  54825. /**
  54826. * The minimum width of the scrollbar.
  54827. *
  54828. * @since 1.2.5
  54829. */
  54830. minWidth: 6,
  54831. /**
  54832. * Whether to show or hide the scrollbar when the scrolled content is
  54833. * zoomed out to it full extent.
  54834. *
  54835. * @type {boolean}
  54836. * @default true
  54837. * @apioption scrollbar.showFull
  54838. */
  54839. step: 0.2,
  54840. /**
  54841. * The z index of the scrollbar group.
  54842. */
  54843. zIndex: 3,
  54844. /**
  54845. * The background color of the scrollbar itself.
  54846. *
  54847. * @sample stock/scrollbar/style/
  54848. * Scrollbar styling
  54849. *
  54850. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  54851. */
  54852. barBackgroundColor: Palette.neutralColor20,
  54853. /**
  54854. * The width of the bar's border.
  54855. *
  54856. * @sample stock/scrollbar/style/
  54857. * Scrollbar styling
  54858. */
  54859. barBorderWidth: 1,
  54860. /**
  54861. * The color of the scrollbar's border.
  54862. *
  54863. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  54864. */
  54865. barBorderColor: Palette.neutralColor20,
  54866. /**
  54867. * The color of the small arrow inside the scrollbar buttons.
  54868. *
  54869. * @sample stock/scrollbar/style/
  54870. * Scrollbar styling
  54871. *
  54872. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  54873. */
  54874. buttonArrowColor: Palette.neutralColor80,
  54875. /**
  54876. * The color of scrollbar buttons.
  54877. *
  54878. * @sample stock/scrollbar/style/
  54879. * Scrollbar styling
  54880. *
  54881. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  54882. */
  54883. buttonBackgroundColor: Palette.neutralColor10,
  54884. /**
  54885. * The color of the border of the scrollbar buttons.
  54886. *
  54887. * @sample stock/scrollbar/style/
  54888. * Scrollbar styling
  54889. *
  54890. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  54891. */
  54892. buttonBorderColor: Palette.neutralColor20,
  54893. /**
  54894. * The border width of the scrollbar buttons.
  54895. *
  54896. * @sample stock/scrollbar/style/
  54897. * Scrollbar styling
  54898. */
  54899. buttonBorderWidth: 1,
  54900. /**
  54901. * The color of the small rifles in the middle of the scrollbar.
  54902. *
  54903. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  54904. */
  54905. rifleColor: Palette.neutralColor80,
  54906. /**
  54907. * The color of the track background.
  54908. *
  54909. * @sample stock/scrollbar/style/
  54910. * Scrollbar styling
  54911. *
  54912. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  54913. */
  54914. trackBackgroundColor: Palette.neutralColor5,
  54915. /**
  54916. * The color of the border of the scrollbar track.
  54917. *
  54918. * @sample stock/scrollbar/style/
  54919. * Scrollbar styling
  54920. *
  54921. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  54922. */
  54923. trackBorderColor: Palette.neutralColor5,
  54924. /**
  54925. * The corner radius of the border of the scrollbar track.
  54926. *
  54927. * @sample stock/scrollbar/style/
  54928. * Scrollbar styling
  54929. *
  54930. * @type {number}
  54931. * @default 0
  54932. * @apioption scrollbar.trackBorderRadius
  54933. */
  54934. /**
  54935. * The width of the border of the scrollbar track.
  54936. *
  54937. * @sample stock/scrollbar/style/
  54938. * Scrollbar styling
  54939. */
  54940. trackBorderWidth: 1
  54941. };
  54942. /* *
  54943. *
  54944. * Default Export
  54945. *
  54946. * */
  54947. return ScrollbarDefaults;
  54948. });
  54949. _registerModule(_modules, 'Core/Scrollbar.js', [_modules['Core/DefaultOptions.js'], _modules['Core/Globals.js'], _modules['Core/Axis/ScrollbarAxis.js'], _modules['Core/ScrollbarDefaults.js'], _modules['Core/Utilities.js']], function (D, H, ScrollbarAxis, ScrollbarDefaults, U) {
  54950. /* *
  54951. *
  54952. * (c) 2010-2021 Torstein Honsi
  54953. *
  54954. * License: www.highcharts.com/license
  54955. *
  54956. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  54957. *
  54958. * */
  54959. var defaultOptions = D.defaultOptions;
  54960. var addEvent = U.addEvent,
  54961. correctFloat = U.correctFloat,
  54962. defined = U.defined,
  54963. destroyObjectProperties = U.destroyObjectProperties,
  54964. fireEvent = U.fireEvent,
  54965. merge = U.merge,
  54966. pick = U.pick,
  54967. removeEvent = U.removeEvent;
  54968. /* *
  54969. *
  54970. * Constants
  54971. *
  54972. * */
  54973. /* eslint-disable no-invalid-this, valid-jsdoc */
  54974. /**
  54975. * A reusable scrollbar, internally used in Highcharts Stock's
  54976. * navigator and optionally on individual axes.
  54977. *
  54978. * @private
  54979. * @class
  54980. * @name Highcharts.Scrollbar
  54981. * @param {Highcharts.SVGRenderer} renderer
  54982. * @param {Highcharts.ScrollbarOptions} options
  54983. * @param {Highcharts.Chart} chart
  54984. */
  54985. var Scrollbar = /** @class */ (function () {
  54986. /* *
  54987. *
  54988. * Constructors
  54989. *
  54990. * */
  54991. function Scrollbar(renderer, options, chart) {
  54992. /* *
  54993. *
  54994. * Properties
  54995. *
  54996. * */
  54997. this._events = [];
  54998. this.chart = void 0;
  54999. this.chartX = 0;
  55000. this.chartY = 0;
  55001. this.from = 0;
  55002. this.group = void 0;
  55003. this.options = void 0;
  55004. this.renderer = void 0;
  55005. this.scrollbar = void 0;
  55006. this.scrollbarButtons = [];
  55007. this.scrollbarGroup = void 0;
  55008. this.scrollbarLeft = 0;
  55009. this.scrollbarRifles = void 0;
  55010. this.scrollbarStrokeWidth = 1;
  55011. this.scrollbarTop = 0;
  55012. this.size = 0;
  55013. this.to = 0;
  55014. this.track = void 0;
  55015. this.trackBorderWidth = 1;
  55016. this.userOptions = void 0;
  55017. this.x = 0;
  55018. this.y = 0;
  55019. this.init(renderer, options, chart);
  55020. }
  55021. /* *
  55022. *
  55023. * Static Functions
  55024. *
  55025. * */
  55026. Scrollbar.compose = function (AxisClass) {
  55027. ScrollbarAxis.compose(AxisClass, Scrollbar);
  55028. };
  55029. /**
  55030. * When we have vertical scrollbar, rifles and arrow in buttons should be
  55031. * rotated. The same method is used in Navigator's handles, to rotate them.
  55032. *
  55033. * @function Highcharts.swapXY
  55034. *
  55035. * @param {Highcharts.SVGPathArray} path
  55036. * Path to be rotated.
  55037. *
  55038. * @param {boolean} [vertical]
  55039. * If vertical scrollbar, swap x-y values.
  55040. *
  55041. * @return {Highcharts.SVGPathArray}
  55042. * Rotated path.
  55043. *
  55044. * @requires modules/stock
  55045. */
  55046. Scrollbar.swapXY = function (path, vertical) {
  55047. if (vertical) {
  55048. path.forEach(function (seg) {
  55049. var len = seg.length;
  55050. var temp;
  55051. for (var i = 0; i < len; i += 2) {
  55052. temp = seg[i + 1];
  55053. if (typeof temp === 'number') {
  55054. seg[i + 1] = seg[i + 2];
  55055. seg[i + 2] = temp;
  55056. }
  55057. }
  55058. });
  55059. }
  55060. return path;
  55061. };
  55062. /* *
  55063. *
  55064. * Functions
  55065. *
  55066. * */
  55067. /**
  55068. * Set up the mouse and touch events for the Scrollbar
  55069. *
  55070. * @private
  55071. * @function Highcharts.Scrollbar#addEvents
  55072. */
  55073. Scrollbar.prototype.addEvents = function () {
  55074. var buttonsOrder = this.options.inverted ? [1, 0] : [0, 1],
  55075. buttons = this.scrollbarButtons,
  55076. bar = this.scrollbarGroup.element,
  55077. track = this.track.element,
  55078. mouseDownHandler = this.mouseDownHandler.bind(this),
  55079. mouseMoveHandler = this.mouseMoveHandler.bind(this),
  55080. mouseUpHandler = this.mouseUpHandler.bind(this);
  55081. // Mouse events
  55082. var _events = [
  55083. [buttons[buttonsOrder[0]].element, 'click',
  55084. this.buttonToMinClick.bind(this)],
  55085. [buttons[buttonsOrder[1]].element, 'click',
  55086. this.buttonToMaxClick.bind(this)],
  55087. [track, 'click',
  55088. this.trackClick.bind(this)],
  55089. [bar, 'mousedown',
  55090. mouseDownHandler],
  55091. [bar.ownerDocument, 'mousemove',
  55092. mouseMoveHandler],
  55093. [bar.ownerDocument, 'mouseup',
  55094. mouseUpHandler]
  55095. ];
  55096. // Touch events
  55097. if (H.hasTouch) {
  55098. _events.push([bar, 'touchstart', mouseDownHandler], [bar.ownerDocument, 'touchmove', mouseMoveHandler], [bar.ownerDocument, 'touchend', mouseUpHandler]);
  55099. }
  55100. // Add them all
  55101. _events.forEach(function (args) {
  55102. addEvent.apply(null, args);
  55103. });
  55104. this._events = _events;
  55105. };
  55106. Scrollbar.prototype.buttonToMaxClick = function (e) {
  55107. var scroller = this;
  55108. var range = (scroller.to - scroller.from) * pick(scroller.options.step, 0.2);
  55109. scroller.updatePosition(scroller.from + range, scroller.to + range);
  55110. fireEvent(scroller, 'changed', {
  55111. from: scroller.from,
  55112. to: scroller.to,
  55113. trigger: 'scrollbar',
  55114. DOMEvent: e
  55115. });
  55116. };
  55117. Scrollbar.prototype.buttonToMinClick = function (e) {
  55118. var scroller = this;
  55119. var range = correctFloat(scroller.to - scroller.from) *
  55120. pick(scroller.options.step, 0.2);
  55121. scroller.updatePosition(correctFloat(scroller.from - range), correctFloat(scroller.to - range));
  55122. fireEvent(scroller, 'changed', {
  55123. from: scroller.from,
  55124. to: scroller.to,
  55125. trigger: 'scrollbar',
  55126. DOMEvent: e
  55127. });
  55128. };
  55129. /**
  55130. * Get normalized (0-1) cursor position over the scrollbar
  55131. *
  55132. * @private
  55133. * @function Highcharts.Scrollbar#cursorToScrollbarPosition
  55134. *
  55135. * @param {*} normalizedEvent
  55136. * normalized event, with chartX and chartY values
  55137. *
  55138. * @return {Highcharts.Dictionary<number>}
  55139. * Local position {chartX, chartY}
  55140. */
  55141. Scrollbar.prototype.cursorToScrollbarPosition = function (normalizedEvent) {
  55142. var scroller = this,
  55143. options = scroller.options,
  55144. minWidthDifference = options.minWidth > scroller.calculatedWidth ?
  55145. options.minWidth :
  55146. 0; // minWidth distorts translation
  55147. return {
  55148. chartX: (normalizedEvent.chartX - scroller.x -
  55149. scroller.xOffset) /
  55150. (scroller.barWidth - minWidthDifference),
  55151. chartY: (normalizedEvent.chartY - scroller.y -
  55152. scroller.yOffset) /
  55153. (scroller.barWidth - minWidthDifference)
  55154. };
  55155. };
  55156. /**
  55157. * Destroys allocated elements.
  55158. *
  55159. * @private
  55160. * @function Highcharts.Scrollbar#destroy
  55161. * @return {void}
  55162. */
  55163. Scrollbar.prototype.destroy = function () {
  55164. var scroller = this,
  55165. navigator = scroller.chart.scroller;
  55166. // Disconnect events added in addEvents
  55167. scroller.removeEvents();
  55168. // Destroy properties
  55169. [
  55170. 'track',
  55171. 'scrollbarRifles',
  55172. 'scrollbar',
  55173. 'scrollbarGroup',
  55174. 'group'
  55175. ].forEach(function (prop) {
  55176. if (scroller[prop] && scroller[prop].destroy) {
  55177. scroller[prop] = scroller[prop].destroy();
  55178. }
  55179. });
  55180. // #6421, chart may have more scrollbars
  55181. if (navigator && scroller === navigator.scrollbar) {
  55182. navigator.scrollbar = null;
  55183. // Destroy elements in collection
  55184. destroyObjectProperties(navigator.scrollbarButtons);
  55185. }
  55186. };
  55187. /**
  55188. * Draw the scrollbar buttons with arrows
  55189. *
  55190. * @private
  55191. * @function Highcharts.Scrollbar#drawScrollbarButton
  55192. * @param {number} index
  55193. * 0 is left, 1 is right
  55194. * @return {void}
  55195. */
  55196. Scrollbar.prototype.drawScrollbarButton = function (index) {
  55197. var scroller = this,
  55198. renderer = scroller.renderer,
  55199. scrollbarButtons = scroller.scrollbarButtons,
  55200. options = scroller.options,
  55201. size = scroller.size,
  55202. group = renderer.g().add(scroller.group);
  55203. var tempElem;
  55204. scrollbarButtons.push(group);
  55205. // Create a rectangle for the scrollbar button
  55206. tempElem = renderer.rect()
  55207. .addClass('highcharts-scrollbar-button')
  55208. .add(group);
  55209. // Presentational attributes
  55210. if (!scroller.chart.styledMode) {
  55211. tempElem.attr({
  55212. stroke: options.buttonBorderColor,
  55213. 'stroke-width': options.buttonBorderWidth,
  55214. fill: options.buttonBackgroundColor
  55215. });
  55216. }
  55217. // Place the rectangle based on the rendered stroke width
  55218. tempElem.attr(tempElem.crisp({
  55219. x: -0.5,
  55220. y: -0.5,
  55221. width: size + 1,
  55222. height: size + 1,
  55223. r: options.buttonBorderRadius
  55224. }, tempElem.strokeWidth()));
  55225. // Button arrow
  55226. tempElem = renderer
  55227. .path(Scrollbar.swapXY([[
  55228. 'M',
  55229. size / 2 + (index ? -1 : 1),
  55230. size / 2 - 3
  55231. ], [
  55232. 'L',
  55233. size / 2 + (index ? -1 : 1),
  55234. size / 2 + 3
  55235. ], [
  55236. 'L',
  55237. size / 2 + (index ? 2 : -2),
  55238. size / 2
  55239. ]], options.vertical))
  55240. .addClass('highcharts-scrollbar-arrow')
  55241. .add(scrollbarButtons[index]);
  55242. if (!scroller.chart.styledMode) {
  55243. tempElem.attr({
  55244. fill: options.buttonArrowColor
  55245. });
  55246. }
  55247. };
  55248. /**
  55249. * @private
  55250. * @function Highcharts.Scrollbar#init
  55251. * @param {Highcharts.SVGRenderer} renderer
  55252. * @param {Highcharts.ScrollbarOptions} options
  55253. * @param {Highcharts.Chart} chart
  55254. */
  55255. Scrollbar.prototype.init = function (renderer, options, chart) {
  55256. var scroller = this;
  55257. scroller.scrollbarButtons = [];
  55258. scroller.renderer = renderer;
  55259. scroller.userOptions = options;
  55260. scroller.options = merge(ScrollbarDefaults, defaultOptions.scrollbar, options);
  55261. scroller.chart = chart;
  55262. // backward compatibility
  55263. scroller.size = pick(scroller.options.size, scroller.options.height);
  55264. // Init
  55265. if (options.enabled) {
  55266. scroller.render();
  55267. scroller.addEvents();
  55268. }
  55269. };
  55270. Scrollbar.prototype.mouseDownHandler = function (e) {
  55271. var scroller = this,
  55272. normalizedEvent = scroller.chart.pointer.normalize(e),
  55273. mousePosition = scroller.cursorToScrollbarPosition(normalizedEvent);
  55274. scroller.chartX = mousePosition.chartX;
  55275. scroller.chartY = mousePosition.chartY;
  55276. scroller.initPositions = [scroller.from, scroller.to];
  55277. scroller.grabbedCenter = true;
  55278. };
  55279. /**
  55280. * Event handler for the mouse move event.
  55281. * @private
  55282. */
  55283. Scrollbar.prototype.mouseMoveHandler = function (e) {
  55284. var scroller = this,
  55285. normalizedEvent = scroller.chart.pointer.normalize(e),
  55286. options = scroller.options,
  55287. direction = options.vertical ? 'chartY' : 'chartX',
  55288. initPositions = scroller.initPositions || [];
  55289. var scrollPosition,
  55290. chartPosition,
  55291. change;
  55292. // In iOS, a mousemove event with e.pageX === 0 is fired when
  55293. // holding the finger down in the center of the scrollbar. This
  55294. // should be ignored.
  55295. if (scroller.grabbedCenter &&
  55296. // #4696, scrollbar failed on Android
  55297. (!e.touches || e.touches[0][direction] !== 0)) {
  55298. chartPosition = scroller.cursorToScrollbarPosition(normalizedEvent)[direction];
  55299. scrollPosition = scroller[direction];
  55300. change = chartPosition - scrollPosition;
  55301. scroller.hasDragged = true;
  55302. scroller.updatePosition(initPositions[0] + change, initPositions[1] + change);
  55303. if (scroller.hasDragged) {
  55304. fireEvent(scroller, 'changed', {
  55305. from: scroller.from,
  55306. to: scroller.to,
  55307. trigger: 'scrollbar',
  55308. DOMType: e.type,
  55309. DOMEvent: e
  55310. });
  55311. }
  55312. }
  55313. };
  55314. /**
  55315. * Event handler for the mouse up event.
  55316. * @private
  55317. */
  55318. Scrollbar.prototype.mouseUpHandler = function (e) {
  55319. var scroller = this;
  55320. if (scroller.hasDragged) {
  55321. fireEvent(scroller, 'changed', {
  55322. from: scroller.from,
  55323. to: scroller.to,
  55324. trigger: 'scrollbar',
  55325. DOMType: e.type,
  55326. DOMEvent: e
  55327. });
  55328. }
  55329. scroller.grabbedCenter =
  55330. scroller.hasDragged =
  55331. scroller.chartX =
  55332. scroller.chartY = null;
  55333. };
  55334. /**
  55335. * Position the scrollbar, method called from a parent with defined
  55336. * dimensions.
  55337. *
  55338. * @private
  55339. * @function Highcharts.Scrollbar#position
  55340. * @param {number} x
  55341. * x-position on the chart
  55342. * @param {number} y
  55343. * y-position on the chart
  55344. * @param {number} width
  55345. * width of the scrollbar
  55346. * @param {number} height
  55347. * height of the scorllbar
  55348. * @return {void}
  55349. */
  55350. Scrollbar.prototype.position = function (x, y, width, height) {
  55351. var scroller = this,
  55352. options = scroller.options,
  55353. vertical = options.vertical,
  55354. method = scroller.rendered ? 'animate' : 'attr';
  55355. var xOffset = height,
  55356. yOffset = 0;
  55357. scroller.x = x;
  55358. scroller.y = y + this.trackBorderWidth;
  55359. scroller.width = width; // width with buttons
  55360. scroller.height = height;
  55361. scroller.xOffset = xOffset;
  55362. scroller.yOffset = yOffset;
  55363. // If Scrollbar is a vertical type, swap options:
  55364. if (vertical) {
  55365. scroller.width = scroller.yOffset = width = yOffset = scroller.size;
  55366. scroller.xOffset = xOffset = 0;
  55367. scroller.barWidth = height - width * 2; // width without buttons
  55368. scroller.x = x = x + scroller.options.margin;
  55369. }
  55370. else {
  55371. scroller.height = scroller.xOffset = height = xOffset =
  55372. scroller.size;
  55373. scroller.barWidth = width - height * 2; // width without buttons
  55374. scroller.y = scroller.y + scroller.options.margin;
  55375. }
  55376. // Set general position for a group:
  55377. scroller.group[method]({
  55378. translateX: x,
  55379. translateY: scroller.y
  55380. });
  55381. // Resize background/track:
  55382. scroller.track[method]({
  55383. width: width,
  55384. height: height
  55385. });
  55386. // Move right/bottom button ot it's place:
  55387. scroller.scrollbarButtons[1][method]({
  55388. translateX: vertical ? 0 : width - xOffset,
  55389. translateY: vertical ? height - yOffset : 0
  55390. });
  55391. };
  55392. /**
  55393. * Removes the event handlers attached previously with addEvents.
  55394. *
  55395. * @private
  55396. * @function Highcharts.Scrollbar#removeEvents
  55397. * @return {void}
  55398. */
  55399. Scrollbar.prototype.removeEvents = function () {
  55400. this._events.forEach(function (args) {
  55401. removeEvent.apply(null, args);
  55402. });
  55403. this._events.length = 0;
  55404. };
  55405. /**
  55406. * Render scrollbar with all required items.
  55407. *
  55408. * @private
  55409. * @function Highcharts.Scrollbar#render
  55410. */
  55411. Scrollbar.prototype.render = function () {
  55412. var scroller = this,
  55413. renderer = scroller.renderer,
  55414. options = scroller.options,
  55415. size = scroller.size,
  55416. styledMode = scroller.chart.styledMode,
  55417. group = renderer.g('scrollbar').attr({
  55418. zIndex: options.zIndex,
  55419. translateY: -99999
  55420. }).add();
  55421. // Draw the scrollbar group
  55422. scroller.group = group;
  55423. // Draw the scrollbar track:
  55424. scroller.track = renderer.rect()
  55425. .addClass('highcharts-scrollbar-track')
  55426. .attr({
  55427. x: 0,
  55428. r: options.trackBorderRadius || 0,
  55429. height: size,
  55430. width: size
  55431. }).add(group);
  55432. if (!styledMode) {
  55433. scroller.track.attr({
  55434. fill: options.trackBackgroundColor,
  55435. stroke: options.trackBorderColor,
  55436. 'stroke-width': options.trackBorderWidth
  55437. });
  55438. }
  55439. scroller.trackBorderWidth = scroller.track.strokeWidth();
  55440. scroller.track.attr({
  55441. y: -this.trackBorderWidth % 2 / 2
  55442. });
  55443. // Draw the scrollbar itself
  55444. scroller.scrollbarGroup = renderer.g().add(group);
  55445. scroller.scrollbar = renderer.rect()
  55446. .addClass('highcharts-scrollbar-thumb')
  55447. .attr({
  55448. height: size,
  55449. width: size,
  55450. r: options.barBorderRadius || 0
  55451. }).add(scroller.scrollbarGroup);
  55452. scroller.scrollbarRifles = renderer
  55453. .path(Scrollbar.swapXY([
  55454. ['M', -3, size / 4],
  55455. ['L', -3, 2 * size / 3],
  55456. ['M', 0, size / 4],
  55457. ['L', 0, 2 * size / 3],
  55458. ['M', 3, size / 4],
  55459. ['L', 3, 2 * size / 3]
  55460. ], options.vertical))
  55461. .addClass('highcharts-scrollbar-rifles')
  55462. .add(scroller.scrollbarGroup);
  55463. if (!styledMode) {
  55464. scroller.scrollbar.attr({
  55465. fill: options.barBackgroundColor,
  55466. stroke: options.barBorderColor,
  55467. 'stroke-width': options.barBorderWidth
  55468. });
  55469. scroller.scrollbarRifles.attr({
  55470. stroke: options.rifleColor,
  55471. 'stroke-width': 1
  55472. });
  55473. }
  55474. scroller.scrollbarStrokeWidth = scroller.scrollbar.strokeWidth();
  55475. scroller.scrollbarGroup.translate(-scroller.scrollbarStrokeWidth % 2 / 2, -scroller.scrollbarStrokeWidth % 2 / 2);
  55476. // Draw the buttons:
  55477. scroller.drawScrollbarButton(0);
  55478. scroller.drawScrollbarButton(1);
  55479. };
  55480. /**
  55481. * Set scrollbar size, with a given scale.
  55482. *
  55483. * @private
  55484. * @function Highcharts.Scrollbar#setRange
  55485. * @param {number} from
  55486. * scale (0-1) where bar should start
  55487. * @param {number} to
  55488. * scale (0-1) where bar should end
  55489. * @return {void}
  55490. */
  55491. Scrollbar.prototype.setRange = function (from, to) {
  55492. var scroller = this,
  55493. options = scroller.options,
  55494. vertical = options.vertical,
  55495. minWidth = options.minWidth,
  55496. fullWidth = scroller.barWidth,
  55497. method = (this.rendered &&
  55498. !this.hasDragged &&
  55499. !(this.chart.navigator && this.chart.navigator.hasDragged)) ? 'animate' : 'attr';
  55500. if (!defined(fullWidth)) {
  55501. return;
  55502. }
  55503. var toPX = fullWidth * Math.min(to, 1);
  55504. var fromPX,
  55505. newSize;
  55506. from = Math.max(from, 0);
  55507. fromPX = Math.ceil(fullWidth * from);
  55508. scroller.calculatedWidth = newSize = correctFloat(toPX - fromPX);
  55509. // We need to recalculate position, if minWidth is used
  55510. if (newSize < minWidth) {
  55511. fromPX = (fullWidth - minWidth + newSize) * from;
  55512. newSize = minWidth;
  55513. }
  55514. var newPos = Math.floor(fromPX + scroller.xOffset + scroller.yOffset);
  55515. var newRiflesPos = newSize / 2 - 0.5; // -0.5 -> rifle line width / 2
  55516. // Store current position:
  55517. scroller.from = from;
  55518. scroller.to = to;
  55519. if (!vertical) {
  55520. scroller.scrollbarGroup[method]({
  55521. translateX: newPos
  55522. });
  55523. scroller.scrollbar[method]({
  55524. width: newSize
  55525. });
  55526. scroller.scrollbarRifles[method]({
  55527. translateX: newRiflesPos
  55528. });
  55529. scroller.scrollbarLeft = newPos;
  55530. scroller.scrollbarTop = 0;
  55531. }
  55532. else {
  55533. scroller.scrollbarGroup[method]({
  55534. translateY: newPos
  55535. });
  55536. scroller.scrollbar[method]({
  55537. height: newSize
  55538. });
  55539. scroller.scrollbarRifles[method]({
  55540. translateY: newRiflesPos
  55541. });
  55542. scroller.scrollbarTop = newPos;
  55543. scroller.scrollbarLeft = 0;
  55544. }
  55545. if (newSize <= 12) {
  55546. scroller.scrollbarRifles.hide();
  55547. }
  55548. else {
  55549. scroller.scrollbarRifles.show(true);
  55550. }
  55551. // Show or hide the scrollbar based on the showFull setting
  55552. if (options.showFull === false) {
  55553. if (from <= 0 && to >= 1) {
  55554. scroller.group.hide();
  55555. }
  55556. else {
  55557. scroller.group.show();
  55558. }
  55559. }
  55560. scroller.rendered = true;
  55561. };
  55562. /**
  55563. * Checks if the extremes should be updated in response to a scrollbar
  55564. * change event.
  55565. *
  55566. * @private
  55567. * @function Highcharts.Scrollbar#shouldUpdateExtremes
  55568. * @param {string} [eventType]
  55569. * @return {boolean}
  55570. */
  55571. Scrollbar.prototype.shouldUpdateExtremes = function (eventType) {
  55572. return (pick(this.options.liveRedraw, H.svg && !H.isTouchDevice && !this.chart.isBoosting) ||
  55573. // Mouseup always should change extremes
  55574. eventType === 'mouseup' ||
  55575. eventType === 'touchend' ||
  55576. // Internal events
  55577. !defined(eventType));
  55578. };
  55579. Scrollbar.prototype.trackClick = function (e) {
  55580. var scroller = this;
  55581. var normalizedEvent = scroller.chart.pointer.normalize(e),
  55582. range = scroller.to - scroller.from,
  55583. top = scroller.y + scroller.scrollbarTop,
  55584. left = scroller.x + scroller.scrollbarLeft;
  55585. if ((scroller.options.vertical && normalizedEvent.chartY > top) ||
  55586. (!scroller.options.vertical && normalizedEvent.chartX > left)) {
  55587. // On the top or on the left side of the track:
  55588. scroller.updatePosition(scroller.from + range, scroller.to + range);
  55589. }
  55590. else {
  55591. // On the bottom or the right side of the track:
  55592. scroller.updatePosition(scroller.from - range, scroller.to - range);
  55593. }
  55594. fireEvent(scroller, 'changed', {
  55595. from: scroller.from,
  55596. to: scroller.to,
  55597. trigger: 'scrollbar',
  55598. DOMEvent: e
  55599. });
  55600. };
  55601. /**
  55602. * Update the scrollbar with new options
  55603. *
  55604. * @private
  55605. * @function Highcharts.Scrollbar#update
  55606. * @param {Highcharts.ScrollbarOptions} options
  55607. */
  55608. Scrollbar.prototype.update = function (options) {
  55609. this.destroy();
  55610. this.init(this.chart.renderer, merge(true, this.options, options), this.chart);
  55611. };
  55612. /**
  55613. * Update position option in the Scrollbar, with normalized 0-1 scale
  55614. *
  55615. * @private
  55616. * @function Highcharts.Scrollbar#updatePosition
  55617. * @param {number} from
  55618. * @param {number} to
  55619. * @return {void}
  55620. */
  55621. Scrollbar.prototype.updatePosition = function (from, to) {
  55622. if (to > 1) {
  55623. from = correctFloat(1 - correctFloat(to - from));
  55624. to = 1;
  55625. }
  55626. if (from < 0) {
  55627. to = correctFloat(to - from);
  55628. from = 0;
  55629. }
  55630. this.from = from;
  55631. this.to = to;
  55632. };
  55633. /* *
  55634. *
  55635. * Static Properties
  55636. *
  55637. * */
  55638. Scrollbar.defaultOptions = ScrollbarDefaults;
  55639. return Scrollbar;
  55640. }());
  55641. /* *
  55642. *
  55643. * Registry
  55644. *
  55645. * */
  55646. defaultOptions.scrollbar = merge(true, Scrollbar.defaultOptions, defaultOptions.scrollbar);
  55647. /* *
  55648. *
  55649. * Default Export
  55650. *
  55651. * */
  55652. return Scrollbar;
  55653. });
  55654. _registerModule(_modules, 'Extensions/RangeSelector.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Chart/Chart.js'], _modules['Core/Globals.js'], _modules['Core/DefaultOptions.js'], _modules['Core/Color/Palette.js'], _modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Utilities.js']], function (Axis, Chart, H, D, palette, SVGElement, U) {
  55655. /* *
  55656. *
  55657. * (c) 2010-2021 Torstein Honsi
  55658. *
  55659. * License: www.highcharts.com/license
  55660. *
  55661. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  55662. *
  55663. * */
  55664. var defaultOptions = D.defaultOptions;
  55665. var addEvent = U.addEvent,
  55666. createElement = U.createElement,
  55667. css = U.css,
  55668. defined = U.defined,
  55669. destroyObjectProperties = U.destroyObjectProperties,
  55670. discardElement = U.discardElement,
  55671. extend = U.extend,
  55672. find = U.find,
  55673. fireEvent = U.fireEvent,
  55674. isNumber = U.isNumber,
  55675. merge = U.merge,
  55676. objectEach = U.objectEach,
  55677. pad = U.pad,
  55678. pick = U.pick,
  55679. pInt = U.pInt,
  55680. splat = U.splat;
  55681. /**
  55682. * Define the time span for the button
  55683. *
  55684. * @typedef {"all"|"day"|"hour"|"millisecond"|"minute"|"month"|"second"|"week"|"year"|"ytd"} Highcharts.RangeSelectorButtonTypeValue
  55685. */
  55686. /**
  55687. * Callback function to react on button clicks.
  55688. *
  55689. * @callback Highcharts.RangeSelectorClickCallbackFunction
  55690. *
  55691. * @param {global.Event} e
  55692. * Event arguments.
  55693. *
  55694. * @param {boolean|undefined}
  55695. * Return false to cancel the default button event.
  55696. */
  55697. /**
  55698. * Callback function to parse values entered in the input boxes and return a
  55699. * valid JavaScript time as milliseconds since 1970.
  55700. *
  55701. * @callback Highcharts.RangeSelectorParseCallbackFunction
  55702. *
  55703. * @param {string} value
  55704. * Input value to parse.
  55705. *
  55706. * @return {number}
  55707. * Parsed JavaScript time value.
  55708. */
  55709. /* ************************************************************************** *
  55710. * Start Range Selector code *
  55711. * ************************************************************************** */
  55712. extend(defaultOptions, {
  55713. /**
  55714. * The range selector is a tool for selecting ranges to display within
  55715. * the chart. It provides buttons to select preconfigured ranges in
  55716. * the chart, like 1 day, 1 week, 1 month etc. It also provides input
  55717. * boxes where min and max dates can be manually input.
  55718. *
  55719. * @product highstock gantt
  55720. * @optionparent rangeSelector
  55721. */
  55722. rangeSelector: {
  55723. /**
  55724. * Whether to enable all buttons from the start. By default buttons are
  55725. * only enabled if the corresponding time range exists on the X axis,
  55726. * but enabling all buttons allows for dynamically loading different
  55727. * time ranges.
  55728. *
  55729. * @sample {highstock} stock/rangeselector/allbuttonsenabled-true/
  55730. * All buttons enabled
  55731. *
  55732. * @since 2.0.3
  55733. */
  55734. allButtonsEnabled: false,
  55735. /**
  55736. * An array of configuration objects for the buttons.
  55737. *
  55738. * Defaults to:
  55739. * ```js
  55740. * buttons: [{
  55741. * type: 'month',
  55742. * count: 1,
  55743. * text: '1m',
  55744. * title: 'View 1 month'
  55745. * }, {
  55746. * type: 'month',
  55747. * count: 3,
  55748. * text: '3m',
  55749. * title: 'View 3 months'
  55750. * }, {
  55751. * type: 'month',
  55752. * count: 6,
  55753. * text: '6m',
  55754. * title: 'View 6 months'
  55755. * }, {
  55756. * type: 'ytd',
  55757. * text: 'YTD',
  55758. * title: 'View year to date'
  55759. * }, {
  55760. * type: 'year',
  55761. * count: 1,
  55762. * text: '1y',
  55763. * title: 'View 1 year'
  55764. * }, {
  55765. * type: 'all',
  55766. * text: 'All',
  55767. * title: 'View all'
  55768. * }]
  55769. * ```
  55770. *
  55771. * @sample {highstock} stock/rangeselector/datagrouping/
  55772. * Data grouping by buttons
  55773. *
  55774. * @type {Array<*>}
  55775. */
  55776. buttons: void 0,
  55777. /**
  55778. * How many units of the defined type the button should span. If `type`
  55779. * is "month" and `count` is 3, the button spans three months.
  55780. *
  55781. * @type {number}
  55782. * @default 1
  55783. * @apioption rangeSelector.buttons.count
  55784. */
  55785. /**
  55786. * Fires when clicking on the rangeSelector button. One parameter,
  55787. * event, is passed to the function, containing common event
  55788. * information.
  55789. *
  55790. * ```js
  55791. * click: function(e) {
  55792. * console.log(this);
  55793. * }
  55794. * ```
  55795. *
  55796. * Return false to stop default button's click action.
  55797. *
  55798. * @sample {highstock} stock/rangeselector/button-click/
  55799. * Click event on the button
  55800. *
  55801. * @type {Highcharts.RangeSelectorClickCallbackFunction}
  55802. * @apioption rangeSelector.buttons.events.click
  55803. */
  55804. /**
  55805. * Additional range (in milliseconds) added to the end of the calculated
  55806. * time span.
  55807. *
  55808. * @sample {highstock} stock/rangeselector/min-max-offsets/
  55809. * Button offsets
  55810. *
  55811. * @type {number}
  55812. * @default 0
  55813. * @since 6.0.0
  55814. * @apioption rangeSelector.buttons.offsetMax
  55815. */
  55816. /**
  55817. * Additional range (in milliseconds) added to the start of the
  55818. * calculated time span.
  55819. *
  55820. * @sample {highstock} stock/rangeselector/min-max-offsets/
  55821. * Button offsets
  55822. *
  55823. * @type {number}
  55824. * @default 0
  55825. * @since 6.0.0
  55826. * @apioption rangeSelector.buttons.offsetMin
  55827. */
  55828. /**
  55829. * When buttons apply dataGrouping on a series, by default zooming
  55830. * in/out will deselect buttons and unset dataGrouping. Enable this
  55831. * option to keep buttons selected when extremes change.
  55832. *
  55833. * @sample {highstock} stock/rangeselector/preserve-datagrouping/
  55834. * Different preserveDataGrouping settings
  55835. *
  55836. * @type {boolean}
  55837. * @default false
  55838. * @since 6.1.2
  55839. * @apioption rangeSelector.buttons.preserveDataGrouping
  55840. */
  55841. /**
  55842. * A custom data grouping object for each button.
  55843. *
  55844. * @see [series.dataGrouping](#plotOptions.series.dataGrouping)
  55845. *
  55846. * @sample {highstock} stock/rangeselector/datagrouping/
  55847. * Data grouping by range selector buttons
  55848. *
  55849. * @type {*}
  55850. * @extends plotOptions.series.dataGrouping
  55851. * @apioption rangeSelector.buttons.dataGrouping
  55852. */
  55853. /**
  55854. * The text for the button itself.
  55855. *
  55856. * @type {string}
  55857. * @apioption rangeSelector.buttons.text
  55858. */
  55859. /**
  55860. * Explanation for the button, shown as a tooltip on hover, and used by
  55861. * assistive technology.
  55862. *
  55863. * @type {string}
  55864. * @apioption rangeSelector.buttons.title
  55865. */
  55866. /**
  55867. * Defined the time span for the button. Can be one of `millisecond`,
  55868. * `second`, `minute`, `hour`, `day`, `week`, `month`, `year`, `ytd`,
  55869. * and `all`.
  55870. *
  55871. * @type {Highcharts.RangeSelectorButtonTypeValue}
  55872. * @apioption rangeSelector.buttons.type
  55873. */
  55874. /**
  55875. * The space in pixels between the buttons in the range selector.
  55876. */
  55877. buttonSpacing: 5,
  55878. /**
  55879. * Whether to collapse the range selector buttons into a dropdown when
  55880. * there is not enough room to show everything in a single row, instead
  55881. * of dividing the range selector into multiple rows.
  55882. * Can be one of the following:
  55883. * - `always`: Always collapse
  55884. * - `responsive`: Only collapse when there is not enough room
  55885. * - `never`: Never collapse
  55886. *
  55887. * @sample {highstock} stock/rangeselector/dropdown/
  55888. * Dropdown option
  55889. *
  55890. * @validvalue ["always", "responsive", "never"]
  55891. * @since 9.0.0
  55892. */
  55893. dropdown: 'responsive',
  55894. /**
  55895. * Enable or disable the range selector. Default to `true` for stock
  55896. * charts, using the `stockChart` factory.
  55897. *
  55898. * @sample {highstock} stock/rangeselector/enabled/
  55899. * Disable the range selector
  55900. *
  55901. * @type {boolean|undefined}
  55902. * @default {highstock} true
  55903. */
  55904. enabled: void 0,
  55905. /**
  55906. * The vertical alignment of the rangeselector box. Allowed properties
  55907. * are `top`, `middle`, `bottom`.
  55908. *
  55909. * @sample {highstock} stock/rangeselector/vertical-align-middle/
  55910. * Middle
  55911. * @sample {highstock} stock/rangeselector/vertical-align-bottom/
  55912. * Bottom
  55913. *
  55914. * @type {Highcharts.VerticalAlignValue}
  55915. * @since 6.0.0
  55916. */
  55917. verticalAlign: 'top',
  55918. /**
  55919. * A collection of attributes for the buttons. The object takes SVG
  55920. * attributes like `fill`, `stroke`, `stroke-width`, as well as `style`,
  55921. * a collection of CSS properties for the text.
  55922. *
  55923. * The object can also be extended with states, so you can set
  55924. * presentational options for `hover`, `select` or `disabled` button
  55925. * states.
  55926. *
  55927. * CSS styles for the text label.
  55928. *
  55929. * In styled mode, the buttons are styled by the
  55930. * `.highcharts-range-selector-buttons .highcharts-button` rule with its
  55931. * different states.
  55932. *
  55933. * @sample {highstock} stock/rangeselector/styling/
  55934. * Styling the buttons and inputs
  55935. *
  55936. * @type {Highcharts.SVGAttributes}
  55937. */
  55938. buttonTheme: {
  55939. /** @ignore */
  55940. width: 28,
  55941. /** @ignore */
  55942. height: 18,
  55943. /** @ignore */
  55944. padding: 2,
  55945. /** @ignore */
  55946. zIndex: 7 // #484, #852
  55947. },
  55948. /**
  55949. * When the rangeselector is floating, the plot area does not reserve
  55950. * space for it. This opens for positioning anywhere on the chart.
  55951. *
  55952. * @sample {highstock} stock/rangeselector/floating/
  55953. * Placing the range selector between the plot area and the
  55954. * navigator
  55955. *
  55956. * @since 6.0.0
  55957. */
  55958. floating: false,
  55959. /**
  55960. * The x offset of the range selector relative to its horizontal
  55961. * alignment within `chart.spacingLeft` and `chart.spacingRight`.
  55962. *
  55963. * @since 6.0.0
  55964. */
  55965. x: 0,
  55966. /**
  55967. * The y offset of the range selector relative to its horizontal
  55968. * alignment within `chart.spacingLeft` and `chart.spacingRight`.
  55969. *
  55970. * @since 6.0.0
  55971. */
  55972. y: 0,
  55973. /**
  55974. * Deprecated. The height of the range selector. Currently it is
  55975. * calculated dynamically.
  55976. *
  55977. * @deprecated
  55978. * @type {number|undefined}
  55979. * @since 2.1.9
  55980. */
  55981. height: void 0,
  55982. /**
  55983. * The border color of the date input boxes.
  55984. *
  55985. * @sample {highstock} stock/rangeselector/styling/
  55986. * Styling the buttons and inputs
  55987. *
  55988. * @type {Highcharts.ColorString}
  55989. * @since 1.3.7
  55990. */
  55991. inputBoxBorderColor: 'none',
  55992. /**
  55993. * The pixel height of the date input boxes.
  55994. *
  55995. * @sample {highstock} stock/rangeselector/styling/
  55996. * Styling the buttons and inputs
  55997. *
  55998. * @since 1.3.7
  55999. */
  56000. inputBoxHeight: 17,
  56001. /**
  56002. * The pixel width of the date input boxes. When `undefined`, the width
  56003. * is fitted to the rendered content.
  56004. *
  56005. * @sample {highstock} stock/rangeselector/styling/
  56006. * Styling the buttons and inputs
  56007. *
  56008. * @type {number|undefined}
  56009. * @since 1.3.7
  56010. */
  56011. inputBoxWidth: void 0,
  56012. /**
  56013. * The date format in the input boxes when not selected for editing.
  56014. * Defaults to `%b %e, %Y`.
  56015. *
  56016. * This is used to determine which type of input to show,
  56017. * `datetime-local`, `date` or `time` and falling back to `text` when
  56018. * the browser does not support the input type or the format contains
  56019. * milliseconds.
  56020. *
  56021. * @sample {highstock} stock/rangeselector/input-type/
  56022. * Input types
  56023. * @sample {highstock} stock/rangeselector/input-format/
  56024. * Milliseconds in the range selector
  56025. *
  56026. */
  56027. inputDateFormat: '%b %e, %Y',
  56028. /**
  56029. * A custom callback function to parse values entered in the input boxes
  56030. * and return a valid JavaScript time as milliseconds since 1970.
  56031. * The first argument passed is a value to parse,
  56032. * second is a boolean indicating use of the UTC time.
  56033. *
  56034. * This will only get called for inputs of type `text`. Since v8.2.3,
  56035. * the input type is dynamically determined based on the granularity
  56036. * of the `inputDateFormat` and the browser support.
  56037. *
  56038. * @sample {highstock} stock/rangeselector/input-format/
  56039. * Milliseconds in the range selector
  56040. *
  56041. * @type {Highcharts.RangeSelectorParseCallbackFunction}
  56042. * @since 1.3.3
  56043. */
  56044. inputDateParser: void 0,
  56045. /**
  56046. * The date format in the input boxes when they are selected for
  56047. * editing. This must be a format that is recognized by JavaScript
  56048. * Date.parse.
  56049. *
  56050. * This will only be used for inputs of type `text`. Since v8.2.3,
  56051. * the input type is dynamically determined based on the granularity
  56052. * of the `inputDateFormat` and the browser support.
  56053. *
  56054. * @sample {highstock} stock/rangeselector/input-format/
  56055. * Milliseconds in the range selector
  56056. *
  56057. */
  56058. inputEditDateFormat: '%Y-%m-%d',
  56059. /**
  56060. * Enable or disable the date input boxes.
  56061. */
  56062. inputEnabled: true,
  56063. /**
  56064. * Positioning for the input boxes. Allowed properties are `align`,
  56065. * `x` and `y`.
  56066. *
  56067. * @since 1.2.4
  56068. */
  56069. inputPosition: {
  56070. /**
  56071. * The alignment of the input box. Allowed properties are `left`,
  56072. * `center`, `right`.
  56073. *
  56074. * @sample {highstock} stock/rangeselector/input-button-position/
  56075. * Alignment
  56076. *
  56077. * @type {Highcharts.AlignValue}
  56078. * @since 6.0.0
  56079. */
  56080. align: 'right',
  56081. /**
  56082. * X offset of the input row.
  56083. */
  56084. x: 0,
  56085. /**
  56086. * Y offset of the input row.
  56087. */
  56088. y: 0
  56089. },
  56090. /**
  56091. * The space in pixels between the labels and the date input boxes in
  56092. * the range selector.
  56093. *
  56094. * @since 9.0.0
  56095. */
  56096. inputSpacing: 5,
  56097. /**
  56098. * The index of the button to appear pre-selected.
  56099. *
  56100. * @type {number}
  56101. */
  56102. selected: void 0,
  56103. /**
  56104. * Positioning for the button row.
  56105. *
  56106. * @since 1.2.4
  56107. */
  56108. buttonPosition: {
  56109. /**
  56110. * The alignment of the input box. Allowed properties are `left`,
  56111. * `center`, `right`.
  56112. *
  56113. * @sample {highstock} stock/rangeselector/input-button-position/
  56114. * Alignment
  56115. *
  56116. * @type {Highcharts.AlignValue}
  56117. * @since 6.0.0
  56118. */
  56119. align: 'left',
  56120. /**
  56121. * X offset of the button row.
  56122. */
  56123. x: 0,
  56124. /**
  56125. * Y offset of the button row.
  56126. */
  56127. y: 0
  56128. },
  56129. /**
  56130. * CSS for the HTML inputs in the range selector.
  56131. *
  56132. * In styled mode, the inputs are styled by the
  56133. * `.highcharts-range-input text` rule in SVG mode, and
  56134. * `input.highcharts-range-selector` when active.
  56135. *
  56136. * @sample {highstock} stock/rangeselector/styling/
  56137. * Styling the buttons and inputs
  56138. *
  56139. * @type {Highcharts.CSSObject}
  56140. * @apioption rangeSelector.inputStyle
  56141. */
  56142. inputStyle: {
  56143. /** @ignore */
  56144. color: palette.highlightColor80,
  56145. /** @ignore */
  56146. cursor: 'pointer'
  56147. },
  56148. /**
  56149. * CSS styles for the labels - the Zoom, From and To texts.
  56150. *
  56151. * In styled mode, the labels are styled by the
  56152. * `.highcharts-range-label` class.
  56153. *
  56154. * @sample {highstock} stock/rangeselector/styling/
  56155. * Styling the buttons and inputs
  56156. *
  56157. * @type {Highcharts.CSSObject}
  56158. */
  56159. labelStyle: {
  56160. /** @ignore */
  56161. color: palette.neutralColor60
  56162. }
  56163. }
  56164. });
  56165. extend(defaultOptions.lang,
  56166. /**
  56167. * Language object. The language object is global and it can't be set
  56168. * on each chart initialization. Instead, use `Highcharts.setOptions` to
  56169. * set it before any chart is initialized.
  56170. *
  56171. * ```js
  56172. * Highcharts.setOptions({
  56173. * lang: {
  56174. * months: [
  56175. * 'Janvier', 'Février', 'Mars', 'Avril',
  56176. * 'Mai', 'Juin', 'Juillet', 'Août',
  56177. * 'Septembre', 'Octobre', 'Novembre', 'Décembre'
  56178. * ],
  56179. * weekdays: [
  56180. * 'Dimanche', 'Lundi', 'Mardi', 'Mercredi',
  56181. * 'Jeudi', 'Vendredi', 'Samedi'
  56182. * ]
  56183. * }
  56184. * });
  56185. * ```
  56186. *
  56187. * @optionparent lang
  56188. */
  56189. {
  56190. /**
  56191. * The text for the label for the range selector buttons.
  56192. *
  56193. * @product highstock gantt
  56194. */
  56195. rangeSelectorZoom: 'Zoom',
  56196. /**
  56197. * The text for the label for the "from" input box in the range
  56198. * selector. Since v9.0, this string is empty as the label is not
  56199. * rendered by default.
  56200. *
  56201. * @product highstock gantt
  56202. */
  56203. rangeSelectorFrom: '',
  56204. /**
  56205. * The text for the label for the "to" input box in the range selector.
  56206. *
  56207. * @product highstock gantt
  56208. */
  56209. rangeSelectorTo: '→'
  56210. });
  56211. /* eslint-disable no-invalid-this, valid-jsdoc */
  56212. /**
  56213. * The range selector.
  56214. *
  56215. * @private
  56216. * @class
  56217. * @name Highcharts.RangeSelector
  56218. * @param {Highcharts.Chart} chart
  56219. */
  56220. var RangeSelector = /** @class */ (function () {
  56221. function RangeSelector(chart) {
  56222. /* *
  56223. *
  56224. * Properties
  56225. *
  56226. * */
  56227. this.buttons = void 0;
  56228. this.buttonOptions = RangeSelector.prototype.defaultButtons;
  56229. this.initialButtonGroupWidth = 0;
  56230. this.options = void 0;
  56231. this.chart = chart;
  56232. // Run RangeSelector
  56233. this.init(chart);
  56234. }
  56235. /**
  56236. * The method to run when one of the buttons in the range selectors is
  56237. * clicked
  56238. *
  56239. * @private
  56240. * @function Highcharts.RangeSelector#clickButton
  56241. * @param {number} i
  56242. * The index of the button
  56243. * @param {boolean} [redraw]
  56244. * @return {void}
  56245. */
  56246. RangeSelector.prototype.clickButton = function (i, redraw) {
  56247. var rangeSelector = this,
  56248. chart = rangeSelector.chart,
  56249. rangeOptions = rangeSelector.buttonOptions[i],
  56250. baseAxis = chart.xAxis[0],
  56251. unionExtremes = (chart.scroller && chart.scroller.getUnionExtremes()) || baseAxis || {},
  56252. dataMin = unionExtremes.dataMin,
  56253. dataMax = unionExtremes.dataMax,
  56254. newMin,
  56255. newMax = baseAxis && Math.round(Math.min(baseAxis.max,
  56256. pick(dataMax,
  56257. baseAxis.max))), // #1568
  56258. type = rangeOptions.type,
  56259. baseXAxisOptions,
  56260. range = rangeOptions._range,
  56261. rangeMin,
  56262. minSetting,
  56263. rangeSetting,
  56264. ctx,
  56265. ytdExtremes,
  56266. dataGrouping = rangeOptions.dataGrouping;
  56267. // chart has no data, base series is removed
  56268. if (dataMin === null || dataMax === null) {
  56269. return;
  56270. }
  56271. // Set the fixed range before range is altered
  56272. chart.fixedRange = range;
  56273. rangeSelector.setSelected(i);
  56274. // Apply dataGrouping associated to button
  56275. if (dataGrouping) {
  56276. this.forcedDataGrouping = true;
  56277. Axis.prototype.setDataGrouping.call(baseAxis || { chart: this.chart }, dataGrouping, false);
  56278. this.frozenStates = rangeOptions.preserveDataGrouping;
  56279. }
  56280. // Apply range
  56281. if (type === 'month' || type === 'year') {
  56282. if (!baseAxis) {
  56283. // This is set to the user options and picked up later when the
  56284. // axis is instantiated so that we know the min and max.
  56285. range = rangeOptions;
  56286. }
  56287. else {
  56288. ctx = {
  56289. range: rangeOptions,
  56290. max: newMax,
  56291. chart: chart,
  56292. dataMin: dataMin,
  56293. dataMax: dataMax
  56294. };
  56295. newMin = baseAxis.minFromRange.call(ctx);
  56296. if (isNumber(ctx.newMax)) {
  56297. newMax = ctx.newMax;
  56298. }
  56299. }
  56300. // Fixed times like minutes, hours, days
  56301. }
  56302. else if (range) {
  56303. newMin = Math.max(newMax - range, dataMin);
  56304. newMax = Math.min(newMin + range, dataMax);
  56305. }
  56306. else if (type === 'ytd') {
  56307. // On user clicks on the buttons, or a delayed action running from
  56308. // the beforeRender event (below), the baseAxis is defined.
  56309. if (baseAxis) {
  56310. // When "ytd" is the pre-selected button for the initial view,
  56311. // its calculation is delayed and rerun in the beforeRender
  56312. // event (below). When the series are initialized, but before
  56313. // the chart is rendered, we have access to the xData array
  56314. // (#942).
  56315. if (typeof dataMax === 'undefined') {
  56316. dataMin = Number.MAX_VALUE;
  56317. dataMax = Number.MIN_VALUE;
  56318. chart.series.forEach(function (series) {
  56319. // reassign it to the last item
  56320. var xData = series.xData;
  56321. dataMin = Math.min(xData[0], dataMin);
  56322. dataMax = Math.max(xData[xData.length - 1], dataMax);
  56323. });
  56324. redraw = false;
  56325. }
  56326. ytdExtremes = rangeSelector.getYTDExtremes(dataMax, dataMin, chart.time.useUTC);
  56327. newMin = rangeMin = ytdExtremes.min;
  56328. newMax = ytdExtremes.max;
  56329. // "ytd" is pre-selected. We don't yet have access to processed
  56330. // point and extremes data (things like pointStart and pointInterval
  56331. // are missing), so we delay the process (#942)
  56332. }
  56333. else {
  56334. rangeSelector.deferredYTDClick = i;
  56335. return;
  56336. }
  56337. }
  56338. else if (type === 'all' && baseAxis) {
  56339. // If the navigator exist and the axis range is declared reset that
  56340. // range and from now on only use the range set by a user, #14742.
  56341. if (chart.navigator && chart.navigator.baseSeries[0]) {
  56342. chart.navigator.baseSeries[0].xAxis.options.range = void 0;
  56343. }
  56344. newMin = dataMin;
  56345. newMax = dataMax;
  56346. }
  56347. if (defined(newMin)) {
  56348. newMin += rangeOptions._offsetMin;
  56349. }
  56350. if (defined(newMax)) {
  56351. newMax += rangeOptions._offsetMax;
  56352. }
  56353. if (this.dropdown) {
  56354. this.dropdown.selectedIndex = i + 1;
  56355. }
  56356. // Update the chart
  56357. if (!baseAxis) {
  56358. // Axis not yet instanciated. Temporarily set min and range
  56359. // options and remove them on chart load (#4317).
  56360. baseXAxisOptions = splat(chart.options.xAxis)[0];
  56361. rangeSetting = baseXAxisOptions.range;
  56362. baseXAxisOptions.range = range;
  56363. minSetting = baseXAxisOptions.min;
  56364. baseXAxisOptions.min = rangeMin;
  56365. addEvent(chart, 'load', function resetMinAndRange() {
  56366. baseXAxisOptions.range = rangeSetting;
  56367. baseXAxisOptions.min = minSetting;
  56368. });
  56369. }
  56370. else {
  56371. // Existing axis object. Set extremes after render time.
  56372. baseAxis.setExtremes(newMin, newMax, pick(redraw, true), void 0, // auto animation
  56373. {
  56374. trigger: 'rangeSelectorButton',
  56375. rangeSelectorButton: rangeOptions
  56376. });
  56377. }
  56378. fireEvent(this, 'afterBtnClick');
  56379. };
  56380. /**
  56381. * Set the selected option. This method only sets the internal flag, it
  56382. * doesn't update the buttons or the actual zoomed range.
  56383. *
  56384. * @private
  56385. * @function Highcharts.RangeSelector#setSelected
  56386. * @param {number} [selected]
  56387. * @return {void}
  56388. */
  56389. RangeSelector.prototype.setSelected = function (selected) {
  56390. this.selected = this.options.selected = selected;
  56391. };
  56392. /**
  56393. * Initialize the range selector
  56394. *
  56395. * @private
  56396. * @function Highcharts.RangeSelector#init
  56397. * @param {Highcharts.Chart} chart
  56398. * @return {void}
  56399. */
  56400. RangeSelector.prototype.init = function (chart) {
  56401. var rangeSelector = this,
  56402. options = chart.options.rangeSelector,
  56403. buttonOptions = options.buttons || rangeSelector.defaultButtons.slice(),
  56404. selectedOption = options.selected,
  56405. blurInputs = function () {
  56406. var minInput = rangeSelector.minInput,
  56407. maxInput = rangeSelector.maxInput;
  56408. // #3274 in some case blur is not defined
  56409. if (minInput && minInput.blur) {
  56410. fireEvent(minInput, 'blur');
  56411. }
  56412. if (maxInput && maxInput.blur) {
  56413. fireEvent(maxInput, 'blur');
  56414. }
  56415. };
  56416. rangeSelector.chart = chart;
  56417. rangeSelector.options = options;
  56418. rangeSelector.buttons = [];
  56419. rangeSelector.buttonOptions = buttonOptions;
  56420. this.eventsToUnbind = [];
  56421. this.eventsToUnbind.push(addEvent(chart.container, 'mousedown', blurInputs));
  56422. this.eventsToUnbind.push(addEvent(chart, 'resize', blurInputs));
  56423. // Extend the buttonOptions with actual range
  56424. buttonOptions.forEach(rangeSelector.computeButtonRange);
  56425. // zoomed range based on a pre-selected button index
  56426. if (typeof selectedOption !== 'undefined' &&
  56427. buttonOptions[selectedOption]) {
  56428. this.clickButton(selectedOption, false);
  56429. }
  56430. this.eventsToUnbind.push(addEvent(chart, 'load', function () {
  56431. // If a data grouping is applied to the current button, release it
  56432. // when extremes change
  56433. if (chart.xAxis && chart.xAxis[0]) {
  56434. addEvent(chart.xAxis[0], 'setExtremes', function (e) {
  56435. if (this.max - this.min !==
  56436. chart.fixedRange &&
  56437. e.trigger !== 'rangeSelectorButton' &&
  56438. e.trigger !== 'updatedData' &&
  56439. rangeSelector.forcedDataGrouping &&
  56440. !rangeSelector.frozenStates) {
  56441. this.setDataGrouping(false, false);
  56442. }
  56443. });
  56444. }
  56445. }));
  56446. };
  56447. /**
  56448. * Dynamically update the range selector buttons after a new range has been
  56449. * set
  56450. *
  56451. * @private
  56452. * @function Highcharts.RangeSelector#updateButtonStates
  56453. * @return {void}
  56454. */
  56455. RangeSelector.prototype.updateButtonStates = function () {
  56456. var rangeSelector = this,
  56457. chart = this.chart,
  56458. dropdown = this.dropdown,
  56459. baseAxis = chart.xAxis[0],
  56460. actualRange = Math.round(baseAxis.max - baseAxis.min),
  56461. hasNoData = !baseAxis.hasVisibleSeries,
  56462. day = 24 * 36e5, // A single day in milliseconds
  56463. unionExtremes = (chart.scroller &&
  56464. chart.scroller.getUnionExtremes()) || baseAxis,
  56465. dataMin = unionExtremes.dataMin,
  56466. dataMax = unionExtremes.dataMax,
  56467. ytdExtremes = rangeSelector.getYTDExtremes(dataMax,
  56468. dataMin,
  56469. chart.time.useUTC),
  56470. ytdMin = ytdExtremes.min,
  56471. ytdMax = ytdExtremes.max,
  56472. selected = rangeSelector.selected,
  56473. selectedExists = isNumber(selected),
  56474. allButtonsEnabled = rangeSelector.options.allButtonsEnabled,
  56475. buttons = rangeSelector.buttons;
  56476. rangeSelector.buttonOptions.forEach(function (rangeOptions, i) {
  56477. var range = rangeOptions._range,
  56478. type = rangeOptions.type,
  56479. count = rangeOptions.count || 1,
  56480. button = buttons[i],
  56481. state = 0,
  56482. disable,
  56483. select,
  56484. offsetRange = rangeOptions._offsetMax -
  56485. rangeOptions._offsetMin,
  56486. isSelected = i === selected,
  56487. // Disable buttons where the range exceeds what is allowed in
  56488. // the current view
  56489. isTooGreatRange = range >
  56490. dataMax - dataMin,
  56491. // Disable buttons where the range is smaller than the minimum
  56492. // range
  56493. isTooSmallRange = range < baseAxis.minRange,
  56494. // Do not select the YTD button if not explicitly told so
  56495. isYTDButNotSelected = false,
  56496. // Disable the All button if we're already showing all
  56497. isAllButAlreadyShowingAll = false,
  56498. isSameRange = range === actualRange;
  56499. // Months and years have a variable range so we check the extremes
  56500. if ((type === 'month' || type === 'year') &&
  56501. (actualRange + 36e5 >=
  56502. { month: 28, year: 365 }[type] * day * count - offsetRange) &&
  56503. (actualRange - 36e5 <=
  56504. { month: 31, year: 366 }[type] * day * count + offsetRange)) {
  56505. isSameRange = true;
  56506. }
  56507. else if (type === 'ytd') {
  56508. isSameRange = (ytdMax - ytdMin + offsetRange) === actualRange;
  56509. isYTDButNotSelected = !isSelected;
  56510. }
  56511. else if (type === 'all') {
  56512. isSameRange = (baseAxis.max - baseAxis.min >=
  56513. dataMax - dataMin);
  56514. isAllButAlreadyShowingAll = (!isSelected &&
  56515. selectedExists &&
  56516. isSameRange);
  56517. }
  56518. // The new zoom area happens to match the range for a button - mark
  56519. // it selected. This happens when scrolling across an ordinal gap.
  56520. // It can be seen in the intraday demos when selecting 1h and scroll
  56521. // across the night gap.
  56522. disable = (!allButtonsEnabled &&
  56523. (isTooGreatRange ||
  56524. isTooSmallRange ||
  56525. isAllButAlreadyShowingAll ||
  56526. hasNoData));
  56527. select = ((isSelected && isSameRange) ||
  56528. (isSameRange && !selectedExists && !isYTDButNotSelected) ||
  56529. (isSelected && rangeSelector.frozenStates));
  56530. if (disable) {
  56531. state = 3;
  56532. }
  56533. else if (select) {
  56534. selectedExists = true; // Only one button can be selected
  56535. state = 2;
  56536. }
  56537. // If state has changed, update the button
  56538. if (button.state !== state) {
  56539. button.setState(state);
  56540. if (dropdown) {
  56541. dropdown.options[i + 1].disabled = disable;
  56542. if (state === 2) {
  56543. dropdown.selectedIndex = i + 1;
  56544. }
  56545. }
  56546. // Reset (#9209)
  56547. if (state === 0 && selected === i) {
  56548. rangeSelector.setSelected();
  56549. }
  56550. }
  56551. });
  56552. };
  56553. /**
  56554. * Compute and cache the range for an individual button
  56555. *
  56556. * @private
  56557. * @function Highcharts.RangeSelector#computeButtonRange
  56558. * @param {Highcharts.RangeSelectorButtonsOptions} rangeOptions
  56559. * @return {void}
  56560. */
  56561. RangeSelector.prototype.computeButtonRange = function (rangeOptions) {
  56562. var type = rangeOptions.type,
  56563. count = rangeOptions.count || 1,
  56564. // these time intervals have a fixed number of milliseconds, as
  56565. // opposed to month, ytd and year
  56566. fixedTimes = {
  56567. millisecond: 1,
  56568. second: 1000,
  56569. minute: 60 * 1000,
  56570. hour: 3600 * 1000,
  56571. day: 24 * 3600 * 1000,
  56572. week: 7 * 24 * 3600 * 1000
  56573. };
  56574. // Store the range on the button object
  56575. if (fixedTimes[type]) {
  56576. rangeOptions._range = fixedTimes[type] * count;
  56577. }
  56578. else if (type === 'month' || type === 'year') {
  56579. rangeOptions._range = {
  56580. month: 30,
  56581. year: 365
  56582. }[type] * 24 * 36e5 * count;
  56583. }
  56584. rangeOptions._offsetMin = pick(rangeOptions.offsetMin, 0);
  56585. rangeOptions._offsetMax = pick(rangeOptions.offsetMax, 0);
  56586. rangeOptions._range +=
  56587. rangeOptions._offsetMax - rangeOptions._offsetMin;
  56588. };
  56589. /**
  56590. * Get the unix timestamp of a HTML input for the dates
  56591. *
  56592. * @private
  56593. * @function Highcharts.RangeSelector#getInputValue
  56594. * @param {string} name
  56595. * @return {number}
  56596. */
  56597. RangeSelector.prototype.getInputValue = function (name) {
  56598. var input = name === 'min' ? this.minInput : this.maxInput;
  56599. var options = this.chart.options.rangeSelector;
  56600. var time = this.chart.time;
  56601. if (input) {
  56602. return ((input.type === 'text' && options.inputDateParser) ||
  56603. this.defaultInputDateParser)(input.value, time.useUTC, time);
  56604. }
  56605. return 0;
  56606. };
  56607. /**
  56608. * Set the internal and displayed value of a HTML input for the dates
  56609. *
  56610. * @private
  56611. * @function Highcharts.RangeSelector#setInputValue
  56612. * @param {string} name
  56613. * @param {number} [inputTime]
  56614. * @return {void}
  56615. */
  56616. RangeSelector.prototype.setInputValue = function (name, inputTime) {
  56617. var options = this.options, time = this.chart.time, input = name === 'min' ? this.minInput : this.maxInput, dateBox = name === 'min' ? this.minDateBox : this.maxDateBox;
  56618. if (input) {
  56619. var hcTimeAttr = input.getAttribute('data-hc-time');
  56620. var updatedTime = defined(hcTimeAttr) ? Number(hcTimeAttr) : void 0;
  56621. if (defined(inputTime)) {
  56622. var previousTime = updatedTime;
  56623. if (defined(previousTime)) {
  56624. input.setAttribute('data-hc-time-previous', previousTime);
  56625. }
  56626. input.setAttribute('data-hc-time', inputTime);
  56627. updatedTime = inputTime;
  56628. }
  56629. input.value = time.dateFormat(this.inputTypeFormats[input.type] || options.inputEditDateFormat, updatedTime);
  56630. if (dateBox) {
  56631. dateBox.attr({
  56632. text: time.dateFormat(options.inputDateFormat, updatedTime)
  56633. });
  56634. }
  56635. }
  56636. };
  56637. /**
  56638. * Set the min and max value of a HTML input for the dates
  56639. *
  56640. * @private
  56641. * @function Highcharts.RangeSelector#setInputExtremes
  56642. * @param {string} name
  56643. * @param {number} min
  56644. * @param {number} max
  56645. * @return {void}
  56646. */
  56647. RangeSelector.prototype.setInputExtremes = function (name, min, max) {
  56648. var input = name === 'min' ? this.minInput : this.maxInput;
  56649. if (input) {
  56650. var format = this.inputTypeFormats[input.type];
  56651. var time = this.chart.time;
  56652. if (format) {
  56653. var newMin = time.dateFormat(format,
  56654. min);
  56655. if (input.min !== newMin) {
  56656. input.min = newMin;
  56657. }
  56658. var newMax = time.dateFormat(format,
  56659. max);
  56660. if (input.max !== newMax) {
  56661. input.max = newMax;
  56662. }
  56663. }
  56664. }
  56665. };
  56666. /**
  56667. * @private
  56668. * @function Highcharts.RangeSelector#showInput
  56669. * @param {string} name
  56670. * @return {void}
  56671. */
  56672. RangeSelector.prototype.showInput = function (name) {
  56673. var dateBox = name === 'min' ? this.minDateBox : this.maxDateBox;
  56674. var input = name === 'min' ? this.minInput : this.maxInput;
  56675. if (input && dateBox && this.inputGroup) {
  56676. var isTextInput = input.type === 'text';
  56677. var _a = this.inputGroup,
  56678. translateX = _a.translateX,
  56679. translateY = _a.translateY;
  56680. var inputBoxWidth = this.options.inputBoxWidth;
  56681. css(input, {
  56682. width: isTextInput ? ((dateBox.width + (inputBoxWidth ? -2 : 20)) + 'px') : 'auto',
  56683. height: isTextInput ? ((dateBox.height - 2) + 'px') : 'auto',
  56684. border: '2px solid silver'
  56685. });
  56686. if (isTextInput && inputBoxWidth) {
  56687. css(input, {
  56688. left: (translateX + dateBox.x) + 'px',
  56689. top: translateY + 'px'
  56690. });
  56691. // Inputs of types date, time or datetime-local should be centered
  56692. // on top of the dateBox
  56693. }
  56694. else {
  56695. css(input, {
  56696. left: Math.min(Math.round(dateBox.x +
  56697. translateX -
  56698. (input.offsetWidth - dateBox.width) / 2), this.chart.chartWidth - input.offsetWidth) + 'px',
  56699. top: (translateY - (input.offsetHeight - dateBox.height) / 2) + 'px'
  56700. });
  56701. }
  56702. }
  56703. };
  56704. /**
  56705. * @private
  56706. * @function Highcharts.RangeSelector#hideInput
  56707. * @param {string} name
  56708. * @return {void}
  56709. */
  56710. RangeSelector.prototype.hideInput = function (name) {
  56711. var input = name === 'min' ? this.minInput : this.maxInput;
  56712. if (input) {
  56713. css(input, {
  56714. top: '-9999em',
  56715. border: 0,
  56716. width: '1px',
  56717. height: '1px'
  56718. });
  56719. }
  56720. };
  56721. /**
  56722. * @private
  56723. * @function Highcharts.RangeSelector#defaultInputDateParser
  56724. */
  56725. RangeSelector.prototype.defaultInputDateParser = function (inputDate, useUTC, time) {
  56726. var hasTimezone = function (str) {
  56727. return str.length > 6 &&
  56728. (str.lastIndexOf('-') === str.length - 6 ||
  56729. str.lastIndexOf('+') === str.length - 6);
  56730. };
  56731. var input = inputDate.split('/').join('-').split(' ').join('T');
  56732. if (input.indexOf('T') === -1) {
  56733. input += 'T00:00';
  56734. }
  56735. if (useUTC) {
  56736. input += 'Z';
  56737. }
  56738. else if (H.isSafari && !hasTimezone(input)) {
  56739. var offset = new Date(input).getTimezoneOffset() / 60;
  56740. input += offset <= 0 ? "+" + pad(-offset) + ":00" : "-" + pad(offset) + ":00";
  56741. }
  56742. var date = Date.parse(input);
  56743. // If the value isn't parsed directly to a value by the
  56744. // browser's Date.parse method, like YYYY-MM-DD in IE8, try
  56745. // parsing it a different way
  56746. if (!isNumber(date)) {
  56747. var parts = inputDate.split('-');
  56748. date = Date.UTC(pInt(parts[0]), pInt(parts[1]) - 1, pInt(parts[2]));
  56749. }
  56750. if (time && useUTC && isNumber(date)) {
  56751. date += time.getTimezoneOffset(date);
  56752. }
  56753. return date;
  56754. };
  56755. /**
  56756. * Draw either the 'from' or the 'to' HTML input box of the range selector
  56757. *
  56758. * @private
  56759. * @function Highcharts.RangeSelector#drawInput
  56760. * @param {string} name
  56761. * @return {RangeSelectorInputElements}
  56762. */
  56763. RangeSelector.prototype.drawInput = function (name) {
  56764. var _a = this,
  56765. chart = _a.chart,
  56766. div = _a.div,
  56767. inputGroup = _a.inputGroup;
  56768. var rangeSelector = this,
  56769. chartStyle = chart.renderer.style || {},
  56770. renderer = chart.renderer,
  56771. options = chart.options.rangeSelector,
  56772. lang = defaultOptions.lang,
  56773. isMin = name === 'min';
  56774. /**
  56775. * @private
  56776. */
  56777. function updateExtremes() {
  56778. var value = rangeSelector.getInputValue(name),
  56779. chartAxis = chart.xAxis[0],
  56780. dataAxis = chart.scroller && chart.scroller.xAxis ?
  56781. chart.scroller.xAxis :
  56782. chartAxis,
  56783. dataMin = dataAxis.dataMin,
  56784. dataMax = dataAxis.dataMax;
  56785. var maxInput = rangeSelector.maxInput,
  56786. minInput = rangeSelector.minInput;
  56787. if (value !== Number(input.getAttribute('data-hc-time-previous')) &&
  56788. isNumber(value)) {
  56789. input.setAttribute('data-hc-time-previous', value);
  56790. // Validate the extremes. If it goes beyound the data min or
  56791. // max, use the actual data extreme (#2438).
  56792. if (isMin && maxInput && isNumber(dataMin)) {
  56793. if (value > Number(maxInput.getAttribute('data-hc-time'))) {
  56794. value = void 0;
  56795. }
  56796. else if (value < dataMin) {
  56797. value = dataMin;
  56798. }
  56799. }
  56800. else if (minInput && isNumber(dataMax)) {
  56801. if (value < Number(minInput.getAttribute('data-hc-time'))) {
  56802. value = void 0;
  56803. }
  56804. else if (value > dataMax) {
  56805. value = dataMax;
  56806. }
  56807. }
  56808. // Set the extremes
  56809. if (typeof value !== 'undefined') { // @todo typof undefined
  56810. chartAxis.setExtremes(isMin ? value : chartAxis.min, isMin ? chartAxis.max : value, void 0, void 0, { trigger: 'rangeSelectorInput' });
  56811. }
  56812. }
  56813. }
  56814. // Create the text label
  56815. var text = lang[isMin ? 'rangeSelectorFrom' : 'rangeSelectorTo'];
  56816. var label = renderer
  56817. .label(text, 0)
  56818. .addClass('highcharts-range-label')
  56819. .attr({
  56820. padding: text ? 2 : 0,
  56821. height: text ? options.inputBoxHeight : 0
  56822. })
  56823. .add(inputGroup);
  56824. // Create an SVG label that shows updated date ranges and and records
  56825. // click events that bring in the HTML input.
  56826. var dateBox = renderer
  56827. .label('', 0)
  56828. .addClass('highcharts-range-input')
  56829. .attr({
  56830. padding: 2,
  56831. width: options.inputBoxWidth,
  56832. height: options.inputBoxHeight,
  56833. 'text-align': 'center'
  56834. })
  56835. .on('click',
  56836. function () {
  56837. // If it is already focused, the onfocus event doesn't fire
  56838. // (#3713)
  56839. rangeSelector.showInput(name);
  56840. rangeSelector[name + 'Input'].focus();
  56841. });
  56842. if (!chart.styledMode) {
  56843. dateBox.attr({
  56844. stroke: options.inputBoxBorderColor,
  56845. 'stroke-width': 1
  56846. });
  56847. }
  56848. dateBox.add(inputGroup);
  56849. // Create the HTML input element. This is rendered as 1x1 pixel then set
  56850. // to the right size when focused.
  56851. var input = createElement('input', {
  56852. name: name,
  56853. className: 'highcharts-range-selector'
  56854. },
  56855. void 0,
  56856. div);
  56857. // #14788: Setting input.type to an unsupported type throws in IE, so
  56858. // we need to use setAttribute instead
  56859. input.setAttribute('type', preferredInputType(options.inputDateFormat || '%b %e, %Y'));
  56860. if (!chart.styledMode) {
  56861. // Styles
  56862. label.css(merge(chartStyle, options.labelStyle));
  56863. dateBox.css(merge({
  56864. color: palette.neutralColor80
  56865. }, chartStyle, options.inputStyle));
  56866. css(input, extend({
  56867. position: 'absolute',
  56868. border: 0,
  56869. boxShadow: '0 0 15px rgba(0,0,0,0.3)',
  56870. width: '1px',
  56871. height: '1px',
  56872. padding: 0,
  56873. textAlign: 'center',
  56874. fontSize: chartStyle.fontSize,
  56875. fontFamily: chartStyle.fontFamily,
  56876. top: '-9999em' // #4798
  56877. }, options.inputStyle));
  56878. }
  56879. // Blow up the input box
  56880. input.onfocus = function () {
  56881. rangeSelector.showInput(name);
  56882. };
  56883. // Hide away the input box
  56884. input.onblur = function () {
  56885. // update extermes only when inputs are active
  56886. if (input === H.doc.activeElement) { // Only when focused
  56887. // Update also when no `change` event is triggered, like when
  56888. // clicking inside the SVG (#4710)
  56889. updateExtremes();
  56890. }
  56891. // #10404 - move hide and blur outside focus
  56892. rangeSelector.hideInput(name);
  56893. rangeSelector.setInputValue(name);
  56894. input.blur(); // #4606
  56895. };
  56896. var keyDown = false;
  56897. // handle changes in the input boxes
  56898. input.onchange = function () {
  56899. // Update extremes and blur input when clicking date input calendar
  56900. if (!keyDown) {
  56901. updateExtremes();
  56902. rangeSelector.hideInput(name);
  56903. input.blur();
  56904. }
  56905. };
  56906. input.onkeypress = function (event) {
  56907. // IE does not fire onchange on enter
  56908. if (event.keyCode === 13) {
  56909. updateExtremes();
  56910. }
  56911. };
  56912. input.onkeydown = function (event) {
  56913. keyDown = true;
  56914. // Arrow keys
  56915. if (event.keyCode === 38 || event.keyCode === 40) {
  56916. updateExtremes();
  56917. }
  56918. };
  56919. input.onkeyup = function () {
  56920. keyDown = false;
  56921. };
  56922. return { dateBox: dateBox, input: input, label: label };
  56923. };
  56924. /**
  56925. * Get the position of the range selector buttons and inputs. This can be
  56926. * overridden from outside for custom positioning.
  56927. *
  56928. * @private
  56929. * @function Highcharts.RangeSelector#getPosition
  56930. *
  56931. * @return {Highcharts.Dictionary<number>}
  56932. */
  56933. RangeSelector.prototype.getPosition = function () {
  56934. var chart = this.chart,
  56935. options = chart.options.rangeSelector,
  56936. top = options.verticalAlign === 'top' ?
  56937. chart.plotTop - chart.axisOffset[0] :
  56938. 0; // set offset only for varticalAlign top
  56939. return {
  56940. buttonTop: top + options.buttonPosition.y,
  56941. inputTop: top + options.inputPosition.y - 10
  56942. };
  56943. };
  56944. /**
  56945. * Get the extremes of YTD. Will choose dataMax if its value is lower than
  56946. * the current timestamp. Will choose dataMin if its value is higher than
  56947. * the timestamp for the start of current year.
  56948. *
  56949. * @private
  56950. * @function Highcharts.RangeSelector#getYTDExtremes
  56951. *
  56952. * @param {number} dataMax
  56953. *
  56954. * @param {number} dataMin
  56955. *
  56956. * @return {*}
  56957. * Returns min and max for the YTD
  56958. */
  56959. RangeSelector.prototype.getYTDExtremes = function (dataMax, dataMin, useUTC) {
  56960. var time = this.chart.time,
  56961. min,
  56962. now = new time.Date(dataMax),
  56963. year = time.get('FullYear',
  56964. now),
  56965. startOfYear = useUTC ?
  56966. time.Date.UTC(year, 0, 1) : // eslint-disable-line new-cap
  56967. +new time.Date(year, 0, 1);
  56968. min = Math.max(dataMin, startOfYear);
  56969. var ts = now.getTime();
  56970. return {
  56971. max: Math.min(dataMax || ts, ts),
  56972. min: min
  56973. };
  56974. };
  56975. /**
  56976. * Render the range selector including the buttons and the inputs. The first
  56977. * time render is called, the elements are created and positioned. On
  56978. * subsequent calls, they are moved and updated.
  56979. *
  56980. * @private
  56981. * @function Highcharts.RangeSelector#render
  56982. * @param {number} [min]
  56983. * X axis minimum
  56984. * @param {number} [max]
  56985. * X axis maximum
  56986. * @return {void}
  56987. */
  56988. RangeSelector.prototype.render = function (min, max) {
  56989. var chart = this.chart,
  56990. renderer = chart.renderer,
  56991. container = chart.container,
  56992. chartOptions = chart.options,
  56993. options = chartOptions.rangeSelector,
  56994. // Place inputs above the container
  56995. inputsZIndex = pick(chartOptions.chart.style &&
  56996. chartOptions.chart.style.zIndex, 0) + 1,
  56997. inputEnabled = options.inputEnabled,
  56998. rendered = this.rendered;
  56999. if (options.enabled === false) {
  57000. return;
  57001. }
  57002. // create the elements
  57003. if (!rendered) {
  57004. this.group = renderer.g('range-selector-group')
  57005. .attr({
  57006. zIndex: 7
  57007. })
  57008. .add();
  57009. this.div = createElement('div', void 0, {
  57010. position: 'relative',
  57011. height: 0,
  57012. zIndex: inputsZIndex
  57013. });
  57014. if (this.buttonOptions.length) {
  57015. this.renderButtons();
  57016. }
  57017. // First create a wrapper outside the container in order to make
  57018. // the inputs work and make export correct
  57019. if (container.parentNode) {
  57020. container.parentNode.insertBefore(this.div, container);
  57021. }
  57022. if (inputEnabled) {
  57023. // Create the group to keep the inputs
  57024. this.inputGroup = renderer.g('input-group').add(this.group);
  57025. var minElems = this.drawInput('min');
  57026. this.minDateBox = minElems.dateBox;
  57027. this.minLabel = minElems.label;
  57028. this.minInput = minElems.input;
  57029. var maxElems = this.drawInput('max');
  57030. this.maxDateBox = maxElems.dateBox;
  57031. this.maxLabel = maxElems.label;
  57032. this.maxInput = maxElems.input;
  57033. }
  57034. }
  57035. if (inputEnabled) {
  57036. // Set or reset the input values
  57037. this.setInputValue('min', min);
  57038. this.setInputValue('max', max);
  57039. var unionExtremes = (chart.scroller && chart.scroller.getUnionExtremes()) || chart.xAxis[0] || {};
  57040. if (defined(unionExtremes.dataMin) && defined(unionExtremes.dataMax)) {
  57041. var minRange = chart.xAxis[0].minRange || 0;
  57042. this.setInputExtremes('min', unionExtremes.dataMin, Math.min(unionExtremes.dataMax, this.getInputValue('max')) - minRange);
  57043. this.setInputExtremes('max', Math.max(unionExtremes.dataMin, this.getInputValue('min')) + minRange, unionExtremes.dataMax);
  57044. }
  57045. // Reflow
  57046. if (this.inputGroup) {
  57047. var x_1 = 0;
  57048. [
  57049. this.minLabel,
  57050. this.minDateBox,
  57051. this.maxLabel,
  57052. this.maxDateBox
  57053. ].forEach(function (label) {
  57054. if (label) {
  57055. var width = label.getBBox().width;
  57056. if (width) {
  57057. label.attr({ x: x_1 });
  57058. x_1 += width + options.inputSpacing;
  57059. }
  57060. }
  57061. });
  57062. }
  57063. }
  57064. this.alignElements();
  57065. this.rendered = true;
  57066. };
  57067. /**
  57068. * Render the range buttons. This only runs the first time, later the
  57069. * positioning is laid out in alignElements.
  57070. *
  57071. * @private
  57072. * @function Highcharts.RangeSelector#renderButtons
  57073. * @return {void}
  57074. */
  57075. RangeSelector.prototype.renderButtons = function () {
  57076. var _this = this;
  57077. var _a = this,
  57078. buttons = _a.buttons,
  57079. chart = _a.chart,
  57080. options = _a.options;
  57081. var lang = defaultOptions.lang;
  57082. var renderer = chart.renderer;
  57083. var buttonTheme = merge(options.buttonTheme);
  57084. var states = buttonTheme && buttonTheme.states;
  57085. // Prevent the button from resetting the width when the button state
  57086. // changes since we need more control over the width when collapsing
  57087. // the buttons
  57088. var width = buttonTheme.width || 28;
  57089. delete buttonTheme.width;
  57090. delete buttonTheme.states;
  57091. this.buttonGroup = renderer.g('range-selector-buttons').add(this.group);
  57092. var dropdown = this.dropdown = createElement('select',
  57093. void 0, {
  57094. position: 'absolute',
  57095. width: '1px',
  57096. height: '1px',
  57097. padding: 0,
  57098. border: 0,
  57099. top: '-9999em',
  57100. cursor: 'pointer',
  57101. opacity: 0.0001
  57102. },
  57103. this.div);
  57104. // Prevent page zoom on iPhone
  57105. addEvent(dropdown, 'touchstart', function () {
  57106. dropdown.style.fontSize = '16px';
  57107. });
  57108. // Forward events from select to button
  57109. [
  57110. [H.isMS ? 'mouseover' : 'mouseenter'],
  57111. [H.isMS ? 'mouseout' : 'mouseleave'],
  57112. ['change', 'click']
  57113. ].forEach(function (_a) {
  57114. var from = _a[0],
  57115. to = _a[1];
  57116. addEvent(dropdown, from, function () {
  57117. var button = buttons[_this.currentButtonIndex()];
  57118. if (button) {
  57119. fireEvent(button.element, to || from);
  57120. }
  57121. });
  57122. });
  57123. this.zoomText = renderer
  57124. .label((lang && lang.rangeSelectorZoom) || '', 0)
  57125. .attr({
  57126. padding: options.buttonTheme.padding,
  57127. height: options.buttonTheme.height,
  57128. paddingLeft: 0,
  57129. paddingRight: 0
  57130. })
  57131. .add(this.buttonGroup);
  57132. if (!this.chart.styledMode) {
  57133. this.zoomText.css(options.labelStyle);
  57134. buttonTheme['stroke-width'] = pick(buttonTheme['stroke-width'], 0);
  57135. }
  57136. createElement('option', {
  57137. textContent: this.zoomText.textStr,
  57138. disabled: true
  57139. }, void 0, dropdown);
  57140. this.buttonOptions.forEach(function (rangeOptions, i) {
  57141. createElement('option', {
  57142. textContent: rangeOptions.title || rangeOptions.text
  57143. }, void 0, dropdown);
  57144. buttons[i] = renderer
  57145. .button(rangeOptions.text, 0, 0, function (e) {
  57146. // extract events from button object and call
  57147. var buttonEvents = (rangeOptions.events &&
  57148. rangeOptions.events.click),
  57149. callDefaultEvent;
  57150. if (buttonEvents) {
  57151. callDefaultEvent =
  57152. buttonEvents.call(rangeOptions, e);
  57153. }
  57154. if (callDefaultEvent !== false) {
  57155. _this.clickButton(i);
  57156. }
  57157. _this.isActive = true;
  57158. }, buttonTheme, states && states.hover, states && states.select, states && states.disabled)
  57159. .attr({
  57160. 'text-align': 'center',
  57161. width: width
  57162. })
  57163. .add(_this.buttonGroup);
  57164. if (rangeOptions.title) {
  57165. buttons[i].attr('title', rangeOptions.title);
  57166. }
  57167. });
  57168. };
  57169. /**
  57170. * Align the elements horizontally and vertically.
  57171. *
  57172. * @private
  57173. * @function Highcharts.RangeSelector#alignElements
  57174. * @return {void}
  57175. */
  57176. RangeSelector.prototype.alignElements = function () {
  57177. var _this = this;
  57178. var _a = this,
  57179. buttonGroup = _a.buttonGroup,
  57180. buttons = _a.buttons,
  57181. chart = _a.chart,
  57182. group = _a.group,
  57183. inputGroup = _a.inputGroup,
  57184. options = _a.options,
  57185. zoomText = _a.zoomText;
  57186. var chartOptions = chart.options;
  57187. var navButtonOptions = (chartOptions.exporting &&
  57188. chartOptions.exporting.enabled !== false &&
  57189. chartOptions.navigation &&
  57190. chartOptions.navigation.buttonOptions);
  57191. var buttonPosition = options.buttonPosition,
  57192. inputPosition = options.inputPosition,
  57193. verticalAlign = options.verticalAlign;
  57194. // Get the X offset required to avoid overlapping with the exporting
  57195. // button. This is is used both by the buttonGroup and the inputGroup.
  57196. var getXOffsetForExportButton = function (group,
  57197. position) {
  57198. if (navButtonOptions &&
  57199. _this.titleCollision(chart) &&
  57200. verticalAlign === 'top' &&
  57201. position.align === 'right' && ((position.y -
  57202. group.getBBox().height - 12) <
  57203. ((navButtonOptions.y || 0) +
  57204. (navButtonOptions.height || 0) +
  57205. chart.spacing[0]))) {
  57206. return -40;
  57207. }
  57208. return 0;
  57209. };
  57210. var plotLeft = chart.plotLeft;
  57211. if (group && buttonPosition && inputPosition) {
  57212. var translateX = buttonPosition.x - chart.spacing[3];
  57213. if (buttonGroup) {
  57214. this.positionButtons();
  57215. if (!this.initialButtonGroupWidth) {
  57216. var width_1 = 0;
  57217. if (zoomText) {
  57218. width_1 += zoomText.getBBox().width + 5;
  57219. }
  57220. buttons.forEach(function (button, i) {
  57221. width_1 += button.width;
  57222. if (i !== buttons.length - 1) {
  57223. width_1 += options.buttonSpacing;
  57224. }
  57225. });
  57226. this.initialButtonGroupWidth = width_1;
  57227. }
  57228. plotLeft -= chart.spacing[3];
  57229. this.updateButtonStates();
  57230. // Detect collision between button group and exporting
  57231. var xOffsetForExportButton_1 = getXOffsetForExportButton(buttonGroup,
  57232. buttonPosition);
  57233. this.alignButtonGroup(xOffsetForExportButton_1);
  57234. // Skip animation
  57235. group.placed = buttonGroup.placed = chart.hasLoaded;
  57236. }
  57237. var xOffsetForExportButton = 0;
  57238. if (inputGroup) {
  57239. // Detect collision between the input group and exporting button
  57240. xOffsetForExportButton = getXOffsetForExportButton(inputGroup, inputPosition);
  57241. if (inputPosition.align === 'left') {
  57242. translateX = plotLeft;
  57243. }
  57244. else if (inputPosition.align === 'right') {
  57245. translateX = -Math.max(chart.axisOffset[1], -xOffsetForExportButton);
  57246. }
  57247. // Update the alignment to the updated spacing box
  57248. inputGroup.align({
  57249. y: inputPosition.y,
  57250. width: inputGroup.getBBox().width,
  57251. align: inputPosition.align,
  57252. // fix wrong getBBox() value on right align
  57253. x: inputPosition.x + translateX - 2
  57254. }, true, chart.spacingBox);
  57255. // Skip animation
  57256. inputGroup.placed = chart.hasLoaded;
  57257. }
  57258. this.handleCollision(xOffsetForExportButton);
  57259. // Vertical align
  57260. group.align({
  57261. verticalAlign: verticalAlign
  57262. }, true, chart.spacingBox);
  57263. var alignTranslateY = group.alignAttr.translateY;
  57264. // Set position
  57265. var groupHeight = group.getBBox().height + 20; // # 20 padding
  57266. var translateY = 0;
  57267. // Calculate bottom position
  57268. if (verticalAlign === 'bottom') {
  57269. var legendOptions = chart.legend && chart.legend.options;
  57270. var legendHeight = (legendOptions &&
  57271. legendOptions.verticalAlign === 'bottom' &&
  57272. legendOptions.enabled &&
  57273. !legendOptions.floating ?
  57274. (chart.legend.legendHeight +
  57275. pick(legendOptions.margin, 10)) :
  57276. 0);
  57277. groupHeight = groupHeight + legendHeight - 20;
  57278. translateY = (alignTranslateY -
  57279. groupHeight -
  57280. (options.floating ? 0 : options.y) -
  57281. (chart.titleOffset ? chart.titleOffset[2] : 0) -
  57282. 10 // 10 spacing
  57283. );
  57284. }
  57285. if (verticalAlign === 'top') {
  57286. if (options.floating) {
  57287. translateY = 0;
  57288. }
  57289. if (chart.titleOffset && chart.titleOffset[0]) {
  57290. translateY = chart.titleOffset[0];
  57291. }
  57292. translateY += ((chart.margin[0] - chart.spacing[0]) || 0);
  57293. }
  57294. else if (verticalAlign === 'middle') {
  57295. if (inputPosition.y === buttonPosition.y) {
  57296. translateY = alignTranslateY;
  57297. }
  57298. else if (inputPosition.y || buttonPosition.y) {
  57299. if (inputPosition.y < 0 ||
  57300. buttonPosition.y < 0) {
  57301. translateY -= Math.min(inputPosition.y, buttonPosition.y);
  57302. }
  57303. else {
  57304. translateY = alignTranslateY - groupHeight;
  57305. }
  57306. }
  57307. }
  57308. group.translate(options.x, options.y + Math.floor(translateY));
  57309. // Translate HTML inputs
  57310. var _b = this,
  57311. minInput = _b.minInput,
  57312. maxInput = _b.maxInput,
  57313. dropdown = _b.dropdown;
  57314. if (options.inputEnabled && minInput && maxInput) {
  57315. minInput.style.marginTop = group.translateY + 'px';
  57316. maxInput.style.marginTop = group.translateY + 'px';
  57317. }
  57318. if (dropdown) {
  57319. dropdown.style.marginTop = group.translateY + 'px';
  57320. }
  57321. }
  57322. };
  57323. /**
  57324. * Align the button group horizontally and vertically.
  57325. *
  57326. * @private
  57327. * @function Highcharts.RangeSelector#alignButtonGroup
  57328. * @param {number} xOffsetForExportButton
  57329. * @param {number} [width]
  57330. * @return {void}
  57331. */
  57332. RangeSelector.prototype.alignButtonGroup = function (xOffsetForExportButton, width) {
  57333. var _a = this,
  57334. chart = _a.chart,
  57335. options = _a.options,
  57336. buttonGroup = _a.buttonGroup,
  57337. buttons = _a.buttons;
  57338. var buttonPosition = options.buttonPosition;
  57339. var plotLeft = chart.plotLeft - chart.spacing[3];
  57340. var translateX = buttonPosition.x - chart.spacing[3];
  57341. if (buttonPosition.align === 'right') {
  57342. translateX += xOffsetForExportButton - plotLeft; // #13014
  57343. }
  57344. else if (buttonPosition.align === 'center') {
  57345. translateX -= plotLeft / 2;
  57346. }
  57347. if (buttonGroup) {
  57348. // Align button group
  57349. buttonGroup.align({
  57350. y: buttonPosition.y,
  57351. width: pick(width, this.initialButtonGroupWidth),
  57352. align: buttonPosition.align,
  57353. x: translateX
  57354. }, true, chart.spacingBox);
  57355. }
  57356. };
  57357. /**
  57358. * @private
  57359. * @function Highcharts.RangeSelector#positionButtons
  57360. * @return {void}
  57361. */
  57362. RangeSelector.prototype.positionButtons = function () {
  57363. var _a = this,
  57364. buttons = _a.buttons,
  57365. chart = _a.chart,
  57366. options = _a.options,
  57367. zoomText = _a.zoomText;
  57368. var verb = chart.hasLoaded ? 'animate' : 'attr';
  57369. var buttonPosition = options.buttonPosition;
  57370. var plotLeft = chart.plotLeft;
  57371. var buttonLeft = plotLeft;
  57372. if (zoomText && zoomText.visibility !== 'hidden') {
  57373. // #8769, allow dynamically updating margins
  57374. zoomText[verb]({
  57375. x: pick(plotLeft + buttonPosition.x, plotLeft)
  57376. });
  57377. // Button start position
  57378. buttonLeft += buttonPosition.x +
  57379. zoomText.getBBox().width + 5;
  57380. }
  57381. this.buttonOptions.forEach(function (rangeOptions, i) {
  57382. if (buttons[i].visibility !== 'hidden') {
  57383. buttons[i][verb]({ x: buttonLeft });
  57384. // increase button position for the next button
  57385. buttonLeft += buttons[i].width + options.buttonSpacing;
  57386. }
  57387. else {
  57388. buttons[i][verb]({ x: plotLeft });
  57389. }
  57390. });
  57391. };
  57392. /**
  57393. * Handle collision between the button group and the input group
  57394. *
  57395. * @private
  57396. * @function Highcharts.RangeSelector#handleCollision
  57397. *
  57398. * @param {number} xOffsetForExportButton
  57399. * The X offset of the group required to make room for the
  57400. * exporting button
  57401. * @return {void}
  57402. */
  57403. RangeSelector.prototype.handleCollision = function (xOffsetForExportButton) {
  57404. var _this = this;
  57405. var _a = this,
  57406. chart = _a.chart,
  57407. buttonGroup = _a.buttonGroup,
  57408. inputGroup = _a.inputGroup;
  57409. var _b = this.options,
  57410. buttonPosition = _b.buttonPosition,
  57411. dropdown = _b.dropdown,
  57412. inputPosition = _b.inputPosition;
  57413. var maxButtonWidth = function () {
  57414. var buttonWidth = 0;
  57415. _this.buttons.forEach(function (button) {
  57416. var bBox = button.getBBox();
  57417. if (bBox.width > buttonWidth) {
  57418. buttonWidth = bBox.width;
  57419. }
  57420. });
  57421. return buttonWidth;
  57422. };
  57423. var groupsOverlap = function (buttonGroupWidth) {
  57424. if (inputGroup && buttonGroup) {
  57425. var inputGroupX = (inputGroup.alignAttr.translateX +
  57426. inputGroup.alignOptions.x -
  57427. xOffsetForExportButton +
  57428. // getBBox for detecing left margin
  57429. inputGroup.getBBox().x +
  57430. // 2px padding to not overlap input and label
  57431. 2);
  57432. var inputGroupWidth = inputGroup.alignOptions.width;
  57433. var buttonGroupX = buttonGroup.alignAttr.translateX +
  57434. buttonGroup.getBBox().x;
  57435. return (buttonGroupX + buttonGroupWidth > inputGroupX) &&
  57436. (inputGroupX + inputGroupWidth > buttonGroupX) &&
  57437. (buttonPosition.y <
  57438. (inputPosition.y +
  57439. inputGroup.getBBox().height));
  57440. }
  57441. return false;
  57442. };
  57443. var moveInputsDown = function () {
  57444. if (inputGroup && buttonGroup) {
  57445. inputGroup.attr({
  57446. translateX: inputGroup.alignAttr.translateX + (chart.axisOffset[1] >= -xOffsetForExportButton ?
  57447. 0 :
  57448. -xOffsetForExportButton),
  57449. translateY: inputGroup.alignAttr.translateY +
  57450. buttonGroup.getBBox().height + 10
  57451. });
  57452. }
  57453. };
  57454. if (buttonGroup) {
  57455. if (dropdown === 'always') {
  57456. this.collapseButtons(xOffsetForExportButton);
  57457. if (groupsOverlap(maxButtonWidth())) {
  57458. // Move the inputs down if there is still a collision
  57459. // after collapsing the buttons
  57460. moveInputsDown();
  57461. }
  57462. return;
  57463. }
  57464. if (dropdown === 'never') {
  57465. this.expandButtons();
  57466. }
  57467. }
  57468. // Detect collision
  57469. if (inputGroup && buttonGroup) {
  57470. if ((inputPosition.align === buttonPosition.align) ||
  57471. // 20 is minimal spacing between elements
  57472. groupsOverlap(this.initialButtonGroupWidth + 20)) {
  57473. if (dropdown === 'responsive') {
  57474. this.collapseButtons(xOffsetForExportButton);
  57475. if (groupsOverlap(maxButtonWidth())) {
  57476. moveInputsDown();
  57477. }
  57478. }
  57479. else {
  57480. moveInputsDown();
  57481. }
  57482. }
  57483. else if (dropdown === 'responsive') {
  57484. this.expandButtons();
  57485. }
  57486. }
  57487. else if (buttonGroup && dropdown === 'responsive') {
  57488. if (this.initialButtonGroupWidth > chart.plotWidth) {
  57489. this.collapseButtons(xOffsetForExportButton);
  57490. }
  57491. else {
  57492. this.expandButtons();
  57493. }
  57494. }
  57495. };
  57496. /**
  57497. * Collapse the buttons and put the select element on top.
  57498. *
  57499. * @private
  57500. * @function Highcharts.RangeSelector#collapseButtons
  57501. * @param {number} xOffsetForExportButton
  57502. * @return {void}
  57503. */
  57504. RangeSelector.prototype.collapseButtons = function (xOffsetForExportButton) {
  57505. var _a = this,
  57506. buttons = _a.buttons,
  57507. buttonOptions = _a.buttonOptions,
  57508. chart = _a.chart,
  57509. dropdown = _a.dropdown,
  57510. options = _a.options,
  57511. zoomText = _a.zoomText;
  57512. var userButtonTheme = (chart.userOptions.rangeSelector &&
  57513. chart.userOptions.rangeSelector.buttonTheme) || {};
  57514. var getAttribs = function (text) { return ({
  57515. text: text ? text + " \u25BE" : '▾',
  57516. width: 'auto',
  57517. paddingLeft: pick(options.buttonTheme.paddingLeft,
  57518. userButtonTheme.padding, 8),
  57519. paddingRight: pick(options.buttonTheme.paddingRight,
  57520. userButtonTheme.padding, 8)
  57521. }); };
  57522. if (zoomText) {
  57523. zoomText.hide();
  57524. }
  57525. var hasActiveButton = false;
  57526. buttonOptions.forEach(function (rangeOptions, i) {
  57527. var button = buttons[i];
  57528. if (button.state !== 2) {
  57529. button.hide();
  57530. }
  57531. else {
  57532. button.show();
  57533. button.attr(getAttribs(rangeOptions.text));
  57534. hasActiveButton = true;
  57535. }
  57536. });
  57537. if (!hasActiveButton) {
  57538. if (dropdown) {
  57539. dropdown.selectedIndex = 0;
  57540. }
  57541. buttons[0].show();
  57542. buttons[0].attr(getAttribs(this.zoomText && this.zoomText.textStr));
  57543. }
  57544. var align = options.buttonPosition.align;
  57545. this.positionButtons();
  57546. if (align === 'right' || align === 'center') {
  57547. this.alignButtonGroup(xOffsetForExportButton, buttons[this.currentButtonIndex()].getBBox().width);
  57548. }
  57549. this.showDropdown();
  57550. };
  57551. /**
  57552. * Show all the buttons and hide the select element.
  57553. *
  57554. * @private
  57555. * @function Highcharts.RangeSelector#expandButtons
  57556. * @return {void}
  57557. */
  57558. RangeSelector.prototype.expandButtons = function () {
  57559. var _a = this,
  57560. buttons = _a.buttons,
  57561. buttonOptions = _a.buttonOptions,
  57562. options = _a.options,
  57563. zoomText = _a.zoomText;
  57564. this.hideDropdown();
  57565. if (zoomText) {
  57566. zoomText.show();
  57567. }
  57568. buttonOptions.forEach(function (rangeOptions, i) {
  57569. var button = buttons[i];
  57570. button.show();
  57571. button.attr({
  57572. text: rangeOptions.text,
  57573. width: options.buttonTheme.width || 28,
  57574. paddingLeft: pick(options.buttonTheme.paddingLeft, 'unset'),
  57575. paddingRight: pick(options.buttonTheme.paddingRight, 'unset')
  57576. });
  57577. if (button.state < 2) {
  57578. button.setState(0);
  57579. }
  57580. });
  57581. this.positionButtons();
  57582. };
  57583. /**
  57584. * Get the index of the visible button when the buttons are collapsed.
  57585. *
  57586. * @private
  57587. * @function Highcharts.RangeSelector#currentButtonIndex
  57588. * @return {number}
  57589. */
  57590. RangeSelector.prototype.currentButtonIndex = function () {
  57591. var dropdown = this.dropdown;
  57592. if (dropdown && dropdown.selectedIndex > 0) {
  57593. return dropdown.selectedIndex - 1;
  57594. }
  57595. return 0;
  57596. };
  57597. /**
  57598. * Position the select element on top of the button.
  57599. *
  57600. * @private
  57601. * @function Highcharts.RangeSelector#showDropdown
  57602. * @return {void}
  57603. */
  57604. RangeSelector.prototype.showDropdown = function () {
  57605. var _a = this,
  57606. buttonGroup = _a.buttonGroup,
  57607. buttons = _a.buttons,
  57608. chart = _a.chart,
  57609. dropdown = _a.dropdown;
  57610. if (buttonGroup && dropdown) {
  57611. var translateX = buttonGroup.translateX,
  57612. translateY = buttonGroup.translateY;
  57613. var bBox = buttons[this.currentButtonIndex()].getBBox();
  57614. css(dropdown, {
  57615. left: (chart.plotLeft + translateX) + 'px',
  57616. top: (translateY + 0.5) + 'px',
  57617. width: bBox.width + 'px',
  57618. height: bBox.height + 'px'
  57619. });
  57620. this.hasVisibleDropdown = true;
  57621. }
  57622. };
  57623. /**
  57624. * @private
  57625. * @function Highcharts.RangeSelector#hideDropdown
  57626. * @return {void}
  57627. */
  57628. RangeSelector.prototype.hideDropdown = function () {
  57629. var dropdown = this.dropdown;
  57630. if (dropdown) {
  57631. css(dropdown, {
  57632. top: '-9999em',
  57633. width: '1px',
  57634. height: '1px'
  57635. });
  57636. this.hasVisibleDropdown = false;
  57637. }
  57638. };
  57639. /**
  57640. * Extracts height of range selector
  57641. *
  57642. * @private
  57643. * @function Highcharts.RangeSelector#getHeight
  57644. * @return {number}
  57645. * Returns rangeSelector height
  57646. */
  57647. RangeSelector.prototype.getHeight = function () {
  57648. var rangeSelector = this,
  57649. options = rangeSelector.options,
  57650. rangeSelectorGroup = rangeSelector.group,
  57651. inputPosition = options.inputPosition,
  57652. buttonPosition = options.buttonPosition,
  57653. yPosition = options.y,
  57654. buttonPositionY = buttonPosition.y,
  57655. inputPositionY = inputPosition.y,
  57656. rangeSelectorHeight = 0,
  57657. minPosition;
  57658. if (options.height) {
  57659. return options.height;
  57660. }
  57661. // Align the elements before we read the height in case we're switching
  57662. // between wrapped and non-wrapped layout
  57663. this.alignElements();
  57664. rangeSelectorHeight = rangeSelectorGroup ?
  57665. // 13px to keep back compatibility
  57666. (rangeSelectorGroup.getBBox(true).height) + 13 +
  57667. yPosition :
  57668. 0;
  57669. minPosition = Math.min(inputPositionY, buttonPositionY);
  57670. if ((inputPositionY < 0 && buttonPositionY < 0) ||
  57671. (inputPositionY > 0 && buttonPositionY > 0)) {
  57672. rangeSelectorHeight += Math.abs(minPosition);
  57673. }
  57674. return rangeSelectorHeight;
  57675. };
  57676. /**
  57677. * Detect collision with title or subtitle
  57678. *
  57679. * @private
  57680. * @function Highcharts.RangeSelector#titleCollision
  57681. *
  57682. * @param {Highcharts.Chart} chart
  57683. *
  57684. * @return {boolean}
  57685. * Returns collision status
  57686. */
  57687. RangeSelector.prototype.titleCollision = function (chart) {
  57688. return !(chart.options.title.text ||
  57689. chart.options.subtitle.text);
  57690. };
  57691. /**
  57692. * Update the range selector with new options
  57693. *
  57694. * @private
  57695. * @function Highcharts.RangeSelector#update
  57696. * @param {Highcharts.RangeSelectorOptions} options
  57697. * @return {void}
  57698. */
  57699. RangeSelector.prototype.update = function (options) {
  57700. var chart = this.chart;
  57701. merge(true, chart.options.rangeSelector, options);
  57702. this.destroy();
  57703. this.init(chart);
  57704. this.render();
  57705. };
  57706. /**
  57707. * Destroys allocated elements.
  57708. *
  57709. * @private
  57710. * @function Highcharts.RangeSelector#destroy
  57711. */
  57712. RangeSelector.prototype.destroy = function () {
  57713. var rSelector = this,
  57714. minInput = rSelector.minInput,
  57715. maxInput = rSelector.maxInput;
  57716. if (rSelector.eventsToUnbind) {
  57717. rSelector.eventsToUnbind.forEach(function (unbind) { return unbind(); });
  57718. rSelector.eventsToUnbind = void 0;
  57719. }
  57720. // Destroy elements in collections
  57721. destroyObjectProperties(rSelector.buttons);
  57722. // Clear input element events
  57723. if (minInput) {
  57724. minInput.onfocus = minInput.onblur = minInput.onchange = null;
  57725. }
  57726. if (maxInput) {
  57727. maxInput.onfocus = maxInput.onblur = maxInput.onchange = null;
  57728. }
  57729. // Destroy HTML and SVG elements
  57730. objectEach(rSelector, function (val, key) {
  57731. if (val && key !== 'chart') {
  57732. if (val instanceof SVGElement) {
  57733. // SVGElement
  57734. val.destroy();
  57735. }
  57736. else if (val instanceof window.HTMLElement) {
  57737. // HTML element
  57738. discardElement(val);
  57739. }
  57740. }
  57741. if (val !== RangeSelector.prototype[key]) {
  57742. rSelector[key] = null;
  57743. }
  57744. }, this);
  57745. };
  57746. return RangeSelector;
  57747. }());
  57748. /**
  57749. * The default buttons for pre-selecting time frames
  57750. */
  57751. RangeSelector.prototype.defaultButtons = [{
  57752. type: 'month',
  57753. count: 1,
  57754. text: '1m',
  57755. title: 'View 1 month'
  57756. }, {
  57757. type: 'month',
  57758. count: 3,
  57759. text: '3m',
  57760. title: 'View 3 months'
  57761. }, {
  57762. type: 'month',
  57763. count: 6,
  57764. text: '6m',
  57765. title: 'View 6 months'
  57766. }, {
  57767. type: 'ytd',
  57768. text: 'YTD',
  57769. title: 'View year to date'
  57770. }, {
  57771. type: 'year',
  57772. count: 1,
  57773. text: '1y',
  57774. title: 'View 1 year'
  57775. }, {
  57776. type: 'all',
  57777. text: 'All',
  57778. title: 'View all'
  57779. }];
  57780. /**
  57781. * The date formats to use when setting min, max and value on date inputs
  57782. */
  57783. RangeSelector.prototype.inputTypeFormats = {
  57784. 'datetime-local': '%Y-%m-%dT%H:%M:%S',
  57785. 'date': '%Y-%m-%d',
  57786. 'time': '%H:%M:%S'
  57787. };
  57788. /**
  57789. * Get the preferred input type based on a date format string.
  57790. *
  57791. * @private
  57792. * @function preferredInputType
  57793. * @param {string} format
  57794. * @return {string}
  57795. */
  57796. function preferredInputType(format) {
  57797. var ms = format.indexOf('%L') !== -1;
  57798. if (ms) {
  57799. return 'text';
  57800. }
  57801. var date = ['a', 'A', 'd', 'e', 'w', 'b', 'B', 'm', 'o', 'y', 'Y'].some(function (char) {
  57802. return format.indexOf('%' + char) !== -1;
  57803. });
  57804. var time = ['H', 'k', 'I', 'l', 'M', 'S'].some(function (char) {
  57805. return format.indexOf('%' + char) !== -1;
  57806. });
  57807. if (date && time) {
  57808. return 'datetime-local';
  57809. }
  57810. if (date) {
  57811. return 'date';
  57812. }
  57813. if (time) {
  57814. return 'time';
  57815. }
  57816. return 'text';
  57817. }
  57818. /**
  57819. * Get the axis min value based on the range option and the current max. For
  57820. * stock charts this is extended via the {@link RangeSelector} so that if the
  57821. * selected range is a multiple of months or years, it is compensated for
  57822. * various month lengths.
  57823. *
  57824. * @private
  57825. * @function Highcharts.Axis#minFromRange
  57826. * @return {number|undefined}
  57827. * The new minimum value.
  57828. */
  57829. Axis.prototype.minFromRange = function () {
  57830. var rangeOptions = this.range,
  57831. type = rangeOptions.type,
  57832. min,
  57833. max = this.max,
  57834. dataMin,
  57835. range,
  57836. time = this.chart.time,
  57837. // Get the true range from a start date
  57838. getTrueRange = function (base,
  57839. count) {
  57840. var timeName = type === 'year' ? 'FullYear' : 'Month';
  57841. var date = new time.Date(base);
  57842. var basePeriod = time.get(timeName,
  57843. date);
  57844. time.set(timeName, date, basePeriod + count);
  57845. if (basePeriod === time.get(timeName, date)) {
  57846. time.set('Date', date, 0); // #6537
  57847. }
  57848. return date.getTime() - base;
  57849. };
  57850. if (isNumber(rangeOptions)) {
  57851. min = max - rangeOptions;
  57852. range = rangeOptions;
  57853. }
  57854. else {
  57855. min = max + getTrueRange(max, -rangeOptions.count);
  57856. // Let the fixedRange reflect initial settings (#5930)
  57857. if (this.chart) {
  57858. this.chart.fixedRange = max - min;
  57859. }
  57860. }
  57861. dataMin = pick(this.dataMin, Number.MIN_VALUE);
  57862. if (!isNumber(min)) {
  57863. min = dataMin;
  57864. }
  57865. if (min <= dataMin) {
  57866. min = dataMin;
  57867. if (typeof range === 'undefined') { // #4501
  57868. range = getTrueRange(min, rangeOptions.count);
  57869. }
  57870. this.newMax = Math.min(min + range, this.dataMax);
  57871. }
  57872. if (!isNumber(max)) {
  57873. min = void 0;
  57874. }
  57875. return min;
  57876. };
  57877. if (!H.RangeSelector) {
  57878. var chartDestroyEvents_1 = [];
  57879. var initRangeSelector_1 = function (chart) {
  57880. var extremes,
  57881. rangeSelector = chart.rangeSelector,
  57882. legend,
  57883. alignTo,
  57884. verticalAlign;
  57885. /**
  57886. * @private
  57887. */
  57888. function render() {
  57889. if (rangeSelector) {
  57890. extremes = chart.xAxis[0].getExtremes();
  57891. legend = chart.legend;
  57892. verticalAlign = (rangeSelector &&
  57893. rangeSelector.options.verticalAlign);
  57894. if (isNumber(extremes.min)) {
  57895. rangeSelector.render(extremes.min, extremes.max);
  57896. }
  57897. // Re-align the legend so that it's below the rangeselector
  57898. if (legend.display &&
  57899. verticalAlign === 'top' &&
  57900. verticalAlign === legend.options.verticalAlign) {
  57901. // Create a new alignment box for the legend.
  57902. alignTo = merge(chart.spacingBox);
  57903. if (legend.options.layout === 'vertical') {
  57904. alignTo.y = chart.plotTop;
  57905. }
  57906. else {
  57907. alignTo.y += rangeSelector.getHeight();
  57908. }
  57909. legend.group.placed = false; // Don't animate the alignment.
  57910. legend.align(alignTo);
  57911. }
  57912. }
  57913. }
  57914. if (rangeSelector) {
  57915. var events = find(chartDestroyEvents_1,
  57916. function (e) { return e[0] === chart; });
  57917. if (!events) {
  57918. chartDestroyEvents_1.push([chart, [
  57919. // redraw the scroller on setExtremes
  57920. addEvent(chart.xAxis[0], 'afterSetExtremes', function (e) {
  57921. if (rangeSelector) {
  57922. rangeSelector.render(e.min, e.max);
  57923. }
  57924. }),
  57925. // redraw the scroller chart resize
  57926. addEvent(chart, 'redraw', render)
  57927. ]]);
  57928. }
  57929. // do it now
  57930. render();
  57931. }
  57932. };
  57933. // Initialize rangeselector for stock charts
  57934. addEvent(Chart, 'afterGetContainer', function () {
  57935. if (this.options.rangeSelector &&
  57936. this.options.rangeSelector.enabled) {
  57937. this.rangeSelector = new RangeSelector(this);
  57938. }
  57939. });
  57940. addEvent(Chart, 'beforeRender', function () {
  57941. var chart = this,
  57942. axes = chart.axes,
  57943. rangeSelector = chart.rangeSelector,
  57944. verticalAlign;
  57945. if (rangeSelector) {
  57946. if (isNumber(rangeSelector.deferredYTDClick)) {
  57947. rangeSelector.clickButton(rangeSelector.deferredYTDClick);
  57948. delete rangeSelector.deferredYTDClick;
  57949. }
  57950. axes.forEach(function (axis) {
  57951. axis.updateNames();
  57952. axis.setScale();
  57953. });
  57954. chart.getAxisMargins();
  57955. rangeSelector.render();
  57956. verticalAlign = rangeSelector.options.verticalAlign;
  57957. if (!rangeSelector.options.floating) {
  57958. if (verticalAlign === 'bottom') {
  57959. this.extraBottomMargin = true;
  57960. }
  57961. else if (verticalAlign !== 'middle') {
  57962. this.extraTopMargin = true;
  57963. }
  57964. }
  57965. }
  57966. });
  57967. addEvent(Chart, 'update', function (e) {
  57968. var chart = this,
  57969. options = e.options,
  57970. optionsRangeSelector = options.rangeSelector,
  57971. rangeSelector = chart.rangeSelector,
  57972. verticalAlign,
  57973. extraBottomMarginWas = this.extraBottomMargin,
  57974. extraTopMarginWas = this.extraTopMargin;
  57975. if (optionsRangeSelector &&
  57976. optionsRangeSelector.enabled &&
  57977. !defined(rangeSelector) &&
  57978. this.options.rangeSelector) {
  57979. this.options.rangeSelector.enabled = true;
  57980. this.rangeSelector = rangeSelector = new RangeSelector(this);
  57981. }
  57982. this.extraBottomMargin = false;
  57983. this.extraTopMargin = false;
  57984. if (rangeSelector) {
  57985. initRangeSelector_1(this);
  57986. verticalAlign = (optionsRangeSelector &&
  57987. optionsRangeSelector.verticalAlign) || (rangeSelector.options && rangeSelector.options.verticalAlign);
  57988. if (!rangeSelector.options.floating) {
  57989. if (verticalAlign === 'bottom') {
  57990. this.extraBottomMargin = true;
  57991. }
  57992. else if (verticalAlign !== 'middle') {
  57993. this.extraTopMargin = true;
  57994. }
  57995. }
  57996. if (this.extraBottomMargin !== extraBottomMarginWas ||
  57997. this.extraTopMargin !== extraTopMarginWas) {
  57998. this.isDirtyBox = true;
  57999. }
  58000. }
  58001. });
  58002. addEvent(Chart, 'render', function () {
  58003. var chart = this,
  58004. rangeSelector = chart.rangeSelector,
  58005. verticalAlign;
  58006. if (rangeSelector && !rangeSelector.options.floating) {
  58007. rangeSelector.render();
  58008. verticalAlign = rangeSelector.options.verticalAlign;
  58009. if (verticalAlign === 'bottom') {
  58010. this.extraBottomMargin = true;
  58011. }
  58012. else if (verticalAlign !== 'middle') {
  58013. this.extraTopMargin = true;
  58014. }
  58015. }
  58016. });
  58017. addEvent(Chart, 'getMargins', function () {
  58018. var rangeSelector = this.rangeSelector,
  58019. rangeSelectorHeight;
  58020. if (rangeSelector) {
  58021. rangeSelectorHeight = rangeSelector.getHeight();
  58022. if (this.extraTopMargin) {
  58023. this.plotTop += rangeSelectorHeight;
  58024. }
  58025. if (this.extraBottomMargin) {
  58026. this.marginBottom += rangeSelectorHeight;
  58027. }
  58028. }
  58029. });
  58030. Chart.prototype.callbacks.push(initRangeSelector_1);
  58031. // Remove resize/afterSetExtremes at chart destroy
  58032. addEvent(Chart, 'destroy', function destroyEvents() {
  58033. for (var i = 0; i < chartDestroyEvents_1.length; i++) {
  58034. var events = chartDestroyEvents_1[i];
  58035. if (events[0] === this) {
  58036. events[1].forEach(function (unbind) { return unbind(); });
  58037. chartDestroyEvents_1.splice(i, 1);
  58038. return;
  58039. }
  58040. }
  58041. });
  58042. H.RangeSelector = RangeSelector;
  58043. }
  58044. return RangeSelector;
  58045. });
  58046. _registerModule(_modules, 'Core/Axis/NavigatorAxis.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
  58047. /* *
  58048. *
  58049. * (c) 2010-2021 Torstein Honsi
  58050. *
  58051. * License: www.highcharts.com/license
  58052. *
  58053. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  58054. *
  58055. * */
  58056. var isTouchDevice = H.isTouchDevice;
  58057. var addEvent = U.addEvent,
  58058. correctFloat = U.correctFloat,
  58059. defined = U.defined,
  58060. isNumber = U.isNumber,
  58061. pick = U.pick;
  58062. /* eslint-disable valid-jsdoc */
  58063. /**
  58064. * @private
  58065. * @class
  58066. */
  58067. var NavigatorAxisAdditions = /** @class */ (function () {
  58068. /* *
  58069. *
  58070. * Constructors
  58071. *
  58072. * */
  58073. function NavigatorAxisAdditions(axis) {
  58074. this.axis = axis;
  58075. }
  58076. /* *
  58077. *
  58078. * Functions
  58079. *
  58080. * */
  58081. /**
  58082. * @private
  58083. */
  58084. NavigatorAxisAdditions.prototype.destroy = function () {
  58085. this.axis = void 0;
  58086. };
  58087. /**
  58088. * Add logic to normalize the zoomed range in order to preserve the pressed
  58089. * state of range selector buttons
  58090. *
  58091. * @private
  58092. * @function Highcharts.Axis#toFixedRange
  58093. * @param {number} [pxMin]
  58094. * @param {number} [pxMax]
  58095. * @param {number} [fixedMin]
  58096. * @param {number} [fixedMax]
  58097. * @return {*}
  58098. */
  58099. NavigatorAxisAdditions.prototype.toFixedRange = function (pxMin, pxMax, fixedMin, fixedMax) {
  58100. var navigator = this;
  58101. var axis = navigator.axis;
  58102. var chart = axis.chart;
  58103. var fixedRange = chart && chart.fixedRange,
  58104. halfPointRange = (axis.pointRange || 0) / 2,
  58105. newMin = pick(fixedMin,
  58106. axis.translate(pxMin,
  58107. true, !axis.horiz)),
  58108. newMax = pick(fixedMax,
  58109. axis.translate(pxMax,
  58110. true, !axis.horiz)),
  58111. changeRatio = fixedRange && (newMax - newMin) / fixedRange;
  58112. // Add/remove half point range to/from the extremes (#1172)
  58113. if (!defined(fixedMin)) {
  58114. newMin = correctFloat(newMin + halfPointRange);
  58115. }
  58116. if (!defined(fixedMax)) {
  58117. newMax = correctFloat(newMax - halfPointRange);
  58118. }
  58119. // If the difference between the fixed range and the actual requested
  58120. // range is too great, the user is dragging across an ordinal gap, and
  58121. // we need to release the range selector button.
  58122. if (changeRatio > 0.7 && changeRatio < 1.3) {
  58123. if (fixedMax) {
  58124. newMin = newMax - fixedRange;
  58125. }
  58126. else {
  58127. newMax = newMin + fixedRange;
  58128. }
  58129. }
  58130. if (!isNumber(newMin) || !isNumber(newMax)) { // #1195, #7411
  58131. newMin = newMax = void 0;
  58132. }
  58133. return {
  58134. min: newMin,
  58135. max: newMax
  58136. };
  58137. };
  58138. return NavigatorAxisAdditions;
  58139. }());
  58140. /**
  58141. * @private
  58142. * @class
  58143. */
  58144. var NavigatorAxis = /** @class */ (function () {
  58145. function NavigatorAxis() {
  58146. }
  58147. /* *
  58148. *
  58149. * Static Functions
  58150. *
  58151. * */
  58152. /**
  58153. * @private
  58154. */
  58155. NavigatorAxis.compose = function (AxisClass) {
  58156. AxisClass.keepProps.push('navigatorAxis');
  58157. /* eslint-disable no-invalid-this */
  58158. addEvent(AxisClass, 'init', function () {
  58159. var axis = this;
  58160. if (!axis.navigatorAxis) {
  58161. axis.navigatorAxis = new NavigatorAxisAdditions(axis);
  58162. }
  58163. });
  58164. // For Stock charts, override selection zooming with some special
  58165. // features because X axis zooming is already allowed by the Navigator
  58166. // and Range selector.
  58167. addEvent(AxisClass, 'zoom', function (e) {
  58168. var axis = this;
  58169. var chart = axis.chart;
  58170. var chartOptions = chart.options;
  58171. var navigator = chartOptions.navigator;
  58172. var navigatorAxis = axis.navigatorAxis;
  58173. var pinchType = chartOptions.chart.pinchType;
  58174. var rangeSelector = chartOptions.rangeSelector;
  58175. var zoomType = chartOptions.chart.zoomType;
  58176. var previousZoom;
  58177. if (axis.isXAxis && ((navigator && navigator.enabled) ||
  58178. (rangeSelector && rangeSelector.enabled))) {
  58179. // For y only zooming, ignore the X axis completely
  58180. if (zoomType === 'y') {
  58181. e.zoomed = false;
  58182. // For xy zooming, record the state of the zoom before zoom
  58183. // selection, then when the reset button is pressed, revert to
  58184. // this state. This should apply only if the chart is
  58185. // initialized with a range (#6612), otherwise zoom all the way
  58186. // out.
  58187. }
  58188. else if (((!isTouchDevice && zoomType === 'xy') ||
  58189. (isTouchDevice && pinchType === 'xy')) &&
  58190. axis.options.range) {
  58191. previousZoom = navigatorAxis.previousZoom;
  58192. if (defined(e.newMin)) {
  58193. navigatorAxis.previousZoom = [axis.min, axis.max];
  58194. }
  58195. else if (previousZoom) {
  58196. e.newMin = previousZoom[0];
  58197. e.newMax = previousZoom[1];
  58198. navigatorAxis.previousZoom = void 0;
  58199. }
  58200. }
  58201. }
  58202. if (typeof e.zoomed !== 'undefined') {
  58203. e.preventDefault();
  58204. }
  58205. });
  58206. /* eslint-enable no-invalid-this */
  58207. };
  58208. /* *
  58209. *
  58210. * Static Properties
  58211. *
  58212. * */
  58213. /**
  58214. * @private
  58215. */
  58216. NavigatorAxis.AdditionsClass = NavigatorAxisAdditions;
  58217. return NavigatorAxis;
  58218. }());
  58219. return NavigatorAxis;
  58220. });
  58221. _registerModule(_modules, 'Core/Navigator.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Chart/Chart.js'], _modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Core/Axis/NavigatorAxis.js'], _modules['Core/DefaultOptions.js'], _modules['Core/Color/Palette.js'], _modules['Core/Renderer/RendererRegistry.js'], _modules['Core/Scrollbar.js'], _modules['Core/Series/Series.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (Axis, Chart, Color, H, NavigatorAxis, D, Palette, RendererRegistry, Scrollbar, Series, SeriesRegistry, U) {
  58222. /* *
  58223. *
  58224. * (c) 2010-2021 Torstein Honsi
  58225. *
  58226. * License: www.highcharts.com/license
  58227. *
  58228. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  58229. *
  58230. * */
  58231. var color = Color.parse;
  58232. var hasTouch = H.hasTouch,
  58233. isTouchDevice = H.isTouchDevice;
  58234. var defaultOptions = D.defaultOptions;
  58235. var seriesTypes = SeriesRegistry.seriesTypes;
  58236. var addEvent = U.addEvent,
  58237. clamp = U.clamp,
  58238. correctFloat = U.correctFloat,
  58239. defined = U.defined,
  58240. destroyObjectProperties = U.destroyObjectProperties,
  58241. erase = U.erase,
  58242. extend = U.extend,
  58243. find = U.find,
  58244. isArray = U.isArray,
  58245. isNumber = U.isNumber,
  58246. merge = U.merge,
  58247. pick = U.pick,
  58248. removeEvent = U.removeEvent,
  58249. splat = U.splat;
  58250. var defaultSeriesType,
  58251. // Finding the min or max of a set of variables where we don't know if they
  58252. // are defined, is a pattern that is repeated several places in Highcharts.
  58253. // Consider making this a global utility method.
  58254. numExt = function (extreme) {
  58255. var args = [];
  58256. for (var _i = 1; _i < arguments.length; _i++) {
  58257. args[_i - 1] = arguments[_i];
  58258. }
  58259. var numbers = [].filter.call(args,
  58260. isNumber);
  58261. if (numbers.length) {
  58262. return Math[extreme].apply(0, numbers);
  58263. }
  58264. };
  58265. defaultSeriesType = typeof seriesTypes.areaspline === 'undefined' ?
  58266. 'line' :
  58267. 'areaspline';
  58268. extend(defaultOptions, {
  58269. /**
  58270. * Maximum range which can be set using the navigator's handles.
  58271. * Opposite of [xAxis.minRange](#xAxis.minRange).
  58272. *
  58273. * @sample {highstock} stock/navigator/maxrange/
  58274. * Defined max and min range
  58275. *
  58276. * @type {number}
  58277. * @since 6.0.0
  58278. * @product highstock gantt
  58279. * @apioption xAxis.maxRange
  58280. */
  58281. /**
  58282. * The navigator is a small series below the main series, displaying
  58283. * a view of the entire data set. It provides tools to zoom in and
  58284. * out on parts of the data as well as panning across the dataset.
  58285. *
  58286. * @product highstock gantt
  58287. * @optionparent navigator
  58288. */
  58289. navigator: {
  58290. /**
  58291. * Whether the navigator and scrollbar should adapt to updated data
  58292. * in the base X axis. When loading data async, as in the demo below,
  58293. * this should be `false`. Otherwise new data will trigger navigator
  58294. * redraw, which will cause unwanted looping. In the demo below, the
  58295. * data in the navigator is set only once. On navigating, only the main
  58296. * chart content is updated.
  58297. *
  58298. * @sample {highstock} stock/demo/lazy-loading/
  58299. * Set to false with async data loading
  58300. *
  58301. * @type {boolean}
  58302. * @default true
  58303. * @apioption navigator.adaptToUpdatedData
  58304. */
  58305. /**
  58306. * An integer identifying the index to use for the base series, or a
  58307. * string representing the id of the series.
  58308. *
  58309. * **Note**: As of Highcharts 5.0, this is now a deprecated option.
  58310. * Prefer [series.showInNavigator](#plotOptions.series.showInNavigator).
  58311. *
  58312. * @see [series.showInNavigator](#plotOptions.series.showInNavigator)
  58313. *
  58314. * @deprecated
  58315. * @type {number|string}
  58316. * @default 0
  58317. * @apioption navigator.baseSeries
  58318. */
  58319. /**
  58320. * Enable or disable the navigator.
  58321. *
  58322. * @sample {highstock} stock/navigator/enabled/
  58323. * Disable the navigator
  58324. *
  58325. * @type {boolean}
  58326. * @default true
  58327. * @apioption navigator.enabled
  58328. */
  58329. /**
  58330. * When the chart is inverted, whether to draw the navigator on the
  58331. * opposite side.
  58332. *
  58333. * @type {boolean}
  58334. * @default false
  58335. * @since 5.0.8
  58336. * @apioption navigator.opposite
  58337. */
  58338. /**
  58339. * The height of the navigator.
  58340. *
  58341. * @sample {highstock} stock/navigator/height/
  58342. * A higher navigator
  58343. */
  58344. height: 40,
  58345. /**
  58346. * The distance from the nearest element, the X axis or X axis labels.
  58347. *
  58348. * @sample {highstock} stock/navigator/margin/
  58349. * A margin of 2 draws the navigator closer to the X axis labels
  58350. */
  58351. margin: 25,
  58352. /**
  58353. * Whether the mask should be inside the range marking the zoomed
  58354. * range, or outside. In Highcharts Stock 1.x it was always `false`.
  58355. *
  58356. * @sample {highstock} stock/navigator/maskinside-false/
  58357. * False, mask outside
  58358. *
  58359. * @since 2.0
  58360. */
  58361. maskInside: true,
  58362. /**
  58363. * Options for the handles for dragging the zoomed area.
  58364. *
  58365. * @sample {highstock} stock/navigator/handles/
  58366. * Colored handles
  58367. */
  58368. handles: {
  58369. /**
  58370. * Width for handles.
  58371. *
  58372. * @sample {highstock} stock/navigator/styled-handles/
  58373. * Styled handles
  58374. *
  58375. * @since 6.0.0
  58376. */
  58377. width: 7,
  58378. /**
  58379. * Height for handles.
  58380. *
  58381. * @sample {highstock} stock/navigator/styled-handles/
  58382. * Styled handles
  58383. *
  58384. * @since 6.0.0
  58385. */
  58386. height: 15,
  58387. /**
  58388. * Array to define shapes of handles. 0-index for left, 1-index for
  58389. * right.
  58390. *
  58391. * Additionally, the URL to a graphic can be given on this form:
  58392. * `url(graphic.png)`. Note that for the image to be applied to
  58393. * exported charts, its URL needs to be accessible by the export
  58394. * server.
  58395. *
  58396. * Custom callbacks for symbol path generation can also be added to
  58397. * `Highcharts.SVGRenderer.prototype.symbols`. The callback is then
  58398. * used by its method name, as shown in the demo.
  58399. *
  58400. * @sample {highstock} stock/navigator/styled-handles/
  58401. * Styled handles
  58402. *
  58403. * @type {Array<string>}
  58404. * @default ["navigator-handle", "navigator-handle"]
  58405. * @since 6.0.0
  58406. */
  58407. symbols: ['navigator-handle', 'navigator-handle'],
  58408. /**
  58409. * Allows to enable/disable handles.
  58410. *
  58411. * @since 6.0.0
  58412. */
  58413. enabled: true,
  58414. /**
  58415. * The width for the handle border and the stripes inside.
  58416. *
  58417. * @sample {highstock} stock/navigator/styled-handles/
  58418. * Styled handles
  58419. *
  58420. * @since 6.0.0
  58421. * @apioption navigator.handles.lineWidth
  58422. */
  58423. lineWidth: 1,
  58424. /**
  58425. * The fill for the handle.
  58426. *
  58427. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  58428. */
  58429. backgroundColor: Palette.neutralColor5,
  58430. /**
  58431. * The stroke for the handle border and the stripes inside.
  58432. *
  58433. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  58434. */
  58435. borderColor: Palette.neutralColor40
  58436. },
  58437. /**
  58438. * The color of the mask covering the areas of the navigator series
  58439. * that are currently not visible in the main series. The default
  58440. * color is bluish with an opacity of 0.3 to see the series below.
  58441. *
  58442. * @see In styled mode, the mask is styled with the
  58443. * `.highcharts-navigator-mask` and
  58444. * `.highcharts-navigator-mask-inside` classes.
  58445. *
  58446. * @sample {highstock} stock/navigator/maskfill/
  58447. * Blue, semi transparent mask
  58448. *
  58449. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  58450. * @default rgba(102,133,194,0.3)
  58451. */
  58452. maskFill: color(Palette.highlightColor60).setOpacity(0.3).get(),
  58453. /**
  58454. * The color of the line marking the currently zoomed area in the
  58455. * navigator.
  58456. *
  58457. * @sample {highstock} stock/navigator/outline/
  58458. * 2px blue outline
  58459. *
  58460. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  58461. * @default #cccccc
  58462. */
  58463. outlineColor: Palette.neutralColor20,
  58464. /**
  58465. * The width of the line marking the currently zoomed area in the
  58466. * navigator.
  58467. *
  58468. * @see In styled mode, the outline stroke width is set with the
  58469. * `.highcharts-navigator-outline` class.
  58470. *
  58471. * @sample {highstock} stock/navigator/outline/
  58472. * 2px blue outline
  58473. *
  58474. * @type {number}
  58475. */
  58476. outlineWidth: 1,
  58477. /**
  58478. * Options for the navigator series. Available options are the same
  58479. * as any series, documented at [plotOptions](#plotOptions.series)
  58480. * and [series](#series).
  58481. *
  58482. * Unless data is explicitly defined on navigator.series, the data
  58483. * is borrowed from the first series in the chart.
  58484. *
  58485. * Default series options for the navigator series are:
  58486. * ```js
  58487. * series: {
  58488. * type: 'areaspline',
  58489. * fillOpacity: 0.05,
  58490. * dataGrouping: {
  58491. * smoothed: true
  58492. * },
  58493. * lineWidth: 1,
  58494. * marker: {
  58495. * enabled: false
  58496. * }
  58497. * }
  58498. * ```
  58499. *
  58500. * @see In styled mode, the navigator series is styled with the
  58501. * `.highcharts-navigator-series` class.
  58502. *
  58503. * @sample {highstock} stock/navigator/series-data/
  58504. * Using a separate data set for the navigator
  58505. * @sample {highstock} stock/navigator/series/
  58506. * A green navigator series
  58507. *
  58508. * @type {*|Array<*>|Highcharts.SeriesOptionsType|Array<Highcharts.SeriesOptionsType>}
  58509. */
  58510. series: {
  58511. /**
  58512. * The type of the navigator series.
  58513. *
  58514. * Heads up:
  58515. * In column-type navigator, zooming is limited to at least one
  58516. * point with its `pointRange`.
  58517. *
  58518. * @sample {highstock} stock/navigator/column/
  58519. * Column type navigator
  58520. *
  58521. * @type {string}
  58522. * @default {highstock} `areaspline` if defined, otherwise `line`
  58523. * @default {gantt} gantt
  58524. */
  58525. type: defaultSeriesType,
  58526. /**
  58527. * The fill opacity of the navigator series.
  58528. */
  58529. fillOpacity: 0.05,
  58530. /**
  58531. * The pixel line width of the navigator series.
  58532. */
  58533. lineWidth: 1,
  58534. /**
  58535. * @ignore-option
  58536. */
  58537. compare: null,
  58538. /**
  58539. * Unless data is explicitly defined, the data is borrowed from the
  58540. * first series in the chart.
  58541. *
  58542. * @type {Array<number|Array<number|string|null>|object|null>}
  58543. * @product highstock
  58544. * @apioption navigator.series.data
  58545. */
  58546. /**
  58547. * Data grouping options for the navigator series.
  58548. *
  58549. * @extends plotOptions.series.dataGrouping
  58550. */
  58551. dataGrouping: {
  58552. approximation: 'average',
  58553. enabled: true,
  58554. groupPixelWidth: 2,
  58555. // Replace smoothed property by anchors, #12455.
  58556. firstAnchor: 'firstPoint',
  58557. anchor: 'middle',
  58558. lastAnchor: 'lastPoint',
  58559. // Day and week differs from plotOptions.series.dataGrouping
  58560. units: [
  58561. ['millisecond', [1, 2, 5, 10, 20, 25, 50, 100, 200, 500]],
  58562. ['second', [1, 2, 5, 10, 15, 30]],
  58563. ['minute', [1, 2, 5, 10, 15, 30]],
  58564. ['hour', [1, 2, 3, 4, 6, 8, 12]],
  58565. ['day', [1, 2, 3, 4]],
  58566. ['week', [1, 2, 3]],
  58567. ['month', [1, 3, 6]],
  58568. ['year', null]
  58569. ]
  58570. },
  58571. /**
  58572. * Data label options for the navigator series. Data labels are
  58573. * disabled by default on the navigator series.
  58574. *
  58575. * @extends plotOptions.series.dataLabels
  58576. */
  58577. dataLabels: {
  58578. enabled: false,
  58579. zIndex: 2 // #1839
  58580. },
  58581. id: 'highcharts-navigator-series',
  58582. className: 'highcharts-navigator-series',
  58583. /**
  58584. * Sets the fill color of the navigator series.
  58585. *
  58586. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  58587. * @apioption navigator.series.color
  58588. */
  58589. /**
  58590. * Line color for the navigator series. Allows setting the color
  58591. * while disallowing the default candlestick setting.
  58592. *
  58593. * @type {Highcharts.ColorString|null}
  58594. */
  58595. lineColor: null,
  58596. marker: {
  58597. enabled: false
  58598. },
  58599. /**
  58600. * Since Highcharts Stock v8, default value is the same as default
  58601. * `pointRange` defined for a specific type (e.g. `null` for
  58602. * column type).
  58603. *
  58604. * In Highcharts Stock version < 8, defaults to 0.
  58605. *
  58606. * @extends plotOptions.series.pointRange
  58607. * @type {number|null}
  58608. * @apioption navigator.series.pointRange
  58609. */
  58610. /**
  58611. * The threshold option. Setting it to 0 will make the default
  58612. * navigator area series draw its area from the 0 value and up.
  58613. *
  58614. * @type {number|null}
  58615. */
  58616. threshold: null
  58617. },
  58618. /**
  58619. * Options for the navigator X axis. Default series options for the
  58620. * navigator xAxis are:
  58621. * ```js
  58622. * xAxis: {
  58623. * tickWidth: 0,
  58624. * lineWidth: 0,
  58625. * gridLineWidth: 1,
  58626. * tickPixelInterval: 200,
  58627. * labels: {
  58628. * align: 'left',
  58629. * style: {
  58630. * color: '#888'
  58631. * },
  58632. * x: 3,
  58633. * y: -4
  58634. * }
  58635. * }
  58636. * ```
  58637. *
  58638. * @extends xAxis
  58639. * @excluding linkedTo, maxZoom, minRange, opposite, range, scrollbar,
  58640. * showEmpty, maxRange
  58641. */
  58642. xAxis: {
  58643. /**
  58644. * Additional range on the right side of the xAxis. Works similar to
  58645. * xAxis.maxPadding, but value is set in milliseconds.
  58646. * Can be set for both, main xAxis and navigator's xAxis.
  58647. *
  58648. * @since 6.0.0
  58649. */
  58650. overscroll: 0,
  58651. className: 'highcharts-navigator-xaxis',
  58652. tickLength: 0,
  58653. lineWidth: 0,
  58654. gridLineColor: Palette.neutralColor10,
  58655. gridLineWidth: 1,
  58656. tickPixelInterval: 200,
  58657. labels: {
  58658. align: 'left',
  58659. /**
  58660. * @type {Highcharts.CSSObject}
  58661. */
  58662. style: {
  58663. /** @ignore */
  58664. color: Palette.neutralColor40
  58665. },
  58666. x: 3,
  58667. y: -4
  58668. },
  58669. crosshair: false
  58670. },
  58671. /**
  58672. * Options for the navigator Y axis. Default series options for the
  58673. * navigator yAxis are:
  58674. * ```js
  58675. * yAxis: {
  58676. * gridLineWidth: 0,
  58677. * startOnTick: false,
  58678. * endOnTick: false,
  58679. * minPadding: 0.1,
  58680. * maxPadding: 0.1,
  58681. * labels: {
  58682. * enabled: false
  58683. * },
  58684. * title: {
  58685. * text: null
  58686. * },
  58687. * tickWidth: 0
  58688. * }
  58689. * ```
  58690. *
  58691. * @extends yAxis
  58692. * @excluding height, linkedTo, maxZoom, minRange, ordinal, range,
  58693. * showEmpty, scrollbar, top, units, maxRange, minLength,
  58694. * maxLength, resize
  58695. */
  58696. yAxis: {
  58697. className: 'highcharts-navigator-yaxis',
  58698. gridLineWidth: 0,
  58699. startOnTick: false,
  58700. endOnTick: false,
  58701. minPadding: 0.1,
  58702. maxPadding: 0.1,
  58703. labels: {
  58704. enabled: false
  58705. },
  58706. crosshair: false,
  58707. title: {
  58708. text: null
  58709. },
  58710. tickLength: 0,
  58711. tickWidth: 0
  58712. }
  58713. }
  58714. });
  58715. /* eslint-disable no-invalid-this, valid-jsdoc */
  58716. /**
  58717. * Draw one of the handles on the side of the zoomed range in the navigator
  58718. *
  58719. * @private
  58720. * @function Highcharts.Renderer#symbols.navigator-handle
  58721. * @param {number} x
  58722. * @param {number} y
  58723. * @param {number} w
  58724. * @param {number} h
  58725. * @param {Highcharts.NavigatorHandlesOptions} options
  58726. * @return {Highcharts.SVGPathArray}
  58727. * Path to be used in a handle
  58728. */
  58729. RendererRegistry.getRendererType().prototype.symbols['navigator-handle'] = function (_x, _y, _w, _h, options) {
  58730. var halfWidth = (options && options.width || 0) / 2,
  58731. markerPosition = Math.round(halfWidth / 3) + 0.5,
  58732. height = options && options.height || 0;
  58733. return [
  58734. ['M', -halfWidth - 1, 0.5],
  58735. ['L', halfWidth, 0.5],
  58736. ['L', halfWidth, height + 0.5],
  58737. ['L', -halfWidth - 1, height + 0.5],
  58738. ['L', -halfWidth - 1, 0.5],
  58739. ['M', -markerPosition, 4],
  58740. ['L', -markerPosition, height - 3],
  58741. ['M', markerPosition - 1, 4],
  58742. ['L', markerPosition - 1, height - 3]
  58743. ];
  58744. };
  58745. /**
  58746. * The Navigator class
  58747. *
  58748. * @private
  58749. * @class
  58750. * @name Highcharts.Navigator
  58751. *
  58752. * @param {Highcharts.Chart} chart
  58753. * Chart object
  58754. */
  58755. var Navigator = /** @class */ (function () {
  58756. function Navigator(chart) {
  58757. this.baseSeries = void 0;
  58758. this.chart = void 0;
  58759. this.handles = void 0;
  58760. this.height = void 0;
  58761. this.left = void 0;
  58762. this.navigatorEnabled = void 0;
  58763. this.navigatorGroup = void 0;
  58764. this.navigatorOptions = void 0;
  58765. this.navigatorSeries = void 0;
  58766. this.navigatorSize = void 0;
  58767. this.opposite = void 0;
  58768. this.outline = void 0;
  58769. this.outlineHeight = void 0;
  58770. this.range = void 0;
  58771. this.rendered = void 0;
  58772. this.shades = void 0;
  58773. this.size = void 0;
  58774. this.top = void 0;
  58775. this.xAxis = void 0;
  58776. this.yAxis = void 0;
  58777. this.zoomedMax = void 0;
  58778. this.zoomedMin = void 0;
  58779. this.init(chart);
  58780. }
  58781. /**
  58782. * Draw one of the handles on the side of the zoomed range in the navigator
  58783. *
  58784. * @private
  58785. * @function Highcharts.Navigator#drawHandle
  58786. *
  58787. * @param {number} x
  58788. * The x center for the handle
  58789. *
  58790. * @param {number} index
  58791. * 0 for left and 1 for right
  58792. *
  58793. * @param {boolean|undefined} inverted
  58794. * flag for chart.inverted
  58795. *
  58796. * @param {string} verb
  58797. * use 'animate' or 'attr'
  58798. */
  58799. Navigator.prototype.drawHandle = function (x, index, inverted, verb) {
  58800. var navigator = this,
  58801. height = navigator.navigatorOptions.handles.height;
  58802. // Place it
  58803. navigator.handles[index][verb](inverted ? {
  58804. translateX: Math.round(navigator.left + navigator.height / 2),
  58805. translateY: Math.round(navigator.top + parseInt(x, 10) + 0.5 - height)
  58806. } : {
  58807. translateX: Math.round(navigator.left + parseInt(x, 10)),
  58808. translateY: Math.round(navigator.top + navigator.height / 2 - height / 2 - 1)
  58809. });
  58810. };
  58811. /**
  58812. * Render outline around the zoomed range
  58813. *
  58814. * @private
  58815. * @function Highcharts.Navigator#drawOutline
  58816. *
  58817. * @param {number} zoomedMin
  58818. * in pixels position where zoomed range starts
  58819. *
  58820. * @param {number} zoomedMax
  58821. * in pixels position where zoomed range ends
  58822. *
  58823. * @param {boolean|undefined} inverted
  58824. * flag if chart is inverted
  58825. *
  58826. * @param {string} verb
  58827. * use 'animate' or 'attr'
  58828. */
  58829. Navigator.prototype.drawOutline = function (zoomedMin, zoomedMax, inverted, verb) {
  58830. var navigator = this,
  58831. maskInside = navigator.navigatorOptions.maskInside,
  58832. outlineWidth = navigator.outline.strokeWidth(),
  58833. halfOutline = outlineWidth / 2,
  58834. outlineCorrection = (outlineWidth % 2) / 2, // #5800
  58835. outlineHeight = navigator.outlineHeight,
  58836. scrollbarHeight = navigator.scrollbarHeight || 0,
  58837. navigatorSize = navigator.size,
  58838. left = navigator.left - scrollbarHeight,
  58839. navigatorTop = navigator.top,
  58840. verticalMin,
  58841. path;
  58842. if (inverted) {
  58843. left -= halfOutline;
  58844. verticalMin = navigatorTop + zoomedMax + outlineCorrection;
  58845. zoomedMax = navigatorTop + zoomedMin + outlineCorrection;
  58846. path = [
  58847. ['M', left + outlineHeight, navigatorTop - scrollbarHeight - outlineCorrection],
  58848. ['L', left + outlineHeight, verticalMin],
  58849. ['L', left, verticalMin],
  58850. ['L', left, zoomedMax],
  58851. ['L', left + outlineHeight, zoomedMax],
  58852. ['L', left + outlineHeight, navigatorTop + navigatorSize + scrollbarHeight]
  58853. ];
  58854. if (maskInside) {
  58855. path.push(['M', left + outlineHeight, verticalMin - halfOutline], // upper left of zoomed range
  58856. ['L', left + outlineHeight, zoomedMax + halfOutline] // upper right of z.r.
  58857. );
  58858. }
  58859. }
  58860. else {
  58861. zoomedMin += left + scrollbarHeight - outlineCorrection;
  58862. zoomedMax += left + scrollbarHeight - outlineCorrection;
  58863. navigatorTop += halfOutline;
  58864. path = [
  58865. ['M', left, navigatorTop],
  58866. ['L', zoomedMin, navigatorTop],
  58867. ['L', zoomedMin, navigatorTop + outlineHeight],
  58868. ['L', zoomedMax, navigatorTop + outlineHeight],
  58869. ['L', zoomedMax, navigatorTop],
  58870. ['L', left + navigatorSize + scrollbarHeight * 2, navigatorTop] // right
  58871. ];
  58872. if (maskInside) {
  58873. path.push(['M', zoomedMin - halfOutline, navigatorTop], // upper left of zoomed range
  58874. ['L', zoomedMax + halfOutline, navigatorTop] // upper right of z.r.
  58875. );
  58876. }
  58877. }
  58878. navigator.outline[verb]({
  58879. d: path
  58880. });
  58881. };
  58882. /**
  58883. * Render outline around the zoomed range
  58884. *
  58885. * @private
  58886. * @function Highcharts.Navigator#drawMasks
  58887. *
  58888. * @param {number} zoomedMin
  58889. * in pixels position where zoomed range starts
  58890. *
  58891. * @param {number} zoomedMax
  58892. * in pixels position where zoomed range ends
  58893. *
  58894. * @param {boolean|undefined} inverted
  58895. * flag if chart is inverted
  58896. *
  58897. * @param {string} verb
  58898. * use 'animate' or 'attr'
  58899. */
  58900. Navigator.prototype.drawMasks = function (zoomedMin, zoomedMax, inverted, verb) {
  58901. var navigator = this,
  58902. left = navigator.left,
  58903. top = navigator.top,
  58904. navigatorHeight = navigator.height,
  58905. height,
  58906. width,
  58907. x,
  58908. y;
  58909. // Determine rectangle position & size
  58910. // According to (non)inverted position:
  58911. if (inverted) {
  58912. x = [left, left, left];
  58913. y = [top, top + zoomedMin, top + zoomedMax];
  58914. width = [navigatorHeight, navigatorHeight, navigatorHeight];
  58915. height = [
  58916. zoomedMin,
  58917. zoomedMax - zoomedMin,
  58918. navigator.size - zoomedMax
  58919. ];
  58920. }
  58921. else {
  58922. x = [left, left + zoomedMin, left + zoomedMax];
  58923. y = [top, top, top];
  58924. width = [
  58925. zoomedMin,
  58926. zoomedMax - zoomedMin,
  58927. navigator.size - zoomedMax
  58928. ];
  58929. height = [navigatorHeight, navigatorHeight, navigatorHeight];
  58930. }
  58931. navigator.shades.forEach(function (shade, i) {
  58932. shade[verb]({
  58933. x: x[i],
  58934. y: y[i],
  58935. width: width[i],
  58936. height: height[i]
  58937. });
  58938. });
  58939. };
  58940. /**
  58941. * Generate DOM elements for a navigator:
  58942. *
  58943. * - main navigator group
  58944. *
  58945. * - all shades
  58946. *
  58947. * - outline
  58948. *
  58949. * - handles
  58950. *
  58951. * @private
  58952. * @function Highcharts.Navigator#renderElements
  58953. */
  58954. Navigator.prototype.renderElements = function () {
  58955. var navigator = this,
  58956. navigatorOptions = navigator.navigatorOptions,
  58957. maskInside = navigatorOptions.maskInside,
  58958. chart = navigator.chart,
  58959. inverted = chart.inverted,
  58960. renderer = chart.renderer,
  58961. navigatorGroup,
  58962. mouseCursor = {
  58963. cursor: inverted ? 'ns-resize' : 'ew-resize'
  58964. };
  58965. // Create the main navigator group
  58966. navigator.navigatorGroup = navigatorGroup = renderer.g('navigator')
  58967. .attr({
  58968. zIndex: 8,
  58969. visibility: 'hidden'
  58970. })
  58971. .add();
  58972. // Create masks, each mask will get events and fill:
  58973. [
  58974. !maskInside,
  58975. maskInside,
  58976. !maskInside
  58977. ].forEach(function (hasMask, index) {
  58978. navigator.shades[index] = renderer.rect()
  58979. .addClass('highcharts-navigator-mask' +
  58980. (index === 1 ? '-inside' : '-outside'))
  58981. .add(navigatorGroup);
  58982. if (!chart.styledMode) {
  58983. navigator.shades[index]
  58984. .attr({
  58985. fill: hasMask ?
  58986. navigatorOptions.maskFill :
  58987. 'rgba(0,0,0,0)'
  58988. })
  58989. .css((index === 1) && mouseCursor);
  58990. }
  58991. });
  58992. // Create the outline:
  58993. navigator.outline = renderer.path()
  58994. .addClass('highcharts-navigator-outline')
  58995. .add(navigatorGroup);
  58996. if (!chart.styledMode) {
  58997. navigator.outline.attr({
  58998. 'stroke-width': navigatorOptions.outlineWidth,
  58999. stroke: navigatorOptions.outlineColor
  59000. });
  59001. }
  59002. // Create the handlers:
  59003. if (navigatorOptions.handles.enabled) {
  59004. [0, 1].forEach(function (index) {
  59005. navigatorOptions.handles.inverted = chart.inverted;
  59006. navigator.handles[index] = renderer.symbol(navigatorOptions.handles.symbols[index], -navigatorOptions.handles.width / 2 - 1, 0, navigatorOptions.handles.width, navigatorOptions.handles.height, navigatorOptions.handles);
  59007. // zIndex = 6 for right handle, 7 for left.
  59008. // Can't be 10, because of the tooltip in inverted chart #2908
  59009. navigator.handles[index].attr({ zIndex: 7 - index })
  59010. .addClass('highcharts-navigator-handle ' +
  59011. 'highcharts-navigator-handle-' +
  59012. ['left', 'right'][index]).add(navigatorGroup);
  59013. if (!chart.styledMode) {
  59014. var handlesOptions = navigatorOptions.handles;
  59015. navigator.handles[index]
  59016. .attr({
  59017. fill: handlesOptions.backgroundColor,
  59018. stroke: handlesOptions.borderColor,
  59019. 'stroke-width': handlesOptions.lineWidth
  59020. })
  59021. .css(mouseCursor);
  59022. }
  59023. });
  59024. }
  59025. };
  59026. /**
  59027. * Update navigator
  59028. *
  59029. * @private
  59030. * @function Highcharts.Navigator#update
  59031. *
  59032. * @param {Highcharts.NavigatorOptions} options
  59033. * Options to merge in when updating navigator
  59034. */
  59035. Navigator.prototype.update = function (options) {
  59036. // Remove references to old navigator series in base series
  59037. (this.series || []).forEach(function (series) {
  59038. if (series.baseSeries) {
  59039. delete series.baseSeries.navigatorSeries;
  59040. }
  59041. });
  59042. // Destroy and rebuild navigator
  59043. this.destroy();
  59044. var chartOptions = this.chart.options;
  59045. merge(true, chartOptions.navigator, this.options, options);
  59046. this.init(this.chart);
  59047. };
  59048. /**
  59049. * Render the navigator
  59050. *
  59051. * @private
  59052. * @function Highcharts.Navigator#render
  59053. * @param {number} min
  59054. * X axis value minimum
  59055. * @param {number} max
  59056. * X axis value maximum
  59057. * @param {number} [pxMin]
  59058. * Pixel value minimum
  59059. * @param {number} [pxMax]
  59060. * Pixel value maximum
  59061. * @return {void}
  59062. */
  59063. Navigator.prototype.render = function (min, max, pxMin, pxMax) {
  59064. var navigator = this,
  59065. chart = navigator.chart,
  59066. navigatorWidth,
  59067. scrollbarLeft,
  59068. scrollbarTop,
  59069. scrollbarHeight = navigator.scrollbarHeight,
  59070. navigatorSize,
  59071. xAxis = navigator.xAxis,
  59072. pointRange = xAxis.pointRange || 0,
  59073. scrollbarXAxis = xAxis.navigatorAxis.fake ? chart.xAxis[0] : xAxis,
  59074. navigatorEnabled = navigator.navigatorEnabled,
  59075. zoomedMin,
  59076. zoomedMax,
  59077. rendered = navigator.rendered,
  59078. inverted = chart.inverted,
  59079. verb,
  59080. newMin,
  59081. newMax,
  59082. currentRange,
  59083. minRange = chart.xAxis[0].minRange,
  59084. maxRange = chart.xAxis[0].options.maxRange;
  59085. // Don't redraw while moving the handles (#4703).
  59086. if (this.hasDragged && !defined(pxMin)) {
  59087. return;
  59088. }
  59089. min = correctFloat(min - pointRange / 2);
  59090. max = correctFloat(max + pointRange / 2);
  59091. // Don't render the navigator until we have data (#486, #4202, #5172).
  59092. if (!isNumber(min) || !isNumber(max)) {
  59093. // However, if navigator was already rendered, we may need to resize
  59094. // it. For example hidden series, but visible navigator (#6022).
  59095. if (rendered) {
  59096. pxMin = 0;
  59097. pxMax = pick(xAxis.width, scrollbarXAxis.width);
  59098. }
  59099. else {
  59100. return;
  59101. }
  59102. }
  59103. navigator.left = pick(xAxis.left,
  59104. // in case of scrollbar only, without navigator
  59105. chart.plotLeft + scrollbarHeight +
  59106. (inverted ? chart.plotWidth : 0));
  59107. navigator.size = zoomedMax = navigatorSize = pick(xAxis.len, (inverted ? chart.plotHeight : chart.plotWidth) -
  59108. 2 * scrollbarHeight);
  59109. if (inverted) {
  59110. navigatorWidth = scrollbarHeight;
  59111. }
  59112. else {
  59113. navigatorWidth = navigatorSize + 2 * scrollbarHeight;
  59114. }
  59115. // Get the pixel position of the handles
  59116. pxMin = pick(pxMin, xAxis.toPixels(min, true));
  59117. pxMax = pick(pxMax, xAxis.toPixels(max, true));
  59118. // Verify (#1851, #2238)
  59119. if (!isNumber(pxMin) || Math.abs(pxMin) === Infinity) {
  59120. pxMin = 0;
  59121. pxMax = navigatorWidth;
  59122. }
  59123. // Are we below the minRange? (#2618, #6191)
  59124. newMin = xAxis.toValue(pxMin, true);
  59125. newMax = xAxis.toValue(pxMax, true);
  59126. currentRange = Math.abs(correctFloat(newMax - newMin));
  59127. if (currentRange < minRange) {
  59128. if (this.grabbedLeft) {
  59129. pxMin = xAxis.toPixels(newMax - minRange - pointRange, true);
  59130. }
  59131. else if (this.grabbedRight) {
  59132. pxMax = xAxis.toPixels(newMin + minRange + pointRange, true);
  59133. }
  59134. }
  59135. else if (defined(maxRange) &&
  59136. correctFloat(currentRange - pointRange) > maxRange) {
  59137. if (this.grabbedLeft) {
  59138. pxMin = xAxis.toPixels(newMax - maxRange - pointRange, true);
  59139. }
  59140. else if (this.grabbedRight) {
  59141. pxMax = xAxis.toPixels(newMin + maxRange + pointRange, true);
  59142. }
  59143. }
  59144. // Handles are allowed to cross, but never exceed the plot area
  59145. navigator.zoomedMax = clamp(Math.max(pxMin, pxMax), 0, zoomedMax);
  59146. navigator.zoomedMin = clamp(navigator.fixedWidth ?
  59147. navigator.zoomedMax - navigator.fixedWidth :
  59148. Math.min(pxMin, pxMax), 0, zoomedMax);
  59149. navigator.range = navigator.zoomedMax - navigator.zoomedMin;
  59150. zoomedMax = Math.round(navigator.zoomedMax);
  59151. zoomedMin = Math.round(navigator.zoomedMin);
  59152. if (navigatorEnabled) {
  59153. navigator.navigatorGroup.attr({
  59154. visibility: 'visible'
  59155. });
  59156. // Place elements
  59157. verb = rendered && !navigator.hasDragged ? 'animate' : 'attr';
  59158. navigator.drawMasks(zoomedMin, zoomedMax, inverted, verb);
  59159. navigator.drawOutline(zoomedMin, zoomedMax, inverted, verb);
  59160. if (navigator.navigatorOptions.handles.enabled) {
  59161. navigator.drawHandle(zoomedMin, 0, inverted, verb);
  59162. navigator.drawHandle(zoomedMax, 1, inverted, verb);
  59163. }
  59164. }
  59165. if (navigator.scrollbar) {
  59166. if (inverted) {
  59167. scrollbarTop = navigator.top - scrollbarHeight;
  59168. scrollbarLeft = navigator.left - scrollbarHeight +
  59169. (navigatorEnabled || !scrollbarXAxis.opposite ? 0 :
  59170. // Multiple axes has offsets:
  59171. (scrollbarXAxis.titleOffset || 0) +
  59172. // Self margin from the axis.title
  59173. scrollbarXAxis.axisTitleMargin);
  59174. scrollbarHeight = navigatorSize + 2 * scrollbarHeight;
  59175. }
  59176. else {
  59177. scrollbarTop = navigator.top + (navigatorEnabled ?
  59178. navigator.height :
  59179. -scrollbarHeight);
  59180. scrollbarLeft = navigator.left - scrollbarHeight;
  59181. }
  59182. // Reposition scrollbar
  59183. navigator.scrollbar.position(scrollbarLeft, scrollbarTop, navigatorWidth, scrollbarHeight);
  59184. // Keep scale 0-1
  59185. navigator.scrollbar.setRange(
  59186. // Use real value, not rounded because range can be very small
  59187. // (#1716)
  59188. navigator.zoomedMin / (navigatorSize || 1), navigator.zoomedMax / (navigatorSize || 1));
  59189. }
  59190. navigator.rendered = true;
  59191. };
  59192. /**
  59193. * Set up the mouse and touch events for the navigator
  59194. *
  59195. * @private
  59196. * @function Highcharts.Navigator#addMouseEvents
  59197. */
  59198. Navigator.prototype.addMouseEvents = function () {
  59199. var navigator = this,
  59200. chart = navigator.chart,
  59201. container = chart.container,
  59202. eventsToUnbind = [],
  59203. mouseMoveHandler,
  59204. mouseUpHandler;
  59205. /**
  59206. * Create mouse events' handlers.
  59207. * Make them as separate functions to enable wrapping them:
  59208. */
  59209. navigator.mouseMoveHandler = mouseMoveHandler = function (e) {
  59210. navigator.onMouseMove(e);
  59211. };
  59212. navigator.mouseUpHandler = mouseUpHandler = function (e) {
  59213. navigator.onMouseUp(e);
  59214. };
  59215. // Add shades and handles mousedown events
  59216. eventsToUnbind = navigator.getPartsEvents('mousedown');
  59217. // Add mouse move and mouseup events. These are bind to doc/container,
  59218. // because Navigator.grabbedSomething flags are stored in mousedown
  59219. // events
  59220. eventsToUnbind.push(addEvent(chart.renderTo, 'mousemove', mouseMoveHandler), addEvent(container.ownerDocument, 'mouseup', mouseUpHandler));
  59221. // Touch events
  59222. if (hasTouch) {
  59223. eventsToUnbind.push(addEvent(chart.renderTo, 'touchmove', mouseMoveHandler), addEvent(container.ownerDocument, 'touchend', mouseUpHandler));
  59224. eventsToUnbind.concat(navigator.getPartsEvents('touchstart'));
  59225. }
  59226. navigator.eventsToUnbind = eventsToUnbind;
  59227. // Data events
  59228. if (navigator.series && navigator.series[0]) {
  59229. eventsToUnbind.push(addEvent(navigator.series[0].xAxis, 'foundExtremes', function () {
  59230. chart.navigator.modifyNavigatorAxisExtremes();
  59231. }));
  59232. }
  59233. };
  59234. /**
  59235. * Generate events for handles and masks
  59236. *
  59237. * @private
  59238. * @function Highcharts.Navigator#getPartsEvents
  59239. *
  59240. * @param {string} eventName
  59241. * Event name handler, 'mousedown' or 'touchstart'
  59242. *
  59243. * @return {Array<Function>}
  59244. * An array of functions to remove navigator functions from the
  59245. * events again.
  59246. */
  59247. Navigator.prototype.getPartsEvents = function (eventName) {
  59248. var navigator = this,
  59249. events = [];
  59250. ['shades', 'handles'].forEach(function (name) {
  59251. navigator[name].forEach(function (navigatorItem, index) {
  59252. events.push(addEvent(navigatorItem.element, eventName, function (e) {
  59253. navigator[name + 'Mousedown'](e, index);
  59254. }));
  59255. });
  59256. });
  59257. return events;
  59258. };
  59259. /**
  59260. * Mousedown on a shaded mask, either:
  59261. *
  59262. * - will be stored for future drag&drop
  59263. *
  59264. * - will directly shift to a new range
  59265. *
  59266. * @private
  59267. * @function Highcharts.Navigator#shadesMousedown
  59268. *
  59269. * @param {Highcharts.PointerEventObject} e
  59270. * Mouse event
  59271. *
  59272. * @param {number} index
  59273. * Index of a mask in Navigator.shades array
  59274. */
  59275. Navigator.prototype.shadesMousedown = function (e, index) {
  59276. e = this.chart.pointer.normalize(e);
  59277. var navigator = this,
  59278. chart = navigator.chart,
  59279. xAxis = navigator.xAxis,
  59280. zoomedMin = navigator.zoomedMin,
  59281. navigatorPosition = navigator.left,
  59282. navigatorSize = navigator.size,
  59283. range = navigator.range,
  59284. chartX = e.chartX,
  59285. fixedMax,
  59286. fixedMin,
  59287. ext,
  59288. left;
  59289. // For inverted chart, swap some options:
  59290. if (chart.inverted) {
  59291. chartX = e.chartY;
  59292. navigatorPosition = navigator.top;
  59293. }
  59294. if (index === 1) {
  59295. // Store information for drag&drop
  59296. navigator.grabbedCenter = chartX;
  59297. navigator.fixedWidth = range;
  59298. navigator.dragOffset = chartX - zoomedMin;
  59299. }
  59300. else {
  59301. // Shift the range by clicking on shaded areas
  59302. left = chartX - navigatorPosition - range / 2;
  59303. if (index === 0) {
  59304. left = Math.max(0, left);
  59305. }
  59306. else if (index === 2 && left + range >= navigatorSize) {
  59307. left = navigatorSize - range;
  59308. if (navigator.reversedExtremes) {
  59309. // #7713
  59310. left -= range;
  59311. fixedMin = navigator.getUnionExtremes().dataMin;
  59312. }
  59313. else {
  59314. // #2293, #3543
  59315. fixedMax = navigator.getUnionExtremes().dataMax;
  59316. }
  59317. }
  59318. if (left !== zoomedMin) { // it has actually moved
  59319. navigator.fixedWidth = range; // #1370
  59320. ext = xAxis.navigatorAxis.toFixedRange(left, left + range, fixedMin, fixedMax);
  59321. if (defined(ext.min)) { // #7411
  59322. chart.xAxis[0].setExtremes(Math.min(ext.min, ext.max), Math.max(ext.min, ext.max), true, null, // auto animation
  59323. { trigger: 'navigator' });
  59324. }
  59325. }
  59326. }
  59327. };
  59328. /**
  59329. * Mousedown on a handle mask.
  59330. * Will store necessary information for drag&drop.
  59331. *
  59332. * @private
  59333. * @function Highcharts.Navigator#handlesMousedown
  59334. * @param {Highcharts.PointerEventObject} e
  59335. * Mouse event
  59336. * @param {number} index
  59337. * Index of a handle in Navigator.handles array
  59338. * @return {void}
  59339. */
  59340. Navigator.prototype.handlesMousedown = function (e, index) {
  59341. e = this.chart.pointer.normalize(e);
  59342. var navigator = this,
  59343. chart = navigator.chart,
  59344. baseXAxis = chart.xAxis[0],
  59345. // For reversed axes, min and max are changed,
  59346. // so the other extreme should be stored
  59347. reverse = navigator.reversedExtremes;
  59348. if (index === 0) {
  59349. // Grab the left handle
  59350. navigator.grabbedLeft = true;
  59351. navigator.otherHandlePos = navigator.zoomedMax;
  59352. navigator.fixedExtreme = reverse ? baseXAxis.min : baseXAxis.max;
  59353. }
  59354. else {
  59355. // Grab the right handle
  59356. navigator.grabbedRight = true;
  59357. navigator.otherHandlePos = navigator.zoomedMin;
  59358. navigator.fixedExtreme = reverse ? baseXAxis.max : baseXAxis.min;
  59359. }
  59360. chart.fixedRange = null;
  59361. };
  59362. /**
  59363. * Mouse move event based on x/y mouse position.
  59364. *
  59365. * @private
  59366. * @function Highcharts.Navigator#onMouseMove
  59367. *
  59368. * @param {Highcharts.PointerEventObject} e
  59369. * Mouse event
  59370. */
  59371. Navigator.prototype.onMouseMove = function (e) {
  59372. var navigator = this,
  59373. chart = navigator.chart,
  59374. left = navigator.left,
  59375. navigatorSize = navigator.navigatorSize,
  59376. range = navigator.range,
  59377. dragOffset = navigator.dragOffset,
  59378. inverted = chart.inverted,
  59379. chartX;
  59380. // In iOS, a mousemove event with e.pageX === 0 is fired when holding
  59381. // the finger down in the center of the scrollbar. This should be
  59382. // ignored.
  59383. if (!e.touches || e.touches[0].pageX !== 0) { // #4696
  59384. e = chart.pointer.normalize(e);
  59385. chartX = e.chartX;
  59386. // Swap some options for inverted chart
  59387. if (inverted) {
  59388. left = navigator.top;
  59389. chartX = e.chartY;
  59390. }
  59391. // Drag left handle or top handle
  59392. if (navigator.grabbedLeft) {
  59393. navigator.hasDragged = true;
  59394. navigator.render(0, 0, chartX - left, navigator.otherHandlePos);
  59395. // Drag right handle or bottom handle
  59396. }
  59397. else if (navigator.grabbedRight) {
  59398. navigator.hasDragged = true;
  59399. navigator.render(0, 0, navigator.otherHandlePos, chartX - left);
  59400. // Drag scrollbar or open area in navigator
  59401. }
  59402. else if (navigator.grabbedCenter) {
  59403. navigator.hasDragged = true;
  59404. if (chartX < dragOffset) { // outside left
  59405. chartX = dragOffset;
  59406. // outside right
  59407. }
  59408. else if (chartX >
  59409. navigatorSize + dragOffset - range) {
  59410. chartX = navigatorSize + dragOffset - range;
  59411. }
  59412. navigator.render(0, 0, chartX - dragOffset, chartX - dragOffset + range);
  59413. }
  59414. if (navigator.hasDragged &&
  59415. navigator.scrollbar &&
  59416. pick(navigator.scrollbar.options.liveRedraw,
  59417. // By default, don't run live redraw on VML, on touch
  59418. // devices or if the chart is in boost.
  59419. H.svg && !isTouchDevice && !this.chart.isBoosting)) {
  59420. e.DOMType = e.type; // DOMType is for IE8
  59421. setTimeout(function () {
  59422. navigator.onMouseUp(e);
  59423. }, 0);
  59424. }
  59425. }
  59426. };
  59427. /**
  59428. * Mouse up event based on x/y mouse position.
  59429. *
  59430. * @private
  59431. * @function Highcharts.Navigator#onMouseUp
  59432. * @param {Highcharts.PointerEventObject} e
  59433. * Mouse event
  59434. * @return {void}
  59435. */
  59436. Navigator.prototype.onMouseUp = function (e) {
  59437. var navigator = this,
  59438. chart = navigator.chart,
  59439. xAxis = navigator.xAxis,
  59440. scrollbar = navigator.scrollbar,
  59441. DOMEvent = e.DOMEvent || e,
  59442. inverted = chart.inverted,
  59443. verb = navigator.rendered && !navigator.hasDragged ?
  59444. 'animate' : 'attr',
  59445. zoomedMax,
  59446. zoomedMin,
  59447. unionExtremes,
  59448. fixedMin,
  59449. fixedMax,
  59450. ext;
  59451. if (
  59452. // MouseUp is called for both, navigator and scrollbar (that order),
  59453. // which causes calling afterSetExtremes twice. Prevent first call
  59454. // by checking if scrollbar is going to set new extremes (#6334)
  59455. (navigator.hasDragged && (!scrollbar || !scrollbar.hasDragged)) ||
  59456. e.trigger === 'scrollbar') {
  59457. unionExtremes = navigator.getUnionExtremes();
  59458. // When dragging one handle, make sure the other one doesn't change
  59459. if (navigator.zoomedMin === navigator.otherHandlePos) {
  59460. fixedMin = navigator.fixedExtreme;
  59461. }
  59462. else if (navigator.zoomedMax === navigator.otherHandlePos) {
  59463. fixedMax = navigator.fixedExtreme;
  59464. }
  59465. // Snap to right edge (#4076)
  59466. if (navigator.zoomedMax === navigator.size) {
  59467. fixedMax = navigator.reversedExtremes ?
  59468. unionExtremes.dataMin :
  59469. unionExtremes.dataMax;
  59470. }
  59471. // Snap to left edge (#7576)
  59472. if (navigator.zoomedMin === 0) {
  59473. fixedMin = navigator.reversedExtremes ?
  59474. unionExtremes.dataMax :
  59475. unionExtremes.dataMin;
  59476. }
  59477. ext = xAxis.navigatorAxis.toFixedRange(navigator.zoomedMin, navigator.zoomedMax, fixedMin, fixedMax);
  59478. if (defined(ext.min)) {
  59479. chart.xAxis[0].setExtremes(Math.min(ext.min, ext.max), Math.max(ext.min, ext.max), true,
  59480. // Run animation when clicking buttons, scrollbar track etc,
  59481. // but not when dragging handles or scrollbar
  59482. navigator.hasDragged ? false : null, {
  59483. trigger: 'navigator',
  59484. triggerOp: 'navigator-drag',
  59485. DOMEvent: DOMEvent // #1838
  59486. });
  59487. }
  59488. }
  59489. if (e.DOMType !== 'mousemove' &&
  59490. e.DOMType !== 'touchmove') {
  59491. navigator.grabbedLeft = navigator.grabbedRight =
  59492. navigator.grabbedCenter = navigator.fixedWidth =
  59493. navigator.fixedExtreme = navigator.otherHandlePos =
  59494. navigator.hasDragged = navigator.dragOffset = null;
  59495. }
  59496. // Update position of navigator shades, outline and handles (#12573)
  59497. if (navigator.navigatorEnabled &&
  59498. isNumber(navigator.zoomedMin) &&
  59499. isNumber(navigator.zoomedMax)) {
  59500. zoomedMin = Math.round(navigator.zoomedMin);
  59501. zoomedMax = Math.round(navigator.zoomedMax);
  59502. if (navigator.shades) {
  59503. navigator.drawMasks(zoomedMin, zoomedMax, inverted, verb);
  59504. }
  59505. if (navigator.outline) {
  59506. navigator.drawOutline(zoomedMin, zoomedMax, inverted, verb);
  59507. }
  59508. if (navigator.navigatorOptions.handles.enabled &&
  59509. Object.keys(navigator.handles).length ===
  59510. navigator.handles.length) {
  59511. navigator.drawHandle(zoomedMin, 0, inverted, verb);
  59512. navigator.drawHandle(zoomedMax, 1, inverted, verb);
  59513. }
  59514. }
  59515. };
  59516. /**
  59517. * Removes the event handlers attached previously with addEvents.
  59518. *
  59519. * @private
  59520. * @function Highcharts.Navigator#removeEvents
  59521. * @return {void}
  59522. */
  59523. Navigator.prototype.removeEvents = function () {
  59524. if (this.eventsToUnbind) {
  59525. this.eventsToUnbind.forEach(function (unbind) {
  59526. unbind();
  59527. });
  59528. this.eventsToUnbind = void 0;
  59529. }
  59530. this.removeBaseSeriesEvents();
  59531. };
  59532. /**
  59533. * Remove data events.
  59534. *
  59535. * @private
  59536. * @function Highcharts.Navigator#removeBaseSeriesEvents
  59537. * @return {void}
  59538. */
  59539. Navigator.prototype.removeBaseSeriesEvents = function () {
  59540. var baseSeries = this.baseSeries || [];
  59541. if (this.navigatorEnabled && baseSeries[0]) {
  59542. if (this.navigatorOptions.adaptToUpdatedData !== false) {
  59543. baseSeries.forEach(function (series) {
  59544. removeEvent(series, 'updatedData', this.updatedDataHandler);
  59545. }, this);
  59546. }
  59547. // We only listen for extremes-events on the first baseSeries
  59548. if (baseSeries[0].xAxis) {
  59549. removeEvent(baseSeries[0].xAxis, 'foundExtremes', this.modifyBaseAxisExtremes);
  59550. }
  59551. }
  59552. };
  59553. /**
  59554. * Initialize the Navigator object
  59555. *
  59556. * @private
  59557. * @function Highcharts.Navigator#init
  59558. *
  59559. * @param {Highcharts.Chart} chart
  59560. */
  59561. Navigator.prototype.init = function (chart) {
  59562. var chartOptions = chart.options,
  59563. navigatorOptions = chartOptions.navigator,
  59564. navigatorEnabled = navigatorOptions.enabled,
  59565. scrollbarOptions = chartOptions.scrollbar,
  59566. scrollbarEnabled = scrollbarOptions.enabled,
  59567. height = navigatorEnabled ? navigatorOptions.height : 0,
  59568. scrollbarHeight = scrollbarEnabled ?
  59569. scrollbarOptions.height :
  59570. 0;
  59571. this.handles = [];
  59572. this.shades = [];
  59573. this.chart = chart;
  59574. this.setBaseSeries();
  59575. this.height = height;
  59576. this.scrollbarHeight = scrollbarHeight;
  59577. this.scrollbarEnabled = scrollbarEnabled;
  59578. this.navigatorEnabled = navigatorEnabled;
  59579. this.navigatorOptions = navigatorOptions;
  59580. this.scrollbarOptions = scrollbarOptions;
  59581. this.outlineHeight = height + scrollbarHeight;
  59582. this.opposite = pick(navigatorOptions.opposite, Boolean(!navigatorEnabled && chart.inverted)); // #6262
  59583. var navigator = this,
  59584. baseSeries = navigator.baseSeries,
  59585. xAxisIndex = chart.xAxis.length,
  59586. yAxisIndex = chart.yAxis.length,
  59587. baseXaxis = baseSeries && baseSeries[0] && baseSeries[0].xAxis ||
  59588. chart.xAxis[0] || { options: {} };
  59589. chart.isDirtyBox = true;
  59590. if (navigator.navigatorEnabled) {
  59591. // an x axis is required for scrollbar also
  59592. navigator.xAxis = new Axis(chart, merge({
  59593. // inherit base xAxis' break and ordinal options
  59594. breaks: baseXaxis.options.breaks,
  59595. ordinal: baseXaxis.options.ordinal
  59596. }, navigatorOptions.xAxis, {
  59597. id: 'navigator-x-axis',
  59598. yAxis: 'navigator-y-axis',
  59599. isX: true,
  59600. type: 'datetime',
  59601. index: xAxisIndex,
  59602. isInternal: true,
  59603. offset: 0,
  59604. keepOrdinalPadding: true,
  59605. startOnTick: false,
  59606. endOnTick: false,
  59607. minPadding: 0,
  59608. maxPadding: 0,
  59609. zoomEnabled: false
  59610. }, chart.inverted ? {
  59611. offsets: [scrollbarHeight, 0, -scrollbarHeight, 0],
  59612. width: height
  59613. } : {
  59614. offsets: [0, -scrollbarHeight, 0, scrollbarHeight],
  59615. height: height
  59616. }));
  59617. navigator.yAxis = new Axis(chart, merge(navigatorOptions.yAxis, {
  59618. id: 'navigator-y-axis',
  59619. alignTicks: false,
  59620. offset: 0,
  59621. index: yAxisIndex,
  59622. isInternal: true,
  59623. reversed: pick((navigatorOptions.yAxis && navigatorOptions.yAxis.reversed), (chart.yAxis[0] && chart.yAxis[0].reversed), false),
  59624. zoomEnabled: false
  59625. }, chart.inverted ? {
  59626. width: height
  59627. } : {
  59628. height: height
  59629. }));
  59630. // If we have a base series, initialize the navigator series
  59631. if (baseSeries || navigatorOptions.series.data) {
  59632. navigator.updateNavigatorSeries(false);
  59633. // If not, set up an event to listen for added series
  59634. }
  59635. else if (chart.series.length === 0) {
  59636. navigator.unbindRedraw = addEvent(chart, 'beforeRedraw', function () {
  59637. // We've got one, now add it as base
  59638. if (chart.series.length > 0 && !navigator.series) {
  59639. navigator.setBaseSeries();
  59640. navigator.unbindRedraw(); // reset
  59641. }
  59642. });
  59643. }
  59644. navigator.reversedExtremes = (chart.inverted && !navigator.xAxis.reversed) || (!chart.inverted && navigator.xAxis.reversed);
  59645. // Render items, so we can bind events to them:
  59646. navigator.renderElements();
  59647. // Add mouse events
  59648. navigator.addMouseEvents();
  59649. // in case of scrollbar only, fake an x axis to get translation
  59650. }
  59651. else {
  59652. navigator.xAxis = {
  59653. chart: chart,
  59654. navigatorAxis: {
  59655. fake: true
  59656. },
  59657. translate: function (value, reverse) {
  59658. var axis = chart.xAxis[0], ext = axis.getExtremes(), scrollTrackWidth = axis.len - 2 * scrollbarHeight, min = numExt('min', axis.options.min, ext.dataMin), valueRange = numExt('max', axis.options.max, ext.dataMax) - min;
  59659. return reverse ?
  59660. // from pixel to value
  59661. (value * valueRange / scrollTrackWidth) + min :
  59662. // from value to pixel
  59663. scrollTrackWidth * (value - min) / valueRange;
  59664. },
  59665. toPixels: function (value) {
  59666. return this.translate(value);
  59667. },
  59668. toValue: function (value) {
  59669. return this.translate(value, true);
  59670. }
  59671. };
  59672. navigator.xAxis.navigatorAxis.axis = navigator.xAxis;
  59673. navigator.xAxis.navigatorAxis.toFixedRange = (NavigatorAxis.AdditionsClass.prototype.toFixedRange.bind(navigator.xAxis.navigatorAxis));
  59674. }
  59675. // Initialize the scrollbar
  59676. if (chart.options.scrollbar.enabled) {
  59677. chart.scrollbar = navigator.scrollbar = new Scrollbar(chart.renderer, merge(chart.options.scrollbar, {
  59678. margin: navigator.navigatorEnabled ? 0 : 10,
  59679. vertical: chart.inverted
  59680. }), chart);
  59681. addEvent(navigator.scrollbar, 'changed', function (e) {
  59682. var range = navigator.size,
  59683. to = range * this.to,
  59684. from = range * this.from;
  59685. navigator.hasDragged = navigator.scrollbar.hasDragged;
  59686. navigator.render(0, 0, from, to);
  59687. if (this.shouldUpdateExtremes(e.DOMType)) {
  59688. setTimeout(function () {
  59689. navigator.onMouseUp(e);
  59690. });
  59691. }
  59692. });
  59693. }
  59694. // Add data events
  59695. navigator.addBaseSeriesEvents();
  59696. // Add redraw events
  59697. navigator.addChartEvents();
  59698. };
  59699. /**
  59700. * Get the union data extremes of the chart - the outer data extremes of the
  59701. * base X axis and the navigator axis.
  59702. *
  59703. * @private
  59704. * @function Highcharts.Navigator#getUnionExtremes
  59705. * @param {boolean} [returnFalseOnNoBaseSeries]
  59706. * as the param says.
  59707. * @return {Highcharts.Dictionary<(number|undefined)>|undefined}
  59708. */
  59709. Navigator.prototype.getUnionExtremes = function (returnFalseOnNoBaseSeries) {
  59710. var baseAxis = this.chart.xAxis[0],
  59711. navAxis = this.xAxis,
  59712. navAxisOptions = navAxis.options,
  59713. baseAxisOptions = baseAxis.options,
  59714. ret;
  59715. if (!returnFalseOnNoBaseSeries || baseAxis.dataMin !== null) {
  59716. ret = {
  59717. dataMin: pick(// #4053
  59718. navAxisOptions && navAxisOptions.min, numExt('min', baseAxisOptions.min, baseAxis.dataMin, navAxis.dataMin, navAxis.min)),
  59719. dataMax: pick(navAxisOptions && navAxisOptions.max, numExt('max', baseAxisOptions.max, baseAxis.dataMax, navAxis.dataMax, navAxis.max))
  59720. };
  59721. }
  59722. return ret;
  59723. };
  59724. /**
  59725. * Set the base series and update the navigator series from this. With a bit
  59726. * of modification we should be able to make this an API method to be called
  59727. * from the outside
  59728. *
  59729. * @private
  59730. * @function Highcharts.Navigator#setBaseSeries
  59731. * @param {Highcharts.SeriesOptionsType} [baseSeriesOptions]
  59732. * Additional series options for a navigator
  59733. * @param {boolean} [redraw]
  59734. * Whether to redraw after update.
  59735. * @return {void}
  59736. */
  59737. Navigator.prototype.setBaseSeries = function (baseSeriesOptions, redraw) {
  59738. var chart = this.chart,
  59739. baseSeries = this.baseSeries = [];
  59740. baseSeriesOptions = (baseSeriesOptions ||
  59741. chart.options && chart.options.navigator.baseSeries ||
  59742. (chart.series.length ?
  59743. // Find the first non-navigator series (#8430)
  59744. find(chart.series, function (s) {
  59745. return !s.options.isInternal;
  59746. }).index :
  59747. 0));
  59748. // Iterate through series and add the ones that should be shown in
  59749. // navigator.
  59750. (chart.series || []).forEach(function (series, i) {
  59751. if (
  59752. // Don't include existing nav series
  59753. !series.options.isInternal &&
  59754. (series.options.showInNavigator ||
  59755. (i === baseSeriesOptions ||
  59756. series.options.id === baseSeriesOptions) &&
  59757. series.options.showInNavigator !== false)) {
  59758. baseSeries.push(series);
  59759. }
  59760. });
  59761. // When run after render, this.xAxis already exists
  59762. if (this.xAxis && !this.xAxis.navigatorAxis.fake) {
  59763. this.updateNavigatorSeries(true, redraw);
  59764. }
  59765. };
  59766. /**
  59767. * Update series in the navigator from baseSeries, adding new if does not
  59768. * exist.
  59769. *
  59770. * @private
  59771. * @function Highcharts.Navigator.updateNavigatorSeries
  59772. * @param {boolean} addEvents
  59773. * @param {boolean} [redraw]
  59774. * @return {void}
  59775. */
  59776. Navigator.prototype.updateNavigatorSeries = function (addEvents, redraw) {
  59777. var navigator = this,
  59778. chart = navigator.chart,
  59779. baseSeries = navigator.baseSeries,
  59780. baseOptions,
  59781. mergedNavSeriesOptions,
  59782. chartNavigatorSeriesOptions = navigator.navigatorOptions.series,
  59783. baseNavigatorOptions,
  59784. navSeriesMixin = {
  59785. enableMouseTracking: false,
  59786. index: null,
  59787. linkedTo: null,
  59788. group: 'nav',
  59789. padXAxis: false,
  59790. xAxis: 'navigator-x-axis',
  59791. yAxis: 'navigator-y-axis',
  59792. showInLegend: false,
  59793. stacking: void 0,
  59794. isInternal: true,
  59795. states: {
  59796. inactive: {
  59797. opacity: 1
  59798. }
  59799. }
  59800. },
  59801. // Remove navigator series that are no longer in the baseSeries
  59802. navigatorSeries = navigator.series =
  59803. (navigator.series || []).filter(function (navSeries) {
  59804. var base = navSeries.baseSeries;
  59805. if (baseSeries.indexOf(base) < 0) { // Not in array
  59806. // If there is still a base series connected to this
  59807. // series, remove event handler and reference.
  59808. if (base) {
  59809. removeEvent(base, 'updatedData', navigator.updatedDataHandler);
  59810. delete base.navigatorSeries;
  59811. }
  59812. // Kill the nav series. It may already have been
  59813. // destroyed (#8715).
  59814. if (navSeries.chart) {
  59815. navSeries.destroy();
  59816. }
  59817. return false;
  59818. }
  59819. return true;
  59820. });
  59821. // Go through each base series and merge the options to create new
  59822. // series
  59823. if (baseSeries && baseSeries.length) {
  59824. baseSeries.forEach(function eachBaseSeries(base) {
  59825. var linkedNavSeries = base.navigatorSeries,
  59826. userNavOptions = extend(
  59827. // Grab color and visibility from base as default
  59828. {
  59829. color: base.color,
  59830. visible: base.visible
  59831. }, !isArray(chartNavigatorSeriesOptions) ?
  59832. chartNavigatorSeriesOptions :
  59833. defaultOptions.navigator.series);
  59834. // Don't update if the series exists in nav and we have disabled
  59835. // adaptToUpdatedData.
  59836. if (linkedNavSeries &&
  59837. navigator.navigatorOptions.adaptToUpdatedData === false) {
  59838. return;
  59839. }
  59840. navSeriesMixin.name = 'Navigator ' + baseSeries.length;
  59841. baseOptions = base.options || {};
  59842. baseNavigatorOptions = baseOptions.navigatorOptions || {};
  59843. // The dataLabels options are not merged correctly
  59844. // if the settings are an array, #13847.
  59845. userNavOptions.dataLabels = splat(userNavOptions.dataLabels);
  59846. mergedNavSeriesOptions = merge(baseOptions, navSeriesMixin, userNavOptions, baseNavigatorOptions);
  59847. // Once nav series type is resolved, pick correct pointRange
  59848. mergedNavSeriesOptions.pointRange = pick(
  59849. // Stricte set pointRange in options
  59850. userNavOptions.pointRange, baseNavigatorOptions.pointRange,
  59851. // Fallback to default values, e.g. `null` for column
  59852. defaultOptions.plotOptions[mergedNavSeriesOptions.type || 'line'].pointRange);
  59853. // Merge data separately. Do a slice to avoid mutating the
  59854. // navigator options from base series (#4923).
  59855. var navigatorSeriesData = baseNavigatorOptions.data || userNavOptions.data;
  59856. navigator.hasNavigatorData =
  59857. navigator.hasNavigatorData || !!navigatorSeriesData;
  59858. mergedNavSeriesOptions.data =
  59859. navigatorSeriesData ||
  59860. baseOptions.data && baseOptions.data.slice(0);
  59861. // Update or add the series
  59862. if (linkedNavSeries && linkedNavSeries.options) {
  59863. linkedNavSeries.update(mergedNavSeriesOptions, redraw);
  59864. }
  59865. else {
  59866. base.navigatorSeries = chart.initSeries(mergedNavSeriesOptions);
  59867. base.navigatorSeries.baseSeries = base; // Store ref
  59868. navigatorSeries.push(base.navigatorSeries);
  59869. }
  59870. });
  59871. }
  59872. // If user has defined data (and no base series) or explicitly defined
  59873. // navigator.series as an array, we create these series on top of any
  59874. // base series.
  59875. if (chartNavigatorSeriesOptions.data &&
  59876. !(baseSeries && baseSeries.length) ||
  59877. isArray(chartNavigatorSeriesOptions)) {
  59878. navigator.hasNavigatorData = false;
  59879. // Allow navigator.series to be an array
  59880. chartNavigatorSeriesOptions =
  59881. splat(chartNavigatorSeriesOptions);
  59882. chartNavigatorSeriesOptions.forEach(function (userSeriesOptions, i) {
  59883. navSeriesMixin.name =
  59884. 'Navigator ' + (navigatorSeries.length + 1);
  59885. mergedNavSeriesOptions = merge(defaultOptions.navigator.series, {
  59886. // Since we don't have a base series to pull color from,
  59887. // try to fake it by using color from series with same
  59888. // index. Otherwise pull from the colors array. We need
  59889. // an explicit color as otherwise updates will increment
  59890. // color counter and we'll get a new color for each
  59891. // update of the nav series.
  59892. color: chart.series[i] &&
  59893. !chart.series[i].options.isInternal &&
  59894. chart.series[i].color ||
  59895. chart.options.colors[i] ||
  59896. chart.options.colors[0]
  59897. }, navSeriesMixin, userSeriesOptions);
  59898. mergedNavSeriesOptions.data = userSeriesOptions.data;
  59899. if (mergedNavSeriesOptions.data) {
  59900. navigator.hasNavigatorData = true;
  59901. navigatorSeries.push(chart.initSeries(mergedNavSeriesOptions));
  59902. }
  59903. });
  59904. }
  59905. if (addEvents) {
  59906. this.addBaseSeriesEvents();
  59907. }
  59908. };
  59909. /**
  59910. * Add data events.
  59911. * For example when main series is updated we need to recalculate extremes
  59912. *
  59913. * @private
  59914. * @function Highcharts.Navigator#addBaseSeriesEvent
  59915. * @return {void}
  59916. */
  59917. Navigator.prototype.addBaseSeriesEvents = function () {
  59918. var navigator = this,
  59919. baseSeries = navigator.baseSeries || [];
  59920. // Bind modified extremes event to first base's xAxis only.
  59921. // In event of > 1 base-xAxes, the navigator will ignore those.
  59922. // Adding this multiple times to the same axis is no problem, as
  59923. // duplicates should be discarded by the browser.
  59924. if (baseSeries[0] && baseSeries[0].xAxis) {
  59925. baseSeries[0].eventsToUnbind.push(addEvent(baseSeries[0].xAxis, 'foundExtremes', this.modifyBaseAxisExtremes));
  59926. }
  59927. baseSeries.forEach(function (base) {
  59928. // Link base series show/hide to navigator series visibility
  59929. base.eventsToUnbind.push(addEvent(base, 'show', function () {
  59930. if (this.navigatorSeries) {
  59931. this.navigatorSeries.setVisible(true, false);
  59932. }
  59933. }));
  59934. base.eventsToUnbind.push(addEvent(base, 'hide', function () {
  59935. if (this.navigatorSeries) {
  59936. this.navigatorSeries.setVisible(false, false);
  59937. }
  59938. }));
  59939. // Respond to updated data in the base series, unless explicitily
  59940. // not adapting to data changes.
  59941. if (this.navigatorOptions.adaptToUpdatedData !== false) {
  59942. if (base.xAxis) {
  59943. base.eventsToUnbind.push(addEvent(base, 'updatedData', this.updatedDataHandler));
  59944. }
  59945. }
  59946. // Handle series removal
  59947. base.eventsToUnbind.push(addEvent(base, 'remove', function () {
  59948. if (this.navigatorSeries) {
  59949. erase(navigator.series, this.navigatorSeries);
  59950. if (defined(this.navigatorSeries.options)) {
  59951. this.navigatorSeries.remove(false);
  59952. }
  59953. delete this.navigatorSeries;
  59954. }
  59955. }));
  59956. }, this);
  59957. };
  59958. /**
  59959. * Get minimum from all base series connected to the navigator
  59960. * @private
  59961. * @param {number} currentSeriesMin
  59962. * Minium from the current series
  59963. * @return {number} Minimum from all series
  59964. */
  59965. Navigator.prototype.getBaseSeriesMin = function (currentSeriesMin) {
  59966. return this.baseSeries.reduce(function (min, series) {
  59967. // (#10193)
  59968. return Math.min(min, series.xData ? series.xData[0] : min);
  59969. }, currentSeriesMin);
  59970. };
  59971. /**
  59972. * Set the navigator x axis extremes to reflect the total. The navigator
  59973. * extremes should always be the extremes of the union of all series in the
  59974. * chart as well as the navigator series.
  59975. *
  59976. * @private
  59977. * @function Highcharts.Navigator#modifyNavigatorAxisExtremes
  59978. */
  59979. Navigator.prototype.modifyNavigatorAxisExtremes = function () {
  59980. var xAxis = this.xAxis,
  59981. unionExtremes;
  59982. if (typeof xAxis.getExtremes !== 'undefined') {
  59983. unionExtremes = this.getUnionExtremes(true);
  59984. if (unionExtremes &&
  59985. (unionExtremes.dataMin !== xAxis.min ||
  59986. unionExtremes.dataMax !== xAxis.max)) {
  59987. xAxis.min = unionExtremes.dataMin;
  59988. xAxis.max = unionExtremes.dataMax;
  59989. }
  59990. }
  59991. };
  59992. /**
  59993. * Hook to modify the base axis extremes with information from the Navigator
  59994. *
  59995. * @private
  59996. * @function Highcharts.Navigator#modifyBaseAxisExtremes
  59997. */
  59998. Navigator.prototype.modifyBaseAxisExtremes = function () {
  59999. var baseXAxis = this,
  60000. navigator = baseXAxis.chart.navigator,
  60001. baseExtremes = baseXAxis.getExtremes(),
  60002. baseMin = baseExtremes.min,
  60003. baseMax = baseExtremes.max,
  60004. baseDataMin = baseExtremes.dataMin,
  60005. baseDataMax = baseExtremes.dataMax,
  60006. range = baseMax - baseMin,
  60007. stickToMin = navigator.stickToMin,
  60008. stickToMax = navigator.stickToMax,
  60009. overscroll = pick(baseXAxis.options.overscroll, 0),
  60010. newMax,
  60011. newMin,
  60012. navigatorSeries = navigator.series && navigator.series[0],
  60013. hasSetExtremes = !!baseXAxis.setExtremes,
  60014. // When the extremes have been set by range selector button, don't
  60015. // stick to min or max. The range selector buttons will handle the
  60016. // extremes. (#5489)
  60017. unmutable = baseXAxis.eventArgs &&
  60018. baseXAxis.eventArgs.trigger === 'rangeSelectorButton';
  60019. if (!unmutable) {
  60020. // If the zoomed range is already at the min, move it to the right
  60021. // as new data comes in
  60022. if (stickToMin) {
  60023. newMin = baseDataMin;
  60024. newMax = newMin + range;
  60025. }
  60026. // If the zoomed range is already at the max, move it to the right
  60027. // as new data comes in
  60028. if (stickToMax) {
  60029. newMax = baseDataMax + overscroll;
  60030. // If stickToMin is true, the new min value is set above
  60031. if (!stickToMin) {
  60032. newMin = Math.max(baseDataMin, // don't go below data extremes (#13184)
  60033. newMax - range, navigator.getBaseSeriesMin(navigatorSeries && navigatorSeries.xData ?
  60034. navigatorSeries.xData[0] :
  60035. -Number.MAX_VALUE));
  60036. }
  60037. }
  60038. // Update the extremes
  60039. if (hasSetExtremes && (stickToMin || stickToMax)) {
  60040. if (isNumber(newMin)) {
  60041. baseXAxis.min = baseXAxis.userMin = newMin;
  60042. baseXAxis.max = baseXAxis.userMax = newMax;
  60043. }
  60044. }
  60045. }
  60046. // Reset
  60047. navigator.stickToMin =
  60048. navigator.stickToMax = null;
  60049. };
  60050. /**
  60051. * Handler for updated data on the base series. When data is modified, the
  60052. * navigator series must reflect it. This is called from the Chart.redraw
  60053. * function before axis and series extremes are computed.
  60054. *
  60055. * @private
  60056. * @function Highcharts.Navigator#updateDataHandler
  60057. */
  60058. Navigator.prototype.updatedDataHandler = function () {
  60059. var navigator = this.chart.navigator,
  60060. baseSeries = this,
  60061. navigatorSeries = this.navigatorSeries;
  60062. // If the scrollbar is scrolled all the way to the right, keep right as
  60063. // new data comes in.
  60064. navigator.stickToMax = navigator.reversedExtremes ?
  60065. Math.round(navigator.zoomedMin) === 0 :
  60066. Math.round(navigator.zoomedMax) >= Math.round(navigator.size);
  60067. navigator.stickToMin = navigator.shouldStickToMin(baseSeries, navigator);
  60068. // Set the navigator series data to the new data of the base series
  60069. if (navigatorSeries && !navigator.hasNavigatorData) {
  60070. navigatorSeries.options.pointStart = baseSeries.xData[0];
  60071. navigatorSeries.setData(baseSeries.options.data, false, null, false); // #5414
  60072. }
  60073. };
  60074. /**
  60075. * Detect if the zoomed area should stick to the minimum, #14742.
  60076. *
  60077. * @private
  60078. * @function Highcharts.Navigator#shouldStickToMin
  60079. */
  60080. Navigator.prototype.shouldStickToMin = function (baseSeries, navigator) {
  60081. var xDataMin = navigator.getBaseSeriesMin(baseSeries.xData[0]),
  60082. xAxis = baseSeries.xAxis,
  60083. max = xAxis.max,
  60084. min = xAxis.min,
  60085. range = xAxis.options.range;
  60086. var stickToMin = true;
  60087. if (isNumber(max) && isNumber(min)) {
  60088. // If range declared, stick to the minimum only if the range
  60089. // is smaller than the data set range.
  60090. if (range && max - xDataMin > 0) {
  60091. stickToMin = max - xDataMin < range && (!this.chart.fixedRange);
  60092. }
  60093. else {
  60094. // If the current axis minimum falls outside the new
  60095. // updated dataset, we must adjust.
  60096. stickToMin = min <= xDataMin;
  60097. }
  60098. }
  60099. return stickToMin;
  60100. };
  60101. /**
  60102. * Add chart events, like redrawing navigator, when chart requires that.
  60103. *
  60104. * @private
  60105. * @function Highcharts.Navigator#addChartEvents
  60106. * @return {void}
  60107. */
  60108. Navigator.prototype.addChartEvents = function () {
  60109. if (!this.eventsToUnbind) {
  60110. this.eventsToUnbind = [];
  60111. }
  60112. this.eventsToUnbind.push(
  60113. // Move the scrollbar after redraw, like after data updata even if
  60114. // axes don't redraw
  60115. addEvent(this.chart, 'redraw', function () {
  60116. var navigator = this.navigator,
  60117. xAxis = navigator && (navigator.baseSeries &&
  60118. navigator.baseSeries[0] &&
  60119. navigator.baseSeries[0].xAxis ||
  60120. this.xAxis[0]); // #5709, #13114
  60121. if (xAxis) {
  60122. navigator.render(xAxis.min,
  60123. xAxis.max);
  60124. }
  60125. }),
  60126. // Make room for the navigator, can be placed around the chart:
  60127. addEvent(this.chart, 'getMargins', function () {
  60128. var chart = this,
  60129. navigator = chart.navigator,
  60130. marginName = navigator.opposite ?
  60131. 'plotTop' : 'marginBottom';
  60132. if (chart.inverted) {
  60133. marginName = navigator.opposite ?
  60134. 'marginRight' : 'plotLeft';
  60135. }
  60136. chart[marginName] =
  60137. (chart[marginName] || 0) + (navigator.navigatorEnabled || !chart.inverted ?
  60138. navigator.outlineHeight :
  60139. 0) + navigator.navigatorOptions.margin;
  60140. }));
  60141. };
  60142. /**
  60143. * Destroys allocated elements.
  60144. *
  60145. * @private
  60146. * @function Highcharts.Navigator#destroy
  60147. */
  60148. Navigator.prototype.destroy = function () {
  60149. // Disconnect events added in addEvents
  60150. this.removeEvents();
  60151. if (this.xAxis) {
  60152. erase(this.chart.xAxis, this.xAxis);
  60153. erase(this.chart.axes, this.xAxis);
  60154. }
  60155. if (this.yAxis) {
  60156. erase(this.chart.yAxis, this.yAxis);
  60157. erase(this.chart.axes, this.yAxis);
  60158. }
  60159. // Destroy series
  60160. (this.series || []).forEach(function (s) {
  60161. if (s.destroy) {
  60162. s.destroy();
  60163. }
  60164. });
  60165. // Destroy properties
  60166. [
  60167. 'series', 'xAxis', 'yAxis', 'shades', 'outline', 'scrollbarTrack',
  60168. 'scrollbarRifles', 'scrollbarGroup', 'scrollbar', 'navigatorGroup',
  60169. 'rendered'
  60170. ].forEach(function (prop) {
  60171. if (this[prop] && this[prop].destroy) {
  60172. this[prop].destroy();
  60173. }
  60174. this[prop] = null;
  60175. }, this);
  60176. // Destroy elements in collection
  60177. [this.handles].forEach(function (coll) {
  60178. destroyObjectProperties(coll);
  60179. }, this);
  60180. };
  60181. return Navigator;
  60182. }());
  60183. // End of prototype
  60184. if (!H.Navigator) {
  60185. H.Navigator = Navigator;
  60186. NavigatorAxis.compose(Axis);
  60187. // For Stock charts. For x only zooming, do not to create the zoom button
  60188. // because X axis zooming is already allowed by the Navigator and Range
  60189. // selector. (#9285)
  60190. addEvent(Chart, 'beforeShowResetZoom', function () {
  60191. var chartOptions = this.options,
  60192. navigator = chartOptions.navigator,
  60193. rangeSelector = chartOptions.rangeSelector;
  60194. if (((navigator && navigator.enabled) ||
  60195. (rangeSelector && rangeSelector.enabled)) &&
  60196. ((!isTouchDevice && chartOptions.chart.zoomType === 'x') ||
  60197. (isTouchDevice && chartOptions.chart.pinchType === 'x'))) {
  60198. return false;
  60199. }
  60200. });
  60201. // Initialize navigator for stock charts
  60202. addEvent(Chart, 'beforeRender', function () {
  60203. var options = this.options;
  60204. if (options.navigator.enabled ||
  60205. options.scrollbar.enabled) {
  60206. this.scroller = this.navigator = new Navigator(this);
  60207. }
  60208. });
  60209. // For stock charts, extend the Chart.setChartSize method so that we can set
  60210. // the final top position of the navigator once the height of the chart,
  60211. // including the legend, is determined. #367. We can't use Chart.getMargins,
  60212. // because labels offsets are not calculated yet.
  60213. addEvent(Chart, 'afterSetChartSize', function () {
  60214. var legend = this.legend,
  60215. navigator = this.navigator,
  60216. scrollbarHeight,
  60217. legendOptions,
  60218. xAxis,
  60219. yAxis;
  60220. if (navigator) {
  60221. legendOptions = legend && legend.options;
  60222. xAxis = navigator.xAxis;
  60223. yAxis = navigator.yAxis;
  60224. scrollbarHeight = navigator.scrollbarHeight;
  60225. // Compute the top position
  60226. if (this.inverted) {
  60227. navigator.left = navigator.opposite ?
  60228. this.chartWidth - scrollbarHeight -
  60229. navigator.height :
  60230. this.spacing[3] + scrollbarHeight;
  60231. navigator.top = this.plotTop + scrollbarHeight;
  60232. }
  60233. else {
  60234. navigator.left = pick(xAxis.left, this.plotLeft + scrollbarHeight);
  60235. navigator.top = navigator.navigatorOptions.top ||
  60236. this.chartHeight -
  60237. navigator.height -
  60238. scrollbarHeight -
  60239. this.spacing[2] -
  60240. (this.rangeSelector && this.extraBottomMargin ?
  60241. this.rangeSelector.getHeight() :
  60242. 0) -
  60243. ((legendOptions &&
  60244. legendOptions.verticalAlign === 'bottom' &&
  60245. legendOptions.layout !== 'proximate' && // #13392
  60246. legendOptions.enabled &&
  60247. !legendOptions.floating) ?
  60248. legend.legendHeight +
  60249. pick(legendOptions.margin, 10) :
  60250. 0) -
  60251. (this.titleOffset ? this.titleOffset[2] : 0);
  60252. }
  60253. if (xAxis && yAxis) { // false if navigator is disabled (#904)
  60254. if (this.inverted) {
  60255. xAxis.options.left = yAxis.options.left = navigator.left;
  60256. }
  60257. else {
  60258. xAxis.options.top = yAxis.options.top = navigator.top;
  60259. }
  60260. xAxis.setAxisSize();
  60261. yAxis.setAxisSize();
  60262. }
  60263. }
  60264. });
  60265. // Merge options, if no scrolling exists yet
  60266. addEvent(Chart, 'update', function (e) {
  60267. var navigatorOptions = (e.options.navigator || {}),
  60268. scrollbarOptions = (e.options.scrollbar || {});
  60269. if (!this.navigator && !this.scroller &&
  60270. (navigatorOptions.enabled || scrollbarOptions.enabled)) {
  60271. merge(true, this.options.navigator, navigatorOptions);
  60272. merge(true, this.options.scrollbar, scrollbarOptions);
  60273. delete e.options.navigator;
  60274. delete e.options.scrollbar;
  60275. }
  60276. });
  60277. // Initialize navigator, if no scrolling exists yet
  60278. addEvent(Chart, 'afterUpdate', function (event) {
  60279. if (!this.navigator && !this.scroller &&
  60280. (this.options.navigator.enabled ||
  60281. this.options.scrollbar.enabled)) {
  60282. this.scroller = this.navigator = new Navigator(this);
  60283. if (pick(event.redraw, true)) {
  60284. this.redraw(event.animation); // #7067
  60285. }
  60286. }
  60287. });
  60288. // Handle adding new series
  60289. addEvent(Chart, 'afterAddSeries', function () {
  60290. if (this.navigator) {
  60291. // Recompute which series should be shown in navigator, and add them
  60292. this.navigator.setBaseSeries(null, false);
  60293. }
  60294. });
  60295. // Handle updating series
  60296. addEvent(Series, 'afterUpdate', function () {
  60297. if (this.chart.navigator && !this.options.isInternal) {
  60298. this.chart.navigator.setBaseSeries(null, false);
  60299. }
  60300. });
  60301. Chart.prototype.callbacks.push(function (chart) {
  60302. var extremes,
  60303. navigator = chart.navigator;
  60304. // Initialize the navigator
  60305. if (navigator && chart.xAxis[0]) {
  60306. extremes = chart.xAxis[0].getExtremes();
  60307. navigator.render(extremes.min, extremes.max);
  60308. }
  60309. });
  60310. }
  60311. H.Navigator = Navigator;
  60312. return H.Navigator;
  60313. });
  60314. _registerModule(_modules, 'masters/modules/gantt.src.js', [_modules['Core/Globals.js'], _modules['Core/Chart/GanttChart.js']], function (Highcharts, GanttChart) {
  60315. Highcharts.GanttChart = GanttChart;
  60316. Highcharts.ganttChart = GanttChart.ganttChart;
  60317. });
  60318. _registerModule(_modules, 'masters/highcharts-gantt.src.js', [_modules['masters/highcharts.src.js']], function (Highcharts) {
  60319. Highcharts.product = 'Highcharts Gantt';
  60320. return Highcharts;
  60321. });
  60322. _modules['masters/highcharts-gantt.src.js']._modules = _modules;
  60323. return _modules['masters/highcharts-gantt.src.js'];
  60324. }));