stock-tools.src.js 316 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305
  1. /**
  2. * @license Highstock JS v8.1.2 (2020-06-16)
  3. *
  4. * Advanced Highstock tools
  5. *
  6. * (c) 2010-2019 Highsoft AS
  7. * Author: Torstein Honsi
  8. *
  9. * License: www.highcharts.com/license
  10. */
  11. 'use strict';
  12. (function (factory) {
  13. if (typeof module === 'object' && module.exports) {
  14. factory['default'] = factory;
  15. module.exports = factory;
  16. } else if (typeof define === 'function' && define.amd) {
  17. define('highcharts/modules/stock-tools', ['highcharts', 'highcharts/modules/stock'], function (Highcharts) {
  18. factory(Highcharts);
  19. factory.Highcharts = Highcharts;
  20. return factory;
  21. });
  22. } else {
  23. factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);
  24. }
  25. }(function (Highcharts) {
  26. var _modules = Highcharts ? Highcharts._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, 'annotations/eventEmitterMixin.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
  33. /* *
  34. *
  35. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  36. *
  37. * */
  38. var addEvent = U.addEvent, fireEvent = U.fireEvent, inArray = U.inArray, objectEach = U.objectEach, pick = U.pick, removeEvent = U.removeEvent;
  39. /* eslint-disable valid-jsdoc */
  40. /**
  41. * It provides methods for:
  42. * - adding and handling DOM events and a drag event,
  43. * - mapping a mouse move event to the distance between two following events.
  44. * The units of the distance are specific to a transformation,
  45. * e.g. for rotation they are radians, for scaling they are scale factors.
  46. *
  47. * @private
  48. * @mixin
  49. * @memberOf Annotation
  50. */
  51. var eventEmitterMixin = {
  52. /**
  53. * Add emitter events.
  54. */
  55. addEvents: function () {
  56. var emitter = this, addMouseDownEvent = function (element) {
  57. addEvent(element, H.isTouchDevice ? 'touchstart' : 'mousedown', function (e) {
  58. emitter.onMouseDown(e);
  59. });
  60. };
  61. addMouseDownEvent(this.graphic.element);
  62. (emitter.labels || []).forEach(function (label) {
  63. if (label.options.useHTML && label.graphic.text) {
  64. // Mousedown event bound to HTML element (#13070).
  65. addMouseDownEvent(label.graphic.text.element);
  66. }
  67. });
  68. objectEach(emitter.options.events, function (event, type) {
  69. var eventHandler = function (e) {
  70. if (type !== 'click' || !emitter.cancelClick) {
  71. event.call(emitter, emitter.chart.pointer.normalize(e), emitter.target);
  72. }
  73. };
  74. if (inArray(type, emitter.nonDOMEvents || []) === -1) {
  75. emitter.graphic.on(type, eventHandler);
  76. }
  77. else {
  78. addEvent(emitter, type, eventHandler);
  79. }
  80. });
  81. if (emitter.options.draggable) {
  82. addEvent(emitter, H.isTouchDevice ? 'touchmove' : 'drag', emitter.onDrag);
  83. if (!emitter.graphic.renderer.styledMode) {
  84. var cssPointer_1 = {
  85. cursor: {
  86. x: 'ew-resize',
  87. y: 'ns-resize',
  88. xy: 'move'
  89. }[emitter.options.draggable]
  90. };
  91. emitter.graphic.css(cssPointer_1);
  92. (emitter.labels || []).forEach(function (label) {
  93. if (label.options.useHTML && label.graphic.text) {
  94. label.graphic.text.css(cssPointer_1);
  95. }
  96. });
  97. }
  98. }
  99. if (!emitter.isUpdating) {
  100. fireEvent(emitter, 'add');
  101. }
  102. },
  103. /**
  104. * Remove emitter document events.
  105. */
  106. removeDocEvents: function () {
  107. if (this.removeDrag) {
  108. this.removeDrag = this.removeDrag();
  109. }
  110. if (this.removeMouseUp) {
  111. this.removeMouseUp = this.removeMouseUp();
  112. }
  113. },
  114. /**
  115. * Mouse down handler.
  116. */
  117. onMouseDown: function (e) {
  118. var emitter = this, pointer = emitter.chart.pointer, prevChartX, prevChartY;
  119. if (e.preventDefault) {
  120. e.preventDefault();
  121. }
  122. // On right click, do nothing:
  123. if (e.button === 2) {
  124. return;
  125. }
  126. e = pointer.normalize(e);
  127. prevChartX = e.chartX;
  128. prevChartY = e.chartY;
  129. emitter.cancelClick = false;
  130. emitter.chart.hasDraggedAnnotation = true;
  131. emitter.removeDrag = addEvent(H.doc, H.isTouchDevice ? 'touchmove' : 'mousemove', function (e) {
  132. emitter.hasDragged = true;
  133. e = pointer.normalize(e);
  134. e.prevChartX = prevChartX;
  135. e.prevChartY = prevChartY;
  136. fireEvent(emitter, 'drag', e);
  137. prevChartX = e.chartX;
  138. prevChartY = e.chartY;
  139. });
  140. emitter.removeMouseUp = addEvent(H.doc, H.isTouchDevice ? 'touchend' : 'mouseup', function (e) {
  141. emitter.cancelClick = emitter.hasDragged;
  142. emitter.hasDragged = false;
  143. emitter.chart.hasDraggedAnnotation = false;
  144. // ControlPoints vs Annotation:
  145. fireEvent(pick(emitter.target, emitter), 'afterUpdate');
  146. emitter.onMouseUp(e);
  147. });
  148. },
  149. /**
  150. * Mouse up handler.
  151. */
  152. onMouseUp: function (_e) {
  153. var chart = this.chart, annotation = this.target || this, annotationsOptions = chart.options.annotations, index = chart.annotations.indexOf(annotation);
  154. this.removeDocEvents();
  155. annotationsOptions[index] = annotation.options;
  156. },
  157. /**
  158. * Drag and drop event. All basic annotations should share this
  159. * capability as well as the extended ones.
  160. */
  161. onDrag: function (e) {
  162. if (this.chart.isInsidePlot(e.chartX - this.chart.plotLeft, e.chartY - this.chart.plotTop)) {
  163. var translation = this.mouseMoveToTranslation(e);
  164. if (this.options.draggable === 'x') {
  165. translation.y = 0;
  166. }
  167. if (this.options.draggable === 'y') {
  168. translation.x = 0;
  169. }
  170. if (this.points.length) {
  171. this.translate(translation.x, translation.y);
  172. }
  173. else {
  174. this.shapes.forEach(function (shape) {
  175. shape.translate(translation.x, translation.y);
  176. });
  177. this.labels.forEach(function (label) {
  178. label.translate(translation.x, translation.y);
  179. });
  180. }
  181. this.redraw(false);
  182. }
  183. },
  184. /**
  185. * Map mouse move event to the radians.
  186. */
  187. mouseMoveToRadians: function (e, cx, cy) {
  188. var prevDy = e.prevChartY - cy, prevDx = e.prevChartX - cx, dy = e.chartY - cy, dx = e.chartX - cx, temp;
  189. if (this.chart.inverted) {
  190. temp = prevDx;
  191. prevDx = prevDy;
  192. prevDy = temp;
  193. temp = dx;
  194. dx = dy;
  195. dy = temp;
  196. }
  197. return Math.atan2(dy, dx) - Math.atan2(prevDy, prevDx);
  198. },
  199. /**
  200. * Map mouse move event to the distance between two following events.
  201. */
  202. mouseMoveToTranslation: function (e) {
  203. var dx = e.chartX - e.prevChartX, dy = e.chartY - e.prevChartY, temp;
  204. if (this.chart.inverted) {
  205. temp = dy;
  206. dy = dx;
  207. dx = temp;
  208. }
  209. return {
  210. x: dx,
  211. y: dy
  212. };
  213. },
  214. /**
  215. * Map mouse move to the scale factors.
  216. *
  217. * @param {Object} e event
  218. * @param {number} cx center x
  219. * @param {number} cy center y
  220. **/
  221. mouseMoveToScale: function (e, cx, cy) {
  222. var prevDx = e.prevChartX - cx, prevDy = e.prevChartY - cy, dx = e.chartX - cx, dy = e.chartY - cy, sx = (dx || 1) / (prevDx || 1), sy = (dy || 1) / (prevDy || 1), temp;
  223. if (this.chart.inverted) {
  224. temp = sy;
  225. sy = sx;
  226. sx = temp;
  227. }
  228. return {
  229. x: sx,
  230. y: sy
  231. };
  232. },
  233. /**
  234. * Destroy the event emitter.
  235. */
  236. destroy: function () {
  237. this.removeDocEvents();
  238. removeEvent(this);
  239. this.hcEvents = null;
  240. }
  241. };
  242. return eventEmitterMixin;
  243. });
  244. _registerModule(_modules, 'annotations/ControlPoint.js', [_modules['parts/Utilities.js'], _modules['annotations/eventEmitterMixin.js']], function (U, eventEmitterMixin) {
  245. /* *
  246. *
  247. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  248. *
  249. * */
  250. /**
  251. * Callback to modify annotation's possitioner controls.
  252. *
  253. * @callback Highcharts.AnnotationControlPointPositionerFunction
  254. * @param {Highcharts.AnnotationControlPoint} this
  255. * @param {Highcharts.AnnotationControllable} target
  256. * @return {Highcharts.PositionObject}
  257. */
  258. var extend = U.extend, merge = U.merge, pick = U.pick;
  259. /* eslint-disable no-invalid-this, valid-jsdoc */
  260. /**
  261. * A control point class which is a connection between controllable
  262. * transform methods and a user actions.
  263. *
  264. * @requires modules/annotations
  265. *
  266. * @class
  267. * @name Highcharts.AnnotationControlPoint
  268. *
  269. * @hideconstructor
  270. *
  271. * @param {Highcharts.Chart} chart
  272. * A chart instance.
  273. *
  274. * @param {Highcharts.AnnotationControllable} target
  275. * A controllable instance which is a target for a control point.
  276. *
  277. * @param {Highcharts.AnnotationControlPointOptionsObject} options
  278. * An options object.
  279. *
  280. * @param {number} [index]
  281. * Point index.
  282. */
  283. var ControlPoint = /** @class */ (function () {
  284. function ControlPoint(chart, target, options, index) {
  285. /**
  286. *
  287. * Properties
  288. *
  289. */
  290. this.addEvents = eventEmitterMixin.addEvents;
  291. this.graphic = void 0;
  292. this.mouseMoveToRadians = eventEmitterMixin.mouseMoveToRadians;
  293. this.mouseMoveToScale = eventEmitterMixin.mouseMoveToScale;
  294. this.mouseMoveToTranslation = eventEmitterMixin.mouseMoveToTranslation;
  295. this.onDrag = eventEmitterMixin.onDrag;
  296. this.onMouseDown = eventEmitterMixin.onMouseDown;
  297. this.onMouseUp = eventEmitterMixin.onMouseUp;
  298. this.removeDocEvents = eventEmitterMixin.removeDocEvents;
  299. /**
  300. *
  301. * Functions
  302. *
  303. */
  304. /**
  305. * List of events for `anntation.options.events` that should not be
  306. * added to `annotation.graphic` but to the `annotation`.
  307. * @private
  308. * @name Highcharts.AnnotationControlPoint#nonDOMEvents
  309. * @type {Array<string>}
  310. */
  311. this.nonDOMEvents = ['drag'];
  312. this.chart = chart;
  313. this.target = target;
  314. this.options = options;
  315. this.index = pick(options.index, index);
  316. }
  317. /**
  318. * Set the visibility of the control point.
  319. *
  320. * @function Highcharts.AnnotationControlPoint#setVisibility
  321. *
  322. * @param {boolean} visible
  323. * Visibility of the control point.
  324. *
  325. * @return {void}
  326. */
  327. ControlPoint.prototype.setVisibility = function (visible) {
  328. this.graphic.attr('visibility', visible ? 'visible' : 'hidden');
  329. this.options.visible = visible;
  330. };
  331. /**
  332. * Render the control point.
  333. * @private
  334. */
  335. ControlPoint.prototype.render = function () {
  336. var chart = this.chart, options = this.options;
  337. this.graphic = chart.renderer
  338. .symbol(options.symbol, 0, 0, options.width, options.height)
  339. .add(chart.controlPointsGroup)
  340. .css(options.style);
  341. this.setVisibility(options.visible);
  342. // npm test -- --tests "highcharts/annotations-advanced/*"
  343. this.addEvents();
  344. };
  345. /**
  346. * Redraw the control point.
  347. * @private
  348. * @param {boolean} [animation]
  349. */
  350. ControlPoint.prototype.redraw = function (animation) {
  351. this.graphic[animation ? 'animate' : 'attr'](this.options.positioner.call(this, this.target));
  352. };
  353. /**
  354. * Destroy the control point.
  355. * @private
  356. */
  357. ControlPoint.prototype.destroy = function () {
  358. eventEmitterMixin.destroy.call(this);
  359. if (this.graphic) {
  360. this.graphic = this.graphic.destroy();
  361. }
  362. this.chart = null;
  363. this.target = null;
  364. this.options = null;
  365. };
  366. /**
  367. * Update the control point.
  368. *
  369. * @function Highcharts.AnnotationControlPoint#update
  370. *
  371. * @param {Partial<Highcharts.AnnotationControlPointOptionsObject>} userOptions
  372. * New options for the control point.
  373. *
  374. * @return {void}
  375. */
  376. ControlPoint.prototype.update = function (userOptions) {
  377. var chart = this.chart, target = this.target, index = this.index, options = merge(true, this.options, userOptions);
  378. this.destroy();
  379. this.constructor(chart, target, options, index);
  380. this.render(chart.controlPointsGroup);
  381. this.redraw();
  382. };
  383. return ControlPoint;
  384. }());
  385. return ControlPoint;
  386. });
  387. _registerModule(_modules, 'annotations/MockPoint.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
  388. /* *
  389. *
  390. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  391. *
  392. * */
  393. /**
  394. * @private
  395. * @interface Highcharts.AnnotationMockLabelOptionsObject
  396. */ /**
  397. * Point instance of the point.
  398. * @name Highcharts.AnnotationMockLabelOptionsObject#point
  399. * @type {Highcharts.AnnotationMockPoint}
  400. */ /**
  401. * X value translated to x axis scale.
  402. * @name Highcharts.AnnotationMockLabelOptionsObject#x
  403. * @type {number|null}
  404. */ /**
  405. * Y value translated to y axis scale.
  406. * @name Highcharts.AnnotationMockLabelOptionsObject#y
  407. * @type {number|null}
  408. */
  409. /**
  410. * A mock series instance imitating a real series from a real point.
  411. * @private
  412. * @interface Highcharts.AnnotationMockSeries
  413. */ /**
  414. * Whether a series is visible.
  415. * @name Highcharts.AnnotationMockSeries#visible
  416. * @type {boolean}
  417. */ /**
  418. * A chart instance.
  419. * @name Highcharts.AnnotationMockSeries#chart
  420. * @type {Highcharts.Chart}
  421. */ /**
  422. * @name Highcharts.AnnotationMockSeries#getPlotBox
  423. * @type {Function}
  424. */
  425. /**
  426. * Indicates if this is a mock point for an annotation.
  427. * @name Highcharts.Point#mock
  428. * @type {boolean|undefined}
  429. */
  430. var defined = U.defined, extend = U.extend, fireEvent = U.fireEvent;
  431. /* eslint-disable no-invalid-this, valid-jsdoc */
  432. /**
  433. * A trimmed point object which imitates {@link Highchart.Point} class. It is
  434. * created when there is a need of pointing to some chart's position using axis
  435. * values or pixel values
  436. *
  437. * @requires modules/annotations
  438. *
  439. * @private
  440. * @class
  441. * @name Highcharts.AnnotationMockPoint
  442. *
  443. * @hideconstructor
  444. *
  445. * @param {Highcharts.Chart} chart
  446. * The chart instance.
  447. *
  448. * @param {Highcharts.AnnotationControllable|null} target
  449. * The related controllable.
  450. *
  451. * @param {Highcharts.AnnotationMockPointOptionsObject|Function} options
  452. * The options object.
  453. */
  454. var MockPoint = /** @class */ (function () {
  455. function MockPoint(chart, target, options) {
  456. this.isInside = void 0;
  457. this.plotX = void 0;
  458. this.plotY = void 0;
  459. this.x = void 0;
  460. this.y = void 0;
  461. /* *
  462. *
  463. * Functions
  464. *
  465. * */
  466. /**
  467. * A flag indicating that a point is not the real one.
  468. *
  469. * @type {boolean}
  470. * @default true
  471. */
  472. this.mock = true;
  473. /**
  474. * A mock series instance imitating a real series from a real point.
  475. *
  476. * @name Annotation.AnnotationMockPoint#series
  477. * @type {Highcharts.AnnotationMockSeries}
  478. */
  479. this.series = {
  480. visible: true,
  481. chart: chart,
  482. getPlotBox: H.Series.prototype.getPlotBox
  483. };
  484. /**
  485. * @name Annotation.AnnotationMockPoint#target
  486. * @type {Highcharts.AnnotationControllable|null}
  487. */
  488. this.target = target || null;
  489. /**
  490. * Options for the mock point.
  491. *
  492. * @name Annotation.AnnotationMockPoint#options
  493. * @type {Highcharts.AnnotationsMockPointOptionsObject}
  494. */
  495. this.options = options;
  496. /**
  497. * If an xAxis is set it represents the point's value in terms of the
  498. * xAxis.
  499. *
  500. * @name Annotation.AnnotationMockPoint#x
  501. * @type {number|undefined}
  502. */
  503. /**
  504. * If an yAxis is set it represents the point's value in terms of the
  505. * yAxis.
  506. *
  507. * @name Annotation.AnnotationMockPoint#y
  508. * @type {number|undefined}
  509. */
  510. /**
  511. * It represents the point's pixel x coordinate relative to its plot
  512. * box.
  513. *
  514. * @name Annotation.AnnotationMockPoint#plotX
  515. * @type {number|undefined}
  516. */
  517. /**
  518. * It represents the point's pixel y position relative to its plot box.
  519. *
  520. * @name Annotation.AnnotationMockPoint#plotY
  521. * @type {number|undefined}
  522. */
  523. /**
  524. * Whether the point is inside the plot box.
  525. *
  526. * @name Annotation.AnnotationMockPoint#isInside
  527. * @type {boolean|undefined}
  528. */
  529. this.applyOptions(this.getOptions());
  530. }
  531. /**
  532. * Create a mock point from a real Highcharts point.
  533. *
  534. * @private
  535. * @static
  536. *
  537. * @param {Highcharts.Point} point
  538. *
  539. * @return {Highcharts.AnnotationMockPoint}
  540. * A mock point instance.
  541. */
  542. MockPoint.fromPoint = function (point) {
  543. return new MockPoint(point.series.chart, null, {
  544. x: point.x,
  545. y: point.y,
  546. xAxis: point.series.xAxis,
  547. yAxis: point.series.yAxis
  548. });
  549. };
  550. /**
  551. * Get the pixel position from the point like object.
  552. *
  553. * @private
  554. * @static
  555. *
  556. * @param {Highcharts.AnnotationPointType} point
  557. *
  558. * @param {boolean} [paneCoordinates]
  559. * whether the pixel position should be relative
  560. *
  561. * @return {Highcharts.PositionObject} pixel position
  562. */
  563. MockPoint.pointToPixels = function (point, paneCoordinates) {
  564. var series = point.series, chart = series.chart, x = point.plotX, y = point.plotY, plotBox;
  565. if (chart.inverted) {
  566. if (point.mock) {
  567. x = point.plotY;
  568. y = point.plotX;
  569. }
  570. else {
  571. x = chart.plotWidth - point.plotY;
  572. y = chart.plotHeight - point.plotX;
  573. }
  574. }
  575. if (series && !paneCoordinates) {
  576. plotBox = series.getPlotBox();
  577. x += plotBox.translateX;
  578. y += plotBox.translateY;
  579. }
  580. return {
  581. x: x,
  582. y: y
  583. };
  584. };
  585. /**
  586. * Get fresh mock point options from the point like object.
  587. *
  588. * @private
  589. * @static
  590. *
  591. * @param {Highcharts.AnnotationPointType} point
  592. *
  593. * @return {Highcharts.AnnotationMockPointOptionsObject}
  594. * A mock point's options.
  595. */
  596. MockPoint.pointToOptions = function (point) {
  597. return {
  598. x: point.x,
  599. y: point.y,
  600. xAxis: point.series.xAxis,
  601. yAxis: point.series.yAxis
  602. };
  603. };
  604. /**
  605. * Check if the point has dynamic options.
  606. * @private
  607. * @return {boolean}
  608. * A positive flag if the point has dynamic options.
  609. */
  610. MockPoint.prototype.hasDynamicOptions = function () {
  611. return typeof this.options === 'function';
  612. };
  613. /**
  614. * Get the point's options.
  615. * @private
  616. * @return {Highcharts.AnnotationMockPointOptionsObject}
  617. * The mock point's options.
  618. */
  619. MockPoint.prototype.getOptions = function () {
  620. return this.hasDynamicOptions() ?
  621. this.options(this.target) :
  622. this.options;
  623. };
  624. /**
  625. * Apply options for the point.
  626. * @private
  627. * @param {Highcharts.AnnotationMockPointOptionsObject} options
  628. */
  629. MockPoint.prototype.applyOptions = function (options) {
  630. this.command = options.command;
  631. this.setAxis(options, 'x');
  632. this.setAxis(options, 'y');
  633. this.refresh();
  634. };
  635. /**
  636. * Set x or y axis.
  637. * @private
  638. * @param {Highcharts.AnnotationMockPointOptionsObject} options
  639. * @param {string} xOrY
  640. * 'x' or 'y' string literal
  641. */
  642. MockPoint.prototype.setAxis = function (options, xOrY) {
  643. var axisName = (xOrY + 'Axis'), axisOptions = options[axisName], chart = this.series.chart;
  644. this.series[axisName] =
  645. axisOptions instanceof H.Axis ?
  646. axisOptions :
  647. defined(axisOptions) ?
  648. (chart[axisName][axisOptions] ||
  649. chart.get(axisOptions)) :
  650. null;
  651. };
  652. /**
  653. * Transform the mock point to an anchor (relative position on the chart).
  654. * @private
  655. * @return {Array<number>}
  656. * A quadruple of numbers which denotes x, y, width and height of the box
  657. **/
  658. MockPoint.prototype.toAnchor = function () {
  659. var anchor = [this.plotX, this.plotY, 0, 0];
  660. if (this.series.chart.inverted) {
  661. anchor[0] = this.plotY;
  662. anchor[1] = this.plotX;
  663. }
  664. return anchor;
  665. };
  666. /**
  667. * Returns a label config object - the same as
  668. * Highcharts.Point.prototype.getLabelConfig
  669. * @private
  670. * @return {Highcharts.AnnotationMockLabelOptionsObject} the point's label config
  671. */
  672. MockPoint.prototype.getLabelConfig = function () {
  673. return {
  674. x: this.x,
  675. y: this.y,
  676. point: this
  677. };
  678. };
  679. /**
  680. * Check if the point is inside its pane.
  681. * @private
  682. * @return {boolean} A flag indicating whether the point is inside the pane.
  683. */
  684. MockPoint.prototype.isInsidePlot = function () {
  685. var plotX = this.plotX, plotY = this.plotY, xAxis = this.series.xAxis, yAxis = this.series.yAxis, e = {
  686. x: plotX,
  687. y: plotY,
  688. isInsidePlot: true
  689. };
  690. if (xAxis) {
  691. e.isInsidePlot = defined(plotX) && plotX >= 0 && plotX <= xAxis.len;
  692. }
  693. if (yAxis) {
  694. e.isInsidePlot =
  695. e.isInsidePlot &&
  696. defined(plotY) &&
  697. plotY >= 0 && plotY <= yAxis.len;
  698. }
  699. fireEvent(this.series.chart, 'afterIsInsidePlot', e);
  700. return e.isInsidePlot;
  701. };
  702. /**
  703. * Refresh point values and coordinates based on its options.
  704. * @private
  705. */
  706. MockPoint.prototype.refresh = function () {
  707. var series = this.series, xAxis = series.xAxis, yAxis = series.yAxis, options = this.getOptions();
  708. if (xAxis) {
  709. this.x = options.x;
  710. this.plotX = xAxis.toPixels(options.x, true);
  711. }
  712. else {
  713. this.x = null;
  714. this.plotX = options.x;
  715. }
  716. if (yAxis) {
  717. this.y = options.y;
  718. this.plotY = yAxis.toPixels(options.y, true);
  719. }
  720. else {
  721. this.y = null;
  722. this.plotY = options.y;
  723. }
  724. this.isInside = this.isInsidePlot();
  725. };
  726. /**
  727. * Translate the point.
  728. *
  729. * @private
  730. *
  731. * @param {number|undefined} cx
  732. * Origin x transformation.
  733. *
  734. * @param {number|undefined} cy
  735. * Origin y transformation.
  736. *
  737. * @param {number} dx
  738. * Translation for x coordinate.
  739. *
  740. * @param {number} dy
  741. * Translation for y coordinate.
  742. **/
  743. MockPoint.prototype.translate = function (_cx, _cy, dx, dy) {
  744. if (!this.hasDynamicOptions()) {
  745. this.plotX += dx;
  746. this.plotY += dy;
  747. this.refreshOptions();
  748. }
  749. };
  750. /**
  751. * Scale the point.
  752. *
  753. * @private
  754. *
  755. * @param {number} cx
  756. * Origin x transformation.
  757. *
  758. * @param {number} cy
  759. * Origin y transformation.
  760. *
  761. * @param {number} sx
  762. * Scale factor x.
  763. *
  764. * @param {number} sy
  765. * Scale factor y.
  766. */
  767. MockPoint.prototype.scale = function (cx, cy, sx, sy) {
  768. if (!this.hasDynamicOptions()) {
  769. var x = this.plotX * sx, y = this.plotY * sy, tx = (1 - sx) * cx, ty = (1 - sy) * cy;
  770. this.plotX = tx + x;
  771. this.plotY = ty + y;
  772. this.refreshOptions();
  773. }
  774. };
  775. /**
  776. * Rotate the point.
  777. * @private
  778. * @param {number} cx origin x rotation
  779. * @param {number} cy origin y rotation
  780. * @param {number} radians
  781. */
  782. MockPoint.prototype.rotate = function (cx, cy, radians) {
  783. if (!this.hasDynamicOptions()) {
  784. var cos = Math.cos(radians), sin = Math.sin(radians), x = this.plotX, y = this.plotY, tx, ty;
  785. x -= cx;
  786. y -= cy;
  787. tx = x * cos - y * sin;
  788. ty = x * sin + y * cos;
  789. this.plotX = tx + cx;
  790. this.plotY = ty + cy;
  791. this.refreshOptions();
  792. }
  793. };
  794. /**
  795. * Refresh point options based on its plot coordinates.
  796. * @private
  797. */
  798. MockPoint.prototype.refreshOptions = function () {
  799. var series = this.series, xAxis = series.xAxis, yAxis = series.yAxis;
  800. this.x = this.options.x = xAxis ?
  801. this.options.x = xAxis.toValue(this.plotX, true) :
  802. this.plotX;
  803. this.y = this.options.y = yAxis ?
  804. yAxis.toValue(this.plotY, true) :
  805. this.plotY;
  806. };
  807. return MockPoint;
  808. }());
  809. return MockPoint;
  810. });
  811. _registerModule(_modules, 'annotations/controllable/controllableMixin.js', [_modules['annotations/ControlPoint.js'], _modules['annotations/MockPoint.js'], _modules['parts/Tooltip.js'], _modules['parts/Utilities.js']], function (ControlPoint, MockPoint, Tooltip, U) {
  812. /* *
  813. *
  814. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  815. *
  816. * */
  817. var isObject = U.isObject, isString = U.isString, merge = U.merge, splat = U.splat;
  818. /**
  819. * An object which denots a controllable's anchor positions - relative and
  820. * absolute.
  821. *
  822. * @private
  823. * @interface Highcharts.AnnotationAnchorObject
  824. */ /**
  825. * Relative to the plot area position
  826. * @name Highcharts.AnnotationAnchorObject#relativePosition
  827. * @type {Highcharts.BBoxObject}
  828. */ /**
  829. * Absolute position
  830. * @name Highcharts.AnnotationAnchorObject#absolutePosition
  831. * @type {Highcharts.BBoxObject}
  832. */
  833. /**
  834. * @interface Highcharts.AnnotationControllable
  835. */ /**
  836. * @name Highcharts.AnnotationControllable#annotation
  837. * @type {Highcharts.Annotation}
  838. */ /**
  839. * @name Highcharts.AnnotationControllable#chart
  840. * @type {Highcharts.Chart}
  841. */ /**
  842. * @name Highcharts.AnnotationControllable#collection
  843. * @type {string}
  844. */ /**
  845. * @private
  846. * @name Highcharts.AnnotationControllable#controlPoints
  847. * @type {Array<Highcharts.AnnotationControlPoint>}
  848. */ /**
  849. * @name Highcharts.AnnotationControllable#points
  850. * @type {Array<Highcharts.Point>}
  851. */
  852. /* eslint-disable no-invalid-this, valid-jsdoc */
  853. /**
  854. * It provides methods for handling points, control points
  855. * and points transformations.
  856. *
  857. * @private
  858. * @mixin
  859. * @name Highcharts.AnnotationControllableMixin
  860. */
  861. var controllableMixin = {
  862. /**
  863. * Init the controllable
  864. */
  865. init: function (annotation, options, index) {
  866. this.annotation = annotation;
  867. this.chart = annotation.chart;
  868. this.options = options;
  869. this.points = [];
  870. this.controlPoints = [];
  871. this.index = index;
  872. this.linkPoints();
  873. this.addControlPoints();
  874. },
  875. /**
  876. * Redirect attr usage on the controllable graphic element.
  877. */
  878. attr: function () {
  879. this.graphic.attr.apply(this.graphic, arguments);
  880. },
  881. /**
  882. * Get the controllable's points options.
  883. *
  884. * @return {Array<Highcharts.PointOptionsObject>}
  885. * An array of points' options.
  886. */
  887. getPointsOptions: function () {
  888. var options = this.options;
  889. return (options.points || (options.point && splat(options.point)));
  890. },
  891. /**
  892. * Utility function for mapping item's options
  893. * to element's attribute
  894. *
  895. * @param {Highcharts.AnnotationsLabelsOptions|Highcharts.AnnotationsShapesOptions} options
  896. *
  897. * @return {Highcharts.SVGAttributes}
  898. * Mapped options.
  899. */
  900. attrsFromOptions: function (options) {
  901. var map = this.constructor.attrsMap, attrs = {}, key, mappedKey, styledMode = this.chart.styledMode;
  902. for (key in options) { // eslint-disable-line guard-for-in
  903. mappedKey = map[key];
  904. if (mappedKey &&
  905. (!styledMode ||
  906. ['fill', 'stroke', 'stroke-width']
  907. .indexOf(mappedKey) === -1)) {
  908. attrs[mappedKey] = options[key];
  909. }
  910. }
  911. return attrs;
  912. },
  913. /**
  914. * Returns object which denotes anchor position - relative and absolute.
  915. *
  916. * @param {Highcharts.AnnotationPointType} point
  917. * A point like object.
  918. *
  919. * @return {Highcharts.AnnotationAnchorObject} a controllable anchor
  920. */
  921. anchor: function (point) {
  922. var plotBox = point.series.getPlotBox(), box = point.mock ?
  923. point.toAnchor() :
  924. Tooltip.prototype.getAnchor.call({
  925. chart: point.series.chart
  926. }, point), anchor = {
  927. x: box[0] + (this.options.x || 0),
  928. y: box[1] + (this.options.y || 0),
  929. height: box[2] || 0,
  930. width: box[3] || 0
  931. };
  932. return {
  933. relativePosition: anchor,
  934. absolutePosition: merge(anchor, {
  935. x: anchor.x + plotBox.translateX,
  936. y: anchor.y + plotBox.translateY
  937. })
  938. };
  939. },
  940. /**
  941. * Map point's options to a point-like object.
  942. *
  943. * @param {string|Function|Highcharts.AnnotationMockPointOptionsObject|Highcharts.AnnotationPointType} pointOptions
  944. * Point's options.
  945. *
  946. * @param {Highcharts.AnnotationPointType} point
  947. * A point-like instance.
  948. *
  949. * @return {Highcharts.AnnotationPointType|null}
  950. * if the point is found/set returns this point, otherwise null
  951. */
  952. point: function (pointOptions, point) {
  953. if (pointOptions && pointOptions.series) {
  954. return pointOptions;
  955. }
  956. if (!point || point.series === null) {
  957. if (isObject(pointOptions)) {
  958. point = new MockPoint(this.chart, this, pointOptions);
  959. }
  960. else if (isString(pointOptions)) {
  961. point = this.chart.get(pointOptions) || null;
  962. }
  963. else if (typeof pointOptions === 'function') {
  964. var pointConfig = pointOptions.call(point, this);
  965. point = pointConfig.series ?
  966. pointConfig :
  967. new MockPoint(this.chart, this, pointOptions);
  968. }
  969. }
  970. return point;
  971. },
  972. /**
  973. * Find point-like objects based on points options.
  974. *
  975. * @return {Array<Annotation.PointLike>} an array of point-like objects
  976. */
  977. linkPoints: function () {
  978. var pointsOptions = this.getPointsOptions(), points = this.points, len = (pointsOptions && pointsOptions.length) || 0, i, point;
  979. for (i = 0; i < len; i++) {
  980. point = this.point(pointsOptions[i], points[i]);
  981. if (!point) {
  982. points.length = 0;
  983. return;
  984. }
  985. if (point.mock) {
  986. point.refresh();
  987. }
  988. points[i] = point;
  989. }
  990. return points;
  991. },
  992. /**
  993. * Add control points to a controllable.
  994. */
  995. addControlPoints: function () {
  996. var controlPointsOptions = this.options.controlPoints;
  997. (controlPointsOptions || []).forEach(function (controlPointOptions, i) {
  998. var options = merge(this.options.controlPointOptions, controlPointOptions);
  999. if (!options.index) {
  1000. options.index = i;
  1001. }
  1002. controlPointsOptions[i] = options;
  1003. this.controlPoints.push(new ControlPoint(this.chart, this, options));
  1004. }, this);
  1005. },
  1006. /**
  1007. * Check if a controllable should be rendered/redrawn.
  1008. *
  1009. * @return {boolean}
  1010. * Whether a controllable should be drawn.
  1011. */
  1012. shouldBeDrawn: function () {
  1013. return Boolean(this.points.length);
  1014. },
  1015. /**
  1016. * Render a controllable.
  1017. */
  1018. render: function (_parentGroup) {
  1019. this.controlPoints.forEach(function (controlPoint) {
  1020. controlPoint.render();
  1021. });
  1022. },
  1023. /**
  1024. * Redraw a controllable.
  1025. *
  1026. * @param {boolean} [animation]
  1027. */
  1028. redraw: function (animation) {
  1029. this.controlPoints.forEach(function (controlPoint) {
  1030. controlPoint.redraw(animation);
  1031. });
  1032. },
  1033. /**
  1034. * Transform a controllable with a specific transformation.
  1035. *
  1036. * @param {string} transformation a transformation name
  1037. * @param {number|null} cx origin x transformation
  1038. * @param {number|null} cy origin y transformation
  1039. * @param {number} p1 param for the transformation
  1040. * @param {number} [p2] param for the transformation
  1041. */
  1042. transform: function (transformation, cx, cy, p1, p2) {
  1043. if (this.chart.inverted) {
  1044. var temp = cx;
  1045. cx = cy;
  1046. cy = temp;
  1047. }
  1048. this.points.forEach(function (point, i) {
  1049. this.transformPoint(transformation, cx, cy, p1, p2, i);
  1050. }, this);
  1051. },
  1052. /**
  1053. * Transform a point with a specific transformation
  1054. * If a transformed point is a real point it is replaced with
  1055. * the mock point.
  1056. *
  1057. * @param {string} transformation a transformation name
  1058. * @param {number|null} cx origin x transformation
  1059. * @param {number|null} cy origin y transformation
  1060. * @param {number} p1 param for the transformation
  1061. * @param {number|undefined} p2 param for the transformation
  1062. * @param {number} i index of the point
  1063. */
  1064. transformPoint: function (transformation, cx, cy, p1, p2, i) {
  1065. var point = this.points[i];
  1066. if (!point.mock) {
  1067. point = this.points[i] = MockPoint.fromPoint(point);
  1068. }
  1069. point[transformation](cx, cy, p1, p2);
  1070. },
  1071. /**
  1072. * Translate a controllable.
  1073. *
  1074. * @param {number} dx translation for x coordinate
  1075. * @param {number} dy translation for y coordinate
  1076. **/
  1077. translate: function (dx, dy) {
  1078. this.transform('translate', null, null, dx, dy);
  1079. },
  1080. /**
  1081. * Translate a specific point within a controllable.
  1082. *
  1083. * @param {number} dx translation for x coordinate
  1084. * @param {number} dy translation for y coordinate
  1085. * @param {number} i index of the point
  1086. **/
  1087. translatePoint: function (dx, dy, i) {
  1088. this.transformPoint('translate', null, null, dx, dy, i);
  1089. },
  1090. /**
  1091. * Translate shape within controllable item.
  1092. * Replaces `controllable.translate` method.
  1093. *
  1094. * @param {number} dx translation for x coordinate
  1095. * @param {number} dy translation for y coordinate
  1096. */
  1097. translateShape: function (dx, dy) {
  1098. var chart = this.annotation.chart,
  1099. // Annotation.options
  1100. shapeOptions = this.annotation.userOptions,
  1101. // Chart.options.annotations
  1102. annotationIndex = chart.annotations.indexOf(this.annotation), chartOptions = chart.options.annotations[annotationIndex];
  1103. this.translatePoint(dx, dy, 0);
  1104. // Options stored in:
  1105. // - chart (for exporting)
  1106. // - current config (for redraws)
  1107. chartOptions[this.collection][this.index].point = this.options.point;
  1108. shapeOptions[this.collection][this.index].point = this.options.point;
  1109. },
  1110. /**
  1111. * Rotate a controllable.
  1112. *
  1113. * @param {number} cx origin x rotation
  1114. * @param {number} cy origin y rotation
  1115. * @param {number} radians
  1116. **/
  1117. rotate: function (cx, cy, radians) {
  1118. this.transform('rotate', cx, cy, radians);
  1119. },
  1120. /**
  1121. * Scale a controllable.
  1122. *
  1123. * @param {number} cx origin x rotation
  1124. * @param {number} cy origin y rotation
  1125. * @param {number} sx scale factor x
  1126. * @param {number} sy scale factor y
  1127. */
  1128. scale: function (cx, cy, sx, sy) {
  1129. this.transform('scale', cx, cy, sx, sy);
  1130. },
  1131. /**
  1132. * Set control points' visibility.
  1133. *
  1134. * @param {boolean} visible
  1135. */
  1136. setControlPointsVisibility: function (visible) {
  1137. this.controlPoints.forEach(function (controlPoint) {
  1138. controlPoint.setVisibility(visible);
  1139. });
  1140. },
  1141. /**
  1142. * Destroy a controllable.
  1143. */
  1144. destroy: function () {
  1145. if (this.graphic) {
  1146. this.graphic = this.graphic.destroy();
  1147. }
  1148. if (this.tracker) {
  1149. this.tracker = this.tracker.destroy();
  1150. }
  1151. this.controlPoints.forEach(function (controlPoint) {
  1152. controlPoint.destroy();
  1153. });
  1154. this.chart = null;
  1155. this.points = null;
  1156. this.controlPoints = null;
  1157. this.options = null;
  1158. if (this.annotation) {
  1159. this.annotation = null;
  1160. }
  1161. },
  1162. /**
  1163. * Update a controllable.
  1164. *
  1165. * @param {Object} newOptions
  1166. */
  1167. update: function (newOptions) {
  1168. var annotation = this.annotation, options = merge(true, this.options, newOptions), parentGroup = this.graphic.parentGroup;
  1169. this.destroy();
  1170. this.constructor(annotation, options);
  1171. this.render(parentGroup);
  1172. this.redraw();
  1173. }
  1174. };
  1175. return controllableMixin;
  1176. });
  1177. _registerModule(_modules, 'annotations/controllable/markerMixin.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
  1178. /* *
  1179. *
  1180. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1181. *
  1182. * */
  1183. var addEvent = U.addEvent, defined = U.defined, merge = U.merge, objectEach = U.objectEach, uniqueKey = U.uniqueKey;
  1184. /**
  1185. * Options for configuring markers for annotations.
  1186. *
  1187. * An example of the arrow marker:
  1188. * <pre>
  1189. * {
  1190. * arrow: {
  1191. * id: 'arrow',
  1192. * tagName: 'marker',
  1193. * refY: 5,
  1194. * refX: 5,
  1195. * markerWidth: 10,
  1196. * markerHeight: 10,
  1197. * children: [{
  1198. * tagName: 'path',
  1199. * attrs: {
  1200. * d: 'M 0 0 L 10 5 L 0 10 Z',
  1201. * strokeWidth: 0
  1202. * }
  1203. * }]
  1204. * }
  1205. * }
  1206. * </pre>
  1207. *
  1208. * @sample highcharts/annotations/custom-markers/
  1209. * Define a custom marker for annotations
  1210. *
  1211. * @sample highcharts/css/annotations-markers/
  1212. * Define markers in a styled mode
  1213. *
  1214. * @type {Highcharts.Dictionary<Highcharts.SVGDefinitionObject>}
  1215. * @since 6.0.0
  1216. * @optionparent defs
  1217. */
  1218. var defaultMarkers = {
  1219. /**
  1220. * @type {Highcharts.SVGDefinitionObject}
  1221. */
  1222. arrow: {
  1223. tagName: 'marker',
  1224. render: false,
  1225. id: 'arrow',
  1226. refY: 5,
  1227. refX: 9,
  1228. markerWidth: 10,
  1229. markerHeight: 10,
  1230. /**
  1231. * @type {Array<Highcharts.DefsOptions>}
  1232. */
  1233. children: [{
  1234. tagName: 'path',
  1235. d: 'M 0 0 L 10 5 L 0 10 Z',
  1236. strokeWidth: 0
  1237. }]
  1238. },
  1239. /**
  1240. * @type {Highcharts.SVGDefinitionObject}
  1241. */
  1242. 'reverse-arrow': {
  1243. tagName: 'marker',
  1244. render: false,
  1245. id: 'reverse-arrow',
  1246. refY: 5,
  1247. refX: 1,
  1248. markerWidth: 10,
  1249. markerHeight: 10,
  1250. children: [{
  1251. tagName: 'path',
  1252. // reverse triangle (used as an arrow)
  1253. d: 'M 0 5 L 10 0 L 10 10 Z',
  1254. strokeWidth: 0
  1255. }]
  1256. }
  1257. };
  1258. H.SVGRenderer.prototype.addMarker = function (id, markerOptions) {
  1259. var options = { id: id };
  1260. var attrs = {
  1261. stroke: markerOptions.color || 'none',
  1262. fill: markerOptions.color || 'rgba(0, 0, 0, 0.75)'
  1263. };
  1264. options.children = markerOptions.children.map(function (child) {
  1265. return merge(attrs, child);
  1266. });
  1267. var marker = this.definition(merge(true, {
  1268. markerWidth: 20,
  1269. markerHeight: 20,
  1270. refX: 0,
  1271. refY: 0,
  1272. orient: 'auto'
  1273. }, markerOptions, options));
  1274. marker.id = id;
  1275. return marker;
  1276. };
  1277. /* eslint-disable no-invalid-this, valid-jsdoc */
  1278. var createMarkerSetter = function (markerType) {
  1279. return function (value) {
  1280. this.attr(markerType, 'url(#' + value + ')');
  1281. };
  1282. };
  1283. /**
  1284. * @private
  1285. * @mixin
  1286. * @name Highcharts.AnnotaitonMarkerMixin
  1287. */
  1288. var markerMixin = {
  1289. markerEndSetter: createMarkerSetter('marker-end'),
  1290. markerStartSetter: createMarkerSetter('marker-start'),
  1291. /**
  1292. * Set markers.
  1293. * @private
  1294. * @param {Highcharts.AnnotationControllablePath} item
  1295. */
  1296. setItemMarkers: function (item) {
  1297. var itemOptions = item.options, chart = item.chart, defs = chart.options.defs, fill = itemOptions.fill, color = defined(fill) && fill !== 'none' ?
  1298. fill :
  1299. itemOptions.stroke, setMarker = function (markerType) {
  1300. var markerId = itemOptions[markerType], def, predefinedMarker, key, marker;
  1301. if (markerId) {
  1302. for (key in defs) { // eslint-disable-line guard-for-in
  1303. def = defs[key];
  1304. if (markerId === def.id &&
  1305. def.tagName === 'marker') {
  1306. predefinedMarker = def;
  1307. break;
  1308. }
  1309. }
  1310. if (predefinedMarker) {
  1311. marker = item[markerType] = chart.renderer
  1312. .addMarker((itemOptions.id || uniqueKey()) + '-' +
  1313. predefinedMarker.id, merge(predefinedMarker, { color: color }));
  1314. item.attr(markerType, marker.attr('id'));
  1315. }
  1316. }
  1317. };
  1318. ['markerStart', 'markerEnd'].forEach(setMarker);
  1319. }
  1320. };
  1321. addEvent(H.Chart, 'afterGetContainer', function () {
  1322. this.options.defs = merge(defaultMarkers, this.options.defs || {});
  1323. objectEach(this.options.defs, function (def) {
  1324. if (def.tagName === 'marker' && def.render !== false) {
  1325. this.renderer.addMarker(def.id, def);
  1326. }
  1327. }, this);
  1328. });
  1329. return markerMixin;
  1330. });
  1331. _registerModule(_modules, 'annotations/controllable/ControllablePath.js', [_modules['annotations/controllable/controllableMixin.js'], _modules['parts/Globals.js'], _modules['annotations/controllable/markerMixin.js'], _modules['parts/Utilities.js']], function (controllableMixin, H, markerMixin, U) {
  1332. /* *
  1333. *
  1334. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1335. *
  1336. * */
  1337. var extend = U.extend, merge = U.merge;
  1338. // See TRACKER_FILL in highcharts.src.js
  1339. var TRACKER_FILL = 'rgba(192,192,192,' + (H.svg ? 0.0001 : 0.002) + ')';
  1340. /* eslint-disable no-invalid-this, valid-jsdoc */
  1341. /**
  1342. * A controllable path class.
  1343. *
  1344. * @requires modules/annotations
  1345. *
  1346. * @private
  1347. * @class
  1348. * @name Highcharts.AnnotationControllablePath
  1349. *
  1350. * @param {Highcharts.Annotation}
  1351. * Related annotation.
  1352. *
  1353. * @param {Highcharts.AnnotationsShapeOptions} options
  1354. * A path's options object.
  1355. *
  1356. * @param {number} index
  1357. * Index of the path.
  1358. **/
  1359. var ControllablePath = function (annotation, options, index) {
  1360. this.init(annotation, options, index);
  1361. this.collection = 'shapes';
  1362. };
  1363. /**
  1364. * A map object which allows to map options attributes to element attributes
  1365. *
  1366. * @name Highcharts.AnnotationControllablePath.attrsMap
  1367. * @type {Highcharts.Dictionary<string>}
  1368. */
  1369. ControllablePath.attrsMap = {
  1370. dashStyle: 'dashstyle',
  1371. strokeWidth: 'stroke-width',
  1372. stroke: 'stroke',
  1373. fill: 'fill',
  1374. zIndex: 'zIndex'
  1375. };
  1376. merge(true, ControllablePath.prototype, controllableMixin, /** @lends Highcharts.AnnotationControllablePath# */ {
  1377. /**
  1378. * @type 'path'
  1379. */
  1380. type: 'path',
  1381. setMarkers: markerMixin.setItemMarkers,
  1382. /**
  1383. * Map the controllable path to 'd' path attribute.
  1384. *
  1385. * @return {Highcharts.SVGPathArray|null}
  1386. * A path's d attribute.
  1387. */
  1388. toD: function () {
  1389. var dOption = this.options.d;
  1390. if (dOption) {
  1391. return typeof dOption === 'function' ?
  1392. dOption.call(this) :
  1393. dOption;
  1394. }
  1395. var points = this.points, len = points.length, showPath = len, point = points[0], position = showPath && this.anchor(point).absolutePosition, pointIndex = 0, command, d = [];
  1396. if (position) {
  1397. d.push(['M', position.x, position.y]);
  1398. while (++pointIndex < len && showPath) {
  1399. point = points[pointIndex];
  1400. command = point.command || 'L';
  1401. position = this.anchor(point).absolutePosition;
  1402. if (command === 'M') {
  1403. d.push([command, position.x, position.y]);
  1404. }
  1405. else if (command === 'L') {
  1406. d.push([command, position.x, position.y]);
  1407. }
  1408. else if (command === 'Z') {
  1409. d.push([command]);
  1410. }
  1411. showPath = point.series.visible;
  1412. }
  1413. }
  1414. return showPath ?
  1415. this.chart.renderer.crispLine(d, this.graphic.strokeWidth()) :
  1416. null;
  1417. },
  1418. shouldBeDrawn: function () {
  1419. return (controllableMixin.shouldBeDrawn.call(this) || Boolean(this.options.d));
  1420. },
  1421. render: function (parent) {
  1422. var options = this.options, attrs = this.attrsFromOptions(options);
  1423. this.graphic = this.annotation.chart.renderer
  1424. .path([['M', 0, 0]])
  1425. .attr(attrs)
  1426. .add(parent);
  1427. if (options.className) {
  1428. this.graphic.addClass(options.className);
  1429. }
  1430. this.tracker = this.annotation.chart.renderer
  1431. .path([['M', 0, 0]])
  1432. .addClass('highcharts-tracker-line')
  1433. .attr({
  1434. zIndex: 2
  1435. })
  1436. .add(parent);
  1437. if (!this.annotation.chart.styledMode) {
  1438. this.tracker.attr({
  1439. 'stroke-linejoin': 'round',
  1440. stroke: TRACKER_FILL,
  1441. fill: TRACKER_FILL,
  1442. 'stroke-width': this.graphic.strokeWidth() +
  1443. options.snap * 2
  1444. });
  1445. }
  1446. controllableMixin.render.call(this);
  1447. extend(this.graphic, {
  1448. markerStartSetter: markerMixin.markerStartSetter,
  1449. markerEndSetter: markerMixin.markerEndSetter
  1450. });
  1451. this.setMarkers(this);
  1452. },
  1453. redraw: function (animation) {
  1454. var d = this.toD(), action = animation ? 'animate' : 'attr';
  1455. if (d) {
  1456. this.graphic[action]({ d: d });
  1457. this.tracker[action]({ d: d });
  1458. }
  1459. else {
  1460. this.graphic.attr({ d: 'M 0 ' + -9e9 });
  1461. this.tracker.attr({ d: 'M 0 ' + -9e9 });
  1462. }
  1463. this.graphic.placed = this.tracker.placed = Boolean(d);
  1464. controllableMixin.redraw.call(this, animation);
  1465. }
  1466. });
  1467. return ControllablePath;
  1468. });
  1469. _registerModule(_modules, 'annotations/controllable/ControllableRect.js', [_modules['annotations/controllable/controllableMixin.js'], _modules['annotations/controllable/ControllablePath.js'], _modules['parts/Utilities.js']], function (controllableMixin, ControllablePath, U) {
  1470. /* *
  1471. *
  1472. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1473. *
  1474. * */
  1475. var merge = U.merge;
  1476. /* eslint-disable no-invalid-this, valid-jsdoc */
  1477. /**
  1478. * A controllable rect class.
  1479. *
  1480. * @requires modules/annotations
  1481. *
  1482. * @private
  1483. * @class
  1484. * @name Highcharts.AnnotationControllableRect
  1485. *
  1486. * @param {Highcharts.Annotation} annotation
  1487. * An annotation instance.
  1488. *
  1489. * @param {Highcharts.AnnotationsShapeOptions} options
  1490. * A rect's options.
  1491. *
  1492. * @param {number} index
  1493. * Index of the rectangle
  1494. */
  1495. var ControllableRect = function (annotation, options, index) {
  1496. this.init(annotation, options, index);
  1497. this.collection = 'shapes';
  1498. };
  1499. /**
  1500. * @typedef {Annotation.ControllablePath.AttrsMap}
  1501. * Annotation.ControllableRect.AttrsMap
  1502. * @property {string} width=width
  1503. * @property {string} height=height
  1504. */
  1505. /**
  1506. * A map object which allows to map options attributes to element attributes
  1507. *
  1508. * @type {Annotation.ControllableRect.AttrsMap}
  1509. */
  1510. ControllableRect.attrsMap = merge(ControllablePath.attrsMap, {
  1511. width: 'width',
  1512. height: 'height'
  1513. });
  1514. merge(true, ControllableRect.prototype, controllableMixin, /** @lends Annotation.ControllableRect# */ {
  1515. /**
  1516. * @type 'rect'
  1517. */
  1518. type: 'rect',
  1519. translate: controllableMixin.translateShape,
  1520. render: function (parent) {
  1521. var attrs = this.attrsFromOptions(this.options);
  1522. this.graphic = this.annotation.chart.renderer
  1523. .rect(0, -9e9, 0, 0)
  1524. .attr(attrs)
  1525. .add(parent);
  1526. controllableMixin.render.call(this);
  1527. },
  1528. redraw: function (animation) {
  1529. var position = this.anchor(this.points[0]).absolutePosition;
  1530. if (position) {
  1531. this.graphic[animation ? 'animate' : 'attr']({
  1532. x: position.x,
  1533. y: position.y,
  1534. width: this.options.width,
  1535. height: this.options.height
  1536. });
  1537. }
  1538. else {
  1539. this.attr({
  1540. x: 0,
  1541. y: -9e9
  1542. });
  1543. }
  1544. this.graphic.placed = Boolean(position);
  1545. controllableMixin.redraw.call(this, animation);
  1546. }
  1547. });
  1548. return ControllableRect;
  1549. });
  1550. _registerModule(_modules, 'annotations/controllable/ControllableCircle.js', [_modules['annotations/controllable/controllableMixin.js'], _modules['annotations/controllable/ControllablePath.js'], _modules['parts/Utilities.js']], function (controllableMixin, ControllablePath, U) {
  1551. /* *
  1552. *
  1553. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1554. *
  1555. * */
  1556. var merge = U.merge;
  1557. /* eslint-disable no-invalid-this, valid-jsdoc */
  1558. /**
  1559. * A controllable circle class.
  1560. *
  1561. * @requires modules/annotations
  1562. *
  1563. * @private
  1564. * @constructor
  1565. * @name Highcharts.AnnotationControllableCircle
  1566. *
  1567. * @param {Highcharts.Annotation} annotation an annotation instance
  1568. * @param {Highcharts.AnnotationsShapeOptions} options a shape's options
  1569. * @param {number} index of the circle
  1570. **/
  1571. var ControllableCircle = function (annotation, options, index) {
  1572. this.init(annotation, options, index);
  1573. this.collection = 'shapes';
  1574. };
  1575. /**
  1576. * A map object which allows to map options attributes to element attributes.
  1577. *
  1578. * @name Highcharts.AnnotationControllableCircle.attrsMap
  1579. * @type {Highcharts.Dictionary<string>}
  1580. */
  1581. ControllableCircle.attrsMap = merge(ControllablePath.attrsMap, {
  1582. r: 'r'
  1583. });
  1584. merge(true, ControllableCircle.prototype, controllableMixin, /** @lends Highcharts.AnnotationControllableCircle# */ {
  1585. /**
  1586. * @type 'circle'
  1587. */
  1588. type: 'circle',
  1589. translate: controllableMixin.translateShape,
  1590. render: function (parent) {
  1591. var attrs = this.attrsFromOptions(this.options);
  1592. this.graphic = this.annotation.chart.renderer
  1593. .circle(0, -9e9, 0)
  1594. .attr(attrs)
  1595. .add(parent);
  1596. controllableMixin.render.call(this);
  1597. },
  1598. redraw: function (animation) {
  1599. var position = this.anchor(this.points[0]).absolutePosition;
  1600. if (position) {
  1601. this.graphic[animation ? 'animate' : 'attr']({
  1602. x: position.x,
  1603. y: position.y,
  1604. r: this.options.r
  1605. });
  1606. }
  1607. else {
  1608. this.graphic.attr({
  1609. x: 0,
  1610. y: -9e9
  1611. });
  1612. }
  1613. this.graphic.placed = Boolean(position);
  1614. controllableMixin.redraw.call(this, animation);
  1615. },
  1616. /**
  1617. * Set the radius.
  1618. *
  1619. * @param {number} r a radius to be set
  1620. */
  1621. setRadius: function (r) {
  1622. this.options.r = r;
  1623. }
  1624. });
  1625. return ControllableCircle;
  1626. });
  1627. _registerModule(_modules, 'annotations/controllable/ControllableLabel.js', [_modules['annotations/controllable/controllableMixin.js'], _modules['parts/Globals.js'], _modules['annotations/MockPoint.js'], _modules['parts/Tooltip.js'], _modules['parts/Utilities.js']], function (controllableMixin, H, MockPoint, Tooltip, U) {
  1628. /* *
  1629. *
  1630. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1631. *
  1632. * */
  1633. var extend = U.extend, format = U.format, isNumber = U.isNumber, merge = U.merge, pick = U.pick;
  1634. /* eslint-disable no-invalid-this, valid-jsdoc */
  1635. /**
  1636. * A controllable label class.
  1637. *
  1638. * @requires modules/annotations
  1639. *
  1640. * @private
  1641. * @class
  1642. * @name Highcharts.AnnotationControllableLabel
  1643. *
  1644. * @param {Highcharts.Annotation} annotation
  1645. * An annotation instance.
  1646. * @param {Highcharts.AnnotationsLabelOptions} options
  1647. * A label's options.
  1648. * @param {number} index
  1649. * Index of the label.
  1650. */
  1651. var ControllableLabel = function (annotation, options, index) {
  1652. this.init(annotation, options, index);
  1653. this.collection = 'labels';
  1654. };
  1655. /**
  1656. * Shapes which do not have background - the object is used for proper
  1657. * setting of the contrast color.
  1658. *
  1659. * @type {Array<string>}
  1660. */
  1661. ControllableLabel.shapesWithoutBackground = ['connector'];
  1662. /**
  1663. * Returns new aligned position based alignment options and box to align to.
  1664. * It is almost a one-to-one copy from SVGElement.prototype.align
  1665. * except it does not use and mutate an element
  1666. *
  1667. * @param {Highcharts.AnnotationAlignObject} alignOptions
  1668. *
  1669. * @param {Highcharts.BBoxObject} box
  1670. *
  1671. * @return {Highcharts.PositionObject}
  1672. * Aligned position.
  1673. */
  1674. ControllableLabel.alignedPosition = function (alignOptions, box) {
  1675. var align = alignOptions.align, vAlign = alignOptions.verticalAlign, x = (box.x || 0) + (alignOptions.x || 0), y = (box.y || 0) + (alignOptions.y || 0), alignFactor, vAlignFactor;
  1676. if (align === 'right') {
  1677. alignFactor = 1;
  1678. }
  1679. else if (align === 'center') {
  1680. alignFactor = 2;
  1681. }
  1682. if (alignFactor) {
  1683. x += (box.width - (alignOptions.width || 0)) / alignFactor;
  1684. }
  1685. if (vAlign === 'bottom') {
  1686. vAlignFactor = 1;
  1687. }
  1688. else if (vAlign === 'middle') {
  1689. vAlignFactor = 2;
  1690. }
  1691. if (vAlignFactor) {
  1692. y += (box.height - (alignOptions.height || 0)) / vAlignFactor;
  1693. }
  1694. return {
  1695. x: Math.round(x),
  1696. y: Math.round(y)
  1697. };
  1698. };
  1699. /**
  1700. * Returns new alignment options for a label if the label is outside the
  1701. * plot area. It is almost a one-to-one copy from
  1702. * Series.prototype.justifyDataLabel except it does not mutate the label and
  1703. * it works with absolute instead of relative position.
  1704. */
  1705. ControllableLabel.justifiedOptions = function (chart, label, alignOptions, alignAttr) {
  1706. var align = alignOptions.align, verticalAlign = alignOptions.verticalAlign, padding = label.box ? 0 : (label.padding || 0), bBox = label.getBBox(), off,
  1707. //
  1708. options = {
  1709. align: align,
  1710. verticalAlign: verticalAlign,
  1711. x: alignOptions.x,
  1712. y: alignOptions.y,
  1713. width: label.width,
  1714. height: label.height
  1715. },
  1716. //
  1717. x = alignAttr.x - chart.plotLeft, y = alignAttr.y - chart.plotTop;
  1718. // Off left
  1719. off = x + padding;
  1720. if (off < 0) {
  1721. if (align === 'right') {
  1722. options.align = 'left';
  1723. }
  1724. else {
  1725. options.x = -off;
  1726. }
  1727. }
  1728. // Off right
  1729. off = x + bBox.width - padding;
  1730. if (off > chart.plotWidth) {
  1731. if (align === 'left') {
  1732. options.align = 'right';
  1733. }
  1734. else {
  1735. options.x = chart.plotWidth - off;
  1736. }
  1737. }
  1738. // Off top
  1739. off = y + padding;
  1740. if (off < 0) {
  1741. if (verticalAlign === 'bottom') {
  1742. options.verticalAlign = 'top';
  1743. }
  1744. else {
  1745. options.y = -off;
  1746. }
  1747. }
  1748. // Off bottom
  1749. off = y + bBox.height - padding;
  1750. if (off > chart.plotHeight) {
  1751. if (verticalAlign === 'top') {
  1752. options.verticalAlign = 'bottom';
  1753. }
  1754. else {
  1755. options.y = chart.plotHeight - off;
  1756. }
  1757. }
  1758. return options;
  1759. };
  1760. /**
  1761. * A map object which allows to map options attributes to element attributes
  1762. *
  1763. * @type {Highcharts.Dictionary<string>}
  1764. */
  1765. ControllableLabel.attrsMap = {
  1766. backgroundColor: 'fill',
  1767. borderColor: 'stroke',
  1768. borderWidth: 'stroke-width',
  1769. zIndex: 'zIndex',
  1770. borderRadius: 'r',
  1771. padding: 'padding'
  1772. };
  1773. merge(true, ControllableLabel.prototype, controllableMixin,
  1774. /** @lends Annotation.ControllableLabel# */ {
  1775. /**
  1776. * Translate the point of the label by deltaX and deltaY translations.
  1777. * The point is the label's anchor.
  1778. *
  1779. * @param {number} dx translation for x coordinate
  1780. * @param {number} dy translation for y coordinate
  1781. **/
  1782. translatePoint: function (dx, dy) {
  1783. controllableMixin.translatePoint.call(this, dx, dy, 0);
  1784. },
  1785. /**
  1786. * Translate x and y position relative to the label's anchor.
  1787. *
  1788. * @param {number} dx translation for x coordinate
  1789. * @param {number} dy translation for y coordinate
  1790. **/
  1791. translate: function (dx, dy) {
  1792. var chart = this.annotation.chart,
  1793. // Annotation.options
  1794. labelOptions = this.annotation.userOptions,
  1795. // Chart.options.annotations
  1796. annotationIndex = chart.annotations.indexOf(this.annotation), chartAnnotations = chart.options.annotations, chartOptions = chartAnnotations[annotationIndex], temp;
  1797. if (chart.inverted) {
  1798. temp = dx;
  1799. dx = dy;
  1800. dy = temp;
  1801. }
  1802. // Local options:
  1803. this.options.x += dx;
  1804. this.options.y += dy;
  1805. // Options stored in chart:
  1806. chartOptions[this.collection][this.index].x = this.options.x;
  1807. chartOptions[this.collection][this.index].y = this.options.y;
  1808. labelOptions[this.collection][this.index].x = this.options.x;
  1809. labelOptions[this.collection][this.index].y = this.options.y;
  1810. },
  1811. render: function (parent) {
  1812. var options = this.options, attrs = this.attrsFromOptions(options), style = options.style;
  1813. this.graphic = this.annotation.chart.renderer
  1814. .label('', 0, -9999, // #10055
  1815. options.shape, null, null, options.useHTML, null, 'annotation-label')
  1816. .attr(attrs)
  1817. .add(parent);
  1818. if (!this.annotation.chart.styledMode) {
  1819. if (style.color === 'contrast') {
  1820. style.color = this.annotation.chart.renderer.getContrast(ControllableLabel.shapesWithoutBackground.indexOf(options.shape) > -1 ? '#FFFFFF' : options.backgroundColor);
  1821. }
  1822. this.graphic
  1823. .css(options.style)
  1824. .shadow(options.shadow);
  1825. }
  1826. if (options.className) {
  1827. this.graphic.addClass(options.className);
  1828. }
  1829. this.graphic.labelrank = options.labelrank;
  1830. controllableMixin.render.call(this);
  1831. },
  1832. redraw: function (animation) {
  1833. var options = this.options, text = this.text || options.format || options.text, label = this.graphic, point = this.points[0], show = false, anchor, attrs;
  1834. label.attr({
  1835. text: text ?
  1836. format(text, point.getLabelConfig(), this.annotation.chart) :
  1837. options.formatter.call(point, this)
  1838. });
  1839. anchor = this.anchor(point);
  1840. attrs = this.position(anchor);
  1841. show = attrs;
  1842. if (show) {
  1843. label.alignAttr = attrs;
  1844. attrs.anchorX = anchor.absolutePosition.x;
  1845. attrs.anchorY = anchor.absolutePosition.y;
  1846. label[animation ? 'animate' : 'attr'](attrs);
  1847. }
  1848. else {
  1849. label.attr({
  1850. x: 0,
  1851. y: -9999 // #10055
  1852. });
  1853. }
  1854. label.placed = Boolean(show);
  1855. controllableMixin.redraw.call(this, animation);
  1856. },
  1857. /**
  1858. * All basic shapes don't support alignTo() method except label.
  1859. * For a controllable label, we need to subtract translation from
  1860. * options.
  1861. */
  1862. anchor: function () {
  1863. var anchor = controllableMixin.anchor.apply(this, arguments), x = this.options.x || 0, y = this.options.y || 0;
  1864. anchor.absolutePosition.x -= x;
  1865. anchor.absolutePosition.y -= y;
  1866. anchor.relativePosition.x -= x;
  1867. anchor.relativePosition.y -= y;
  1868. return anchor;
  1869. },
  1870. /**
  1871. * Returns the label position relative to its anchor.
  1872. *
  1873. * @param {Highcharts.AnnotationAnchorObject} anchor
  1874. *
  1875. * @return {Highcharts.PositionObject|null}
  1876. */
  1877. position: function (anchor) {
  1878. var item = this.graphic, chart = this.annotation.chart, point = this.points[0], itemOptions = this.options, anchorAbsolutePosition = anchor.absolutePosition, anchorRelativePosition = anchor.relativePosition, itemPosition, alignTo, itemPosRelativeX, itemPosRelativeY, showItem = point.series.visible &&
  1879. MockPoint.prototype.isInsidePlot.call(point);
  1880. if (showItem) {
  1881. if (itemOptions.distance) {
  1882. itemPosition = Tooltip.prototype.getPosition.call({
  1883. chart: chart,
  1884. distance: pick(itemOptions.distance, 16)
  1885. }, item.width, item.height, {
  1886. plotX: anchorRelativePosition.x,
  1887. plotY: anchorRelativePosition.y,
  1888. negative: point.negative,
  1889. ttBelow: point.ttBelow,
  1890. h: (anchorRelativePosition.height || anchorRelativePosition.width)
  1891. });
  1892. }
  1893. else if (itemOptions.positioner) {
  1894. itemPosition = itemOptions.positioner.call(this);
  1895. }
  1896. else {
  1897. alignTo = {
  1898. x: anchorAbsolutePosition.x,
  1899. y: anchorAbsolutePosition.y,
  1900. width: 0,
  1901. height: 0
  1902. };
  1903. itemPosition = ControllableLabel.alignedPosition(extend(itemOptions, {
  1904. width: item.width,
  1905. height: item.height
  1906. }), alignTo);
  1907. if (this.options.overflow === 'justify') {
  1908. itemPosition = ControllableLabel.alignedPosition(ControllableLabel.justifiedOptions(chart, item, itemOptions, itemPosition), alignTo);
  1909. }
  1910. }
  1911. if (itemOptions.crop) {
  1912. itemPosRelativeX = itemPosition.x - chart.plotLeft;
  1913. itemPosRelativeY = itemPosition.y - chart.plotTop;
  1914. showItem =
  1915. chart.isInsidePlot(itemPosRelativeX, itemPosRelativeY) &&
  1916. chart.isInsidePlot(itemPosRelativeX + item.width, itemPosRelativeY + item.height);
  1917. }
  1918. }
  1919. return showItem ? itemPosition : null;
  1920. }
  1921. });
  1922. /* ********************************************************************** */
  1923. /**
  1924. * General symbol definition for labels with connector
  1925. * @private
  1926. */
  1927. H.SVGRenderer.prototype.symbols.connector = function (x, y, w, h, options) {
  1928. var anchorX = options && options.anchorX, anchorY = options && options.anchorY, path, yOffset, lateral = w / 2;
  1929. if (isNumber(anchorX) && isNumber(anchorY)) {
  1930. path = [['M', anchorX, anchorY]];
  1931. // Prefer 45 deg connectors
  1932. yOffset = y - anchorY;
  1933. if (yOffset < 0) {
  1934. yOffset = -h - yOffset;
  1935. }
  1936. if (yOffset < w) {
  1937. lateral = anchorX < x + (w / 2) ? yOffset : w - yOffset;
  1938. }
  1939. // Anchor below label
  1940. if (anchorY > y + h) {
  1941. path.push(['L', x + lateral, y + h]);
  1942. // Anchor above label
  1943. }
  1944. else if (anchorY < y) {
  1945. path.push(['L', x + lateral, y]);
  1946. // Anchor left of label
  1947. }
  1948. else if (anchorX < x) {
  1949. path.push(['L', x, y + h / 2]);
  1950. // Anchor right of label
  1951. }
  1952. else if (anchorX > x + w) {
  1953. path.push(['L', x + w, y + h / 2]);
  1954. }
  1955. }
  1956. return path || [];
  1957. };
  1958. return ControllableLabel;
  1959. });
  1960. _registerModule(_modules, 'annotations/controllable/ControllableImage.js', [_modules['annotations/controllable/ControllableLabel.js'], _modules['annotations/controllable/controllableMixin.js'], _modules['parts/Utilities.js']], function (ControllableLabel, controllableMixin, U) {
  1961. /* *
  1962. *
  1963. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1964. *
  1965. * */
  1966. var merge = U.merge;
  1967. /* eslint-disable no-invalid-this, valid-jsdoc */
  1968. /**
  1969. * A controllable image class.
  1970. *
  1971. * @requires modules/annotations
  1972. *
  1973. * @private
  1974. * @class
  1975. * @name Highcharts.AnnotationControllableImage
  1976. *
  1977. * @param {Highcharts.Annotation} annotation
  1978. * An annotation instance.
  1979. *
  1980. * @param {Highcharts.AnnotationsShapeOptions} options
  1981. * A controllable's options.
  1982. *
  1983. * @param {number} index
  1984. * Index of the image.
  1985. **/
  1986. var ControllableImage = function (annotation, options, index) {
  1987. this.init(annotation, options, index);
  1988. this.collection = 'shapes';
  1989. };
  1990. /**
  1991. * A map object which allows to map options attributes to element attributes
  1992. *
  1993. * @name Highcharts.AnnotationControllableImage.attrsMap
  1994. * @type {Highcharts.Dictionary<string>}
  1995. */
  1996. ControllableImage.attrsMap = {
  1997. width: 'width',
  1998. height: 'height',
  1999. zIndex: 'zIndex'
  2000. };
  2001. merge(true, ControllableImage.prototype, controllableMixin, /** @lends Annotation.ControllableImage# */ {
  2002. /**
  2003. * @type 'image'
  2004. */
  2005. type: 'image',
  2006. translate: controllableMixin.translateShape,
  2007. render: function (parent) {
  2008. var attrs = this.attrsFromOptions(this.options), options = this.options;
  2009. this.graphic = this.annotation.chart.renderer
  2010. .image(options.src, 0, -9e9, options.width, options.height)
  2011. .attr(attrs)
  2012. .add(parent);
  2013. this.graphic.width = options.width;
  2014. this.graphic.height = options.height;
  2015. controllableMixin.render.call(this);
  2016. },
  2017. redraw: function (animation) {
  2018. var anchor = this.anchor(this.points[0]), position = ControllableLabel.prototype.position.call(this, anchor);
  2019. if (position) {
  2020. this.graphic[animation ? 'animate' : 'attr']({
  2021. x: position.x,
  2022. y: position.y
  2023. });
  2024. }
  2025. else {
  2026. this.graphic.attr({
  2027. x: 0,
  2028. y: -9e9
  2029. });
  2030. }
  2031. this.graphic.placed = Boolean(position);
  2032. controllableMixin.redraw.call(this, animation);
  2033. }
  2034. });
  2035. return ControllableImage;
  2036. });
  2037. _registerModule(_modules, 'annotations/annotations.src.js', [_modules['parts/Chart.js'], _modules['annotations/controllable/controllableMixin.js'], _modules['annotations/controllable/ControllableRect.js'], _modules['annotations/controllable/ControllableCircle.js'], _modules['annotations/controllable/ControllablePath.js'], _modules['annotations/controllable/ControllableImage.js'], _modules['annotations/controllable/ControllableLabel.js'], _modules['annotations/ControlPoint.js'], _modules['annotations/eventEmitterMixin.js'], _modules['parts/Globals.js'], _modules['annotations/MockPoint.js'], _modules['parts/Pointer.js'], _modules['parts/Utilities.js']], function (Chart, ControllableMixin, ControllableRect, ControllableCircle, ControllablePath, ControllableImage, ControllableLabel, ControlPoint, EventEmitterMixin, H, MockPoint, Pointer, U) {
  2038. /* *
  2039. *
  2040. * (c) 2009-2017 Highsoft, Black Label
  2041. *
  2042. * License: www.highcharts.com/license
  2043. *
  2044. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  2045. *
  2046. * */
  2047. var chartProto = Chart.prototype;
  2048. var addEvent = U.addEvent, defined = U.defined, destroyObjectProperties = U.destroyObjectProperties, erase = U.erase, extend = U.extend, find = U.find, fireEvent = U.fireEvent, merge = U.merge, pick = U.pick, splat = U.splat, wrap = U.wrap;
  2049. /* *********************************************************************
  2050. *
  2051. * ANNOTATION
  2052. *
  2053. ******************************************************************** */
  2054. /**
  2055. * Possible directions for draggable annotations. An empty string (`''`)
  2056. * makes the annotation undraggable.
  2057. *
  2058. * @typedef {''|'x'|'xy'|'y'} Highcharts.AnnotationDraggableValue
  2059. */
  2060. /**
  2061. * @private
  2062. * @typedef {
  2063. * Highcharts.AnnotationControllableCircle|
  2064. * Highcharts.AnnotationControllableImage|
  2065. * Highcharts.AnnotationControllablePath|
  2066. * Highcharts.AnnotationControllableRect
  2067. * }
  2068. * Highcharts.AnnotationShapeType
  2069. * @requires modules/annotations
  2070. */
  2071. /**
  2072. * @private
  2073. * @typedef {
  2074. * Highcharts.AnnotationControllableLabel
  2075. * }
  2076. * Highcharts.AnnotationLabelType
  2077. * @requires modules/annotations
  2078. */
  2079. /**
  2080. * A point-like object, a mock point or a point used in series.
  2081. * @private
  2082. * @typedef {Highcharts.AnnotationMockPoint|Highcharts.Point} Highcharts.AnnotationPointType
  2083. * @requires modules/annotations
  2084. */
  2085. /* eslint-disable no-invalid-this, valid-jsdoc */
  2086. /**
  2087. * An annotation class which serves as a container for items like labels or
  2088. * shapes. Created items are positioned on the chart either by linking them to
  2089. * existing points or created mock points
  2090. *
  2091. * @class
  2092. * @name Highcharts.Annotation
  2093. *
  2094. * @param {Highcharts.Chart} chart a chart instance
  2095. * @param {Highcharts.AnnotationsOptions} userOptions the options object
  2096. */
  2097. var Annotation = /** @class */ (function () {
  2098. /* *
  2099. *
  2100. * Constructors
  2101. *
  2102. * */
  2103. function Annotation(chart, userOptions) {
  2104. /* *
  2105. *
  2106. * Properties
  2107. *
  2108. * */
  2109. this.annotation = void 0;
  2110. this.coll = 'annotations';
  2111. this.collection = void 0;
  2112. this.graphic = void 0;
  2113. this.group = void 0;
  2114. this.labelCollector = void 0;
  2115. this.labelsGroup = void 0;
  2116. this.shapesGroup = void 0;
  2117. var labelsAndShapes;
  2118. /**
  2119. * The chart that the annotation belongs to.
  2120. *
  2121. * @type {Highcharts.Chart}
  2122. */
  2123. this.chart = chart;
  2124. /**
  2125. * The array of points which defines the annotation.
  2126. *
  2127. * @type {Array<Highcharts.Point>}
  2128. */
  2129. this.points = [];
  2130. /**
  2131. * The array of control points.
  2132. *
  2133. * @private
  2134. * @name Highcharts.Annotation#controlPoints
  2135. * @type {Array<Annotation.ControlPoint>}
  2136. */
  2137. this.controlPoints = [];
  2138. this.coll = 'annotations';
  2139. /**
  2140. * The array of labels which belong to the annotation.
  2141. *
  2142. * @private
  2143. * @name Highcharts.Annotation#labels
  2144. * @type {Array<Highcharts.AnnotationLabelType>}
  2145. */
  2146. this.labels = [];
  2147. /**
  2148. * The array of shapes which belong to the annotation.
  2149. *
  2150. * @private
  2151. * @name Highcharts.Annotation#shapes
  2152. * @type {Array<Highcharts.AnnotationShapeType>}
  2153. */
  2154. this.shapes = [];
  2155. /**
  2156. * The options for the annotations.
  2157. *
  2158. * @name Highcharts.Annotation#options
  2159. * @type {Highcharts.AnnotationsOptions}
  2160. */
  2161. this.options = merge(this.defaultOptions, userOptions);
  2162. /**
  2163. * The user options for the annotations.
  2164. *
  2165. * @name Highcharts.Annotation#userOptions
  2166. * @type {Highcharts.AnnotationsOptions}
  2167. */
  2168. this.userOptions = userOptions;
  2169. // Handle labels and shapes - those are arrays
  2170. // Merging does not work with arrays (stores reference)
  2171. labelsAndShapes = this.getLabelsAndShapesOptions(this.options, userOptions);
  2172. this.options.labels = labelsAndShapes.labels;
  2173. this.options.shapes = labelsAndShapes.shapes;
  2174. /**
  2175. * The callback that reports to the overlapping-labels module which
  2176. * labels it should account for.
  2177. * @private
  2178. * @name Highcharts.Annotation#labelCollector
  2179. * @type {Function}
  2180. */
  2181. /**
  2182. * The group svg element.
  2183. *
  2184. * @name Highcharts.Annotation#group
  2185. * @type {Highcharts.SVGElement}
  2186. */
  2187. /**
  2188. * The group svg element of the annotation's shapes.
  2189. *
  2190. * @name Highcharts.Annotation#shapesGroup
  2191. * @type {Highcharts.SVGElement}
  2192. */
  2193. /**
  2194. * The group svg element of the annotation's labels.
  2195. *
  2196. * @name Highcharts.Annotation#labelsGroup
  2197. * @type {Highcharts.SVGElement}
  2198. */
  2199. this.init(chart, this.options);
  2200. }
  2201. /**
  2202. * Initialize the annotation.
  2203. * @private
  2204. */
  2205. Annotation.prototype.init = function () {
  2206. this.linkPoints();
  2207. this.addControlPoints();
  2208. this.addShapes();
  2209. this.addLabels();
  2210. this.setLabelCollector();
  2211. };
  2212. Annotation.prototype.getLabelsAndShapesOptions = function (baseOptions, newOptions) {
  2213. var mergedOptions = {};
  2214. ['labels', 'shapes'].forEach(function (name) {
  2215. if (baseOptions[name]) {
  2216. mergedOptions[name] = splat(newOptions[name]).map(function (basicOptions, i) {
  2217. return merge(baseOptions[name][i], basicOptions);
  2218. });
  2219. }
  2220. });
  2221. return mergedOptions;
  2222. };
  2223. Annotation.prototype.addShapes = function () {
  2224. (this.options.shapes || []).forEach(function (shapeOptions, i) {
  2225. var shape = this.initShape(shapeOptions, i);
  2226. merge(true, this.options.shapes[i], shape.options);
  2227. }, this);
  2228. };
  2229. Annotation.prototype.addLabels = function () {
  2230. (this.options.labels || []).forEach(function (labelsOptions, i) {
  2231. var labels = this.initLabel(labelsOptions, i);
  2232. merge(true, this.options.labels[i], labels.options);
  2233. }, this);
  2234. };
  2235. Annotation.prototype.addClipPaths = function () {
  2236. this.setClipAxes();
  2237. if (this.clipXAxis && this.clipYAxis) {
  2238. this.clipRect = this.chart.renderer.clipRect(this.getClipBox());
  2239. }
  2240. };
  2241. Annotation.prototype.setClipAxes = function () {
  2242. var xAxes = this.chart.xAxis, yAxes = this.chart.yAxis, linkedAxes = (this.options.labels || [])
  2243. .concat(this.options.shapes || [])
  2244. .reduce(function (axes, labelOrShape) {
  2245. return [
  2246. xAxes[labelOrShape &&
  2247. labelOrShape.point &&
  2248. labelOrShape.point.xAxis] || axes[0],
  2249. yAxes[labelOrShape &&
  2250. labelOrShape.point &&
  2251. labelOrShape.point.yAxis] || axes[1]
  2252. ];
  2253. }, []);
  2254. this.clipXAxis = linkedAxes[0];
  2255. this.clipYAxis = linkedAxes[1];
  2256. };
  2257. Annotation.prototype.getClipBox = function () {
  2258. if (this.clipXAxis && this.clipYAxis) {
  2259. return {
  2260. x: this.clipXAxis.left,
  2261. y: this.clipYAxis.top,
  2262. width: this.clipXAxis.width,
  2263. height: this.clipYAxis.height
  2264. };
  2265. }
  2266. };
  2267. Annotation.prototype.setLabelCollector = function () {
  2268. var annotation = this;
  2269. annotation.labelCollector = function () {
  2270. return annotation.labels.reduce(function (labels, label) {
  2271. if (!label.options.allowOverlap) {
  2272. labels.push(label.graphic);
  2273. }
  2274. return labels;
  2275. }, []);
  2276. };
  2277. annotation.chart.labelCollectors.push(annotation.labelCollector);
  2278. };
  2279. /**
  2280. * Set an annotation options.
  2281. * @private
  2282. * @param {Highcharts.AnnotationsOptions} - user options for an annotation
  2283. */
  2284. Annotation.prototype.setOptions = function (userOptions) {
  2285. this.options = merge(this.defaultOptions, userOptions);
  2286. };
  2287. Annotation.prototype.redraw = function (animation) {
  2288. this.linkPoints();
  2289. if (!this.graphic) {
  2290. this.render();
  2291. }
  2292. if (this.clipRect) {
  2293. this.clipRect.animate(this.getClipBox());
  2294. }
  2295. this.redrawItems(this.shapes, animation);
  2296. this.redrawItems(this.labels, animation);
  2297. ControllableMixin.redraw.call(this, animation);
  2298. };
  2299. /**
  2300. * @private
  2301. * @param {Array<Highcharts.AnnotationControllable>} items
  2302. * @param {boolean} [animation]
  2303. */
  2304. Annotation.prototype.redrawItems = function (items, animation) {
  2305. var i = items.length;
  2306. // needs a backward loop
  2307. // labels/shapes array might be modified
  2308. // due to destruction of the item
  2309. while (i--) {
  2310. this.redrawItem(items[i], animation);
  2311. }
  2312. };
  2313. /**
  2314. * @private
  2315. * @param {Array<Highcharts.AnnotationControllable>} items
  2316. */
  2317. Annotation.prototype.renderItems = function (items) {
  2318. var i = items.length;
  2319. while (i--) {
  2320. this.renderItem(items[i]);
  2321. }
  2322. };
  2323. Annotation.prototype.render = function () {
  2324. var renderer = this.chart.renderer;
  2325. this.graphic = renderer
  2326. .g('annotation')
  2327. .attr({
  2328. zIndex: this.options.zIndex,
  2329. visibility: this.options.visible ?
  2330. 'visible' :
  2331. 'hidden'
  2332. })
  2333. .add();
  2334. this.shapesGroup = renderer
  2335. .g('annotation-shapes')
  2336. .add(this.graphic)
  2337. .clip(this.chart.plotBoxClip);
  2338. this.labelsGroup = renderer
  2339. .g('annotation-labels')
  2340. .attr({
  2341. // hideOverlappingLabels requires translation
  2342. translateX: 0,
  2343. translateY: 0
  2344. })
  2345. .add(this.graphic);
  2346. this.addClipPaths();
  2347. if (this.clipRect) {
  2348. this.graphic.clip(this.clipRect);
  2349. }
  2350. // Render shapes and labels before adding events (#13070).
  2351. this.renderItems(this.shapes);
  2352. this.renderItems(this.labels);
  2353. this.addEvents();
  2354. ControllableMixin.render.call(this);
  2355. };
  2356. /**
  2357. * Set the annotation's visibility.
  2358. * @private
  2359. * @param {boolean} [visible]
  2360. * Whether to show or hide an annotation. If the param is omitted, the
  2361. * annotation's visibility is toggled.
  2362. */
  2363. Annotation.prototype.setVisibility = function (visible) {
  2364. var options = this.options, visibility = pick(visible, !options.visible);
  2365. this.graphic.attr('visibility', visibility ? 'visible' : 'hidden');
  2366. if (!visibility) {
  2367. this.setControlPointsVisibility(false);
  2368. }
  2369. options.visible = visibility;
  2370. };
  2371. Annotation.prototype.setControlPointsVisibility = function (visible) {
  2372. var setItemControlPointsVisibility = function (item) {
  2373. item.setControlPointsVisibility(visible);
  2374. };
  2375. ControllableMixin.setControlPointsVisibility.call(this, visible);
  2376. this.shapes.forEach(setItemControlPointsVisibility);
  2377. this.labels.forEach(setItemControlPointsVisibility);
  2378. };
  2379. /**
  2380. * Destroy the annotation. This function does not touch the chart
  2381. * that the annotation belongs to (all annotations are kept in
  2382. * the chart.annotations array) - it is recommended to use
  2383. * {@link Highcharts.Chart#removeAnnotation} instead.
  2384. * @private
  2385. */
  2386. Annotation.prototype.destroy = function () {
  2387. var chart = this.chart, destroyItem = function (item) {
  2388. item.destroy();
  2389. };
  2390. this.labels.forEach(destroyItem);
  2391. this.shapes.forEach(destroyItem);
  2392. this.clipXAxis = null;
  2393. this.clipYAxis = null;
  2394. erase(chart.labelCollectors, this.labelCollector);
  2395. EventEmitterMixin.destroy.call(this);
  2396. ControllableMixin.destroy.call(this);
  2397. destroyObjectProperties(this, chart);
  2398. };
  2399. /**
  2400. * See {@link Highcharts.Chart#removeAnnotation}.
  2401. * @private
  2402. */
  2403. Annotation.prototype.remove = function () {
  2404. // Let chart.update() remove annoations on demand
  2405. return this.chart.removeAnnotation(this);
  2406. };
  2407. /**
  2408. * Updates an annotation.
  2409. *
  2410. * @function Highcharts.Annotation#update
  2411. *
  2412. * @param {Partial<Highcharts.AnnotationsOptions>} userOptions
  2413. * New user options for the annotation.
  2414. *
  2415. * @return {void}
  2416. */
  2417. Annotation.prototype.update = function (userOptions, redraw) {
  2418. var chart = this.chart, labelsAndShapes = this.getLabelsAndShapesOptions(this.userOptions, userOptions), userOptionsIndex = chart.annotations.indexOf(this), options = merge(true, this.userOptions, userOptions);
  2419. options.labels = labelsAndShapes.labels;
  2420. options.shapes = labelsAndShapes.shapes;
  2421. this.destroy();
  2422. this.constructor(chart, options);
  2423. // Update options in chart options, used in exporting (#9767):
  2424. chart.options.annotations[userOptionsIndex] = options;
  2425. this.isUpdating = true;
  2426. if (pick(redraw, true)) {
  2427. chart.redraw();
  2428. }
  2429. fireEvent(this, 'afterUpdate');
  2430. this.isUpdating = false;
  2431. };
  2432. /* *************************************************************
  2433. * ITEM SECTION
  2434. * Contains methods for handling a single item in an annotation
  2435. **************************************************************** */
  2436. /**
  2437. * Initialisation of a single shape
  2438. * @private
  2439. * @param {Object} shapeOptions - a confg object for a single shape
  2440. */
  2441. Annotation.prototype.initShape = function (shapeOptions, index) {
  2442. var options = merge(this.options.shapeOptions, {
  2443. controlPointOptions: this.options.controlPointOptions
  2444. }, shapeOptions), shape = new Annotation.shapesMap[options.type](this, options, index);
  2445. shape.itemType = 'shape';
  2446. this.shapes.push(shape);
  2447. return shape;
  2448. };
  2449. /**
  2450. * Initialisation of a single label
  2451. * @private
  2452. */
  2453. Annotation.prototype.initLabel = function (labelOptions, index) {
  2454. var options = merge(this.options.labelOptions, {
  2455. controlPointOptions: this.options.controlPointOptions
  2456. }, labelOptions), label = new ControllableLabel(this, options, index);
  2457. label.itemType = 'label';
  2458. this.labels.push(label);
  2459. return label;
  2460. };
  2461. /**
  2462. * Redraw a single item.
  2463. * @private
  2464. * @param {Annotation.Label|Annotation.Shape} item
  2465. * @param {boolean} [animation]
  2466. */
  2467. Annotation.prototype.redrawItem = function (item, animation) {
  2468. item.linkPoints();
  2469. if (!item.shouldBeDrawn()) {
  2470. this.destroyItem(item);
  2471. }
  2472. else {
  2473. if (!item.graphic) {
  2474. this.renderItem(item);
  2475. }
  2476. item.redraw(pick(animation, true) && item.graphic.placed);
  2477. if (item.points.length) {
  2478. this.adjustVisibility(item);
  2479. }
  2480. }
  2481. };
  2482. /**
  2483. * Hide or show annotaiton attached to points.
  2484. * @private
  2485. * @param {Annotation.Label|Annotation.Shape} item
  2486. */
  2487. Annotation.prototype.adjustVisibility = function (item) {
  2488. var hasVisiblePoints = false, label = item.graphic;
  2489. item.points.forEach(function (point) {
  2490. if (point.series.visible !== false &&
  2491. point.visible !== false) {
  2492. hasVisiblePoints = true;
  2493. }
  2494. });
  2495. if (!hasVisiblePoints) {
  2496. label.hide();
  2497. }
  2498. else if (label.visibility === 'hidden') {
  2499. label.show();
  2500. }
  2501. };
  2502. /**
  2503. * Destroy a single item.
  2504. * @private
  2505. * @param {Annotation.Label|Annotation.Shape} item
  2506. */
  2507. Annotation.prototype.destroyItem = function (item) {
  2508. // erase from shapes or labels array
  2509. erase(this[item.itemType + 's'], item);
  2510. item.destroy();
  2511. };
  2512. /**
  2513. * @private
  2514. */
  2515. Annotation.prototype.renderItem = function (item) {
  2516. item.render(item.itemType === 'label' ?
  2517. this.labelsGroup :
  2518. this.shapesGroup);
  2519. };
  2520. /**
  2521. * @private
  2522. */
  2523. Annotation.ControlPoint = ControlPoint;
  2524. /**
  2525. * @private
  2526. */
  2527. Annotation.MockPoint = MockPoint;
  2528. /**
  2529. * An object uses for mapping between a shape type and a constructor.
  2530. * To add a new shape type extend this object with type name as a key
  2531. * and a constructor as its value.
  2532. */
  2533. Annotation.shapesMap = {
  2534. 'rect': ControllableRect,
  2535. 'circle': ControllableCircle,
  2536. 'path': ControllablePath,
  2537. 'image': ControllableImage
  2538. };
  2539. /**
  2540. * @private
  2541. */
  2542. Annotation.types = {};
  2543. return Annotation;
  2544. }());
  2545. merge(true, Annotation.prototype, ControllableMixin, EventEmitterMixin,
  2546. // restore original Annotation implementation after mixin overwrite
  2547. merge(Annotation.prototype,
  2548. /** @lends Highcharts.Annotation# */
  2549. {
  2550. /**
  2551. * List of events for `annotation.options.events` that should not be
  2552. * added to `annotation.graphic` but to the `annotation`.
  2553. *
  2554. * @private
  2555. * @type {Array<string>}
  2556. */
  2557. nonDOMEvents: ['add', 'afterUpdate', 'drag', 'remove'],
  2558. /**
  2559. * A basic type of an annotation. It allows to add custom labels
  2560. * or shapes. The items can be tied to points, axis coordinates
  2561. * or chart pixel coordinates.
  2562. *
  2563. * @sample highcharts/annotations/basic/
  2564. * Basic annotations
  2565. * @sample highcharts/demo/annotations/
  2566. * Advanced annotations
  2567. * @sample highcharts/css/annotations
  2568. * Styled mode
  2569. * @sample highcharts/annotations-advanced/controllable
  2570. * Controllable items
  2571. * @sample {highstock} stock/annotations/fibonacci-retracements
  2572. * Custom annotation, Fibonacci retracement
  2573. *
  2574. * @type {Array<*>}
  2575. * @since 6.0.0
  2576. * @requires modules/annotations
  2577. * @optionparent annotations
  2578. *
  2579. * @private
  2580. */
  2581. defaultOptions: {
  2582. /**
  2583. * Sets an ID for an annotation. Can be user later when
  2584. * removing an annotation in [Chart#removeAnnotation(id)](
  2585. * /class-reference/Highcharts.Chart#removeAnnotation) method.
  2586. *
  2587. * @type {number|string}
  2588. * @apioption annotations.id
  2589. */
  2590. /**
  2591. * Whether the annotation is visible.
  2592. *
  2593. * @sample highcharts/annotations/visible/
  2594. * Set annotation visibility
  2595. */
  2596. visible: true,
  2597. /**
  2598. * Allow an annotation to be draggable by a user. Possible
  2599. * values are `'x'`, `'xy'`, `'y'` and `''` (disabled).
  2600. *
  2601. * @sample highcharts/annotations/draggable/
  2602. * Annotations draggable: 'xy'
  2603. *
  2604. * @type {Highcharts.AnnotationDraggableValue}
  2605. */
  2606. draggable: 'xy',
  2607. /**
  2608. * Options for annotation's labels. Each label inherits options
  2609. * from the labelOptions object. An option from the labelOptions
  2610. * can be overwritten by config for a specific label.
  2611. *
  2612. * @requires modules/annotations
  2613. */
  2614. labelOptions: {
  2615. /**
  2616. * The alignment of the annotation's label. If right,
  2617. * the right side of the label should be touching the point.
  2618. *
  2619. * @sample highcharts/annotations/label-position/
  2620. * Set labels position
  2621. *
  2622. * @type {Highcharts.AlignValue}
  2623. */
  2624. align: 'center',
  2625. /**
  2626. * Whether to allow the annotation's labels to overlap.
  2627. * To make the labels less sensitive for overlapping,
  2628. * the can be set to 0.
  2629. *
  2630. * @sample highcharts/annotations/tooltip-like/
  2631. * Hide overlapping labels
  2632. */
  2633. allowOverlap: false,
  2634. /**
  2635. * The background color or gradient for the annotation's
  2636. * label.
  2637. *
  2638. * @sample highcharts/annotations/label-presentation/
  2639. * Set labels graphic options
  2640. *
  2641. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  2642. */
  2643. backgroundColor: 'rgba(0, 0, 0, 0.75)',
  2644. /**
  2645. * The border color for the annotation's label.
  2646. *
  2647. * @sample highcharts/annotations/label-presentation/
  2648. * Set labels graphic options
  2649. *
  2650. * @type {Highcharts.ColorString}
  2651. */
  2652. borderColor: 'black',
  2653. /**
  2654. * The border radius in pixels for the annotaiton's label.
  2655. *
  2656. * @sample highcharts/annotations/label-presentation/
  2657. * Set labels graphic options
  2658. */
  2659. borderRadius: 3,
  2660. /**
  2661. * The border width in pixels for the annotation's label
  2662. *
  2663. * @sample highcharts/annotations/label-presentation/
  2664. * Set labels graphic options
  2665. */
  2666. borderWidth: 1,
  2667. /**
  2668. * A class name for styling by CSS.
  2669. *
  2670. * @sample highcharts/css/annotations
  2671. * Styled mode annotations
  2672. *
  2673. * @since 6.0.5
  2674. */
  2675. className: '',
  2676. /**
  2677. * Whether to hide the annotation's label
  2678. * that is outside the plot area.
  2679. *
  2680. * @sample highcharts/annotations/label-crop-overflow/
  2681. * Crop or justify labels
  2682. */
  2683. crop: false,
  2684. /**
  2685. * The label's pixel distance from the point.
  2686. *
  2687. * @sample highcharts/annotations/label-position/
  2688. * Set labels position
  2689. *
  2690. * @type {number}
  2691. * @apioption annotations.labelOptions.distance
  2692. */
  2693. /**
  2694. * A
  2695. * [format](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
  2696. * string for the data label.
  2697. *
  2698. * @see [plotOptions.series.dataLabels.format](plotOptions.series.dataLabels.format.html)
  2699. *
  2700. * @sample highcharts/annotations/label-text/
  2701. * Set labels text
  2702. *
  2703. * @type {string}
  2704. * @apioption annotations.labelOptions.format
  2705. */
  2706. /**
  2707. * Alias for the format option.
  2708. *
  2709. * @see [format](annotations.labelOptions.format.html)
  2710. *
  2711. * @sample highcharts/annotations/label-text/
  2712. * Set labels text
  2713. *
  2714. * @type {string}
  2715. * @apioption annotations.labelOptions.text
  2716. */
  2717. /**
  2718. * Callback JavaScript function to format the annotation's
  2719. * label. Note that if a `format` or `text` are defined,
  2720. * the format or text take precedence and the formatter is
  2721. * ignored. `This` refers to a point object.
  2722. *
  2723. * @sample highcharts/annotations/label-text/
  2724. * Set labels text
  2725. *
  2726. * @type {Highcharts.FormatterCallbackFunction<Highcharts.Point>}
  2727. * @default function () { return defined(this.y) ? this.y : 'Annotation label'; }
  2728. */
  2729. formatter: function () {
  2730. return defined(this.y) ? this.y : 'Annotation label';
  2731. },
  2732. /**
  2733. * How to handle the annotation's label that flow outside
  2734. * the plot area. The justify option aligns the label inside
  2735. * the plot area.
  2736. *
  2737. * @sample highcharts/annotations/label-crop-overflow/
  2738. * Crop or justify labels
  2739. *
  2740. * @validvalue ["allow", "justify"]
  2741. */
  2742. overflow: 'justify',
  2743. /**
  2744. * When either the borderWidth or the backgroundColor is
  2745. * set, this is the padding within the box.
  2746. *
  2747. * @sample highcharts/annotations/label-presentation/
  2748. * Set labels graphic options
  2749. */
  2750. padding: 5,
  2751. /**
  2752. * The shadow of the box. The shadow can be an object
  2753. * configuration containing `color`, `offsetX`, `offsetY`,
  2754. * `opacity` and `width`.
  2755. *
  2756. * @sample highcharts/annotations/label-presentation/
  2757. * Set labels graphic options
  2758. *
  2759. * @type {boolean|Highcharts.ShadowOptionsObject}
  2760. */
  2761. shadow: false,
  2762. /**
  2763. * The name of a symbol to use for the border around the
  2764. * label. Symbols are predefined functions on the Renderer
  2765. * object.
  2766. *
  2767. * @sample highcharts/annotations/shapes/
  2768. * Available shapes for labels
  2769. */
  2770. shape: 'callout',
  2771. /**
  2772. * Styles for the annotation's label.
  2773. *
  2774. * @see [plotOptions.series.dataLabels.style](plotOptions.series.dataLabels.style.html)
  2775. *
  2776. * @sample highcharts/annotations/label-presentation/
  2777. * Set labels graphic options
  2778. *
  2779. * @type {Highcharts.CSSObject}
  2780. */
  2781. style: {
  2782. /** @ignore */
  2783. fontSize: '11px',
  2784. /** @ignore */
  2785. fontWeight: 'normal',
  2786. /** @ignore */
  2787. color: 'contrast'
  2788. },
  2789. /**
  2790. * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
  2791. * to render the annotation's label.
  2792. */
  2793. useHTML: false,
  2794. /**
  2795. * The vertical alignment of the annotation's label.
  2796. *
  2797. * @sample highcharts/annotations/label-position/
  2798. * Set labels position
  2799. *
  2800. * @type {Highcharts.VerticalAlignValue}
  2801. */
  2802. verticalAlign: 'bottom',
  2803. /**
  2804. * The x position offset of the label relative to the point.
  2805. * Note that if a `distance` is defined, the distance takes
  2806. * precedence over `x` and `y` options.
  2807. *
  2808. * @sample highcharts/annotations/label-position/
  2809. * Set labels position
  2810. */
  2811. x: 0,
  2812. /**
  2813. * The y position offset of the label relative to the point.
  2814. * Note that if a `distance` is defined, the distance takes
  2815. * precedence over `x` and `y` options.
  2816. *
  2817. * @sample highcharts/annotations/label-position/
  2818. * Set labels position
  2819. */
  2820. y: -16
  2821. },
  2822. /**
  2823. * An array of labels for the annotation. For options that apply
  2824. * to multiple labels, they can be added to the
  2825. * [labelOptions](annotations.labelOptions.html).
  2826. *
  2827. * @type {Array<*>}
  2828. * @extends annotations.labelOptions
  2829. * @apioption annotations.labels
  2830. */
  2831. /**
  2832. * This option defines the point to which the label will be
  2833. * connected. It can be either the point which exists in the
  2834. * series - it is referenced by the point's id - or a new point
  2835. * with defined x, y properties and optionally axes.
  2836. *
  2837. * @sample highcharts/annotations/mock-point/
  2838. * Attach annotation to a mock point
  2839. *
  2840. * @declare Highcharts.AnnotationMockPointOptionsObject
  2841. * @type {string|*}
  2842. * @requires modules/annotations
  2843. * @apioption annotations.labels.point
  2844. */
  2845. /**
  2846. * The x position of the point. Units can be either in axis
  2847. * or chart pixel coordinates.
  2848. *
  2849. * @type {number}
  2850. * @apioption annotations.labels.point.x
  2851. */
  2852. /**
  2853. * The y position of the point. Units can be either in axis
  2854. * or chart pixel coordinates.
  2855. *
  2856. * @type {number}
  2857. * @apioption annotations.labels.point.y
  2858. */
  2859. /**
  2860. * This number defines which xAxis the point is connected to.
  2861. * It refers to either the axis id or the index of the axis in
  2862. * the xAxis array. If the option is not configured or the axis
  2863. * is not found the point's x coordinate refers to the chart
  2864. * pixels.
  2865. *
  2866. * @type {number|string|null}
  2867. * @apioption annotations.labels.point.xAxis
  2868. */
  2869. /**
  2870. * This number defines which yAxis the point is connected to.
  2871. * It refers to either the axis id or the index of the axis in
  2872. * the yAxis array. If the option is not configured or the axis
  2873. * is not found the point's y coordinate refers to the chart
  2874. * pixels.
  2875. *
  2876. * @type {number|string|null}
  2877. * @apioption annotations.labels.point.yAxis
  2878. */
  2879. /**
  2880. * An array of shapes for the annotation. For options that apply
  2881. * to multiple shapes, then can be added to the
  2882. * [shapeOptions](annotations.shapeOptions.html).
  2883. *
  2884. * @type {Array<*>}
  2885. * @extends annotations.shapeOptions
  2886. * @apioption annotations.shapes
  2887. */
  2888. /**
  2889. * This option defines the point to which the shape will be
  2890. * connected. It can be either the point which exists in the
  2891. * series - it is referenced by the point's id - or a new point
  2892. * with defined x, y properties and optionally axes.
  2893. *
  2894. * @declare Highcharts.AnnotationMockPointOptionsObject
  2895. * @type {string|Highcharts.AnnotationMockPointOptionsObject}
  2896. * @extends annotations.labels.point
  2897. * @apioption annotations.shapes.point
  2898. */
  2899. /**
  2900. * An array of points for the shape. This option is available
  2901. * for shapes which can use multiple points such as path. A
  2902. * point can be either a point object or a point's id.
  2903. *
  2904. * @see [annotations.shapes.point](annotations.shapes.point.html)
  2905. *
  2906. * @declare Highcharts.AnnotationMockPointOptionsObject
  2907. * @type {Array<string|*>}
  2908. * @extends annotations.labels.point
  2909. * @apioption annotations.shapes.points
  2910. */
  2911. /**
  2912. * The URL for an image to use as the annotation shape. Note,
  2913. * type has to be set to `'image'`.
  2914. *
  2915. * @see [annotations.shapes.type](annotations.shapes.type)
  2916. * @sample highcharts/annotations/shape-src/
  2917. * Define a marker image url for annotations
  2918. *
  2919. * @type {string}
  2920. * @apioption annotations.shapes.src
  2921. */
  2922. /**
  2923. * Id of the marker which will be drawn at the final vertex of
  2924. * the path. Custom markers can be defined in defs property.
  2925. *
  2926. * @see [defs.markers](defs.markers.html)
  2927. *
  2928. * @sample highcharts/annotations/custom-markers/
  2929. * Define a custom marker for annotations
  2930. *
  2931. * @type {string}
  2932. * @apioption annotations.shapes.markerEnd
  2933. */
  2934. /**
  2935. * Id of the marker which will be drawn at the first vertex of
  2936. * the path. Custom markers can be defined in defs property.
  2937. *
  2938. * @see [defs.markers](defs.markers.html)
  2939. *
  2940. * @sample {highcharts} highcharts/annotations/custom-markers/
  2941. * Define a custom marker for annotations
  2942. *
  2943. * @type {string}
  2944. * @apioption annotations.shapes.markerStart
  2945. */
  2946. /**
  2947. * Options for annotation's shapes. Each shape inherits options
  2948. * from the shapeOptions object. An option from the shapeOptions
  2949. * can be overwritten by config for a specific shape.
  2950. *
  2951. * @requires modules/annotations
  2952. */
  2953. shapeOptions: {
  2954. /**
  2955. * The width of the shape.
  2956. *
  2957. * @sample highcharts/annotations/shape/
  2958. * Basic shape annotation
  2959. *
  2960. * @type {number}
  2961. * @apioption annotations.shapeOptions.width
  2962. **/
  2963. /**
  2964. * The height of the shape.
  2965. *
  2966. * @sample highcharts/annotations/shape/
  2967. * Basic shape annotation
  2968. *
  2969. * @type {number}
  2970. * @apioption annotations.shapeOptions.height
  2971. */
  2972. /**
  2973. * The type of the shape, e.g. circle or rectangle.
  2974. *
  2975. * @sample highcharts/annotations/shape/
  2976. * Basic shape annotation
  2977. *
  2978. * @type {string}
  2979. * @default 'rect'
  2980. * @apioption annotations.shapeOptions.type
  2981. */
  2982. /**
  2983. * The URL for an image to use as the annotation shape.
  2984. * Note, type has to be set to `'image'`.
  2985. *
  2986. * @see [annotations.shapeOptions.type](annotations.shapeOptions.type)
  2987. * @sample highcharts/annotations/shape-src/
  2988. * Define a marker image url for annotations
  2989. *
  2990. * @type {string}
  2991. * @apioption annotations.shapeOptions.src
  2992. */
  2993. /**
  2994. * Name of the dash style to use for the shape's stroke.
  2995. *
  2996. * @sample {highcharts} highcharts/plotoptions/series-dashstyle-all/
  2997. * Possible values demonstrated
  2998. *
  2999. * @type {Highcharts.DashStyleValue}
  3000. * @apioption annotations.shapeOptions.dashStyle
  3001. */
  3002. /**
  3003. * The color of the shape's stroke.
  3004. *
  3005. * @sample highcharts/annotations/shape/
  3006. * Basic shape annotation
  3007. *
  3008. * @type {Highcharts.ColorString}
  3009. */
  3010. stroke: 'rgba(0, 0, 0, 0.75)',
  3011. /**
  3012. * The pixel stroke width of the shape.
  3013. *
  3014. * @sample highcharts/annotations/shape/
  3015. * Basic shape annotation
  3016. */
  3017. strokeWidth: 1,
  3018. /**
  3019. * The color of the shape's fill.
  3020. *
  3021. * @sample highcharts/annotations/shape/
  3022. * Basic shape annotation
  3023. *
  3024. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  3025. */
  3026. fill: 'rgba(0, 0, 0, 0.75)',
  3027. /**
  3028. * The radius of the shape.
  3029. *
  3030. * @sample highcharts/annotations/shape/
  3031. * Basic shape annotation
  3032. */
  3033. r: 0,
  3034. /**
  3035. * Defines additional snapping area around an annotation
  3036. * making this annotation to focus. Defined in pixels.
  3037. */
  3038. snap: 2
  3039. },
  3040. /**
  3041. * Options for annotation's control points. Each control point
  3042. * inherits options from controlPointOptions object.
  3043. * Options from the controlPointOptions can be overwritten
  3044. * by options in a specific control point.
  3045. *
  3046. * @declare Highcharts.AnnotationControlPointOptionsObject
  3047. * @requires modules/annotations
  3048. * @apioption annotations.controlPointOptions
  3049. */
  3050. controlPointOptions: {
  3051. /**
  3052. * @type {Highcharts.AnnotationControlPointPositionerFunction}
  3053. * @apioption annotations.controlPointOptions.positioner
  3054. */
  3055. symbol: 'circle',
  3056. width: 10,
  3057. height: 10,
  3058. style: {
  3059. stroke: 'black',
  3060. 'stroke-width': 2,
  3061. fill: 'white'
  3062. },
  3063. visible: false,
  3064. events: {}
  3065. },
  3066. /**
  3067. * Event callback when annotation is added to the chart.
  3068. *
  3069. * @type {Highcharts.EventCallbackFunction<Highcharts.Annotation>}
  3070. * @since 7.1.0
  3071. * @apioption annotations.events.add
  3072. */
  3073. /**
  3074. * Event callback when annotation is updated (e.g. drag and
  3075. * droppped or resized by control points).
  3076. *
  3077. * @type {Highcharts.EventCallbackFunction<Highcharts.Annotation>}
  3078. * @since 7.1.0
  3079. * @apioption annotations.events.afterUpdate
  3080. */
  3081. /**
  3082. * Event callback when annotation is removed from the chart.
  3083. *
  3084. * @type {Highcharts.EventCallbackFunction<Highcharts.Annotation>}
  3085. * @since 7.1.0
  3086. * @apioption annotations.events.remove
  3087. */
  3088. /**
  3089. * Events available in annotations.
  3090. *
  3091. * @requires modules/annotations
  3092. */
  3093. events: {},
  3094. /**
  3095. * The Z index of the annotation.
  3096. */
  3097. zIndex: 6
  3098. }
  3099. }));
  3100. H.extendAnnotation = function (Constructor, BaseConstructor, prototype, defaultOptions) {
  3101. BaseConstructor = BaseConstructor || Annotation;
  3102. merge(true, Constructor.prototype, BaseConstructor.prototype, prototype);
  3103. Constructor.prototype.defaultOptions = merge(Constructor.prototype.defaultOptions, defaultOptions || {});
  3104. };
  3105. /* *********************************************************************
  3106. *
  3107. * EXTENDING CHART PROTOTYPE
  3108. *
  3109. ******************************************************************** */
  3110. extend(chartProto, /** @lends Highcharts.Chart# */ {
  3111. initAnnotation: function (userOptions) {
  3112. var Constructor = Annotation.types[userOptions.type] || Annotation, annotation = new Constructor(this, userOptions);
  3113. this.annotations.push(annotation);
  3114. return annotation;
  3115. },
  3116. /**
  3117. * Add an annotation to the chart after render time.
  3118. *
  3119. * @param {Highcharts.AnnotationsOptions} options
  3120. * The annotation options for the new, detailed annotation.
  3121. * @param {boolean} [redraw]
  3122. *
  3123. * @return {Highcharts.Annotation} - The newly generated annotation.
  3124. */
  3125. addAnnotation: function (userOptions, redraw) {
  3126. var annotation = this.initAnnotation(userOptions);
  3127. this.options.annotations.push(annotation.options);
  3128. if (pick(redraw, true)) {
  3129. annotation.redraw();
  3130. }
  3131. return annotation;
  3132. },
  3133. /**
  3134. * Remove an annotation from the chart.
  3135. *
  3136. * @param {number|string|Highcharts.Annotation} idOrAnnotation
  3137. * The annotation's id or direct annotation object.
  3138. */
  3139. removeAnnotation: function (idOrAnnotation) {
  3140. var annotations = this.annotations, annotation = idOrAnnotation.coll === 'annotations' ?
  3141. idOrAnnotation :
  3142. find(annotations, function (annotation) {
  3143. return annotation.options.id === idOrAnnotation;
  3144. });
  3145. if (annotation) {
  3146. fireEvent(annotation, 'remove');
  3147. erase(this.options.annotations, annotation.options);
  3148. erase(annotations, annotation);
  3149. annotation.destroy();
  3150. }
  3151. },
  3152. drawAnnotations: function () {
  3153. this.plotBoxClip.attr(this.plotBox);
  3154. this.annotations.forEach(function (annotation) {
  3155. annotation.redraw();
  3156. });
  3157. }
  3158. });
  3159. // Let chart.update() update annotations
  3160. chartProto.collectionsWithUpdate.push('annotations');
  3161. // Let chart.update() create annoations on demand
  3162. chartProto.collectionsWithInit.annotations = [chartProto.addAnnotation];
  3163. chartProto.callbacks.push(function (chart) {
  3164. chart.annotations = [];
  3165. if (!chart.options.annotations) {
  3166. chart.options.annotations = [];
  3167. }
  3168. chart.plotBoxClip = this.renderer.clipRect(this.plotBox);
  3169. chart.controlPointsGroup = chart.renderer
  3170. .g('control-points')
  3171. .attr({ zIndex: 99 })
  3172. .clip(chart.plotBoxClip)
  3173. .add();
  3174. chart.options.annotations.forEach(function (annotationOptions, i) {
  3175. var annotation = chart.initAnnotation(annotationOptions);
  3176. chart.options.annotations[i] = annotation.options;
  3177. });
  3178. chart.drawAnnotations();
  3179. addEvent(chart, 'redraw', chart.drawAnnotations);
  3180. addEvent(chart, 'destroy', function () {
  3181. chart.plotBoxClip.destroy();
  3182. chart.controlPointsGroup.destroy();
  3183. });
  3184. });
  3185. wrap(Pointer.prototype, 'onContainerMouseDown', function (proceed) {
  3186. if (!this.chart.hasDraggedAnnotation) {
  3187. proceed.apply(this, Array.prototype.slice.call(arguments, 1));
  3188. }
  3189. });
  3190. H.Annotation = Annotation;
  3191. return Annotation;
  3192. });
  3193. _registerModule(_modules, 'mixins/navigation.js', [], function () {
  3194. /**
  3195. *
  3196. * (c) 2010-2018 Paweł Fus
  3197. *
  3198. * License: www.highcharts.com/license
  3199. *
  3200. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  3201. *
  3202. * */
  3203. var chartNavigation = {
  3204. /**
  3205. * Initializes `chart.navigation` object which delegates `update()` methods
  3206. * to all other common classes (used in exporting and navigationBindings).
  3207. *
  3208. * @private
  3209. * @param {Highcharts.Chart} chart
  3210. * The chart instance.
  3211. * @return {void}
  3212. */
  3213. initUpdate: function (chart) {
  3214. if (!chart.navigation) {
  3215. chart.navigation = {
  3216. updates: [],
  3217. update: function (options, redraw) {
  3218. this.updates.forEach(function (updateConfig) {
  3219. updateConfig.update.call(updateConfig.context, options, redraw);
  3220. });
  3221. }
  3222. };
  3223. }
  3224. },
  3225. /**
  3226. * Registers an `update()` method in the `chart.navigation` object.
  3227. *
  3228. * @private
  3229. * @param {Highcharts.ChartNavigationUpdateFunction} update
  3230. * The `update()` method that will be called in `chart.update()`.
  3231. * @param {Highcharts.Chart} chart
  3232. * The chart instance. `update()` will use that as a context
  3233. * (`this`).
  3234. * @return {void}
  3235. */
  3236. addUpdate: function (update, chart) {
  3237. if (!chart.navigation) {
  3238. this.initUpdate(chart);
  3239. }
  3240. chart.navigation.updates.push({
  3241. update: update,
  3242. context: chart
  3243. });
  3244. }
  3245. };
  3246. return chartNavigation;
  3247. });
  3248. _registerModule(_modules, 'annotations/navigationBindings.js', [_modules['annotations/annotations.src.js'], _modules['mixins/navigation.js'], _modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (Annotation, chartNavigationMixin, H, U) {
  3249. /* *
  3250. *
  3251. * (c) 2009-2017 Highsoft, Black Label
  3252. *
  3253. * License: www.highcharts.com/license
  3254. *
  3255. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  3256. *
  3257. * */
  3258. var addEvent = U.addEvent, attr = U.attr, extend = U.extend, format = U.format, fireEvent = U.fireEvent, isArray = U.isArray, isFunction = U.isFunction, isNumber = U.isNumber, isObject = U.isObject, merge = U.merge, objectEach = U.objectEach, pick = U.pick, setOptions = U.setOptions;
  3259. /**
  3260. * A config object for navigation bindings in annotations.
  3261. *
  3262. * @interface Highcharts.NavigationBindingsOptionsObject
  3263. */ /**
  3264. * ClassName of the element for a binding.
  3265. * @name Highcharts.NavigationBindingsOptionsObject#className
  3266. * @type {string|undefined}
  3267. */ /**
  3268. * Last event to be fired after last step event.
  3269. * @name Highcharts.NavigationBindingsOptionsObject#end
  3270. * @type {Function|undefined}
  3271. */ /**
  3272. * Initial event, fired on a button click.
  3273. * @name Highcharts.NavigationBindingsOptionsObject#init
  3274. * @type {Function|undefined}
  3275. */ /**
  3276. * Event fired on first click on a chart.
  3277. * @name Highcharts.NavigationBindingsOptionsObject#start
  3278. * @type {Function|undefined}
  3279. */ /**
  3280. * Last event to be fired after last step event. Array of step events to be
  3281. * called sequentially after each user click.
  3282. * @name Highcharts.NavigationBindingsOptionsObject#steps
  3283. * @type {Array<Function>|undefined}
  3284. */
  3285. var doc = H.doc, win = H.win, PREFIX = 'highcharts-';
  3286. /* eslint-disable no-invalid-this, valid-jsdoc */
  3287. /**
  3288. * IE 9-11 polyfill for Element.closest():
  3289. * @private
  3290. */
  3291. function closestPolyfill(el, s) {
  3292. var ElementProto = win.Element.prototype, elementMatches = ElementProto.matches ||
  3293. ElementProto.msMatchesSelector ||
  3294. ElementProto.webkitMatchesSelector, ret = null;
  3295. if (ElementProto.closest) {
  3296. ret = ElementProto.closest.call(el, s);
  3297. }
  3298. else {
  3299. do {
  3300. if (elementMatches.call(el, s)) {
  3301. return el;
  3302. }
  3303. el = el.parentElement || el.parentNode;
  3304. } while (el !== null && el.nodeType === 1);
  3305. }
  3306. return ret;
  3307. }
  3308. /**
  3309. * @private
  3310. * @interface bindingsUtils
  3311. */
  3312. var bindingsUtils = {
  3313. /**
  3314. * Update size of background (rect) in some annotations: Measure, Simple
  3315. * Rect.
  3316. *
  3317. * @private
  3318. * @function Highcharts.NavigationBindingsUtilsObject.updateRectSize
  3319. *
  3320. * @param {Highcharts.PointerEventObject} event
  3321. * Normalized browser event
  3322. *
  3323. * @param {Highcharts.Annotation} annotation
  3324. * Annotation to be updated
  3325. */
  3326. updateRectSize: function (event, annotation) {
  3327. var chart = annotation.chart, options = annotation.options.typeOptions, coords = chart.pointer.getCoordinates(event), width = coords.xAxis[0].value - options.point.x, height = options.point.y - coords.yAxis[0].value;
  3328. annotation.update({
  3329. typeOptions: {
  3330. background: {
  3331. width: chart.inverted ? height : width,
  3332. height: chart.inverted ? width : height
  3333. }
  3334. }
  3335. });
  3336. },
  3337. /**
  3338. * Get field type according to value
  3339. *
  3340. * @private
  3341. * @function Highcharts.NavigationBindingsUtilsObject.getFieldType
  3342. *
  3343. * @param {'boolean'|'number'|'string'} value
  3344. * Atomic type (one of: string, number, boolean)
  3345. *
  3346. * @return {'checkbox'|'number'|'text'}
  3347. * Field type (one of: text, number, checkbox)
  3348. */
  3349. getFieldType: function (value) {
  3350. return {
  3351. 'string': 'text',
  3352. 'number': 'number',
  3353. 'boolean': 'checkbox'
  3354. }[typeof value];
  3355. }
  3356. };
  3357. /**
  3358. * @private
  3359. */
  3360. var NavigationBindings = /** @class */ (function () {
  3361. /* *
  3362. *
  3363. * Constructors
  3364. *
  3365. * */
  3366. function NavigationBindings(chart, options) {
  3367. this.boundClassNames = void 0;
  3368. this.selectedButton = void 0;
  3369. this.chart = chart;
  3370. this.options = options;
  3371. this.eventsToUnbind = [];
  3372. this.container = doc.getElementsByClassName(this.options.bindingsClassName || '');
  3373. }
  3374. // Private properties added by bindings:
  3375. // Active (selected) annotation that is editted through popup/forms
  3376. // activeAnnotation: Annotation
  3377. // Holder for current step, used on mouse move to update bound object
  3378. // mouseMoveEvent: function () {}
  3379. // Next event in `step` array to be called on chart's click
  3380. // nextEvent: function () {}
  3381. // Index in the `step` array of the current event
  3382. // stepIndex: 0
  3383. // Flag to determine if current binding has steps
  3384. // steps: true|false
  3385. // Bindings holder for all events
  3386. // selectedButton: {}
  3387. // Holder for user options, returned from `start` event, and passed on to
  3388. // `step`'s' and `end`.
  3389. // currentUserDetails: {}
  3390. /* *
  3391. *
  3392. * Functions
  3393. *
  3394. * */
  3395. /**
  3396. * Initi all events conencted to NavigationBindings.
  3397. *
  3398. * @private
  3399. * @function Highcharts.NavigationBindings#initEvents
  3400. */
  3401. NavigationBindings.prototype.initEvents = function () {
  3402. var navigation = this, chart = navigation.chart, bindingsContainer = navigation.container, options = navigation.options;
  3403. // Shorthand object for getting events for buttons:
  3404. navigation.boundClassNames = {};
  3405. objectEach((options.bindings || {}), function (value) {
  3406. navigation.boundClassNames[value.className] = value;
  3407. });
  3408. // Handle multiple containers with the same class names:
  3409. [].forEach.call(bindingsContainer, function (subContainer) {
  3410. navigation.eventsToUnbind.push(addEvent(subContainer, 'click', function (event) {
  3411. var bindings = navigation.getButtonEvents(subContainer, event);
  3412. if (bindings) {
  3413. navigation.bindingsButtonClick(bindings.button, bindings.events, event);
  3414. }
  3415. }));
  3416. });
  3417. objectEach(options.events || {}, function (callback, eventName) {
  3418. if (isFunction(callback)) {
  3419. navigation.eventsToUnbind.push(addEvent(navigation, eventName, callback));
  3420. }
  3421. });
  3422. navigation.eventsToUnbind.push(addEvent(chart.container, 'click', function (e) {
  3423. if (!chart.cancelClick &&
  3424. chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) {
  3425. navigation.bindingsChartClick(this, e);
  3426. }
  3427. }));
  3428. navigation.eventsToUnbind.push(addEvent(chart.container, H.isTouchDevice ? 'touchmove' : 'mousemove', function (e) {
  3429. navigation.bindingsContainerMouseMove(this, e);
  3430. }));
  3431. };
  3432. /**
  3433. * Common chart.update() delegation, shared between bindings and exporting.
  3434. *
  3435. * @private
  3436. * @function Highcharts.NavigationBindings#initUpdate
  3437. */
  3438. NavigationBindings.prototype.initUpdate = function () {
  3439. var navigation = this;
  3440. chartNavigationMixin.addUpdate(function (options) {
  3441. navigation.update(options);
  3442. }, this.chart);
  3443. };
  3444. /**
  3445. * Hook for click on a button, method selcts/unselects buttons,
  3446. * then calls `bindings.init` callback.
  3447. *
  3448. * @private
  3449. * @function Highcharts.NavigationBindings#bindingsButtonClick
  3450. *
  3451. * @param {Highcharts.HTMLDOMElement} [button]
  3452. * Clicked button
  3453. *
  3454. * @param {object} events
  3455. * Events passed down from bindings (`init`, `start`, `step`, `end`)
  3456. *
  3457. * @param {Highcharts.PointerEventObject} clickEvent
  3458. * Browser's click event
  3459. */
  3460. NavigationBindings.prototype.bindingsButtonClick = function (button, events, clickEvent) {
  3461. var navigation = this, chart = navigation.chart;
  3462. if (navigation.selectedButtonElement) {
  3463. fireEvent(navigation, 'deselectButton', { button: navigation.selectedButtonElement });
  3464. if (navigation.nextEvent) {
  3465. // Remove in-progress annotations adders:
  3466. if (navigation.currentUserDetails &&
  3467. navigation.currentUserDetails.coll === 'annotations') {
  3468. chart.removeAnnotation(navigation.currentUserDetails);
  3469. }
  3470. navigation.mouseMoveEvent = navigation.nextEvent = false;
  3471. }
  3472. }
  3473. navigation.selectedButton = events;
  3474. navigation.selectedButtonElement = button;
  3475. fireEvent(navigation, 'selectButton', { button: button });
  3476. // Call "init" event, for example to open modal window
  3477. if (events.init) {
  3478. events.init.call(navigation, button, clickEvent);
  3479. }
  3480. if (events.start || events.steps) {
  3481. chart.renderer.boxWrapper.addClass(PREFIX + 'draw-mode');
  3482. }
  3483. };
  3484. /**
  3485. * Hook for click on a chart, first click on a chart calls `start` event,
  3486. * then on all subsequent clicks iterate over `steps` array.
  3487. * When finished, calls `end` event.
  3488. *
  3489. * @private
  3490. * @function Highcharts.NavigationBindings#bindingsChartClick
  3491. *
  3492. * @param {Highcharts.Chart} chart
  3493. * Chart that click was performed on.
  3494. *
  3495. * @param {Highcharts.PointerEventObject} clickEvent
  3496. * Browser's click event.
  3497. */
  3498. NavigationBindings.prototype.bindingsChartClick = function (chart, clickEvent) {
  3499. var navigation = this, chart = navigation.chart, selectedButton = navigation.selectedButton, svgContainer = chart.renderer.boxWrapper;
  3500. // Click outside popups, should close them and deselect the annotation
  3501. if (navigation.activeAnnotation &&
  3502. !clickEvent.activeAnnotation &&
  3503. // Element could be removed in the child action, e.g. button
  3504. clickEvent.target.parentNode &&
  3505. // TO DO: Polyfill for IE11?
  3506. !closestPolyfill(clickEvent.target, '.' + PREFIX + 'popup')) {
  3507. fireEvent(navigation, 'closePopup');
  3508. navigation.deselectAnnotation();
  3509. }
  3510. if (!selectedButton || !selectedButton.start) {
  3511. return;
  3512. }
  3513. if (!navigation.nextEvent) {
  3514. // Call init method:
  3515. navigation.currentUserDetails = selectedButton.start.call(navigation, clickEvent);
  3516. // If steps exists (e.g. Annotations), bind them:
  3517. if (selectedButton.steps) {
  3518. navigation.stepIndex = 0;
  3519. navigation.steps = true;
  3520. navigation.mouseMoveEvent = navigation.nextEvent =
  3521. selectedButton.steps[navigation.stepIndex];
  3522. }
  3523. else {
  3524. fireEvent(navigation, 'deselectButton', { button: navigation.selectedButtonElement });
  3525. svgContainer.removeClass(PREFIX + 'draw-mode');
  3526. navigation.steps = false;
  3527. navigation.selectedButton = null;
  3528. // First click is also the last one:
  3529. if (selectedButton.end) {
  3530. selectedButton.end.call(navigation, clickEvent, navigation.currentUserDetails);
  3531. }
  3532. }
  3533. }
  3534. else {
  3535. navigation.nextEvent(clickEvent, navigation.currentUserDetails);
  3536. if (navigation.steps) {
  3537. navigation.stepIndex++;
  3538. if (selectedButton.steps[navigation.stepIndex]) {
  3539. // If we have more steps, bind them one by one:
  3540. navigation.mouseMoveEvent = navigation.nextEvent =
  3541. selectedButton.steps[navigation.stepIndex];
  3542. }
  3543. else {
  3544. fireEvent(navigation, 'deselectButton', { button: navigation.selectedButtonElement });
  3545. svgContainer.removeClass(PREFIX + 'draw-mode');
  3546. // That was the last step, call end():
  3547. if (selectedButton.end) {
  3548. selectedButton.end.call(navigation, clickEvent, navigation.currentUserDetails);
  3549. }
  3550. navigation.nextEvent = false;
  3551. navigation.mouseMoveEvent = false;
  3552. navigation.selectedButton = null;
  3553. }
  3554. }
  3555. }
  3556. };
  3557. /**
  3558. * Hook for mouse move on a chart's container. It calls current step.
  3559. *
  3560. * @private
  3561. * @function Highcharts.NavigationBindings#bindingsContainerMouseMove
  3562. *
  3563. * @param {Highcharts.HTMLDOMElement} container
  3564. * Chart's container.
  3565. *
  3566. * @param {global.Event} moveEvent
  3567. * Browser's move event.
  3568. */
  3569. NavigationBindings.prototype.bindingsContainerMouseMove = function (_container, moveEvent) {
  3570. if (this.mouseMoveEvent) {
  3571. this.mouseMoveEvent(moveEvent, this.currentUserDetails);
  3572. }
  3573. };
  3574. /**
  3575. * Translate fields (e.g. `params.period` or `marker.styles.color`) to
  3576. * Highcharts options object (e.g. `{ params: { period } }`).
  3577. *
  3578. * @private
  3579. * @function Highcharts.NavigationBindings#fieldsToOptions<T>
  3580. *
  3581. * @param {Highcharts.Dictionary<string>} fields
  3582. * Fields from popup form.
  3583. *
  3584. * @param {T} config
  3585. * Default config to be modified.
  3586. *
  3587. * @return {T}
  3588. * Modified config
  3589. */
  3590. NavigationBindings.prototype.fieldsToOptions = function (fields, config) {
  3591. objectEach(fields, function (value, field) {
  3592. var parsedValue = parseFloat(value), path = field.split('.'), parent = config, pathLength = path.length - 1;
  3593. // If it's a number (not "format" options), parse it:
  3594. if (isNumber(parsedValue) &&
  3595. !value.match(/px/g) &&
  3596. !field.match(/format/g)) {
  3597. value = parsedValue;
  3598. }
  3599. // Remove empty strings or values like 0
  3600. if (value !== '' && value !== 'undefined') {
  3601. path.forEach(function (name, index) {
  3602. var nextName = pick(path[index + 1], '');
  3603. if (pathLength === index) {
  3604. // Last index, put value:
  3605. parent[name] = value;
  3606. }
  3607. else if (!parent[name]) {
  3608. // Create middle property:
  3609. parent[name] = nextName.match(/\d/g) ? [] : {};
  3610. parent = parent[name];
  3611. }
  3612. else {
  3613. // Jump into next property
  3614. parent = parent[name];
  3615. }
  3616. });
  3617. }
  3618. });
  3619. return config;
  3620. };
  3621. /**
  3622. * Shorthand method to deselect an annotation.
  3623. *
  3624. * @function Highcharts.NavigationBindings#deselectAnnotation
  3625. */
  3626. NavigationBindings.prototype.deselectAnnotation = function () {
  3627. if (this.activeAnnotation) {
  3628. this.activeAnnotation.setControlPointsVisibility(false);
  3629. this.activeAnnotation = false;
  3630. }
  3631. };
  3632. /**
  3633. * Generates API config for popup in the same format as options for
  3634. * Annotation object.
  3635. *
  3636. * @function Highcharts.NavigationBindings#annotationToFields
  3637. *
  3638. * @param {Highcharts.Annotation} annotation
  3639. * Annotations object
  3640. *
  3641. * @return {Highcharts.Dictionary<string>}
  3642. * Annotation options to be displayed in popup box
  3643. */
  3644. NavigationBindings.prototype.annotationToFields = function (annotation) {
  3645. var options = annotation.options, editables = NavigationBindings.annotationsEditable, nestedEditables = editables.nestedOptions, getFieldType = this.utils.getFieldType, type = pick(options.type, options.shapes && options.shapes[0] &&
  3646. options.shapes[0].type, options.labels && options.labels[0] &&
  3647. options.labels[0].itemType, 'label'), nonEditables = NavigationBindings.annotationsNonEditable[options.langKey] || [], visualOptions = {
  3648. langKey: options.langKey,
  3649. type: type
  3650. };
  3651. /**
  3652. * Nested options traversing. Method goes down to the options and copies
  3653. * allowed options (with values) to new object, which is last parameter:
  3654. * "parent".
  3655. *
  3656. * @private
  3657. *
  3658. * @param {*} option
  3659. * Atomic type or object/array
  3660. *
  3661. * @param {string} key
  3662. * Option name, for example "visible" or "x", "y"
  3663. *
  3664. * @param {object} parentEditables
  3665. * Editables from NavigationBindings.annotationsEditable
  3666. *
  3667. * @param {object} parent
  3668. * Where new options will be assigned
  3669. */
  3670. function traverse(option, key, parentEditables, parent) {
  3671. var nextParent;
  3672. if (parentEditables &&
  3673. nonEditables.indexOf(key) === -1 &&
  3674. ((parentEditables.indexOf &&
  3675. parentEditables.indexOf(key)) >= 0 ||
  3676. parentEditables[key] || // nested array
  3677. parentEditables === true // simple array
  3678. )) {
  3679. // Roots:
  3680. if (isArray(option)) {
  3681. parent[key] = [];
  3682. option.forEach(function (arrayOption, i) {
  3683. if (!isObject(arrayOption)) {
  3684. // Simple arrays, e.g. [String, Number, Boolean]
  3685. traverse(arrayOption, 0, nestedEditables[key], parent[key]);
  3686. }
  3687. else {
  3688. // Advanced arrays, e.g. [Object, Object]
  3689. parent[key][i] = {};
  3690. objectEach(arrayOption, function (nestedOption, nestedKey) {
  3691. traverse(nestedOption, nestedKey, nestedEditables[key], parent[key][i]);
  3692. });
  3693. }
  3694. });
  3695. }
  3696. else if (isObject(option)) {
  3697. nextParent = {};
  3698. if (isArray(parent)) {
  3699. parent.push(nextParent);
  3700. nextParent[key] = {};
  3701. nextParent = nextParent[key];
  3702. }
  3703. else {
  3704. parent[key] = nextParent;
  3705. }
  3706. objectEach(option, function (nestedOption, nestedKey) {
  3707. traverse(nestedOption, nestedKey, key === 0 ? parentEditables : nestedEditables[key], nextParent);
  3708. });
  3709. }
  3710. else {
  3711. // Leaf:
  3712. if (key === 'format') {
  3713. parent[key] = [
  3714. format(option, annotation.labels[0].points[0]).toString(),
  3715. 'text'
  3716. ];
  3717. }
  3718. else if (isArray(parent)) {
  3719. parent.push([option, getFieldType(option)]);
  3720. }
  3721. else {
  3722. parent[key] = [option, getFieldType(option)];
  3723. }
  3724. }
  3725. }
  3726. }
  3727. objectEach(options, function (option, key) {
  3728. if (key === 'typeOptions') {
  3729. visualOptions[key] = {};
  3730. objectEach(options[key], function (typeOption, typeKey) {
  3731. traverse(typeOption, typeKey, nestedEditables, visualOptions[key], true);
  3732. });
  3733. }
  3734. else {
  3735. traverse(option, key, editables[type], visualOptions);
  3736. }
  3737. });
  3738. return visualOptions;
  3739. };
  3740. /**
  3741. * Get all class names for all parents in the element. Iterates until finds
  3742. * main container.
  3743. *
  3744. * @function Highcharts.NavigationBindings#getClickedClassNames
  3745. *
  3746. * @param {Highcharts.HTMLDOMElement}
  3747. * Container that event is bound to.
  3748. *
  3749. * @param {global.Event} event
  3750. * Browser's event.
  3751. *
  3752. * @return {Array<Array<string, Highcharts.HTMLDOMElement>>}
  3753. * Array of class names with corresponding elements
  3754. */
  3755. NavigationBindings.prototype.getClickedClassNames = function (container, event) {
  3756. var element = event.target, classNames = [], elemClassName;
  3757. while (element) {
  3758. elemClassName = attr(element, 'class');
  3759. if (elemClassName) {
  3760. classNames = classNames.concat(elemClassName
  3761. .split(' ')
  3762. .map(function (name) {
  3763. return [
  3764. name,
  3765. element
  3766. ];
  3767. }));
  3768. }
  3769. element = element.parentNode;
  3770. if (element === container) {
  3771. return classNames;
  3772. }
  3773. }
  3774. return classNames;
  3775. };
  3776. /**
  3777. * Get events bound to a button. It's a custom event delegation to find all
  3778. * events connected to the element.
  3779. *
  3780. * @private
  3781. * @function Highcharts.NavigationBindings#getButtonEvents
  3782. *
  3783. * @param {Highcharts.HTMLDOMElement} container
  3784. * Container that event is bound to.
  3785. *
  3786. * @param {global.Event} event
  3787. * Browser's event.
  3788. *
  3789. * @return {object}
  3790. * Object with events (init, start, steps, and end)
  3791. */
  3792. NavigationBindings.prototype.getButtonEvents = function (container, event) {
  3793. var navigation = this, classNames = this.getClickedClassNames(container, event), bindings;
  3794. classNames.forEach(function (className) {
  3795. if (navigation.boundClassNames[className[0]] && !bindings) {
  3796. bindings = {
  3797. events: navigation.boundClassNames[className[0]],
  3798. button: className[1]
  3799. };
  3800. }
  3801. });
  3802. return bindings;
  3803. };
  3804. /**
  3805. * Bindings are just events, so the whole update process is simply
  3806. * removing old events and adding new ones.
  3807. *
  3808. * @private
  3809. * @function Highcharts.NavigationBindings#update
  3810. */
  3811. NavigationBindings.prototype.update = function (options) {
  3812. this.options = merge(true, this.options, options);
  3813. this.removeEvents();
  3814. this.initEvents();
  3815. };
  3816. /**
  3817. * Remove all events created in the navigation.
  3818. *
  3819. * @private
  3820. * @function Highcharts.NavigationBindings#removeEvents
  3821. */
  3822. NavigationBindings.prototype.removeEvents = function () {
  3823. this.eventsToUnbind.forEach(function (unbinder) {
  3824. unbinder();
  3825. });
  3826. };
  3827. NavigationBindings.prototype.destroy = function () {
  3828. this.removeEvents();
  3829. };
  3830. /* *
  3831. *
  3832. * Static Properties
  3833. *
  3834. * */
  3835. // Define which options from annotations should show up in edit box:
  3836. NavigationBindings.annotationsEditable = {
  3837. // `typeOptions` are always available
  3838. // Nested and shared options:
  3839. nestedOptions: {
  3840. labelOptions: ['style', 'format', 'backgroundColor'],
  3841. labels: ['style'],
  3842. label: ['style'],
  3843. style: ['fontSize', 'color'],
  3844. background: ['fill', 'strokeWidth', 'stroke'],
  3845. innerBackground: ['fill', 'strokeWidth', 'stroke'],
  3846. outerBackground: ['fill', 'strokeWidth', 'stroke'],
  3847. shapeOptions: ['fill', 'strokeWidth', 'stroke'],
  3848. shapes: ['fill', 'strokeWidth', 'stroke'],
  3849. line: ['strokeWidth', 'stroke'],
  3850. backgroundColors: [true],
  3851. connector: ['fill', 'strokeWidth', 'stroke'],
  3852. crosshairX: ['strokeWidth', 'stroke'],
  3853. crosshairY: ['strokeWidth', 'stroke']
  3854. },
  3855. // Simple shapes:
  3856. circle: ['shapes'],
  3857. verticalLine: [],
  3858. label: ['labelOptions'],
  3859. // Measure
  3860. measure: ['background', 'crosshairY', 'crosshairX'],
  3861. // Others:
  3862. fibonacci: [],
  3863. tunnel: ['background', 'line', 'height'],
  3864. pitchfork: ['innerBackground', 'outerBackground'],
  3865. rect: ['shapes'],
  3866. // Crooked lines, elliots, arrows etc:
  3867. crookedLine: [],
  3868. basicAnnotation: []
  3869. };
  3870. // Define non editable fields per annotation, for example Rectangle inherits
  3871. // options from Measure, but crosshairs are not available
  3872. NavigationBindings.annotationsNonEditable = {
  3873. rectangle: ['crosshairX', 'crosshairY', 'label']
  3874. };
  3875. return NavigationBindings;
  3876. }());
  3877. /**
  3878. * General utils for bindings
  3879. *
  3880. * @private
  3881. * @name Highcharts.NavigationBindings.utils
  3882. * @type {bindingsUtils}
  3883. */
  3884. NavigationBindings.prototype.utils = bindingsUtils;
  3885. H.Chart.prototype.initNavigationBindings = function () {
  3886. var chart = this, options = chart.options;
  3887. if (options && options.navigation && options.navigation.bindings) {
  3888. chart.navigationBindings = new NavigationBindings(chart, options.navigation);
  3889. chart.navigationBindings.initEvents();
  3890. chart.navigationBindings.initUpdate();
  3891. }
  3892. };
  3893. addEvent(H.Chart, 'load', function () {
  3894. this.initNavigationBindings();
  3895. });
  3896. addEvent(H.Chart, 'destroy', function () {
  3897. if (this.navigationBindings) {
  3898. this.navigationBindings.destroy();
  3899. }
  3900. });
  3901. addEvent(NavigationBindings, 'deselectButton', function () {
  3902. this.selectedButtonElement = null;
  3903. });
  3904. addEvent(Annotation, 'remove', function () {
  3905. if (this.chart.navigationBindings) {
  3906. this.chart.navigationBindings.deselectAnnotation();
  3907. }
  3908. });
  3909. /**
  3910. * Show edit-annotation form:
  3911. * @private
  3912. */
  3913. function selectableAnnotation(annotationType) {
  3914. var originalClick = annotationType.prototype.defaultOptions.events &&
  3915. annotationType.prototype.defaultOptions.events.click;
  3916. /**
  3917. * @private
  3918. */
  3919. function selectAndshowPopup(event) {
  3920. var annotation = this, navigation = annotation.chart.navigationBindings, prevAnnotation = navigation.activeAnnotation;
  3921. if (originalClick) {
  3922. originalClick.call(annotation, event);
  3923. }
  3924. if (prevAnnotation !== annotation) {
  3925. // Select current:
  3926. navigation.deselectAnnotation();
  3927. navigation.activeAnnotation = annotation;
  3928. annotation.setControlPointsVisibility(true);
  3929. fireEvent(navigation, 'showPopup', {
  3930. annotation: annotation,
  3931. formType: 'annotation-toolbar',
  3932. options: navigation.annotationToFields(annotation),
  3933. onSubmit: function (data) {
  3934. var config = {}, typeOptions;
  3935. if (data.actionType === 'remove') {
  3936. navigation.activeAnnotation = false;
  3937. navigation.chart.removeAnnotation(annotation);
  3938. }
  3939. else {
  3940. navigation.fieldsToOptions(data.fields, config);
  3941. navigation.deselectAnnotation();
  3942. typeOptions = config.typeOptions;
  3943. if (annotation.options.type === 'measure') {
  3944. // Manually disable crooshars according to
  3945. // stroke width of the shape:
  3946. typeOptions.crosshairY.enabled =
  3947. typeOptions.crosshairY.strokeWidth !== 0;
  3948. typeOptions.crosshairX.enabled =
  3949. typeOptions.crosshairX.strokeWidth !== 0;
  3950. }
  3951. annotation.update(config);
  3952. }
  3953. }
  3954. });
  3955. }
  3956. else {
  3957. // Deselect current:
  3958. navigation.deselectAnnotation();
  3959. fireEvent(navigation, 'closePopup');
  3960. }
  3961. // Let bubble event to chart.click:
  3962. event.activeAnnotation = true;
  3963. }
  3964. merge(true, annotationType.prototype.defaultOptions.events, {
  3965. click: selectAndshowPopup
  3966. });
  3967. }
  3968. if (H.Annotation) {
  3969. // Basic shapes:
  3970. selectableAnnotation(Annotation);
  3971. // Advanced annotations:
  3972. objectEach(Annotation.types, function (annotationType) {
  3973. selectableAnnotation(annotationType);
  3974. });
  3975. }
  3976. setOptions({
  3977. /**
  3978. * @optionparent lang
  3979. *
  3980. * @private
  3981. */
  3982. lang: {
  3983. /**
  3984. * Configure the Popup strings in the chart. Requires the
  3985. * `annotations.js` or `annotations-advanced.src.js` module to be
  3986. * loaded.
  3987. *
  3988. * @since 7.0.0
  3989. * @product highcharts highstock
  3990. */
  3991. navigation: {
  3992. /**
  3993. * Translations for all field names used in popup.
  3994. *
  3995. * @product highcharts highstock
  3996. */
  3997. popup: {
  3998. simpleShapes: 'Simple shapes',
  3999. lines: 'Lines',
  4000. circle: 'Circle',
  4001. rectangle: 'Rectangle',
  4002. label: 'Label',
  4003. shapeOptions: 'Shape options',
  4004. typeOptions: 'Details',
  4005. fill: 'Fill',
  4006. format: 'Text',
  4007. strokeWidth: 'Line width',
  4008. stroke: 'Line color',
  4009. title: 'Title',
  4010. name: 'Name',
  4011. labelOptions: 'Label options',
  4012. labels: 'Labels',
  4013. backgroundColor: 'Background color',
  4014. backgroundColors: 'Background colors',
  4015. borderColor: 'Border color',
  4016. borderRadius: 'Border radius',
  4017. borderWidth: 'Border width',
  4018. style: 'Style',
  4019. padding: 'Padding',
  4020. fontSize: 'Font size',
  4021. color: 'Color',
  4022. height: 'Height',
  4023. shapes: 'Shape options'
  4024. }
  4025. }
  4026. },
  4027. /**
  4028. * @optionparent navigation
  4029. * @product highcharts highstock
  4030. *
  4031. * @private
  4032. */
  4033. navigation: {
  4034. /**
  4035. * A CSS class name where all bindings will be attached to. Multiple
  4036. * charts on the same page should have separate class names to prevent
  4037. * duplicating events.
  4038. *
  4039. * Default value of versions < 7.0.4 `highcharts-bindings-wrapper`
  4040. *
  4041. * @since 7.0.0
  4042. * @type {string}
  4043. */
  4044. bindingsClassName: 'highcharts-bindings-container',
  4045. /**
  4046. * Bindings definitions for custom HTML buttons. Each binding implements
  4047. * simple event-driven interface:
  4048. *
  4049. * - `className`: classname used to bind event to
  4050. *
  4051. * - `init`: initial event, fired on button click
  4052. *
  4053. * - `start`: fired on first click on a chart
  4054. *
  4055. * - `steps`: array of sequential events fired one after another on each
  4056. * of users clicks
  4057. *
  4058. * - `end`: last event to be called after last step event
  4059. *
  4060. * @type {Highcharts.Dictionary<Highcharts.NavigationBindingsOptionsObject>|*}
  4061. * @sample stock/stocktools/stocktools-thresholds
  4062. * Custom bindings in Highstock
  4063. * @since 7.0.0
  4064. * @product highcharts highstock
  4065. */
  4066. bindings: {
  4067. /**
  4068. * A circle annotation bindings. Includes `start` and one event in
  4069. * `steps` array.
  4070. *
  4071. * @type {Highcharts.NavigationBindingsOptionsObject}
  4072. * @default {"className": "highcharts-circle-annotation", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  4073. */
  4074. circleAnnotation: {
  4075. /** @ignore-option */
  4076. className: 'highcharts-circle-annotation',
  4077. /** @ignore-option */
  4078. start: function (e) {
  4079. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation;
  4080. return this.chart.addAnnotation(merge({
  4081. langKey: 'circle',
  4082. type: 'basicAnnotation',
  4083. shapes: [{
  4084. type: 'circle',
  4085. point: {
  4086. xAxis: 0,
  4087. yAxis: 0,
  4088. x: coords.xAxis[0].value,
  4089. y: coords.yAxis[0].value
  4090. },
  4091. r: 5
  4092. }]
  4093. }, navigation
  4094. .annotationsOptions, navigation
  4095. .bindings
  4096. .circleAnnotation
  4097. .annotationsOptions));
  4098. },
  4099. /** @ignore-option */
  4100. steps: [
  4101. function (e, annotation) {
  4102. var point = annotation.options.shapes[0].point, x = this.chart.xAxis[0].toPixels(point.x), y = this.chart.yAxis[0].toPixels(point.y), inverted = this.chart.inverted, distance = Math.max(Math.sqrt(Math.pow(inverted ? y - e.chartX : x - e.chartX, 2) +
  4103. Math.pow(inverted ? x - e.chartY : y - e.chartY, 2)), 5);
  4104. annotation.update({
  4105. shapes: [{
  4106. r: distance
  4107. }]
  4108. });
  4109. }
  4110. ]
  4111. },
  4112. /**
  4113. * A rectangle annotation bindings. Includes `start` and one event
  4114. * in `steps` array.
  4115. *
  4116. * @type {Highcharts.NavigationBindingsOptionsObject}
  4117. * @default {"className": "highcharts-rectangle-annotation", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  4118. */
  4119. rectangleAnnotation: {
  4120. /** @ignore-option */
  4121. className: 'highcharts-rectangle-annotation',
  4122. /** @ignore-option */
  4123. start: function (e) {
  4124. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, x = coords.xAxis[0].value, y = coords.yAxis[0].value;
  4125. return this.chart.addAnnotation(merge({
  4126. langKey: 'rectangle',
  4127. type: 'basicAnnotation',
  4128. shapes: [{
  4129. type: 'path',
  4130. points: [{
  4131. xAxis: 0,
  4132. yAxis: 0,
  4133. x: x,
  4134. y: y
  4135. }, {
  4136. xAxis: 0,
  4137. yAxis: 0,
  4138. x: x,
  4139. y: y
  4140. }, {
  4141. xAxis: 0,
  4142. yAxis: 0,
  4143. x: x,
  4144. y: y
  4145. }, {
  4146. xAxis: 0,
  4147. yAxis: 0,
  4148. x: x,
  4149. y: y
  4150. }]
  4151. }]
  4152. }, navigation
  4153. .annotationsOptions, navigation
  4154. .bindings
  4155. .rectangleAnnotation
  4156. .annotationsOptions));
  4157. },
  4158. /** @ignore-option */
  4159. steps: [
  4160. function (e, annotation) {
  4161. var points = annotation.options.shapes[0].points, coords = this.chart.pointer.getCoordinates(e), x = coords.xAxis[0].value, y = coords.yAxis[0].value;
  4162. // Top right point
  4163. points[1].x = x;
  4164. // Bottom right point (cursor position)
  4165. points[2].x = x;
  4166. points[2].y = y;
  4167. // Bottom left
  4168. points[3].y = y;
  4169. annotation.update({
  4170. shapes: [{
  4171. points: points
  4172. }]
  4173. });
  4174. }
  4175. ]
  4176. },
  4177. /**
  4178. * A label annotation bindings. Includes `start` event only.
  4179. *
  4180. * @type {Highcharts.NavigationBindingsOptionsObject}
  4181. * @default {"className": "highcharts-label-annotation", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  4182. */
  4183. labelAnnotation: {
  4184. /** @ignore-option */
  4185. className: 'highcharts-label-annotation',
  4186. /** @ignore-option */
  4187. start: function (e) {
  4188. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation;
  4189. return this.chart.addAnnotation(merge({
  4190. langKey: 'label',
  4191. type: 'basicAnnotation',
  4192. labelOptions: {
  4193. format: '{y:.2f}'
  4194. },
  4195. labels: [{
  4196. point: {
  4197. xAxis: 0,
  4198. yAxis: 0,
  4199. x: coords.xAxis[0].value,
  4200. y: coords.yAxis[0].value
  4201. },
  4202. overflow: 'none',
  4203. crop: true
  4204. }]
  4205. }, navigation
  4206. .annotationsOptions, navigation
  4207. .bindings
  4208. .labelAnnotation
  4209. .annotationsOptions));
  4210. }
  4211. }
  4212. },
  4213. /**
  4214. * Path where Highcharts will look for icons. Change this to use icons
  4215. * from a different server.
  4216. *
  4217. * @type {string}
  4218. * @default https://code.highcharts.com/8.1.2/gfx/stock-icons/
  4219. * @since 7.1.3
  4220. * @apioption navigation.iconsURL
  4221. */
  4222. /**
  4223. * A `showPopup` event. Fired when selecting for example an annotation.
  4224. *
  4225. * @type {Function}
  4226. * @apioption navigation.events.showPopup
  4227. */
  4228. /**
  4229. * A `closePopup` event. Fired when Popup should be hidden, for example
  4230. * when clicking on an annotation again.
  4231. *
  4232. * @type {Function}
  4233. * @apioption navigation.events.closePopup
  4234. */
  4235. /**
  4236. * Event fired on a button click.
  4237. *
  4238. * @type {Function}
  4239. * @sample highcharts/annotations/gui/
  4240. * Change icon in a dropddown on event
  4241. * @sample highcharts/annotations/gui-buttons/
  4242. * Change button class on event
  4243. * @apioption navigation.events.selectButton
  4244. */
  4245. /**
  4246. * Event fired when button state should change, for example after
  4247. * adding an annotation.
  4248. *
  4249. * @type {Function}
  4250. * @sample highcharts/annotations/gui/
  4251. * Change icon in a dropddown on event
  4252. * @sample highcharts/annotations/gui-buttons/
  4253. * Change button class on event
  4254. * @apioption navigation.events.deselectButton
  4255. */
  4256. /**
  4257. * Events to communicate between Stock Tools and custom GUI.
  4258. *
  4259. * @since 7.0.0
  4260. * @product highcharts highstock
  4261. * @optionparent navigation.events
  4262. */
  4263. events: {},
  4264. /**
  4265. * Additional options to be merged into all annotations.
  4266. *
  4267. * @sample stock/stocktools/navigation-annotation-options
  4268. * Set red color of all line annotations
  4269. *
  4270. * @type {Highcharts.AnnotationsOptions}
  4271. * @extends annotations
  4272. * @exclude crookedLine, elliottWave, fibonacci, infinityLine,
  4273. * measure, pitchfork, tunnel, verticalLine, basicAnnotation
  4274. * @apioption navigation.annotationsOptions
  4275. */
  4276. annotationsOptions: {}
  4277. }
  4278. });
  4279. return NavigationBindings;
  4280. });
  4281. _registerModule(_modules, 'modules/stock-tools-bindings.js', [_modules['parts/Globals.js'], _modules['annotations/navigationBindings.js'], _modules['parts/Utilities.js']], function (H, NavigationBindings, U) {
  4282. /**
  4283. *
  4284. * Events generator for Stock tools
  4285. *
  4286. * (c) 2009-2020 Paweł Fus
  4287. *
  4288. * License: www.highcharts.com/license
  4289. *
  4290. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  4291. *
  4292. * */
  4293. var correctFloat = U.correctFloat, defined = U.defined, extend = U.extend, fireEvent = U.fireEvent, isNumber = U.isNumber, merge = U.merge, pick = U.pick, setOptions = U.setOptions, uniqueKey = U.uniqueKey;
  4294. var bindingsUtils = NavigationBindings.prototype.utils, PREFIX = 'highcharts-';
  4295. /* eslint-disable no-invalid-this, valid-jsdoc */
  4296. /**
  4297. * Generates function which will add a flag series using modal in GUI.
  4298. * Method fires an event "showPopup" with config:
  4299. * `{type, options, callback}`.
  4300. *
  4301. * Example: NavigationBindings.utils.addFlagFromForm('url(...)') - will
  4302. * generate function that shows modal in GUI.
  4303. *
  4304. * @private
  4305. * @function bindingsUtils.addFlagFromForm
  4306. *
  4307. * @param {Highcharts.FlagsShapeValue} type
  4308. * Type of flag series, e.g. "squarepin"
  4309. *
  4310. * @return {Function}
  4311. * Callback to be used in `start` callback
  4312. */
  4313. bindingsUtils.addFlagFromForm = function (type) {
  4314. return function (e) {
  4315. var navigation = this, chart = navigation.chart, toolbar = chart.stockTools, getFieldType = bindingsUtils.getFieldType, point = bindingsUtils.attractToPoint(e, chart), pointConfig = {
  4316. x: point.x,
  4317. y: point.y
  4318. }, seriesOptions = {
  4319. type: 'flags',
  4320. onSeries: point.series.id,
  4321. shape: type,
  4322. data: [pointConfig],
  4323. point: {
  4324. events: {
  4325. click: function () {
  4326. var point = this, options = point.options;
  4327. fireEvent(navigation, 'showPopup', {
  4328. point: point,
  4329. formType: 'annotation-toolbar',
  4330. options: {
  4331. langKey: 'flags',
  4332. type: 'flags',
  4333. title: [
  4334. options.title,
  4335. getFieldType(options.title)
  4336. ],
  4337. name: [
  4338. options.name,
  4339. getFieldType(options.name)
  4340. ]
  4341. },
  4342. onSubmit: function (updated) {
  4343. if (updated.actionType === 'remove') {
  4344. point.remove();
  4345. }
  4346. else {
  4347. point.update(navigation.fieldsToOptions(updated.fields, {}));
  4348. }
  4349. }
  4350. });
  4351. }
  4352. }
  4353. }
  4354. };
  4355. if (!toolbar || !toolbar.guiEnabled) {
  4356. chart.addSeries(seriesOptions);
  4357. }
  4358. fireEvent(navigation, 'showPopup', {
  4359. formType: 'flag',
  4360. // Enabled options:
  4361. options: {
  4362. langKey: 'flags',
  4363. type: 'flags',
  4364. title: ['A', getFieldType('A')],
  4365. name: ['Flag A', getFieldType('Flag A')]
  4366. },
  4367. // Callback on submit:
  4368. onSubmit: function (data) {
  4369. navigation.fieldsToOptions(data.fields, seriesOptions.data[0]);
  4370. chart.addSeries(seriesOptions);
  4371. }
  4372. });
  4373. };
  4374. };
  4375. bindingsUtils.manageIndicators = function (data) {
  4376. var navigation = this, chart = navigation.chart, seriesConfig = {
  4377. linkedTo: data.linkedTo,
  4378. type: data.type
  4379. }, indicatorsWithVolume = [
  4380. 'ad',
  4381. 'cmf',
  4382. 'mfi',
  4383. 'vbp',
  4384. 'vwap'
  4385. ], indicatorsWithAxes = [
  4386. 'ad',
  4387. 'atr',
  4388. 'cci',
  4389. 'cmf',
  4390. 'macd',
  4391. 'mfi',
  4392. 'roc',
  4393. 'rsi',
  4394. 'ao',
  4395. 'aroon',
  4396. 'aroonoscillator',
  4397. 'trix',
  4398. 'apo',
  4399. 'dpo',
  4400. 'ppo',
  4401. 'natr',
  4402. 'williamsr',
  4403. 'stochastic',
  4404. 'slowstochastic',
  4405. 'linearRegression',
  4406. 'linearRegressionSlope',
  4407. 'linearRegressionIntercept',
  4408. 'linearRegressionAngle'
  4409. ], yAxis, series;
  4410. if (data.actionType === 'edit') {
  4411. navigation.fieldsToOptions(data.fields, seriesConfig);
  4412. series = chart.get(data.seriesId);
  4413. if (series) {
  4414. series.update(seriesConfig, false);
  4415. }
  4416. }
  4417. else if (data.actionType === 'remove') {
  4418. series = chart.get(data.seriesId);
  4419. if (series) {
  4420. yAxis = series.yAxis;
  4421. if (series.linkedSeries) {
  4422. series.linkedSeries.forEach(function (linkedSeries) {
  4423. linkedSeries.remove(false);
  4424. });
  4425. }
  4426. series.remove(false);
  4427. if (indicatorsWithAxes.indexOf(series.type) >= 0) {
  4428. yAxis.remove(false);
  4429. navigation.resizeYAxes();
  4430. }
  4431. }
  4432. }
  4433. else {
  4434. seriesConfig.id = uniqueKey();
  4435. navigation.fieldsToOptions(data.fields, seriesConfig);
  4436. if (indicatorsWithAxes.indexOf(data.type) >= 0) {
  4437. yAxis = chart.addAxis({
  4438. id: uniqueKey(),
  4439. offset: 0,
  4440. opposite: true,
  4441. title: {
  4442. text: ''
  4443. },
  4444. tickPixelInterval: 40,
  4445. showLastLabel: false,
  4446. labels: {
  4447. align: 'left',
  4448. y: -2
  4449. }
  4450. }, false, false);
  4451. seriesConfig.yAxis = yAxis.options.id;
  4452. navigation.resizeYAxes();
  4453. }
  4454. else {
  4455. seriesConfig.yAxis = chart.get(data.linkedTo).options.yAxis;
  4456. }
  4457. if (indicatorsWithVolume.indexOf(data.type) >= 0) {
  4458. seriesConfig.params.volumeSeriesID = chart.series.filter(function (series) {
  4459. return series.options.type === 'column';
  4460. })[0].options.id;
  4461. }
  4462. chart.addSeries(seriesConfig, false);
  4463. }
  4464. fireEvent(navigation, 'deselectButton', {
  4465. button: navigation.selectedButtonElement
  4466. });
  4467. chart.redraw();
  4468. };
  4469. /**
  4470. * Update height for an annotation. Height is calculated as a difference
  4471. * between last point in `typeOptions` and current position. It's a value,
  4472. * not pixels height.
  4473. *
  4474. * @private
  4475. * @function bindingsUtils.updateHeight
  4476. *
  4477. * @param {Highcharts.PointerEventObject} e
  4478. * normalized browser event
  4479. *
  4480. * @param {Highcharts.Annotation} annotation
  4481. * Annotation to be updated
  4482. *
  4483. * @return {void}
  4484. */
  4485. bindingsUtils.updateHeight = function (e, annotation) {
  4486. annotation.update({
  4487. typeOptions: {
  4488. height: this.chart.pointer.getCoordinates(e).yAxis[0].value -
  4489. annotation.options.typeOptions.points[1].y
  4490. }
  4491. });
  4492. };
  4493. // @todo
  4494. // Consider using getHoverData(), but always kdTree (columns?)
  4495. bindingsUtils.attractToPoint = function (e, chart) {
  4496. var coords = chart.pointer.getCoordinates(e), x = coords.xAxis[0].value, y = coords.yAxis[0].value, distX = Number.MAX_VALUE, closestPoint;
  4497. chart.series.forEach(function (series) {
  4498. series.points.forEach(function (point) {
  4499. if (point && distX > Math.abs(point.x - x)) {
  4500. distX = Math.abs(point.x - x);
  4501. closestPoint = point;
  4502. }
  4503. });
  4504. });
  4505. return {
  4506. x: closestPoint.x,
  4507. y: closestPoint.y,
  4508. below: y < closestPoint.y,
  4509. series: closestPoint.series,
  4510. xAxis: closestPoint.series.xAxis.index || 0,
  4511. yAxis: closestPoint.series.yAxis.index || 0
  4512. };
  4513. };
  4514. /**
  4515. * Shorthand to check if given yAxis comes from navigator.
  4516. *
  4517. * @private
  4518. * @function bindingsUtils.isNotNavigatorYAxis
  4519. *
  4520. * @param {Highcharts.Axis} axis
  4521. * Axis to check.
  4522. *
  4523. * @return {boolean}
  4524. * True, if axis comes from navigator.
  4525. */
  4526. bindingsUtils.isNotNavigatorYAxis = function (axis) {
  4527. return axis.userOptions.className !== PREFIX + 'navigator-yaxis';
  4528. };
  4529. /**
  4530. * Update each point after specified index, most of the annotations use
  4531. * this. For example crooked line: logic behind updating each point is the
  4532. * same, only index changes when adding an annotation.
  4533. *
  4534. * Example: NavigationBindings.utils.updateNthPoint(1) - will generate
  4535. * function that updates all consecutive points except point with index=0.
  4536. *
  4537. * @private
  4538. * @function bindingsUtils.updateNthPoint
  4539. *
  4540. * @param {number} startIndex
  4541. * Index from each point should udpated
  4542. *
  4543. * @return {Function}
  4544. * Callback to be used in steps array
  4545. */
  4546. bindingsUtils.updateNthPoint = function (startIndex) {
  4547. return function (e, annotation) {
  4548. var options = annotation.options.typeOptions, coords = this.chart.pointer.getCoordinates(e), x = coords.xAxis[0].value, y = coords.yAxis[0].value;
  4549. options.points.forEach(function (point, index) {
  4550. if (index >= startIndex) {
  4551. point.x = x;
  4552. point.y = y;
  4553. }
  4554. });
  4555. annotation.update({
  4556. typeOptions: {
  4557. points: options.points
  4558. }
  4559. });
  4560. };
  4561. };
  4562. // Extends NavigationBindigs to support indicators and resizers:
  4563. extend(NavigationBindings.prototype, {
  4564. /* eslint-disable valid-jsdoc */
  4565. /**
  4566. * Get current positions for all yAxes. If new axis does not have position,
  4567. * returned is default height and last available top place.
  4568. *
  4569. * @private
  4570. * @function Highcharts.NavigationBindings#getYAxisPositions
  4571. *
  4572. * @param {Array<Highcharts.Axis>} yAxes
  4573. * Array of yAxes available in the chart.
  4574. *
  4575. * @param {number} plotHeight
  4576. * Available height in the chart.
  4577. *
  4578. * @param {number} defaultHeight
  4579. * Default height in percents.
  4580. *
  4581. * @return {Array}
  4582. * An array of calculated positions in percentages.
  4583. * Format: `{top: Number, height: Number}`
  4584. */
  4585. getYAxisPositions: function (yAxes, plotHeight, defaultHeight) {
  4586. var positions, allAxesHeight = 0;
  4587. /** @private */
  4588. function isPercentage(prop) {
  4589. return defined(prop) && !isNumber(prop) && prop.match('%');
  4590. }
  4591. positions = yAxes.map(function (yAxis) {
  4592. var height = isPercentage(yAxis.options.height) ?
  4593. parseFloat(yAxis.options.height) / 100 :
  4594. yAxis.height / plotHeight, top = isPercentage(yAxis.options.top) ?
  4595. parseFloat(yAxis.options.top) / 100 :
  4596. correctFloat(yAxis.top - yAxis.chart.plotTop) / plotHeight;
  4597. // New yAxis does not contain "height" info yet
  4598. if (!isNumber(height)) {
  4599. height = defaultHeight / 100;
  4600. }
  4601. allAxesHeight = correctFloat(allAxesHeight + height);
  4602. return {
  4603. height: height * 100,
  4604. top: top * 100
  4605. };
  4606. });
  4607. positions.allAxesHeight = allAxesHeight;
  4608. return positions;
  4609. },
  4610. /**
  4611. * Get current resize options for each yAxis. Note that each resize is
  4612. * linked to the next axis, except the last one which shouldn't affect
  4613. * axes in the navigator. Because indicator can be removed with it's yAxis
  4614. * in the middle of yAxis array, we need to bind closest yAxes back.
  4615. *
  4616. * @private
  4617. * @function Highcharts.NavigationBindings#getYAxisResizers
  4618. *
  4619. * @param {Array<Highcharts.Axis>} yAxes
  4620. * Array of yAxes available in the chart
  4621. *
  4622. * @return {Array<object>}
  4623. * An array of resizer options.
  4624. * Format: `{enabled: Boolean, controlledAxis: { next: [String]}}`
  4625. */
  4626. getYAxisResizers: function (yAxes) {
  4627. var resizers = [];
  4628. yAxes.forEach(function (_yAxis, index) {
  4629. var nextYAxis = yAxes[index + 1];
  4630. // We have next axis, bind them:
  4631. if (nextYAxis) {
  4632. resizers[index] = {
  4633. enabled: true,
  4634. controlledAxis: {
  4635. next: [
  4636. pick(nextYAxis.options.id, nextYAxis.options.index)
  4637. ]
  4638. }
  4639. };
  4640. }
  4641. else {
  4642. // Remove binding:
  4643. resizers[index] = {
  4644. enabled: false
  4645. };
  4646. }
  4647. });
  4648. return resizers;
  4649. },
  4650. /**
  4651. * Resize all yAxes (except navigator) to fit the plotting height. Method
  4652. * checks if new axis is added, then shrinks other main axis up to 5 panes.
  4653. * If added is more thatn 5 panes, it rescales all other axes to fit new
  4654. * yAxis.
  4655. *
  4656. * If axis is removed, and we have more than 5 panes, rescales all other
  4657. * axes. If chart has less than 5 panes, first pane receives all extra
  4658. * space.
  4659. *
  4660. * @private
  4661. * @function Highcharts.NavigationBindings#resizeYAxes
  4662. * @param {number} [defaultHeight]
  4663. * Default height for yAxis
  4664. */
  4665. resizeYAxes: function (defaultHeight) {
  4666. defaultHeight = defaultHeight || 20; // in %, but as a number
  4667. var chart = this.chart,
  4668. // Only non-navigator axes
  4669. yAxes = chart.yAxis.filter(bindingsUtils.isNotNavigatorYAxis), plotHeight = chart.plotHeight, allAxesLength = yAxes.length,
  4670. // Gather current heights (in %)
  4671. positions = this.getYAxisPositions(yAxes, plotHeight, defaultHeight), resizers = this.getYAxisResizers(yAxes), allAxesHeight = positions.allAxesHeight, changedSpace = defaultHeight;
  4672. // More than 100%
  4673. if (allAxesHeight > 1) {
  4674. // Simple case, add new panes up to 5
  4675. if (allAxesLength < 6) {
  4676. // Added axis, decrease first pane's height:
  4677. positions[0].height = correctFloat(positions[0].height - changedSpace);
  4678. // And update all other "top" positions:
  4679. positions = this.recalculateYAxisPositions(positions, changedSpace);
  4680. }
  4681. else {
  4682. // We have more panes, rescale all others to gain some space,
  4683. // This is new height for upcoming yAxis:
  4684. defaultHeight = 100 / allAxesLength;
  4685. // This is how much we need to take from each other yAxis:
  4686. changedSpace = defaultHeight / (allAxesLength - 1);
  4687. // Now update all positions:
  4688. positions = this.recalculateYAxisPositions(positions, changedSpace, true, -1);
  4689. }
  4690. // Set last position manually:
  4691. positions[allAxesLength - 1] = {
  4692. top: correctFloat(100 - defaultHeight),
  4693. height: defaultHeight
  4694. };
  4695. }
  4696. else {
  4697. // Less than 100%
  4698. changedSpace = correctFloat(1 - allAxesHeight) * 100;
  4699. // Simple case, return first pane it's space:
  4700. if (allAxesLength < 5) {
  4701. positions[0].height = correctFloat(positions[0].height + changedSpace);
  4702. positions = this.recalculateYAxisPositions(positions, changedSpace);
  4703. }
  4704. else {
  4705. // There were more panes, return to each pane a bit of space:
  4706. changedSpace /= allAxesLength;
  4707. // Removed axis, add extra space to the first pane:
  4708. // And update all other positions:
  4709. positions = this.recalculateYAxisPositions(positions, changedSpace, true, 1);
  4710. }
  4711. }
  4712. positions.forEach(function (position, index) {
  4713. // if (index === 0) debugger;
  4714. yAxes[index].update({
  4715. height: position.height + '%',
  4716. top: position.top + '%',
  4717. resize: resizers[index]
  4718. }, false);
  4719. });
  4720. },
  4721. /**
  4722. * Utility to modify calculated positions according to the remaining/needed
  4723. * space. Later, these positions are used in `yAxis.update({ top, height })`
  4724. *
  4725. * @private
  4726. * @function Highcharts.NavigationBindings#recalculateYAxisPositions
  4727. * @param {Array<Highcharts.Dictionary<number>>} positions
  4728. * Default positions of all yAxes.
  4729. * @param {number} changedSpace
  4730. * How much space should be added or removed.
  4731. * @param {boolean} modifyHeight
  4732. * Update only `top` or both `top` and `height`.
  4733. * @param {number} adder
  4734. * `-1` or `1`, to determine whether we should add or remove space.
  4735. *
  4736. * @return {Array<object>}
  4737. * Modified positions,
  4738. */
  4739. recalculateYAxisPositions: function (positions, changedSpace, modifyHeight, adder) {
  4740. positions.forEach(function (position, index) {
  4741. var prevPosition = positions[index - 1];
  4742. position.top = !prevPosition ? 0 :
  4743. correctFloat(prevPosition.height + prevPosition.top);
  4744. if (modifyHeight) {
  4745. position.height = correctFloat(position.height + adder * changedSpace);
  4746. }
  4747. });
  4748. return positions;
  4749. }
  4750. /* eslint-enable valid-jsdoc */
  4751. });
  4752. /**
  4753. * @type {Highcharts.Dictionary<Highcharts.NavigationBindingsOptionsObject>}
  4754. * @since 7.0.0
  4755. * @optionparent navigation.bindings
  4756. */
  4757. var stockToolsBindings = {
  4758. // Line type annotations:
  4759. /**
  4760. * A segment annotation bindings. Includes `start` and one event in `steps`
  4761. * array.
  4762. *
  4763. * @type {Highcharts.NavigationBindingsOptionsObject}
  4764. * @product highstock
  4765. * @default {"className": "highcharts-segment", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  4766. */
  4767. segment: {
  4768. /** @ignore-option */
  4769. className: 'highcharts-segment',
  4770. // eslint-disable-next-line valid-jsdoc
  4771. /** @ignore-option */
  4772. start: function (e) {
  4773. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  4774. langKey: 'segment',
  4775. type: 'crookedLine',
  4776. typeOptions: {
  4777. points: [{
  4778. x: coords.xAxis[0].value,
  4779. y: coords.yAxis[0].value
  4780. }, {
  4781. x: coords.xAxis[0].value,
  4782. y: coords.yAxis[0].value
  4783. }]
  4784. }
  4785. }, navigation.annotationsOptions, navigation.bindings.segment.annotationsOptions);
  4786. return this.chart.addAnnotation(options);
  4787. },
  4788. /** @ignore-option */
  4789. steps: [
  4790. bindingsUtils.updateNthPoint(1)
  4791. ]
  4792. },
  4793. /**
  4794. * A segment with an arrow annotation bindings. Includes `start` and one
  4795. * event in `steps` array.
  4796. *
  4797. * @type {Highcharts.NavigationBindingsOptionsObject}
  4798. * @product highstock
  4799. * @default {"className": "highcharts-arrow-segment", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  4800. */
  4801. arrowSegment: {
  4802. /** @ignore-option */
  4803. className: 'highcharts-arrow-segment',
  4804. // eslint-disable-next-line valid-jsdoc
  4805. /** @ignore-option */
  4806. start: function (e) {
  4807. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  4808. langKey: 'arrowSegment',
  4809. type: 'crookedLine',
  4810. typeOptions: {
  4811. line: {
  4812. markerEnd: 'arrow'
  4813. },
  4814. points: [{
  4815. x: coords.xAxis[0].value,
  4816. y: coords.yAxis[0].value
  4817. }, {
  4818. x: coords.xAxis[0].value,
  4819. y: coords.yAxis[0].value
  4820. }]
  4821. }
  4822. }, navigation.annotationsOptions, navigation.bindings.arrowSegment.annotationsOptions);
  4823. return this.chart.addAnnotation(options);
  4824. },
  4825. /** @ignore-option */
  4826. steps: [
  4827. bindingsUtils.updateNthPoint(1)
  4828. ]
  4829. },
  4830. /**
  4831. * A ray annotation bindings. Includes `start` and one event in `steps`
  4832. * array.
  4833. *
  4834. * @type {Highcharts.NavigationBindingsOptionsObject}
  4835. * @product highstock
  4836. * @default {"className": "highcharts-ray", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  4837. */
  4838. ray: {
  4839. /** @ignore-option */
  4840. className: 'highcharts-ray',
  4841. // eslint-disable-next-line valid-jsdoc
  4842. /** @ignore-option */
  4843. start: function (e) {
  4844. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  4845. langKey: 'ray',
  4846. type: 'crookedLine',
  4847. typeOptions: {
  4848. type: 'ray',
  4849. points: [{
  4850. x: coords.xAxis[0].value,
  4851. y: coords.yAxis[0].value
  4852. }, {
  4853. x: coords.xAxis[0].value,
  4854. y: coords.yAxis[0].value
  4855. }]
  4856. }
  4857. }, navigation.annotationsOptions, navigation.bindings.ray.annotationsOptions);
  4858. return this.chart.addAnnotation(options);
  4859. },
  4860. /** @ignore-option */
  4861. steps: [
  4862. bindingsUtils.updateNthPoint(1)
  4863. ]
  4864. },
  4865. /**
  4866. * A ray with an arrow annotation bindings. Includes `start` and one event
  4867. * in `steps` array.
  4868. *
  4869. * @type {Highcharts.NavigationBindingsOptionsObject}
  4870. * @product highstock
  4871. * @default {"className": "highcharts-arrow-ray", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  4872. */
  4873. arrowRay: {
  4874. /** @ignore-option */
  4875. className: 'highcharts-arrow-ray',
  4876. // eslint-disable-next-line valid-jsdoc
  4877. /** @ignore-option */
  4878. start: function (e) {
  4879. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  4880. langKey: 'arrowRay',
  4881. type: 'infinityLine',
  4882. typeOptions: {
  4883. type: 'ray',
  4884. line: {
  4885. markerEnd: 'arrow'
  4886. },
  4887. points: [{
  4888. x: coords.xAxis[0].value,
  4889. y: coords.yAxis[0].value
  4890. }, {
  4891. x: coords.xAxis[0].value,
  4892. y: coords.yAxis[0].value
  4893. }]
  4894. }
  4895. }, navigation.annotationsOptions, navigation.bindings.arrowRay.annotationsOptions);
  4896. return this.chart.addAnnotation(options);
  4897. },
  4898. /** @ignore-option */
  4899. steps: [
  4900. bindingsUtils.updateNthPoint(1)
  4901. ]
  4902. },
  4903. /**
  4904. * A line annotation. Includes `start` and one event in `steps` array.
  4905. *
  4906. * @type {Highcharts.NavigationBindingsOptionsObject}
  4907. * @product highstock
  4908. * @default {"className": "highcharts-infinity-line", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  4909. */
  4910. infinityLine: {
  4911. /** @ignore-option */
  4912. className: 'highcharts-infinity-line',
  4913. // eslint-disable-next-line valid-jsdoc
  4914. /** @ignore-option */
  4915. start: function (e) {
  4916. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  4917. langKey: 'infinityLine',
  4918. type: 'infinityLine',
  4919. typeOptions: {
  4920. type: 'line',
  4921. points: [{
  4922. x: coords.xAxis[0].value,
  4923. y: coords.yAxis[0].value
  4924. }, {
  4925. x: coords.xAxis[0].value,
  4926. y: coords.yAxis[0].value
  4927. }]
  4928. }
  4929. }, navigation.annotationsOptions, navigation.bindings.infinityLine.annotationsOptions);
  4930. return this.chart.addAnnotation(options);
  4931. },
  4932. /** @ignore-option */
  4933. steps: [
  4934. bindingsUtils.updateNthPoint(1)
  4935. ]
  4936. },
  4937. /**
  4938. * A line with arrow annotation. Includes `start` and one event in `steps`
  4939. * array.
  4940. *
  4941. * @type {Highcharts.NavigationBindingsOptionsObject}
  4942. * @product highstock
  4943. * @default {"className": "highcharts-arrow-infinity-line", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  4944. */
  4945. arrowInfinityLine: {
  4946. /** @ignore-option */
  4947. className: 'highcharts-arrow-infinity-line',
  4948. // eslint-disable-next-line valid-jsdoc
  4949. /** @ignore-option */
  4950. start: function (e) {
  4951. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  4952. langKey: 'arrowInfinityLine',
  4953. type: 'infinityLine',
  4954. typeOptions: {
  4955. type: 'line',
  4956. line: {
  4957. markerEnd: 'arrow'
  4958. },
  4959. points: [{
  4960. x: coords.xAxis[0].value,
  4961. y: coords.yAxis[0].value
  4962. }, {
  4963. x: coords.xAxis[0].value,
  4964. y: coords.yAxis[0].value
  4965. }]
  4966. }
  4967. }, navigation.annotationsOptions, navigation.bindings.arrowInfinityLine.annotationsOptions);
  4968. return this.chart.addAnnotation(options);
  4969. },
  4970. /** @ignore-option */
  4971. steps: [
  4972. bindingsUtils.updateNthPoint(1)
  4973. ]
  4974. },
  4975. /**
  4976. * A horizontal line annotation. Includes `start` event.
  4977. *
  4978. * @type {Highcharts.NavigationBindingsOptionsObject}
  4979. * @product highstock
  4980. * @default {"className": "highcharts-horizontal-line", "start": function() {}, "annotationsOptions": {}}
  4981. */
  4982. horizontalLine: {
  4983. /** @ignore-option */
  4984. className: 'highcharts-horizontal-line',
  4985. // eslint-disable-next-line valid-jsdoc
  4986. /** @ignore-option */
  4987. start: function (e) {
  4988. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  4989. langKey: 'horizontalLine',
  4990. type: 'infinityLine',
  4991. draggable: 'y',
  4992. typeOptions: {
  4993. type: 'horizontalLine',
  4994. points: [{
  4995. x: coords.xAxis[0].value,
  4996. y: coords.yAxis[0].value
  4997. }]
  4998. }
  4999. }, navigation.annotationsOptions, navigation.bindings.horizontalLine.annotationsOptions);
  5000. this.chart.addAnnotation(options);
  5001. }
  5002. },
  5003. /**
  5004. * A vertical line annotation. Includes `start` event.
  5005. *
  5006. * @type {Highcharts.NavigationBindingsOptionsObject}
  5007. * @product highstock
  5008. * @default {"className": "highcharts-vertical-line", "start": function() {}, "annotationsOptions": {}}
  5009. */
  5010. verticalLine: {
  5011. /** @ignore-option */
  5012. className: 'highcharts-vertical-line',
  5013. // eslint-disable-next-line valid-jsdoc
  5014. /** @ignore-option */
  5015. start: function (e) {
  5016. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  5017. langKey: 'verticalLine',
  5018. type: 'infinityLine',
  5019. draggable: 'x',
  5020. typeOptions: {
  5021. type: 'verticalLine',
  5022. points: [{
  5023. x: coords.xAxis[0].value,
  5024. y: coords.yAxis[0].value
  5025. }]
  5026. }
  5027. }, navigation.annotationsOptions, navigation.bindings.verticalLine.annotationsOptions);
  5028. this.chart.addAnnotation(options);
  5029. }
  5030. },
  5031. /**
  5032. * Crooked line (three points) annotation bindings. Includes `start` and two
  5033. * events in `steps` (for second and third points in crooked line) array.
  5034. *
  5035. * @type {Highcharts.NavigationBindingsOptionsObject}
  5036. * @product highstock
  5037. * @default {"className": "highcharts-crooked3", "start": function() {}, "steps": [function() {}, function() {}], "annotationsOptions": {}}
  5038. */
  5039. // Crooked Line type annotations:
  5040. crooked3: {
  5041. /** @ignore-option */
  5042. className: 'highcharts-crooked3',
  5043. // eslint-disable-next-line valid-jsdoc
  5044. /** @ignore-option */
  5045. start: function (e) {
  5046. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  5047. langKey: 'crooked3',
  5048. type: 'crookedLine',
  5049. typeOptions: {
  5050. points: [{
  5051. x: coords.xAxis[0].value,
  5052. y: coords.yAxis[0].value
  5053. }, {
  5054. x: coords.xAxis[0].value,
  5055. y: coords.yAxis[0].value
  5056. }, {
  5057. x: coords.xAxis[0].value,
  5058. y: coords.yAxis[0].value
  5059. }]
  5060. }
  5061. }, navigation.annotationsOptions, navigation.bindings.crooked3.annotationsOptions);
  5062. return this.chart.addAnnotation(options);
  5063. },
  5064. /** @ignore-option */
  5065. steps: [
  5066. bindingsUtils.updateNthPoint(1),
  5067. bindingsUtils.updateNthPoint(2)
  5068. ]
  5069. },
  5070. /**
  5071. * Crooked line (five points) annotation bindings. Includes `start` and four
  5072. * events in `steps` (for all consequent points in crooked line) array.
  5073. *
  5074. * @type {Highcharts.NavigationBindingsOptionsObject}
  5075. * @product highstock
  5076. * @default {"className": "highcharts-crooked3", "start": function() {}, "steps": [function() {}, function() {}, function() {}, function() {}], "annotationsOptions": {}}
  5077. */
  5078. crooked5: {
  5079. /** @ignore-option */
  5080. className: 'highcharts-crooked5',
  5081. // eslint-disable-next-line valid-jsdoc
  5082. /** @ignore-option */
  5083. start: function (e) {
  5084. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  5085. langKey: 'crookedLine',
  5086. type: 'crookedLine',
  5087. typeOptions: {
  5088. points: [{
  5089. x: coords.xAxis[0].value,
  5090. y: coords.yAxis[0].value
  5091. }, {
  5092. x: coords.xAxis[0].value,
  5093. y: coords.yAxis[0].value
  5094. }, {
  5095. x: coords.xAxis[0].value,
  5096. y: coords.yAxis[0].value
  5097. }, {
  5098. x: coords.xAxis[0].value,
  5099. y: coords.yAxis[0].value
  5100. }, {
  5101. x: coords.xAxis[0].value,
  5102. y: coords.yAxis[0].value
  5103. }]
  5104. }
  5105. }, navigation.annotationsOptions, navigation.bindings.crooked5.annotationsOptions);
  5106. return this.chart.addAnnotation(options);
  5107. },
  5108. /** @ignore-option */
  5109. steps: [
  5110. bindingsUtils.updateNthPoint(1),
  5111. bindingsUtils.updateNthPoint(2),
  5112. bindingsUtils.updateNthPoint(3),
  5113. bindingsUtils.updateNthPoint(4)
  5114. ]
  5115. },
  5116. /**
  5117. * Elliott wave (three points) annotation bindings. Includes `start` and two
  5118. * events in `steps` (for second and third points) array.
  5119. *
  5120. * @type {Highcharts.NavigationBindingsOptionsObject}
  5121. * @product highstock
  5122. * @default {"className": "highcharts-elliott3", "start": function() {}, "steps": [function() {}, function() {}], "annotationsOptions": {}}
  5123. */
  5124. elliott3: {
  5125. /** @ignore-option */
  5126. className: 'highcharts-elliott3',
  5127. // eslint-disable-next-line valid-jsdoc
  5128. /** @ignore-option */
  5129. start: function (e) {
  5130. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  5131. langKey: 'elliott3',
  5132. type: 'elliottWave',
  5133. typeOptions: {
  5134. points: [{
  5135. x: coords.xAxis[0].value,
  5136. y: coords.yAxis[0].value
  5137. }, {
  5138. x: coords.xAxis[0].value,
  5139. y: coords.yAxis[0].value
  5140. }, {
  5141. x: coords.xAxis[0].value,
  5142. y: coords.yAxis[0].value
  5143. }, {
  5144. x: coords.xAxis[0].value,
  5145. y: coords.yAxis[0].value
  5146. }]
  5147. },
  5148. labelOptions: {
  5149. style: {
  5150. color: '#666666'
  5151. }
  5152. }
  5153. }, navigation.annotationsOptions, navigation.bindings.elliott3.annotationsOptions);
  5154. return this.chart.addAnnotation(options);
  5155. },
  5156. /** @ignore-option */
  5157. steps: [
  5158. bindingsUtils.updateNthPoint(1),
  5159. bindingsUtils.updateNthPoint(2),
  5160. bindingsUtils.updateNthPoint(3)
  5161. ]
  5162. },
  5163. /**
  5164. * Elliott wave (five points) annotation bindings. Includes `start` and four
  5165. * event in `steps` (for all consequent points in Elliott wave) array.
  5166. *
  5167. * @type {Highcharts.NavigationBindingsOptionsObject}
  5168. * @product highstock
  5169. * @default {"className": "highcharts-elliott3", "start": function() {}, "steps": [function() {}, function() {}, function() {}, function() {}], "annotationsOptions": {}}
  5170. */
  5171. elliott5: {
  5172. /** @ignore-option */
  5173. className: 'highcharts-elliott5',
  5174. // eslint-disable-next-line valid-jsdoc
  5175. /** @ignore-option */
  5176. start: function (e) {
  5177. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  5178. langKey: 'elliott5',
  5179. type: 'elliottWave',
  5180. typeOptions: {
  5181. points: [{
  5182. x: coords.xAxis[0].value,
  5183. y: coords.yAxis[0].value
  5184. }, {
  5185. x: coords.xAxis[0].value,
  5186. y: coords.yAxis[0].value
  5187. }, {
  5188. x: coords.xAxis[0].value,
  5189. y: coords.yAxis[0].value
  5190. }, {
  5191. x: coords.xAxis[0].value,
  5192. y: coords.yAxis[0].value
  5193. }, {
  5194. x: coords.xAxis[0].value,
  5195. y: coords.yAxis[0].value
  5196. }, {
  5197. x: coords.xAxis[0].value,
  5198. y: coords.yAxis[0].value
  5199. }]
  5200. },
  5201. labelOptions: {
  5202. style: {
  5203. color: '#666666'
  5204. }
  5205. }
  5206. }, navigation.annotationsOptions, navigation.bindings.elliott5.annotationsOptions);
  5207. return this.chart.addAnnotation(options);
  5208. },
  5209. /** @ignore-option */
  5210. steps: [
  5211. bindingsUtils.updateNthPoint(1),
  5212. bindingsUtils.updateNthPoint(2),
  5213. bindingsUtils.updateNthPoint(3),
  5214. bindingsUtils.updateNthPoint(4),
  5215. bindingsUtils.updateNthPoint(5)
  5216. ]
  5217. },
  5218. /**
  5219. * A measure (x-dimension) annotation bindings. Includes `start` and one
  5220. * event in `steps` array.
  5221. *
  5222. * @type {Highcharts.NavigationBindingsOptionsObject}
  5223. * @product highstock
  5224. * @default {"className": "highcharts-measure-x", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  5225. */
  5226. measureX: {
  5227. /** @ignore-option */
  5228. className: 'highcharts-measure-x',
  5229. // eslint-disable-next-line valid-jsdoc
  5230. /** @ignore-option */
  5231. start: function (e) {
  5232. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  5233. langKey: 'measure',
  5234. type: 'measure',
  5235. typeOptions: {
  5236. selectType: 'x',
  5237. point: {
  5238. x: coords.xAxis[0].value,
  5239. y: coords.yAxis[0].value,
  5240. xAxis: 0,
  5241. yAxis: 0
  5242. },
  5243. crosshairX: {
  5244. strokeWidth: 1,
  5245. stroke: '#000000'
  5246. },
  5247. crosshairY: {
  5248. enabled: false,
  5249. strokeWidth: 0,
  5250. stroke: '#000000'
  5251. },
  5252. background: {
  5253. width: 0,
  5254. height: 0,
  5255. strokeWidth: 0,
  5256. stroke: '#ffffff'
  5257. }
  5258. },
  5259. labelOptions: {
  5260. style: {
  5261. color: '#666666'
  5262. }
  5263. }
  5264. }, navigation.annotationsOptions, navigation.bindings.measureX.annotationsOptions);
  5265. return this.chart.addAnnotation(options);
  5266. },
  5267. /** @ignore-option */
  5268. steps: [
  5269. bindingsUtils.updateRectSize
  5270. ]
  5271. },
  5272. /**
  5273. * A measure (y-dimension) annotation bindings. Includes `start` and one
  5274. * event in `steps` array.
  5275. *
  5276. * @type {Highcharts.NavigationBindingsOptionsObject}
  5277. * @product highstock
  5278. * @default {"className": "highcharts-measure-y", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  5279. */
  5280. measureY: {
  5281. /** @ignore-option */
  5282. className: 'highcharts-measure-y',
  5283. // eslint-disable-next-line valid-jsdoc
  5284. /** @ignore-option */
  5285. start: function (e) {
  5286. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  5287. langKey: 'measure',
  5288. type: 'measure',
  5289. typeOptions: {
  5290. selectType: 'y',
  5291. point: {
  5292. x: coords.xAxis[0].value,
  5293. y: coords.yAxis[0].value,
  5294. xAxis: 0,
  5295. yAxis: 0
  5296. },
  5297. crosshairX: {
  5298. enabled: false,
  5299. strokeWidth: 0,
  5300. stroke: '#000000'
  5301. },
  5302. crosshairY: {
  5303. strokeWidth: 1,
  5304. stroke: '#000000'
  5305. },
  5306. background: {
  5307. width: 0,
  5308. height: 0,
  5309. strokeWidth: 0,
  5310. stroke: '#ffffff'
  5311. }
  5312. },
  5313. labelOptions: {
  5314. style: {
  5315. color: '#666666'
  5316. }
  5317. }
  5318. }, navigation.annotationsOptions, navigation.bindings.measureY.annotationsOptions);
  5319. return this.chart.addAnnotation(options);
  5320. },
  5321. /** @ignore-option */
  5322. steps: [
  5323. bindingsUtils.updateRectSize
  5324. ]
  5325. },
  5326. /**
  5327. * A measure (xy-dimension) annotation bindings. Includes `start` and one
  5328. * event in `steps` array.
  5329. *
  5330. * @type {Highcharts.NavigationBindingsOptionsObject}
  5331. * @product highstock
  5332. * @default {"className": "highcharts-measure-xy", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
  5333. */
  5334. measureXY: {
  5335. /** @ignore-option */
  5336. className: 'highcharts-measure-xy',
  5337. // eslint-disable-next-line valid-jsdoc
  5338. /** @ignore-option */
  5339. start: function (e) {
  5340. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  5341. langKey: 'measure',
  5342. type: 'measure',
  5343. typeOptions: {
  5344. selectType: 'xy',
  5345. point: {
  5346. x: coords.xAxis[0].value,
  5347. y: coords.yAxis[0].value,
  5348. xAxis: 0,
  5349. yAxis: 0
  5350. },
  5351. background: {
  5352. width: 0,
  5353. height: 0,
  5354. strokeWidth: 10
  5355. },
  5356. crosshairX: {
  5357. strokeWidth: 1,
  5358. stroke: '#000000'
  5359. },
  5360. crosshairY: {
  5361. strokeWidth: 1,
  5362. stroke: '#000000'
  5363. }
  5364. },
  5365. labelOptions: {
  5366. style: {
  5367. color: '#666666'
  5368. }
  5369. }
  5370. }, navigation.annotationsOptions, navigation.bindings.measureXY.annotationsOptions);
  5371. return this.chart.addAnnotation(options);
  5372. },
  5373. /** @ignore-option */
  5374. steps: [
  5375. bindingsUtils.updateRectSize
  5376. ]
  5377. },
  5378. // Advanced type annotations:
  5379. /**
  5380. * A fibonacci annotation bindings. Includes `start` and two events in
  5381. * `steps` array (updates second point, then height).
  5382. *
  5383. * @type {Highcharts.NavigationBindingsOptionsObject}
  5384. * @product highstock
  5385. * @default {"className": "highcharts-fibonacci", "start": function() {}, "steps": [function() {}, function() {}], "annotationsOptions": {}}
  5386. */
  5387. fibonacci: {
  5388. /** @ignore-option */
  5389. className: 'highcharts-fibonacci',
  5390. // eslint-disable-next-line valid-jsdoc
  5391. /** @ignore-option */
  5392. start: function (e) {
  5393. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  5394. langKey: 'fibonacci',
  5395. type: 'fibonacci',
  5396. typeOptions: {
  5397. points: [{
  5398. x: coords.xAxis[0].value,
  5399. y: coords.yAxis[0].value
  5400. }, {
  5401. x: coords.xAxis[0].value,
  5402. y: coords.yAxis[0].value
  5403. }]
  5404. },
  5405. labelOptions: {
  5406. style: {
  5407. color: '#666666'
  5408. }
  5409. }
  5410. }, navigation.annotationsOptions, navigation.bindings.fibonacci.annotationsOptions);
  5411. return this.chart.addAnnotation(options);
  5412. },
  5413. /** @ignore-option */
  5414. steps: [
  5415. bindingsUtils.updateNthPoint(1),
  5416. bindingsUtils.updateHeight
  5417. ]
  5418. },
  5419. /**
  5420. * A parallel channel (tunnel) annotation bindings. Includes `start` and
  5421. * two events in `steps` array (updates second point, then height).
  5422. *
  5423. * @type {Highcharts.NavigationBindingsOptionsObject}
  5424. * @product highstock
  5425. * @default {"className": "highcharts-parallel-channel", "start": function() {}, "steps": [function() {}, function() {}], "annotationsOptions": {}}
  5426. */
  5427. parallelChannel: {
  5428. /** @ignore-option */
  5429. className: 'highcharts-parallel-channel',
  5430. // eslint-disable-next-line valid-jsdoc
  5431. /** @ignore-option */
  5432. start: function (e) {
  5433. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  5434. langKey: 'parallelChannel',
  5435. type: 'tunnel',
  5436. typeOptions: {
  5437. points: [{
  5438. x: coords.xAxis[0].value,
  5439. y: coords.yAxis[0].value
  5440. }, {
  5441. x: coords.xAxis[0].value,
  5442. y: coords.yAxis[0].value
  5443. }]
  5444. }
  5445. }, navigation.annotationsOptions, navigation.bindings.parallelChannel.annotationsOptions);
  5446. return this.chart.addAnnotation(options);
  5447. },
  5448. /** @ignore-option */
  5449. steps: [
  5450. bindingsUtils.updateNthPoint(1),
  5451. bindingsUtils.updateHeight
  5452. ]
  5453. },
  5454. /**
  5455. * An Andrew's pitchfork annotation bindings. Includes `start` and two
  5456. * events in `steps` array (sets second and third control points).
  5457. *
  5458. * @type {Highcharts.NavigationBindingsOptionsObject}
  5459. * @product highstock
  5460. * @default {"className": "highcharts-pitchfork", "start": function() {}, "steps": [function() {}, function() {}], "annotationsOptions": {}}
  5461. */
  5462. pitchfork: {
  5463. /** @ignore-option */
  5464. className: 'highcharts-pitchfork',
  5465. // eslint-disable-next-line valid-jsdoc
  5466. /** @ignore-option */
  5467. start: function (e) {
  5468. var coords = this.chart.pointer.getCoordinates(e), navigation = this.chart.options.navigation, options = merge({
  5469. langKey: 'pitchfork',
  5470. type: 'pitchfork',
  5471. typeOptions: {
  5472. points: [{
  5473. x: coords.xAxis[0].value,
  5474. y: coords.yAxis[0].value,
  5475. controlPoint: {
  5476. style: {
  5477. fill: 'red'
  5478. }
  5479. }
  5480. }, {
  5481. x: coords.xAxis[0].value,
  5482. y: coords.yAxis[0].value
  5483. }, {
  5484. x: coords.xAxis[0].value,
  5485. y: coords.yAxis[0].value
  5486. }],
  5487. innerBackground: {
  5488. fill: 'rgba(100, 170, 255, 0.8)'
  5489. }
  5490. },
  5491. shapeOptions: {
  5492. strokeWidth: 2
  5493. }
  5494. }, navigation.annotationsOptions, navigation.bindings.pitchfork.annotationsOptions);
  5495. return this.chart.addAnnotation(options);
  5496. },
  5497. /** @ignore-option */
  5498. steps: [
  5499. bindingsUtils.updateNthPoint(1),
  5500. bindingsUtils.updateNthPoint(2)
  5501. ]
  5502. },
  5503. // Labels with arrow and auto increments
  5504. /**
  5505. * A vertical counter annotation bindings. Includes `start` event. On click,
  5506. * finds the closest point and marks it with a numeric annotation -
  5507. * incrementing counter on each add.
  5508. *
  5509. * @type {Highcharts.NavigationBindingsOptionsObject}
  5510. * @product highstock
  5511. * @default {"className": "highcharts-vertical-counter", "start": function() {}, "annotationsOptions": {}}
  5512. */
  5513. verticalCounter: {
  5514. /** @ignore-option */
  5515. className: 'highcharts-vertical-counter',
  5516. // eslint-disable-next-line valid-jsdoc
  5517. /** @ignore-option */
  5518. start: function (e) {
  5519. var closestPoint = bindingsUtils.attractToPoint(e, this.chart), navigation = this.chart.options.navigation, verticalCounter = !defined(this.verticalCounter) ? 0 :
  5520. this.verticalCounter, options = merge({
  5521. langKey: 'verticalCounter',
  5522. type: 'verticalLine',
  5523. typeOptions: {
  5524. point: {
  5525. x: closestPoint.x,
  5526. y: closestPoint.y,
  5527. xAxis: closestPoint.xAxis,
  5528. yAxis: closestPoint.yAxis
  5529. },
  5530. label: {
  5531. offset: closestPoint.below ? 40 : -40,
  5532. text: verticalCounter.toString()
  5533. }
  5534. },
  5535. labelOptions: {
  5536. style: {
  5537. color: '#666666',
  5538. fontSize: '11px'
  5539. }
  5540. },
  5541. shapeOptions: {
  5542. stroke: 'rgba(0, 0, 0, 0.75)',
  5543. strokeWidth: 1
  5544. }
  5545. }, navigation.annotationsOptions, navigation.bindings.verticalCounter.annotationsOptions), annotation;
  5546. annotation = this.chart.addAnnotation(options);
  5547. verticalCounter++;
  5548. annotation.options.events.click.call(annotation, {});
  5549. }
  5550. },
  5551. /**
  5552. * A vertical arrow annotation bindings. Includes `start` event. On click,
  5553. * finds the closest point and marks it with an arrow and a label with
  5554. * value.
  5555. *
  5556. * @type {Highcharts.NavigationBindingsOptionsObject}
  5557. * @product highstock
  5558. * @default {"className": "highcharts-vertical-label", "start": function() {}, "annotationsOptions": {}}
  5559. */
  5560. verticalLabel: {
  5561. /** @ignore-option */
  5562. className: 'highcharts-vertical-label',
  5563. // eslint-disable-next-line valid-jsdoc
  5564. /** @ignore-option */
  5565. start: function (e) {
  5566. var closestPoint = bindingsUtils.attractToPoint(e, this.chart), navigation = this.chart.options.navigation, options = merge({
  5567. langKey: 'verticalLabel',
  5568. type: 'verticalLine',
  5569. typeOptions: {
  5570. point: {
  5571. x: closestPoint.x,
  5572. y: closestPoint.y,
  5573. xAxis: closestPoint.xAxis,
  5574. yAxis: closestPoint.yAxis
  5575. },
  5576. label: {
  5577. offset: closestPoint.below ? 40 : -40
  5578. }
  5579. },
  5580. labelOptions: {
  5581. style: {
  5582. color: '#666666',
  5583. fontSize: '11px'
  5584. }
  5585. },
  5586. shapeOptions: {
  5587. stroke: 'rgba(0, 0, 0, 0.75)',
  5588. strokeWidth: 1
  5589. }
  5590. }, navigation.annotationsOptions, navigation.bindings.verticalLabel.annotationsOptions), annotation;
  5591. annotation = this.chart.addAnnotation(options);
  5592. annotation.options.events.click.call(annotation, {});
  5593. }
  5594. },
  5595. /**
  5596. * A vertical arrow annotation bindings. Includes `start` event. On click,
  5597. * finds the closest point and marks it with an arrow. Green arrow when
  5598. * pointing from above, red when pointing from below the point.
  5599. *
  5600. * @type {Highcharts.NavigationBindingsOptionsObject}
  5601. * @product highstock
  5602. * @default {"className": "highcharts-vertical-arrow", "start": function() {}, "annotationsOptions": {}}
  5603. */
  5604. verticalArrow: {
  5605. /** @ignore-option */
  5606. className: 'highcharts-vertical-arrow',
  5607. // eslint-disable-next-line valid-jsdoc
  5608. /** @ignore-option */
  5609. start: function (e) {
  5610. var closestPoint = bindingsUtils.attractToPoint(e, this.chart), navigation = this.chart.options.navigation, options = merge({
  5611. langKey: 'verticalArrow',
  5612. type: 'verticalLine',
  5613. typeOptions: {
  5614. point: {
  5615. x: closestPoint.x,
  5616. y: closestPoint.y,
  5617. xAxis: closestPoint.xAxis,
  5618. yAxis: closestPoint.yAxis
  5619. },
  5620. label: {
  5621. offset: closestPoint.below ? 40 : -40,
  5622. format: ' '
  5623. },
  5624. connector: {
  5625. fill: 'none',
  5626. stroke: closestPoint.below ? 'red' : 'green'
  5627. }
  5628. },
  5629. shapeOptions: {
  5630. stroke: 'rgba(0, 0, 0, 0.75)',
  5631. strokeWidth: 1
  5632. }
  5633. }, navigation.annotationsOptions, navigation.bindings.verticalArrow.annotationsOptions), annotation;
  5634. annotation = this.chart.addAnnotation(options);
  5635. annotation.options.events.click.call(annotation, {});
  5636. }
  5637. },
  5638. // Flag types:
  5639. /**
  5640. * A flag series bindings. Includes `start` event. On click, finds the
  5641. * closest point and marks it with a flag with `'circlepin'` shape.
  5642. *
  5643. * @type {Highcharts.NavigationBindingsOptionsObject}
  5644. * @product highstock
  5645. * @default {"className": "highcharts-flag-circlepin", "start": function() {}}
  5646. */
  5647. flagCirclepin: {
  5648. /** @ignore-option */
  5649. className: 'highcharts-flag-circlepin',
  5650. /** @ignore-option */
  5651. start: bindingsUtils.addFlagFromForm('circlepin')
  5652. },
  5653. /**
  5654. * A flag series bindings. Includes `start` event. On click, finds the
  5655. * closest point and marks it with a flag with `'diamondpin'` shape.
  5656. *
  5657. * @type {Highcharts.NavigationBindingsOptionsObject}
  5658. * @product highstock
  5659. * @default {"className": "highcharts-flag-diamondpin", "start": function() {}}
  5660. */
  5661. flagDiamondpin: {
  5662. /** @ignore-option */
  5663. className: 'highcharts-flag-diamondpin',
  5664. /** @ignore-option */
  5665. start: bindingsUtils.addFlagFromForm('flag')
  5666. },
  5667. /**
  5668. * A flag series bindings. Includes `start` event.
  5669. * On click, finds the closest point and marks it with a flag with
  5670. * `'squarepin'` shape.
  5671. *
  5672. * @type {Highcharts.NavigationBindingsOptionsObject}
  5673. * @product highstock
  5674. * @default {"className": "highcharts-flag-squarepin", "start": function() {}}
  5675. */
  5676. flagSquarepin: {
  5677. /** @ignore-option */
  5678. className: 'highcharts-flag-squarepin',
  5679. /** @ignore-option */
  5680. start: bindingsUtils.addFlagFromForm('squarepin')
  5681. },
  5682. /**
  5683. * A flag series bindings. Includes `start` event.
  5684. * On click, finds the closest point and marks it with a flag without pin
  5685. * shape.
  5686. *
  5687. * @type {Highcharts.NavigationBindingsOptionsObject}
  5688. * @product highstock
  5689. * @default {"className": "highcharts-flag-simplepin", "start": function() {}}
  5690. */
  5691. flagSimplepin: {
  5692. /** @ignore-option */
  5693. className: 'highcharts-flag-simplepin',
  5694. /** @ignore-option */
  5695. start: bindingsUtils.addFlagFromForm('nopin')
  5696. },
  5697. // Other tools:
  5698. /**
  5699. * Enables zooming in xAxis on a chart. Includes `start` event which
  5700. * changes [chart.zoomType](#chart.zoomType).
  5701. *
  5702. * @type {Highcharts.NavigationBindingsOptionsObject}
  5703. * @product highstock
  5704. * @default {"className": "highcharts-zoom-x", "init": function() {}}
  5705. */
  5706. zoomX: {
  5707. /** @ignore-option */
  5708. className: 'highcharts-zoom-x',
  5709. // eslint-disable-next-line valid-jsdoc
  5710. /** @ignore-option */
  5711. init: function (button) {
  5712. this.chart.update({
  5713. chart: {
  5714. zoomType: 'x'
  5715. }
  5716. });
  5717. fireEvent(this, 'deselectButton', { button: button });
  5718. }
  5719. },
  5720. /**
  5721. * Enables zooming in yAxis on a chart. Includes `start` event which
  5722. * changes [chart.zoomType](#chart.zoomType).
  5723. *
  5724. * @type {Highcharts.NavigationBindingsOptionsObject}
  5725. * @product highstock
  5726. * @default {"className": "highcharts-zoom-y", "init": function() {}}
  5727. */
  5728. zoomY: {
  5729. /** @ignore-option */
  5730. className: 'highcharts-zoom-y',
  5731. // eslint-disable-next-line valid-jsdoc
  5732. /** @ignore-option */
  5733. init: function (button) {
  5734. this.chart.update({
  5735. chart: {
  5736. zoomType: 'y'
  5737. }
  5738. });
  5739. fireEvent(this, 'deselectButton', { button: button });
  5740. }
  5741. },
  5742. /**
  5743. * Enables zooming in xAxis and yAxis on a chart. Includes `start` event
  5744. * which changes [chart.zoomType](#chart.zoomType).
  5745. *
  5746. * @type {Highcharts.NavigationBindingsOptionsObject}
  5747. * @product highstock
  5748. * @default {"className": "highcharts-zoom-xy", "init": function() {}}
  5749. */
  5750. zoomXY: {
  5751. /** @ignore-option */
  5752. className: 'highcharts-zoom-xy',
  5753. // eslint-disable-next-line valid-jsdoc
  5754. /** @ignore-option */
  5755. init: function (button) {
  5756. this.chart.update({
  5757. chart: {
  5758. zoomType: 'xy'
  5759. }
  5760. });
  5761. fireEvent(this, 'deselectButton', { button: button });
  5762. }
  5763. },
  5764. /**
  5765. * Changes main series to `'line'` type.
  5766. *
  5767. * @type {Highcharts.NavigationBindingsOptionsObject}
  5768. * @product highstock
  5769. * @default {"className": "highcharts-series-type-line", "init": function() {}}
  5770. */
  5771. seriesTypeLine: {
  5772. /** @ignore-option */
  5773. className: 'highcharts-series-type-line',
  5774. // eslint-disable-next-line valid-jsdoc
  5775. /** @ignore-option */
  5776. init: function (button) {
  5777. this.chart.series[0].update({
  5778. type: 'line',
  5779. useOhlcData: true
  5780. });
  5781. fireEvent(this, 'deselectButton', { button: button });
  5782. }
  5783. },
  5784. /**
  5785. * Changes main series to `'ohlc'` type.
  5786. *
  5787. * @type {Highcharts.NavigationBindingsOptionsObject}
  5788. * @product highstock
  5789. * @default {"className": "highcharts-series-type-ohlc", "init": function() {}}
  5790. */
  5791. seriesTypeOhlc: {
  5792. /** @ignore-option */
  5793. className: 'highcharts-series-type-ohlc',
  5794. // eslint-disable-next-line valid-jsdoc
  5795. /** @ignore-option */
  5796. init: function (button) {
  5797. this.chart.series[0].update({
  5798. type: 'ohlc'
  5799. });
  5800. fireEvent(this, 'deselectButton', { button: button });
  5801. }
  5802. },
  5803. /**
  5804. * Changes main series to `'candlestick'` type.
  5805. *
  5806. * @type {Highcharts.NavigationBindingsOptionsObject}
  5807. * @product highstock
  5808. * @default {"className": "highcharts-series-type-candlestick", "init": function() {}}
  5809. */
  5810. seriesTypeCandlestick: {
  5811. /** @ignore-option */
  5812. className: 'highcharts-series-type-candlestick',
  5813. // eslint-disable-next-line valid-jsdoc
  5814. /** @ignore-option */
  5815. init: function (button) {
  5816. this.chart.series[0].update({
  5817. type: 'candlestick'
  5818. });
  5819. fireEvent(this, 'deselectButton', { button: button });
  5820. }
  5821. },
  5822. /**
  5823. * Displays chart in fullscreen.
  5824. *
  5825. * @type {Highcharts.NavigationBindingsOptionsObject}
  5826. * @product highstock
  5827. * @default {"className": "highcharts-full-screen", "init": function() {}}
  5828. */
  5829. fullScreen: {
  5830. /** @ignore-option */
  5831. className: 'highcharts-full-screen',
  5832. // eslint-disable-next-line valid-jsdoc
  5833. /** @ignore-option */
  5834. init: function (button) {
  5835. this.chart.fullscreen.toggle();
  5836. fireEvent(this, 'deselectButton', { button: button });
  5837. }
  5838. },
  5839. /**
  5840. * Hides/shows two price indicators:
  5841. * - last price in the dataset
  5842. * - last price in the selected range
  5843. *
  5844. * @type {Highcharts.NavigationBindingsOptionsObject}
  5845. * @product highstock
  5846. * @default {"className": "highcharts-current-price-indicator", "init": function() {}}
  5847. */
  5848. currentPriceIndicator: {
  5849. /** @ignore-option */
  5850. className: 'highcharts-current-price-indicator',
  5851. // eslint-disable-next-line valid-jsdoc
  5852. /** @ignore-option */
  5853. init: function (button) {
  5854. var chart = this.chart, series = chart.series[0], options = series.options, lastVisiblePrice = (options.lastVisiblePrice &&
  5855. options.lastVisiblePrice.enabled), lastPrice = options.lastPrice && options.lastPrice.enabled, gui = chart.stockTools, iconsURL = gui.getIconsURL();
  5856. if (gui && gui.guiEnabled) {
  5857. if (lastPrice) {
  5858. button.firstChild.style['background-image'] =
  5859. 'url("' + iconsURL +
  5860. 'current-price-show.svg")';
  5861. }
  5862. else {
  5863. button.firstChild.style['background-image'] =
  5864. 'url("' + iconsURL +
  5865. 'current-price-hide.svg")';
  5866. }
  5867. }
  5868. series.update({
  5869. // line
  5870. lastPrice: {
  5871. enabled: !lastPrice,
  5872. color: 'red'
  5873. },
  5874. // label
  5875. lastVisiblePrice: {
  5876. enabled: !lastVisiblePrice,
  5877. label: {
  5878. enabled: true
  5879. }
  5880. }
  5881. });
  5882. fireEvent(this, 'deselectButton', { button: button });
  5883. }
  5884. },
  5885. /**
  5886. * Indicators bindings. Includes `init` event to show a popup.
  5887. *
  5888. * Note: In order to show base series from the chart in the popup's
  5889. * dropdown each series requires
  5890. * [series.id](https://api.highcharts.com/highstock/series.line.id) to be
  5891. * defined.
  5892. *
  5893. * @type {Highcharts.NavigationBindingsOptionsObject}
  5894. * @product highstock
  5895. * @default {"className": "highcharts-indicators", "init": function() {}}
  5896. */
  5897. indicators: {
  5898. /** @ignore-option */
  5899. className: 'highcharts-indicators',
  5900. // eslint-disable-next-line valid-jsdoc
  5901. /** @ignore-option */
  5902. init: function () {
  5903. var navigation = this;
  5904. fireEvent(navigation, 'showPopup', {
  5905. formType: 'indicators',
  5906. options: {},
  5907. // Callback on submit:
  5908. onSubmit: function (data) {
  5909. navigation.utils.manageIndicators.call(navigation, data);
  5910. }
  5911. });
  5912. }
  5913. },
  5914. /**
  5915. * Hides/shows all annotations on a chart.
  5916. *
  5917. * @type {Highcharts.NavigationBindingsOptionsObject}
  5918. * @product highstock
  5919. * @default {"className": "highcharts-toggle-annotations", "init": function() {}}
  5920. */
  5921. toggleAnnotations: {
  5922. /** @ignore-option */
  5923. className: 'highcharts-toggle-annotations',
  5924. // eslint-disable-next-line valid-jsdoc
  5925. /** @ignore-option */
  5926. init: function (button) {
  5927. var chart = this.chart, gui = chart.stockTools, iconsURL = gui.getIconsURL();
  5928. this.toggledAnnotations = !this.toggledAnnotations;
  5929. (chart.annotations || []).forEach(function (annotation) {
  5930. annotation.setVisibility(!this.toggledAnnotations);
  5931. }, this);
  5932. if (gui && gui.guiEnabled) {
  5933. if (this.toggledAnnotations) {
  5934. button.firstChild.style['background-image'] =
  5935. 'url("' + iconsURL +
  5936. 'annotations-hidden.svg")';
  5937. }
  5938. else {
  5939. button.firstChild.style['background-image'] =
  5940. 'url("' + iconsURL +
  5941. 'annotations-visible.svg")';
  5942. }
  5943. }
  5944. fireEvent(this, 'deselectButton', { button: button });
  5945. }
  5946. },
  5947. /**
  5948. * Save a chart in localStorage under `highcharts-chart` key.
  5949. * Stored items:
  5950. * - annotations
  5951. * - indicators (with yAxes)
  5952. * - flags
  5953. *
  5954. * @type {Highcharts.NavigationBindingsOptionsObject}
  5955. * @product highstock
  5956. * @default {"className": "highcharts-save-chart", "init": function() {}}
  5957. */
  5958. saveChart: {
  5959. /** @ignore-option */
  5960. className: 'highcharts-save-chart',
  5961. // eslint-disable-next-line valid-jsdoc
  5962. /** @ignore-option */
  5963. init: function (button) {
  5964. var navigation = this, chart = navigation.chart, annotations = [], indicators = [], flags = [], yAxes = [];
  5965. chart.annotations.forEach(function (annotation, index) {
  5966. annotations[index] = annotation.userOptions;
  5967. });
  5968. chart.series.forEach(function (series) {
  5969. if (series.is('sma')) {
  5970. indicators.push(series.userOptions);
  5971. }
  5972. else if (series.type === 'flags') {
  5973. flags.push(series.userOptions);
  5974. }
  5975. });
  5976. chart.yAxis.forEach(function (yAxis) {
  5977. if (bindingsUtils.isNotNavigatorYAxis(yAxis)) {
  5978. yAxes.push(yAxis.options);
  5979. }
  5980. });
  5981. H.win.localStorage.setItem(PREFIX + 'chart', JSON.stringify({
  5982. annotations: annotations,
  5983. indicators: indicators,
  5984. flags: flags,
  5985. yAxes: yAxes
  5986. }));
  5987. fireEvent(this, 'deselectButton', { button: button });
  5988. }
  5989. }
  5990. };
  5991. setOptions({
  5992. navigation: {
  5993. bindings: stockToolsBindings
  5994. }
  5995. });
  5996. NavigationBindings.prototype.utils = merge(bindingsUtils, NavigationBindings.prototype.utils);
  5997. });
  5998. _registerModule(_modules, 'modules/stock-tools-gui.js', [_modules['parts/Chart.js'], _modules['parts/Globals.js'], _modules['annotations/navigationBindings.js'], _modules['parts/Utilities.js']], function (Chart, H, NavigationBindings, U) {
  5999. /* *
  6000. *
  6001. * GUI generator for Stock tools
  6002. *
  6003. * (c) 2009-2017 Sebastian Bochan
  6004. *
  6005. * License: www.highcharts.com/license
  6006. *
  6007. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  6008. *
  6009. * */
  6010. var addEvent = U.addEvent, createElement = U.createElement, css = U.css, extend = U.extend, fireEvent = U.fireEvent, getStyle = U.getStyle, isArray = U.isArray, merge = U.merge, pick = U.pick, setOptions = U.setOptions;
  6011. var win = H.win, DIV = 'div', SPAN = 'span', UL = 'ul', LI = 'li', PREFIX = 'highcharts-', activeClass = PREFIX + 'active';
  6012. setOptions({
  6013. /**
  6014. * @optionparent lang
  6015. */
  6016. lang: {
  6017. /**
  6018. * Configure the stockTools GUI titles(hints) in the chart. Requires
  6019. * the `stock-tools.js` module to be loaded.
  6020. *
  6021. * @product highstock
  6022. * @since 7.0.0
  6023. */
  6024. stockTools: {
  6025. gui: {
  6026. // Main buttons:
  6027. simpleShapes: 'Simple shapes',
  6028. lines: 'Lines',
  6029. crookedLines: 'Crooked lines',
  6030. measure: 'Measure',
  6031. advanced: 'Advanced',
  6032. toggleAnnotations: 'Toggle annotations',
  6033. verticalLabels: 'Vertical labels',
  6034. flags: 'Flags',
  6035. zoomChange: 'Zoom change',
  6036. typeChange: 'Type change',
  6037. saveChart: 'Save chart',
  6038. indicators: 'Indicators',
  6039. currentPriceIndicator: 'Current Price Indicators',
  6040. // Other features:
  6041. zoomX: 'Zoom X',
  6042. zoomY: 'Zoom Y',
  6043. zoomXY: 'Zooom XY',
  6044. fullScreen: 'Fullscreen',
  6045. typeOHLC: 'OHLC',
  6046. typeLine: 'Line',
  6047. typeCandlestick: 'Candlestick',
  6048. // Basic shapes:
  6049. circle: 'Circle',
  6050. label: 'Label',
  6051. rectangle: 'Rectangle',
  6052. // Flags:
  6053. flagCirclepin: 'Flag circle',
  6054. flagDiamondpin: 'Flag diamond',
  6055. flagSquarepin: 'Flag square',
  6056. flagSimplepin: 'Flag simple',
  6057. // Measures:
  6058. measureXY: 'Measure XY',
  6059. measureX: 'Measure X',
  6060. measureY: 'Measure Y',
  6061. // Segment, ray and line:
  6062. segment: 'Segment',
  6063. arrowSegment: 'Arrow segment',
  6064. ray: 'Ray',
  6065. arrowRay: 'Arrow ray',
  6066. line: 'Line',
  6067. arrowLine: 'Arrow line',
  6068. horizontalLine: 'Horizontal line',
  6069. verticalLine: 'Vertical line',
  6070. infinityLine: 'Infinity line',
  6071. // Crooked lines:
  6072. crooked3: 'Crooked 3 line',
  6073. crooked5: 'Crooked 5 line',
  6074. elliott3: 'Elliott 3 line',
  6075. elliott5: 'Elliott 5 line',
  6076. // Counters:
  6077. verticalCounter: 'Vertical counter',
  6078. verticalLabel: 'Vertical label',
  6079. verticalArrow: 'Vertical arrow',
  6080. // Advanced:
  6081. fibonacci: 'Fibonacci',
  6082. pitchfork: 'Pitchfork',
  6083. parallelChannel: 'Parallel channel'
  6084. }
  6085. },
  6086. navigation: {
  6087. popup: {
  6088. // Annotations:
  6089. circle: 'Circle',
  6090. rectangle: 'Rectangle',
  6091. label: 'Label',
  6092. segment: 'Segment',
  6093. arrowSegment: 'Arrow segment',
  6094. ray: 'Ray',
  6095. arrowRay: 'Arrow ray',
  6096. line: 'Line',
  6097. arrowLine: 'Arrow line',
  6098. horizontalLine: 'Horizontal line',
  6099. verticalLine: 'Vertical line',
  6100. crooked3: 'Crooked 3 line',
  6101. crooked5: 'Crooked 5 line',
  6102. elliott3: 'Elliott 3 line',
  6103. elliott5: 'Elliott 5 line',
  6104. verticalCounter: 'Vertical counter',
  6105. verticalLabel: 'Vertical label',
  6106. verticalArrow: 'Vertical arrow',
  6107. fibonacci: 'Fibonacci',
  6108. pitchfork: 'Pitchfork',
  6109. parallelChannel: 'Parallel channel',
  6110. infinityLine: 'Infinity line',
  6111. measure: 'Measure',
  6112. measureXY: 'Measure XY',
  6113. measureX: 'Measure X',
  6114. measureY: 'Measure Y',
  6115. // Flags:
  6116. flags: 'Flags',
  6117. // GUI elements:
  6118. addButton: 'add',
  6119. saveButton: 'save',
  6120. editButton: 'edit',
  6121. removeButton: 'remove',
  6122. series: 'Series',
  6123. volume: 'Volume',
  6124. connector: 'Connector',
  6125. // Field names:
  6126. innerBackground: 'Inner background',
  6127. outerBackground: 'Outer background',
  6128. crosshairX: 'Crosshair X',
  6129. crosshairY: 'Crosshair Y',
  6130. tunnel: 'Tunnel',
  6131. background: 'Background'
  6132. }
  6133. }
  6134. },
  6135. /**
  6136. * Configure the stockTools gui strings in the chart. Requires the
  6137. * [stockTools module]() to be loaded. For a description of the module
  6138. * and information on its features, see [Highcharts StockTools]().
  6139. *
  6140. * @product highstock
  6141. *
  6142. * @sample stock/demo/stock-tools-gui Stock Tools GUI
  6143. *
  6144. * @sample stock/demo/stock-tools-custom-gui Stock Tools customized GUI
  6145. *
  6146. * @since 7.0.0
  6147. * @optionparent stockTools
  6148. */
  6149. stockTools: {
  6150. /**
  6151. * Definitions of buttons in Stock Tools GUI.
  6152. */
  6153. gui: {
  6154. /**
  6155. * Path where Highcharts will look for icons. Change this to use
  6156. * icons from a different server.
  6157. *
  6158. * Since 7.1.3 use [iconsURL](#navigation.iconsURL) for popup and
  6159. * stock tools.
  6160. *
  6161. * @deprecated
  6162. * @apioption stockTools.gui.iconsURL
  6163. *
  6164. */
  6165. /**
  6166. * Enable or disable the stockTools gui.
  6167. */
  6168. enabled: true,
  6169. /**
  6170. * A CSS class name to apply to the stocktools' div,
  6171. * allowing unique CSS styling for each chart.
  6172. */
  6173. className: 'highcharts-bindings-wrapper',
  6174. /**
  6175. * A CSS class name to apply to the container of buttons,
  6176. * allowing unique CSS styling for each chart.
  6177. */
  6178. toolbarClassName: 'stocktools-toolbar',
  6179. /**
  6180. * A collection of strings pointing to config options for the
  6181. * toolbar items. Each name refers to unique key from definitions
  6182. * object.
  6183. *
  6184. * @default [
  6185. * 'indicators',
  6186. * 'separator',
  6187. * 'simpleShapes',
  6188. * 'lines',
  6189. * 'crookedLines',
  6190. * 'measure',
  6191. * 'advanced',
  6192. * 'toggleAnnotations',
  6193. * 'separator',
  6194. * 'verticalLabels',
  6195. * 'flags',
  6196. * 'separator',
  6197. * 'zoomChange',
  6198. * 'fullScreen',
  6199. * 'typeChange',
  6200. * 'separator',
  6201. * 'currentPriceIndicator',
  6202. * 'saveChart'
  6203. * ]
  6204. */
  6205. buttons: [
  6206. 'indicators',
  6207. 'separator',
  6208. 'simpleShapes',
  6209. 'lines',
  6210. 'crookedLines',
  6211. 'measure',
  6212. 'advanced',
  6213. 'toggleAnnotations',
  6214. 'separator',
  6215. 'verticalLabels',
  6216. 'flags',
  6217. 'separator',
  6218. 'zoomChange',
  6219. 'fullScreen',
  6220. 'typeChange',
  6221. 'separator',
  6222. 'currentPriceIndicator',
  6223. 'saveChart'
  6224. ],
  6225. /**
  6226. * An options object of the buttons definitions. Each name refers to
  6227. * unique key from buttons array.
  6228. */
  6229. definitions: {
  6230. separator: {
  6231. /**
  6232. * A predefined background symbol for the button.
  6233. */
  6234. symbol: 'separator.svg'
  6235. },
  6236. simpleShapes: {
  6237. /**
  6238. * A collection of strings pointing to config options for
  6239. * the items.
  6240. *
  6241. * @type {array}
  6242. * @default [
  6243. * 'label',
  6244. * 'circle',
  6245. * 'rectangle'
  6246. * ]
  6247. *
  6248. */
  6249. items: [
  6250. 'label',
  6251. 'circle',
  6252. 'rectangle'
  6253. ],
  6254. circle: {
  6255. /**
  6256. * A predefined background symbol for the button.
  6257. *
  6258. * @type {string}
  6259. *
  6260. */
  6261. symbol: 'circle.svg'
  6262. },
  6263. rectangle: {
  6264. /**
  6265. * A predefined background symbol for the button.
  6266. *
  6267. * @type {string}
  6268. *
  6269. */
  6270. symbol: 'rectangle.svg'
  6271. },
  6272. label: {
  6273. /**
  6274. * A predefined background symbol for the button.
  6275. *
  6276. * @type {string}
  6277. *
  6278. */
  6279. symbol: 'label.svg'
  6280. }
  6281. },
  6282. flags: {
  6283. /**
  6284. * A collection of strings pointing to config options for
  6285. * the items.
  6286. *
  6287. * @type {array}
  6288. * @default [
  6289. * 'flagCirclepin',
  6290. * 'flagDiamondpin',
  6291. * 'flagSquarepin',
  6292. * 'flagSimplepin'
  6293. * ]
  6294. *
  6295. */
  6296. items: [
  6297. 'flagCirclepin',
  6298. 'flagDiamondpin',
  6299. 'flagSquarepin',
  6300. 'flagSimplepin'
  6301. ],
  6302. flagSimplepin: {
  6303. /**
  6304. * A predefined background symbol for the button.
  6305. *
  6306. * @type {string}
  6307. *
  6308. */
  6309. symbol: 'flag-basic.svg'
  6310. },
  6311. flagDiamondpin: {
  6312. /**
  6313. * A predefined background symbol for the button.
  6314. *
  6315. * @type {string}
  6316. *
  6317. */
  6318. symbol: 'flag-diamond.svg'
  6319. },
  6320. flagSquarepin: {
  6321. /**
  6322. * A predefined background symbol for the button.
  6323. *
  6324. * @type {string}
  6325. */
  6326. symbol: 'flag-trapeze.svg'
  6327. },
  6328. flagCirclepin: {
  6329. /**
  6330. * A predefined background symbol for the button.
  6331. *
  6332. * @type {string}
  6333. */
  6334. symbol: 'flag-elipse.svg'
  6335. }
  6336. },
  6337. lines: {
  6338. /**
  6339. * A collection of strings pointing to config options for
  6340. * the items.
  6341. *
  6342. * @type {array}
  6343. * @default [
  6344. * 'segment',
  6345. * 'arrowSegment',
  6346. * 'ray',
  6347. * 'arrowRay',
  6348. * 'line',
  6349. * 'arrowLine',
  6350. * 'horizontalLine',
  6351. * 'verticalLine'
  6352. * ]
  6353. */
  6354. items: [
  6355. 'segment',
  6356. 'arrowSegment',
  6357. 'ray',
  6358. 'arrowRay',
  6359. 'line',
  6360. 'arrowLine',
  6361. 'horizontalLine',
  6362. 'verticalLine'
  6363. ],
  6364. segment: {
  6365. /**
  6366. * A predefined background symbol for the button.
  6367. *
  6368. * @type {string}
  6369. */
  6370. symbol: 'segment.svg'
  6371. },
  6372. arrowSegment: {
  6373. /**
  6374. * A predefined background symbol for the button.
  6375. *
  6376. * @type {string}
  6377. */
  6378. symbol: 'arrow-segment.svg'
  6379. },
  6380. ray: {
  6381. /**
  6382. * A predefined background symbol for the button.
  6383. *
  6384. * @type {string}
  6385. */
  6386. symbol: 'ray.svg'
  6387. },
  6388. arrowRay: {
  6389. /**
  6390. * A predefined background symbol for the button.
  6391. *
  6392. * @type {string}
  6393. */
  6394. symbol: 'arrow-ray.svg'
  6395. },
  6396. line: {
  6397. /**
  6398. * A predefined background symbol for the button.
  6399. *
  6400. * @type {string}
  6401. */
  6402. symbol: 'line.svg'
  6403. },
  6404. arrowLine: {
  6405. /**
  6406. * A predefined background symbol for the button.
  6407. *
  6408. * @type {string}
  6409. */
  6410. symbol: 'arrow-line.svg'
  6411. },
  6412. verticalLine: {
  6413. /**
  6414. * A predefined background symbol for the button.
  6415. *
  6416. * @type {string}
  6417. */
  6418. symbol: 'vertical-line.svg'
  6419. },
  6420. horizontalLine: {
  6421. /**
  6422. * A predefined background symbol for the button.
  6423. *
  6424. * @type {string}
  6425. */
  6426. symbol: 'horizontal-line.svg'
  6427. }
  6428. },
  6429. crookedLines: {
  6430. /**
  6431. * A collection of strings pointing to config options for
  6432. * the items.
  6433. *
  6434. * @type {array}
  6435. * @default [
  6436. * 'elliott3',
  6437. * 'elliott5',
  6438. * 'crooked3',
  6439. * 'crooked5'
  6440. * ]
  6441. *
  6442. */
  6443. items: [
  6444. 'elliott3',
  6445. 'elliott5',
  6446. 'crooked3',
  6447. 'crooked5'
  6448. ],
  6449. crooked3: {
  6450. /**
  6451. * A predefined background symbol for the button.
  6452. *
  6453. * @type {string}
  6454. */
  6455. symbol: 'crooked-3.svg'
  6456. },
  6457. crooked5: {
  6458. /**
  6459. * A predefined background symbol for the button.
  6460. *
  6461. * @type {string}
  6462. */
  6463. symbol: 'crooked-5.svg'
  6464. },
  6465. elliott3: {
  6466. /**
  6467. * A predefined background symbol for the button.
  6468. *
  6469. * @type {string}
  6470. */
  6471. symbol: 'elliott-3.svg'
  6472. },
  6473. elliott5: {
  6474. /**
  6475. * A predefined background symbol for the button.
  6476. *
  6477. * @type {string}
  6478. */
  6479. symbol: 'elliott-5.svg'
  6480. }
  6481. },
  6482. verticalLabels: {
  6483. /**
  6484. * A collection of strings pointing to config options for
  6485. * the items.
  6486. *
  6487. * @type {array}
  6488. * @default [
  6489. * 'verticalCounter',
  6490. * 'verticalLabel',
  6491. * 'verticalArrow'
  6492. * ]
  6493. */
  6494. items: [
  6495. 'verticalCounter',
  6496. 'verticalLabel',
  6497. 'verticalArrow'
  6498. ],
  6499. verticalCounter: {
  6500. /**
  6501. * A predefined background symbol for the button.
  6502. *
  6503. * @type {string}
  6504. */
  6505. symbol: 'vertical-counter.svg'
  6506. },
  6507. verticalLabel: {
  6508. /**
  6509. * A predefined background symbol for the button.
  6510. *
  6511. * @type {string}
  6512. */
  6513. symbol: 'vertical-label.svg'
  6514. },
  6515. verticalArrow: {
  6516. /**
  6517. * A predefined background symbol for the button.
  6518. *
  6519. * @type {string}
  6520. */
  6521. symbol: 'vertical-arrow.svg'
  6522. }
  6523. },
  6524. advanced: {
  6525. /**
  6526. * A collection of strings pointing to config options for
  6527. * the items.
  6528. *
  6529. * @type {array}
  6530. * @default [
  6531. * 'fibonacci',
  6532. * 'pitchfork',
  6533. * 'parallelChannel'
  6534. * ]
  6535. */
  6536. items: [
  6537. 'fibonacci',
  6538. 'pitchfork',
  6539. 'parallelChannel'
  6540. ],
  6541. pitchfork: {
  6542. /**
  6543. * A predefined background symbol for the button.
  6544. *
  6545. * @type {string}
  6546. */
  6547. symbol: 'pitchfork.svg'
  6548. },
  6549. fibonacci: {
  6550. /**
  6551. * A predefined background symbol for the button.
  6552. *
  6553. * @type {string}
  6554. */
  6555. symbol: 'fibonacci.svg'
  6556. },
  6557. parallelChannel: {
  6558. /**
  6559. * A predefined background symbol for the button.
  6560. *
  6561. * @type {string}
  6562. */
  6563. symbol: 'parallel-channel.svg'
  6564. }
  6565. },
  6566. measure: {
  6567. /**
  6568. * A collection of strings pointing to config options for
  6569. * the items.
  6570. *
  6571. * @type {array}
  6572. * @default [
  6573. * 'measureXY',
  6574. * 'measureX',
  6575. * 'measureY'
  6576. * ]
  6577. */
  6578. items: [
  6579. 'measureXY',
  6580. 'measureX',
  6581. 'measureY'
  6582. ],
  6583. measureX: {
  6584. /**
  6585. * A predefined background symbol for the button.
  6586. *
  6587. * @type {string}
  6588. */
  6589. symbol: 'measure-x.svg'
  6590. },
  6591. measureY: {
  6592. /**
  6593. * A predefined background symbol for the button.
  6594. *
  6595. * @type {string}
  6596. */
  6597. symbol: 'measure-y.svg'
  6598. },
  6599. measureXY: {
  6600. /**
  6601. * A predefined background symbol for the button.
  6602. *
  6603. * @type {string}
  6604. */
  6605. symbol: 'measure-xy.svg'
  6606. }
  6607. },
  6608. toggleAnnotations: {
  6609. /**
  6610. * A predefined background symbol for the button.
  6611. *
  6612. * @type {string}
  6613. */
  6614. symbol: 'annotations-visible.svg'
  6615. },
  6616. currentPriceIndicator: {
  6617. /**
  6618. * A predefined background symbol for the button.
  6619. *
  6620. * @type {string}
  6621. */
  6622. symbol: 'current-price-show.svg'
  6623. },
  6624. indicators: {
  6625. /**
  6626. * A predefined background symbol for the button.
  6627. *
  6628. * @type {string}
  6629. */
  6630. symbol: 'indicators.svg'
  6631. },
  6632. zoomChange: {
  6633. /**
  6634. * A collection of strings pointing to config options for
  6635. * the items.
  6636. *
  6637. * @type {array}
  6638. * @default [
  6639. * 'zoomX',
  6640. * 'zoomY',
  6641. * 'zoomXY'
  6642. * ]
  6643. */
  6644. items: [
  6645. 'zoomX',
  6646. 'zoomY',
  6647. 'zoomXY'
  6648. ],
  6649. zoomX: {
  6650. /**
  6651. * A predefined background symbol for the button.
  6652. *
  6653. * @type {string}
  6654. */
  6655. symbol: 'zoom-x.svg'
  6656. },
  6657. zoomY: {
  6658. /**
  6659. * A predefined background symbol for the button.
  6660. *
  6661. * @type {string}
  6662. */
  6663. symbol: 'zoom-y.svg'
  6664. },
  6665. zoomXY: {
  6666. /**
  6667. * A predefined background symbol for the button.
  6668. *
  6669. * @type {string}
  6670. */
  6671. symbol: 'zoom-xy.svg'
  6672. }
  6673. },
  6674. typeChange: {
  6675. /**
  6676. * A collection of strings pointing to config options for
  6677. * the items.
  6678. *
  6679. * @type {array}
  6680. * @default [
  6681. * 'typeOHLC',
  6682. * 'typeLine',
  6683. * 'typeCandlestick'
  6684. * ]
  6685. */
  6686. items: [
  6687. 'typeOHLC',
  6688. 'typeLine',
  6689. 'typeCandlestick'
  6690. ],
  6691. typeOHLC: {
  6692. /**
  6693. * A predefined background symbol for the button.
  6694. *
  6695. * @type {string}
  6696. */
  6697. symbol: 'series-ohlc.svg'
  6698. },
  6699. typeLine: {
  6700. /**
  6701. * A predefined background symbol for the button.
  6702. *
  6703. * @type {string}
  6704. */
  6705. symbol: 'series-line.svg'
  6706. },
  6707. typeCandlestick: {
  6708. /**
  6709. * A predefined background symbol for the button.
  6710. *
  6711. * @type {string}
  6712. */
  6713. symbol: 'series-candlestick.svg'
  6714. }
  6715. },
  6716. fullScreen: {
  6717. /**
  6718. * A predefined background symbol for the button.
  6719. *
  6720. * @type {string}
  6721. */
  6722. symbol: 'fullscreen.svg'
  6723. },
  6724. saveChart: {
  6725. /**
  6726. * A predefined background symbol for the button.
  6727. *
  6728. * @type {string}
  6729. */
  6730. symbol: 'save-chart.svg'
  6731. }
  6732. }
  6733. }
  6734. }
  6735. });
  6736. /* eslint-disable no-invalid-this, valid-jsdoc */
  6737. // Run HTML generator
  6738. addEvent(H.Chart, 'afterGetContainer', function () {
  6739. this.setStockTools();
  6740. });
  6741. addEvent(H.Chart, 'getMargins', function () {
  6742. var listWrapper = this.stockTools && this.stockTools.listWrapper, offsetWidth = listWrapper && ((listWrapper.startWidth +
  6743. getStyle(listWrapper, 'padding-left') +
  6744. getStyle(listWrapper, 'padding-right')) || listWrapper.offsetWidth);
  6745. if (offsetWidth && offsetWidth < this.plotWidth) {
  6746. this.plotLeft += offsetWidth;
  6747. }
  6748. });
  6749. addEvent(H.Chart, 'destroy', function () {
  6750. if (this.stockTools) {
  6751. this.stockTools.destroy();
  6752. }
  6753. });
  6754. addEvent(H.Chart, 'redraw', function () {
  6755. if (this.stockTools && this.stockTools.guiEnabled) {
  6756. this.stockTools.redraw();
  6757. }
  6758. });
  6759. /**
  6760. * Toolbar Class
  6761. * @private
  6762. * @constructor
  6763. * @param {Object} - options of toolbar
  6764. * @param {Chart} - Reference to chart
  6765. */
  6766. var Toolbar = /** @class */ (function () {
  6767. function Toolbar(options, langOptions, chart) {
  6768. this.arrowDown = void 0;
  6769. this.arrowUp = void 0;
  6770. this.arrowWrapper = void 0;
  6771. this.listWrapper = void 0;
  6772. this.showhideBtn = void 0;
  6773. this.submenu = void 0;
  6774. this.toolbar = void 0;
  6775. this.wrapper = void 0;
  6776. this.chart = chart;
  6777. this.options = options;
  6778. this.lang = langOptions;
  6779. // set url for icons.
  6780. this.iconsURL = this.getIconsURL();
  6781. this.guiEnabled = options.enabled;
  6782. this.visible = pick(options.visible, true);
  6783. this.placed = pick(options.placed, false);
  6784. // General events collection which should be removed upon
  6785. // destroy/update:
  6786. this.eventsToUnbind = [];
  6787. if (this.guiEnabled) {
  6788. this.createHTML();
  6789. this.init();
  6790. this.showHideNavigatorion();
  6791. }
  6792. fireEvent(this, 'afterInit');
  6793. }
  6794. /**
  6795. * Initialize the toolbar. Create buttons and submenu for each option
  6796. * defined in `stockTools.gui`.
  6797. * @private
  6798. */
  6799. Toolbar.prototype.init = function () {
  6800. var _self = this, lang = this.lang, guiOptions = this.options, toolbar = this.toolbar, addSubmenu = _self.addSubmenu, buttons = guiOptions.buttons, defs = guiOptions.definitions, allButtons = toolbar.childNodes, button;
  6801. // create buttons
  6802. buttons.forEach(function (btnName) {
  6803. button = _self.addButton(toolbar, defs, btnName, lang);
  6804. _self.eventsToUnbind.push(addEvent(button.buttonWrapper, 'click', function () {
  6805. _self.eraseActiveButtons(allButtons, button.buttonWrapper);
  6806. }));
  6807. if (isArray(defs[btnName].items)) {
  6808. // create submenu buttons
  6809. addSubmenu.call(_self, button, defs[btnName]);
  6810. }
  6811. });
  6812. };
  6813. /**
  6814. * Create submenu (list of buttons) for the option. In example main button
  6815. * is Line, in submenu will be buttons with types of lines.
  6816. * @private
  6817. * @param {Highcharts.Dictionary<Highcharts.HTMLDOMElement>}
  6818. * button which has submenu
  6819. * @param {Highcharts.StockToolsGuiDefinitionsButtonsOptions}
  6820. * list of all buttons
  6821. */
  6822. Toolbar.prototype.addSubmenu = function (parentBtn, button) {
  6823. var _self = this, submenuArrow = parentBtn.submenuArrow, buttonWrapper = parentBtn.buttonWrapper, buttonWidth = getStyle(buttonWrapper, 'width'), wrapper = this.wrapper, menuWrapper = this.listWrapper, allButtons = this.toolbar.childNodes, topMargin = 0, submenuWrapper;
  6824. // create submenu container
  6825. this.submenu = submenuWrapper = createElement(UL, {
  6826. className: PREFIX + 'submenu-wrapper'
  6827. }, null, buttonWrapper);
  6828. // create submenu buttons and select the first one
  6829. this.addSubmenuItems(buttonWrapper, button);
  6830. // show / hide submenu
  6831. _self.eventsToUnbind.push(addEvent(submenuArrow, 'click', function (e) {
  6832. e.stopPropagation();
  6833. // Erase active class on all other buttons
  6834. _self.eraseActiveButtons(allButtons, buttonWrapper);
  6835. // hide menu
  6836. if (buttonWrapper.className.indexOf(PREFIX + 'current') >= 0) {
  6837. menuWrapper.style.width =
  6838. menuWrapper.startWidth + 'px';
  6839. buttonWrapper.classList.remove(PREFIX + 'current');
  6840. submenuWrapper.style.display = 'none';
  6841. }
  6842. else {
  6843. // show menu
  6844. // to calculate height of element
  6845. submenuWrapper.style.display = 'block';
  6846. topMargin = submenuWrapper.offsetHeight -
  6847. buttonWrapper.offsetHeight - 3;
  6848. // calculate position of submenu in the box
  6849. // if submenu is inside, reset top margin
  6850. if (
  6851. // cut on the bottom
  6852. !(submenuWrapper.offsetHeight +
  6853. buttonWrapper.offsetTop >
  6854. wrapper.offsetHeight &&
  6855. // cut on the top
  6856. buttonWrapper.offsetTop > topMargin)) {
  6857. topMargin = 0;
  6858. }
  6859. // apply calculated styles
  6860. css(submenuWrapper, {
  6861. top: -topMargin + 'px',
  6862. left: buttonWidth + 3 + 'px'
  6863. });
  6864. buttonWrapper.className += ' ' + PREFIX + 'current';
  6865. menuWrapper.startWidth = wrapper.offsetWidth;
  6866. menuWrapper.style.width = menuWrapper.startWidth +
  6867. getStyle(menuWrapper, 'padding-left') +
  6868. submenuWrapper.offsetWidth + 3 + 'px';
  6869. }
  6870. }));
  6871. };
  6872. /**
  6873. * Create buttons in submenu
  6874. * @private
  6875. * @param {Highcharts.HTMLDOMElement}
  6876. * button where submenu is placed
  6877. * @param {Highcharts.StockToolsGuiDefinitionsButtonsOptions}
  6878. * list of all buttons options
  6879. *
  6880. */
  6881. Toolbar.prototype.addSubmenuItems = function (buttonWrapper, button) {
  6882. var _self = this, submenuWrapper = this.submenu, lang = this.lang, menuWrapper = this.listWrapper, items = button.items, firstSubmenuItem, submenuBtn;
  6883. // add items to submenu
  6884. items.forEach(function (btnName) {
  6885. // add buttons to submenu
  6886. submenuBtn = _self.addButton(submenuWrapper, button, btnName, lang);
  6887. _self.eventsToUnbind.push(addEvent(submenuBtn.mainButton, 'click', function () {
  6888. _self.switchSymbol(this, buttonWrapper, true);
  6889. menuWrapper.style.width =
  6890. menuWrapper.startWidth + 'px';
  6891. submenuWrapper.style.display = 'none';
  6892. }));
  6893. });
  6894. // select first submenu item
  6895. firstSubmenuItem = submenuWrapper
  6896. .querySelectorAll('li > .' + PREFIX + 'menu-item-btn')[0];
  6897. // replace current symbol, in main button, with submenu's button style
  6898. _self.switchSymbol(firstSubmenuItem, false);
  6899. };
  6900. /*
  6901. * Erase active class on all other buttons.
  6902. *
  6903. * @param {Array} - Array of HTML buttons
  6904. * @param {HTMLDOMElement} - Current HTML button
  6905. *
  6906. */
  6907. Toolbar.prototype.eraseActiveButtons = function (buttons, currentButton, submenuItems) {
  6908. [].forEach.call(buttons, function (btn) {
  6909. if (btn !== currentButton) {
  6910. btn.classList.remove(PREFIX + 'current');
  6911. btn.classList.remove(PREFIX + 'active');
  6912. submenuItems =
  6913. btn.querySelectorAll('.' + PREFIX + 'submenu-wrapper');
  6914. // hide submenu
  6915. if (submenuItems.length > 0) {
  6916. submenuItems[0].style.display = 'none';
  6917. }
  6918. }
  6919. });
  6920. };
  6921. /**
  6922. * Create single button. Consist of HTML elements `li`, `span`, and (if
  6923. * exists) submenu container.
  6924. * @private
  6925. * @param {Highcharts.HTMLDOMElement} target
  6926. * HTML reference, where button should be added
  6927. * @param {Highcharts.StockToolsGuiDefinitionsButtonsOptions|Highcharts.StockToolsGuiDefinitionsOptions} options
  6928. * All options, by btnName refer to particular button
  6929. * @param {string} btnName
  6930. * of functionality mapped for specific class
  6931. * @param {Highcharts.Dictionary<string>} lang
  6932. * All titles, by btnName refer to particular button
  6933. * @return {Object} - references to all created HTML elements
  6934. */
  6935. Toolbar.prototype.addButton = function (target, options, btnName, lang) {
  6936. if (lang === void 0) { lang = {}; }
  6937. var btnOptions = options[btnName], items = btnOptions.items, classMapping = Toolbar.prototype.classMapping, userClassName = btnOptions.className || '', mainButton, submenuArrow, buttonWrapper;
  6938. // main button wrapper
  6939. buttonWrapper = createElement(LI, {
  6940. className: pick(classMapping[btnName], '') + ' ' + userClassName,
  6941. title: lang[btnName] || btnName
  6942. }, null, target);
  6943. // single button
  6944. mainButton = createElement(SPAN, {
  6945. className: PREFIX + 'menu-item-btn'
  6946. }, null, buttonWrapper);
  6947. // submenu
  6948. if (items && items.length) {
  6949. // arrow is a hook to show / hide submenu
  6950. submenuArrow = createElement(SPAN, {
  6951. className: PREFIX + 'submenu-item-arrow ' +
  6952. PREFIX + 'arrow-right'
  6953. }, null, buttonWrapper);
  6954. submenuArrow.style['background-image'] = 'url(' +
  6955. this.iconsURL + 'arrow-bottom.svg)';
  6956. }
  6957. else {
  6958. mainButton.style['background-image'] = 'url(' +
  6959. this.iconsURL + btnOptions.symbol + ')';
  6960. }
  6961. return {
  6962. buttonWrapper: buttonWrapper,
  6963. mainButton: mainButton,
  6964. submenuArrow: submenuArrow
  6965. };
  6966. };
  6967. /*
  6968. * Create navigation's HTML elements: container and arrows.
  6969. *
  6970. */
  6971. Toolbar.prototype.addNavigation = function () {
  6972. var stockToolbar = this, wrapper = stockToolbar.wrapper;
  6973. // arrow wrapper
  6974. stockToolbar.arrowWrapper = createElement(DIV, {
  6975. className: PREFIX + 'arrow-wrapper'
  6976. });
  6977. stockToolbar.arrowUp = createElement(DIV, {
  6978. className: PREFIX + 'arrow-up'
  6979. }, null, stockToolbar.arrowWrapper);
  6980. stockToolbar.arrowUp.style['background-image'] =
  6981. 'url(' + this.iconsURL + 'arrow-right.svg)';
  6982. stockToolbar.arrowDown = createElement(DIV, {
  6983. className: PREFIX + 'arrow-down'
  6984. }, null, stockToolbar.arrowWrapper);
  6985. stockToolbar.arrowDown.style['background-image'] =
  6986. 'url(' + this.iconsURL + 'arrow-right.svg)';
  6987. wrapper.insertBefore(stockToolbar.arrowWrapper, wrapper.childNodes[0]);
  6988. // attach scroll events
  6989. stockToolbar.scrollButtons();
  6990. };
  6991. /*
  6992. * Add events to navigation (two arrows) which allows user to scroll
  6993. * top/down GUI buttons, if container's height is not enough.
  6994. *
  6995. */
  6996. Toolbar.prototype.scrollButtons = function () {
  6997. var targetY = 0, _self = this, wrapper = _self.wrapper, toolbar = _self.toolbar, step = 0.1 * wrapper.offsetHeight; // 0.1 = 10%
  6998. _self.eventsToUnbind.push(addEvent(_self.arrowUp, 'click', function () {
  6999. if (targetY > 0) {
  7000. targetY -= step;
  7001. toolbar.style['margin-top'] = -targetY + 'px';
  7002. }
  7003. }));
  7004. _self.eventsToUnbind.push(addEvent(_self.arrowDown, 'click', function () {
  7005. if (wrapper.offsetHeight + targetY <=
  7006. toolbar.offsetHeight + step) {
  7007. targetY += step;
  7008. toolbar.style['margin-top'] = -targetY + 'px';
  7009. }
  7010. }));
  7011. };
  7012. /*
  7013. * Create stockTools HTML main elements.
  7014. *
  7015. */
  7016. Toolbar.prototype.createHTML = function () {
  7017. var stockToolbar = this, chart = stockToolbar.chart, guiOptions = stockToolbar.options, container = chart.container, navigation = chart.options.navigation, bindingsClassName = navigation && navigation.bindingsClassName, listWrapper, toolbar, wrapper;
  7018. // create main container
  7019. stockToolbar.wrapper = wrapper = createElement(DIV, {
  7020. className: PREFIX + 'stocktools-wrapper ' +
  7021. guiOptions.className + ' ' + bindingsClassName
  7022. });
  7023. container.parentNode.insertBefore(wrapper, container);
  7024. // toolbar
  7025. stockToolbar.toolbar = toolbar = createElement(UL, {
  7026. className: PREFIX + 'stocktools-toolbar ' +
  7027. guiOptions.toolbarClassName
  7028. });
  7029. // add container for list of buttons
  7030. stockToolbar.listWrapper = listWrapper = createElement(DIV, {
  7031. className: PREFIX + 'menu-wrapper'
  7032. });
  7033. wrapper.insertBefore(listWrapper, wrapper.childNodes[0]);
  7034. listWrapper.insertBefore(toolbar, listWrapper.childNodes[0]);
  7035. stockToolbar.showHideToolbar();
  7036. // add navigation which allows user to scroll down / top GUI buttons
  7037. stockToolbar.addNavigation();
  7038. };
  7039. /**
  7040. * Function called in redraw verifies if the navigation should be visible.
  7041. * @private
  7042. */
  7043. Toolbar.prototype.showHideNavigatorion = function () {
  7044. // arrows
  7045. // 50px space for arrows
  7046. if (this.visible &&
  7047. this.toolbar.offsetHeight > (this.wrapper.offsetHeight - 50)) {
  7048. this.arrowWrapper.style.display = 'block';
  7049. }
  7050. else {
  7051. // reset margin if whole toolbar is visible
  7052. this.toolbar.style.marginTop = '0px';
  7053. // hide arrows
  7054. this.arrowWrapper.style.display = 'none';
  7055. }
  7056. };
  7057. /**
  7058. * Create button which shows or hides GUI toolbar.
  7059. * @private
  7060. */
  7061. Toolbar.prototype.showHideToolbar = function () {
  7062. var stockToolbar = this, chart = this.chart, wrapper = stockToolbar.wrapper, toolbar = this.listWrapper, submenu = this.submenu, visible = this.visible, showhideBtn;
  7063. // Show hide toolbar
  7064. this.showhideBtn = showhideBtn = createElement(DIV, {
  7065. className: PREFIX + 'toggle-toolbar ' + PREFIX + 'arrow-left'
  7066. }, null, wrapper);
  7067. showhideBtn.style['background-image'] =
  7068. 'url(' + this.iconsURL + 'arrow-right.svg)';
  7069. if (!visible) {
  7070. // hide
  7071. if (submenu) {
  7072. submenu.style.display = 'none';
  7073. }
  7074. showhideBtn.style.left = '0px';
  7075. stockToolbar.visible = visible = false;
  7076. toolbar.classList.add(PREFIX + 'hide');
  7077. showhideBtn.classList.toggle(PREFIX + 'arrow-right');
  7078. wrapper.style.height = showhideBtn.offsetHeight + 'px';
  7079. }
  7080. else {
  7081. wrapper.style.height = '100%';
  7082. showhideBtn.style.top = getStyle(toolbar, 'padding-top') + 'px';
  7083. showhideBtn.style.left = (wrapper.offsetWidth +
  7084. getStyle(toolbar, 'padding-left')) + 'px';
  7085. }
  7086. // Toggle menu
  7087. stockToolbar.eventsToUnbind.push(addEvent(showhideBtn, 'click', function () {
  7088. chart.update({
  7089. stockTools: {
  7090. gui: {
  7091. visible: !visible,
  7092. placed: true
  7093. }
  7094. }
  7095. });
  7096. }));
  7097. };
  7098. /*
  7099. * In main GUI button, replace icon and class with submenu button's
  7100. * class / symbol.
  7101. *
  7102. * @param {HTMLDOMElement} - submenu button
  7103. * @param {Boolean} - true or false
  7104. *
  7105. */
  7106. Toolbar.prototype.switchSymbol = function (button, redraw) {
  7107. var buttonWrapper = button.parentNode, buttonWrapperClass = buttonWrapper.classList.value,
  7108. // main button in first level og GUI
  7109. mainNavButton = buttonWrapper.parentNode.parentNode;
  7110. // set class
  7111. mainNavButton.className = '';
  7112. if (buttonWrapperClass) {
  7113. mainNavButton.classList.add(buttonWrapperClass.trim());
  7114. }
  7115. // set icon
  7116. mainNavButton
  7117. .querySelectorAll('.' + PREFIX + 'menu-item-btn')[0]
  7118. .style['background-image'] =
  7119. button.style['background-image'];
  7120. // set active class
  7121. if (redraw) {
  7122. this.selectButton(mainNavButton);
  7123. }
  7124. };
  7125. /*
  7126. * Set select state (active class) on button.
  7127. *
  7128. * @param {HTMLDOMElement} - button
  7129. *
  7130. */
  7131. Toolbar.prototype.selectButton = function (button) {
  7132. if (button.className.indexOf(activeClass) >= 0) {
  7133. button.classList.remove(activeClass);
  7134. }
  7135. else {
  7136. button.classList.add(activeClass);
  7137. }
  7138. };
  7139. /*
  7140. * Remove active class from all buttons except defined.
  7141. *
  7142. * @param {HTMLDOMElement} - button which should not be deactivated
  7143. *
  7144. */
  7145. Toolbar.prototype.unselectAllButtons = function (button) {
  7146. var activeButtons = button.parentNode
  7147. .querySelectorAll('.' + activeClass);
  7148. [].forEach.call(activeButtons, function (activeBtn) {
  7149. if (activeBtn !== button) {
  7150. activeBtn.classList.remove(activeClass);
  7151. }
  7152. });
  7153. };
  7154. /*
  7155. * Update GUI with given options.
  7156. *
  7157. * @param {Object} - general options for Stock Tools
  7158. */
  7159. Toolbar.prototype.update = function (options) {
  7160. merge(true, this.chart.options.stockTools, options);
  7161. this.destroy();
  7162. this.chart.setStockTools(options);
  7163. // If Stock Tools are updated, then bindings should be updated too:
  7164. if (this.chart.navigationBindings) {
  7165. this.chart.navigationBindings.update();
  7166. }
  7167. };
  7168. /**
  7169. * Destroy all HTML GUI elements.
  7170. * @private
  7171. */
  7172. Toolbar.prototype.destroy = function () {
  7173. var stockToolsDiv = this.wrapper, parent = stockToolsDiv && stockToolsDiv.parentNode;
  7174. this.eventsToUnbind.forEach(function (unbinder) {
  7175. unbinder();
  7176. });
  7177. // Remove the empty element
  7178. if (parent) {
  7179. parent.removeChild(stockToolsDiv);
  7180. }
  7181. // redraw
  7182. this.chart.isDirtyBox = true;
  7183. this.chart.redraw();
  7184. };
  7185. /**
  7186. * Redraw, GUI requires to verify if the navigation should be visible.
  7187. * @private
  7188. */
  7189. Toolbar.prototype.redraw = function () {
  7190. this.showHideNavigatorion();
  7191. };
  7192. Toolbar.prototype.getIconsURL = function () {
  7193. return this.chart.options.navigation.iconsURL ||
  7194. this.options.iconsURL ||
  7195. 'https://code.highcharts.com/8.1.2/gfx/stock-icons/';
  7196. };
  7197. return Toolbar;
  7198. }());
  7199. /**
  7200. * Mapping JSON fields to CSS classes.
  7201. * @private
  7202. */
  7203. Toolbar.prototype.classMapping = {
  7204. circle: PREFIX + 'circle-annotation',
  7205. rectangle: PREFIX + 'rectangle-annotation',
  7206. label: PREFIX + 'label-annotation',
  7207. segment: PREFIX + 'segment',
  7208. arrowSegment: PREFIX + 'arrow-segment',
  7209. ray: PREFIX + 'ray',
  7210. arrowRay: PREFIX + 'arrow-ray',
  7211. line: PREFIX + 'infinity-line',
  7212. arrowLine: PREFIX + 'arrow-infinity-line',
  7213. verticalLine: PREFIX + 'vertical-line',
  7214. horizontalLine: PREFIX + 'horizontal-line',
  7215. crooked3: PREFIX + 'crooked3',
  7216. crooked5: PREFIX + 'crooked5',
  7217. elliott3: PREFIX + 'elliott3',
  7218. elliott5: PREFIX + 'elliott5',
  7219. pitchfork: PREFIX + 'pitchfork',
  7220. fibonacci: PREFIX + 'fibonacci',
  7221. parallelChannel: PREFIX + 'parallel-channel',
  7222. measureX: PREFIX + 'measure-x',
  7223. measureY: PREFIX + 'measure-y',
  7224. measureXY: PREFIX + 'measure-xy',
  7225. verticalCounter: PREFIX + 'vertical-counter',
  7226. verticalLabel: PREFIX + 'vertical-label',
  7227. verticalArrow: PREFIX + 'vertical-arrow',
  7228. currentPriceIndicator: PREFIX + 'current-price-indicator',
  7229. indicators: PREFIX + 'indicators',
  7230. flagCirclepin: PREFIX + 'flag-circlepin',
  7231. flagDiamondpin: PREFIX + 'flag-diamondpin',
  7232. flagSquarepin: PREFIX + 'flag-squarepin',
  7233. flagSimplepin: PREFIX + 'flag-simplepin',
  7234. zoomX: PREFIX + 'zoom-x',
  7235. zoomY: PREFIX + 'zoom-y',
  7236. zoomXY: PREFIX + 'zoom-xy',
  7237. typeLine: PREFIX + 'series-type-line',
  7238. typeOHLC: PREFIX + 'series-type-ohlc',
  7239. typeCandlestick: PREFIX + 'series-type-candlestick',
  7240. fullScreen: PREFIX + 'full-screen',
  7241. toggleAnnotations: PREFIX + 'toggle-annotations',
  7242. saveChart: PREFIX + 'save-chart',
  7243. separator: PREFIX + 'separator'
  7244. };
  7245. extend(Chart.prototype, {
  7246. /**
  7247. * Verify if Toolbar should be added.
  7248. * @private
  7249. * @param {Highcharts.StockToolsOptions} - chart options
  7250. */
  7251. setStockTools: function (options) {
  7252. var chartOptions = this.options, lang = chartOptions.lang, guiOptions = merge(chartOptions.stockTools && chartOptions.stockTools.gui, options && options.gui), langOptions = lang.stockTools && lang.stockTools.gui;
  7253. this.stockTools = new H.Toolbar(guiOptions, langOptions, this);
  7254. if (this.stockTools.guiEnabled) {
  7255. this.isDirtyBox = true;
  7256. }
  7257. }
  7258. });
  7259. // Comunication with bindings:
  7260. addEvent(NavigationBindings, 'selectButton', function (event) {
  7261. var button = event.button, className = PREFIX + 'submenu-wrapper', gui = this.chart.stockTools;
  7262. if (gui && gui.guiEnabled) {
  7263. // Unslect other active buttons
  7264. gui.unselectAllButtons(event.button);
  7265. // If clicked on a submenu, select state for it's parent
  7266. if (button.parentNode.className.indexOf(className) >= 0) {
  7267. button = button.parentNode.parentNode;
  7268. }
  7269. // Set active class on the current button
  7270. gui.selectButton(button);
  7271. }
  7272. });
  7273. addEvent(NavigationBindings, 'deselectButton', function (event) {
  7274. var button = event.button, className = PREFIX + 'submenu-wrapper', gui = this.chart.stockTools;
  7275. if (gui && gui.guiEnabled) {
  7276. // If deselecting a button from a submenu, select state for it's parent
  7277. if (button.parentNode.className.indexOf(className) >= 0) {
  7278. button = button.parentNode.parentNode;
  7279. }
  7280. gui.selectButton(button);
  7281. }
  7282. });
  7283. H.Toolbar = Toolbar;
  7284. return H.Toolbar;
  7285. });
  7286. _registerModule(_modules, 'masters/modules/stock-tools.src.js', [], function () {
  7287. });
  7288. }));