| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565 |
- /**
- * @license Highcharts JS v8.0.0 (2019-12-10)
- *
- * Accessibility module
- *
- * (c) 2010-2019 Highsoft AS
- * Author: Oystein Moseng
- *
- * License: www.highcharts.com/license
- */
- 'use strict';
- (function (factory) {
- if (typeof module === 'object' && module.exports) {
- factory['default'] = factory;
- module.exports = factory;
- } else if (typeof define === 'function' && define.amd) {
- define('highcharts/modules/accessibility', ['highcharts'], function (Highcharts) {
- factory(Highcharts);
- factory.Highcharts = Highcharts;
- return factory;
- });
- } else {
- factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);
- }
- }(function (Highcharts) {
- var _modules = Highcharts ? Highcharts._modules : {};
- function _registerModule(obj, path, args, fn) {
- if (!obj.hasOwnProperty(path)) {
- obj[path] = fn.apply(null, args);
- }
- }
- _registerModule(_modules, 'modules/accessibility/utils/htmlUtilities.js', [_modules['parts/Globals.js']], function (H) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Utility functions for accessibility module.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var merge = H.merge, win = H.win, doc = win.document;
- /* eslint-disable valid-jsdoc */
- /**
- * @private
- * @param {Highcharts.HTMLDOMElement} el
- * @param {string} className
- * @return {void}
- */
- function addClass(el, className) {
- if (el.classList) {
- el.classList.add(className);
- }
- else if (el.className.indexOf(className) < 0) {
- // Note: Dumb check for class name exists, should be fine for practical
- // use cases, but will return false positives if the element has a class
- // that contains the className.
- el.className += className;
- }
- }
- /**
- * @private
- * @param {string} str
- * @return {string}
- */
- function escapeStringForHTML(str) {
- return str
- .replace(/&/g, '&')
- .replace(/</g, '<')
- .replace(/>/g, '>')
- .replace(/"/g, '"')
- .replace(/'/g, ''')
- .replace(/\//g, '/');
- }
- /**
- * Get an element by ID
- * @param {string} id
- * @private
- * @return {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement|null}
- */
- function getElement(id) {
- return doc.getElementById(id);
- }
- /**
- * Get a fake mouse event of a given type
- * @param {string} type
- * @private
- * @return {global.MouseEvent}
- */
- function getFakeMouseEvent(type) {
- if (typeof win.MouseEvent === 'function') {
- return new win.MouseEvent(type);
- }
- // No MouseEvent support, try using initMouseEvent
- if (doc.createEvent) {
- var evt = doc.createEvent('MouseEvent');
- if (evt.initMouseEvent) {
- evt.initMouseEvent(type, true, // Bubble
- true, // Cancel
- win, // View
- type === 'click' ? 1 : 0, // Detail
- // Coords
- 0, 0, 0, 0,
- // Pressed keys
- false, false, false, false, 0, // button
- null // related target
- );
- return evt;
- }
- }
- return { type: type };
- }
- /**
- * Remove an element from the DOM.
- * @private
- * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} [element]
- * @return {void}
- */
- function removeElement(element) {
- if (element && element.parentNode) {
- element.parentNode.removeChild(element);
- }
- }
- /**
- * Utility function. Reverses child nodes of a DOM element.
- * @private
- * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} node
- * @return {void}
- */
- function reverseChildNodes(node) {
- var i = node.childNodes.length;
- while (i--) {
- node.appendChild(node.childNodes[i]);
- }
- }
- /**
- * Set attributes on element. Set to null to remove attribute.
- * @private
- * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} el
- * @param {Highcharts.HTMLAttributes|Highcharts.SVGAttributes} attrs
- * @return {void}
- */
- function setElAttrs(el, attrs) {
- Object.keys(attrs).forEach(function (attr) {
- var val = attrs[attr];
- if (val === null) {
- el.removeAttribute(attr);
- }
- else {
- var cleanedVal = escapeStringForHTML('' + val);
- el.setAttribute(attr, cleanedVal);
- }
- });
- }
- /**
- * Used for aria-label attributes, painting on a canvas will fail if the
- * text contains tags.
- * @private
- * @param {string} str
- * @return {string}
- */
- function stripHTMLTagsFromString(str) {
- return typeof str === 'string' ?
- str.replace(/<\/?[^>]+(>|$)/g, '') : str;
- }
- /**
- * Utility function for hiding an element visually, but still keeping it
- * available to screen reader users.
- * @private
- * @param {Highcharts.HTMLDOMElement} element
- * @return {void}
- */
- function visuallyHideElement(element) {
- var hiddenStyle = {
- position: 'absolute',
- width: '1px',
- height: '1px',
- overflow: 'hidden',
- '-ms-filter': 'progid:DXImageTransform.Microsoft.Alpha(Opacity=1)',
- filter: 'alpha(opacity=1)',
- opacity: '0.01'
- };
- merge(true, element.style, hiddenStyle);
- }
- var HTMLUtilities = {
- addClass: addClass,
- escapeStringForHTML: escapeStringForHTML,
- getElement: getElement,
- getFakeMouseEvent: getFakeMouseEvent,
- removeElement: removeElement,
- reverseChildNodes: reverseChildNodes,
- setElAttrs: setElAttrs,
- stripHTMLTagsFromString: stripHTMLTagsFromString,
- visuallyHideElement: visuallyHideElement
- };
- return HTMLUtilities;
- });
- _registerModule(_modules, 'modules/accessibility/utils/chartUtilities.js', [_modules['modules/accessibility/utils/htmlUtilities.js'], _modules['parts/Globals.js']], function (HTMLUtilities, H) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Utils for dealing with charts.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var stripHTMLTags = HTMLUtilities.stripHTMLTagsFromString;
- var find = H.find;
- /* eslint-disable valid-jsdoc */
- /**
- * @return {string}
- */
- function getChartTitle(chart) {
- return stripHTMLTags(chart.options.title.text ||
- chart.langFormat('accessibility.defaultChartTitle', { chart: chart }));
- }
- /**
- * @param {Highcharts.Axis} axis
- * @return {string}
- */
- function getAxisDescription(axis) {
- return stripHTMLTags(axis && (axis.userOptions && axis.userOptions.accessibility &&
- axis.userOptions.accessibility.description ||
- axis.axisTitle && axis.axisTitle.textStr ||
- axis.options.id ||
- axis.categories && 'categories' ||
- axis.isDatetimeAxis && 'Time' ||
- 'values'));
- }
- /**
- * Get the DOM element for the first point in the series.
- * @private
- * @param {Highcharts.Series} series
- * The series to get element for.
- * @return {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement|undefined}
- * The DOM element for the point.
- */
- function getSeriesFirstPointElement(series) {
- if (series.points &&
- series.points.length &&
- series.points[0].graphic) {
- return series.points[0].graphic.element;
- }
- }
- /**
- * Get the DOM element for the series that we put accessibility info on.
- * @private
- * @param {Highcharts.Series} series
- * The series to get element for.
- * @return {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement|undefined}
- * The DOM element for the series
- */
- function getSeriesA11yElement(series) {
- var firstPointEl = getSeriesFirstPointElement(series);
- return (firstPointEl &&
- firstPointEl.parentNode || series.graph &&
- series.graph.element || series.group &&
- series.group.element); // Could be tracker series depending on series type
- }
- /**
- * Remove aria-hidden from element. Also unhides parents of the element, and
- * hides siblings that are not explicitly unhidden.
- * @private
- * @param {Highcharts.Chart} chart
- * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} element
- * @return {void}
- */
- function unhideChartElementFromAT(chart, element) {
- element.setAttribute('aria-hidden', false);
- if (element === chart.renderTo || !element.parentNode) {
- return;
- }
- // Hide siblings unless their hidden state is already explicitly set
- Array.prototype.forEach.call(element.parentNode.childNodes, function (node) {
- if (!node.hasAttribute('aria-hidden')) {
- node.setAttribute('aria-hidden', true);
- }
- });
- // Repeat for parent
- unhideChartElementFromAT(chart, element.parentNode);
- }
- /**
- * Hide series from screen readers.
- * @private
- * @param {Highcharts.Series} series
- * The series to hide
- * @return {void}
- */
- function hideSeriesFromAT(series) {
- var seriesEl = getSeriesA11yElement(series);
- if (seriesEl) {
- seriesEl.setAttribute('aria-hidden', true);
- }
- }
- /**
- * Get series objects by series name.
- * @private
- * @param {Highcharts.Chart} chart
- * @param {string} name
- * @return {Array<Highcharts.Series>}
- */
- function getSeriesFromName(chart, name) {
- if (!name) {
- return chart.series;
- }
- return (chart.series || []).filter(function (s) {
- return s.name === name;
- });
- }
- /**
- * Get point in a series from x/y values.
- * @private
- * @param {Array<Highcharts.Series>} series
- * @param {number} x
- * @param {number} y
- * @return {Highcharts.Point|undefined}
- */
- function getPointFromXY(series, x, y) {
- var i = series.length, res;
- while (i--) {
- res = find(series[i].points || [], function (p) {
- return p.x === x && p.y === y;
- });
- if (res) {
- return res;
- }
- }
- }
- var ChartUtilities = {
- getChartTitle: getChartTitle,
- getAxisDescription: getAxisDescription,
- getPointFromXY: getPointFromXY,
- getSeriesFirstPointElement: getSeriesFirstPointElement,
- getSeriesFromName: getSeriesFromName,
- getSeriesA11yElement: getSeriesA11yElement,
- unhideChartElementFromAT: unhideChartElementFromAT,
- hideSeriesFromAT: hideSeriesFromAT
- };
- return ChartUtilities;
- });
- _registerModule(_modules, 'modules/accessibility/KeyboardNavigationHandler.js', [_modules['parts/Globals.js']], function (H) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Keyboard navigation handler base class definition
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var find = H.find;
- /**
- * Options for the keyboard navigation handler.
- *
- * @interface Highcharts.KeyboardNavigationHandlerOptionsObject
- */ /**
- * An array containing pairs of an array of keycodes, mapped to a handler
- * function. When the keycode is received, the handler is called with the
- * keycode as parameter.
- * @name Highcharts.KeyboardNavigationHandlerOptionsObject#keyCodeMap
- * @type {Array<Array<Array<number>, Function>>}
- */ /**
- * Function to run on initialization of module.
- * @name Highcharts.KeyboardNavigationHandlerOptionsObject#init
- * @type {Function}
- */ /**
- * Function to run before moving to next/prev module. Receives moving direction
- * as parameter: +1 for next, -1 for previous.
- * @name Highcharts.KeyboardNavigationHandlerOptionsObject#terminate
- * @type {Function|undefined}
- */ /**
- * Function to run to validate module. Should return false if module should not
- * run, true otherwise. Receives chart as parameter.
- * @name Highcharts.KeyboardNavigationHandlerOptionsObject#validate
- * @type {Function|undefined}
- */
- /* eslint-disable no-invalid-this, valid-jsdoc */
- /**
- * Define a keyboard navigation handler for use with a
- * Highcharts.AccessibilityComponent instance. This functions as an abstraction
- * layer for keyboard navigation, and defines a map of keyCodes to handler
- * functions.
- *
- * @requires module:modules/accessibility
- *
- * @sample highcharts/accessibility/custom-component
- * Custom accessibility component
- *
- * @class
- * @name Highcharts.KeyboardNavigationHandler
- *
- * @param {Highcharts.Chart} chart
- * The chart this module should act on.
- *
- * @param {Highcharts.KeyboardNavigationHandlerOptionsObject} options
- * Options for the keyboard navigation handler.
- */
- function KeyboardNavigationHandler(chart, options) {
- this.chart = chart;
- this.keyCodeMap = options.keyCodeMap || [];
- this.validate = options.validate;
- this.init = options.init;
- this.terminate = options.terminate;
- // Response enum
- this.response = {
- success: 1,
- prev: 2,
- next: 3,
- noHandler: 4,
- fail: 5 // Handler failed
- };
- }
- KeyboardNavigationHandler.prototype = {
- /**
- * Find handler function(s) for key code in the keyCodeMap and run it.
- *
- * @function KeyboardNavigationHandler#run
- * @param {global.KeyboardEvent} e
- * @return {number} Returns a response code indicating whether the run was
- * a success/fail/unhandled, or if we should move to next/prev module.
- */
- run: function (e) {
- var keyCode = e.which || e.keyCode, response = this.response.noHandler, handlerCodeSet = find(this.keyCodeMap, function (codeSet) {
- return codeSet[0].indexOf(keyCode) > -1;
- });
- if (handlerCodeSet) {
- response = handlerCodeSet[1].call(this, keyCode, e);
- }
- else if (keyCode === 9) {
- // Default tab handler, move to next/prev module
- response = this.response[e.shiftKey ? 'prev' : 'next'];
- }
- else if (keyCode === 27) {
- // Default esc handler, hide tooltip
- if (this.chart && this.chart.tooltip) {
- this.chart.tooltip.hide(0);
- }
- response = this.response.success;
- }
- return response;
- }
- };
- return KeyboardNavigationHandler;
- });
- _registerModule(_modules, 'modules/accessibility/utils/EventProvider.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Class that can keep track of events added, and clean them up on destroy.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var extend = U.extend;
- /* eslint-disable no-invalid-this, valid-jsdoc */
- /**
- * @private
- * @class
- */
- var EventProvider = function () {
- this.eventRemovers = [];
- };
- extend(EventProvider.prototype, {
- /**
- * Add an event to an element and keep track of it for later removal.
- * Same args as Highcharts.addEvent.
- * @private
- * @return {Function}
- */
- addEvent: function () {
- var remover = H.addEvent.apply(H, arguments);
- this.eventRemovers.push(remover);
- return remover;
- },
- /**
- * Remove all added events.
- * @private
- * @return {void}
- */
- removeAddedEvents: function () {
- this.eventRemovers.forEach(function (remover) {
- remover();
- });
- this.eventRemovers = [];
- }
- });
- return EventProvider;
- });
- _registerModule(_modules, 'modules/accessibility/utils/DOMElementProvider.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js'], _modules['modules/accessibility/utils/htmlUtilities.js']], function (H, U, HTMLUtilities) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Class that can keep track of elements added to DOM and clean them up on
- * destroy.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var doc = H.win.document;
- var extend = U.extend;
- var removeElement = HTMLUtilities.removeElement;
- /* eslint-disable no-invalid-this, valid-jsdoc */
- /**
- * @private
- * @class
- */
- var DOMElementProvider = function () {
- this.elements = [];
- };
- extend(DOMElementProvider.prototype, {
- /**
- * Create an element and keep track of it for later removal.
- * Same args as document.createElement
- * @private
- */
- createElement: function () {
- var el = doc.createElement.apply(doc, arguments);
- this.elements.push(el);
- return el;
- },
- /**
- * Destroy all created elements, removing them from the DOM.
- * @private
- */
- destroyCreatedElements: function () {
- this.elements.forEach(function (element) {
- removeElement(element);
- });
- this.elements = [];
- }
- });
- return DOMElementProvider;
- });
- _registerModule(_modules, 'modules/accessibility/AccessibilityComponent.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js'], _modules['modules/accessibility/utils/htmlUtilities.js'], _modules['modules/accessibility/utils/chartUtilities.js'], _modules['modules/accessibility/utils/EventProvider.js'], _modules['modules/accessibility/utils/DOMElementProvider.js']], function (H, U, HTMLUtilities, ChartUtilities, EventProvider, DOMElementProvider) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Accessibility component class definition
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var win = H.win, doc = win.document, merge = H.merge, fireEvent = H.fireEvent;
- var extend = U.extend;
- var removeElement = HTMLUtilities.removeElement, getFakeMouseEvent = HTMLUtilities.getFakeMouseEvent;
- var unhideChartElementFromAT = ChartUtilities.unhideChartElementFromAT;
- /* eslint-disable valid-jsdoc */
- /** @lends Highcharts.AccessibilityComponent */
- var functionsToOverrideByDerivedClasses = {
- /**
- * Called on component initialization.
- */
- init: function () { },
- /**
- * Get keyboard navigation handler for this component.
- * @return {Highcharts.KeyboardNavigationHandler}
- */
- getKeyboardNavigation: function () { },
- /**
- * Called on updates to the chart, including options changes.
- * Note that this is also called on first render of chart.
- */
- onChartUpdate: function () { },
- /**
- * Called on every chart render.
- */
- onChartRender: function () { },
- /**
- * Called when accessibility is disabled or chart is destroyed.
- */
- destroy: function () { }
- };
- /**
- * The AccessibilityComponent base class, representing a part of the chart that
- * has accessibility logic connected to it. This class can be inherited from to
- * create a custom accessibility component for a chart.
- *
- * Components should take care to destroy added elements and unregister event
- * handlers on destroy. This is handled automatically if using this.addEvent and
- * this.createElement.
- *
- * @sample highcharts/accessibility/custom-component
- * Custom accessibility component
- *
- * @requires module:modules/accessibility
- * @class
- * @name Highcharts.AccessibilityComponent
- */
- function AccessibilityComponent() { }
- /**
- * @lends Highcharts.AccessibilityComponent
- */
- AccessibilityComponent.prototype = {
- /**
- * Initialize the class
- * @private
- * @param {Highcharts.Chart} chart
- * Chart object
- */
- initBase: function (chart) {
- this.chart = chart;
- this.eventProvider = new EventProvider();
- this.domElementProvider = new DOMElementProvider();
- // Key code enum for common keys
- this.keyCodes = {
- left: 37,
- right: 39,
- up: 38,
- down: 40,
- enter: 13,
- space: 32,
- esc: 27,
- tab: 9
- };
- },
- /**
- * Add an event to an element and keep track of it for later removal.
- * See EventProvider for details.
- * @private
- */
- addEvent: function () {
- return this.eventProvider.addEvent
- .apply(this.eventProvider, arguments);
- },
- /**
- * Create an element and keep track of it for later removal.
- * See DOMElementProvider for details.
- * @private
- */
- createElement: function () {
- return this.domElementProvider.createElement.apply(this.domElementProvider, arguments);
- },
- /**
- * Fire an event on an element that is either wrapped by Highcharts,
- * or a DOM element
- * @private
- * @param {Highcharts.HTMLElement|Highcharts.HTMLDOMElement|
- * Highcharts.SVGDOMElement|Highcharts.SVGElement} el
- * @param {Event} eventObject
- */
- fireEventOnWrappedOrUnwrappedElement: function (el, eventObject) {
- var type = eventObject.type;
- if (doc.createEvent && (el.dispatchEvent || el.fireEvent)) {
- if (el.dispatchEvent) {
- el.dispatchEvent(eventObject);
- }
- else {
- el.fireEvent(type, eventObject);
- }
- }
- else {
- fireEvent(el, type, eventObject);
- }
- },
- /**
- * Utility function to attempt to fake a click event on an element.
- * @private
- * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} element
- */
- fakeClickEvent: function (element) {
- if (element) {
- var fakeEventObject = getFakeMouseEvent('click');
- this.fireEventOnWrappedOrUnwrappedElement(element, fakeEventObject);
- }
- },
- /**
- * Add a new proxy group to the proxy container. Creates the proxy container
- * if it does not exist.
- * @private
- * @param {Highcharts.HTMLAttributes} [attrs]
- * The attributes to set on the new group div.
- * @return {Highcharts.HTMLDOMElement}
- * The new proxy group element.
- */
- addProxyGroup: function (attrs) {
- this.createOrUpdateProxyContainer();
- var groupDiv = this.createElement('div');
- Object.keys(attrs || {}).forEach(function (prop) {
- if (attrs[prop] !== null) {
- groupDiv.setAttribute(prop, attrs[prop]);
- }
- });
- this.chart.a11yProxyContainer.appendChild(groupDiv);
- return groupDiv;
- },
- /**
- * Creates and updates DOM position of proxy container
- * @private
- */
- createOrUpdateProxyContainer: function () {
- var chart = this.chart, rendererSVGEl = chart.renderer.box;
- chart.a11yProxyContainer = chart.a11yProxyContainer ||
- this.createProxyContainerElement();
- if (rendererSVGEl.nextSibling !== chart.a11yProxyContainer) {
- chart.container.insertBefore(chart.a11yProxyContainer, rendererSVGEl.nextSibling);
- }
- },
- /**
- * @private
- * @return {Highcharts.HTMLDOMElement} element
- */
- createProxyContainerElement: function () {
- var pc = doc.createElement('div');
- pc.className = 'highcharts-a11y-proxy-container';
- return pc;
- },
- /**
- * Create an invisible proxy HTML button in the same position as an SVG
- * element
- * @private
- * @param {Highcharts.SVGElement} svgElement
- * The wrapped svg el to proxy.
- * @param {Highcharts.HTMLDOMElement} parentGroup
- * The proxy group element in the proxy container to add this button to.
- * @param {Highcharts.SVGAttributes} [attributes]
- * Additional attributes to set.
- * @param {Highcharts.SVGElement} [posElement]
- * Element to use for positioning instead of svgElement.
- * @param {Function} [preClickEvent]
- * Function to call before click event fires.
- *
- * @return {Highcharts.HTMLDOMElement} The proxy button.
- */
- createProxyButton: function (svgElement, parentGroup, attributes, posElement, preClickEvent) {
- var svgEl = svgElement.element, proxy = this.createElement('button'), attrs = merge({
- 'aria-label': svgEl.getAttribute('aria-label')
- }, attributes), bBox = this.getElementPosition(posElement || svgElement);
- Object.keys(attrs).forEach(function (prop) {
- if (attrs[prop] !== null) {
- proxy.setAttribute(prop, attrs[prop]);
- }
- });
- proxy.className = 'highcharts-a11y-proxy-button';
- if (preClickEvent) {
- this.addEvent(proxy, 'click', preClickEvent);
- }
- this.setProxyButtonStyle(proxy, bBox);
- this.proxyMouseEventsForButton(svgEl, proxy);
- // Add to chart div and unhide from screen readers
- parentGroup.appendChild(proxy);
- if (!attrs['aria-hidden']) {
- unhideChartElementFromAT(this.chart, proxy);
- }
- return proxy;
- },
- /**
- * Get the position relative to chart container for a wrapped SVG element.
- * @private
- * @param {Highcharts.SVGElement} element
- * The element to calculate position for.
- * @return {Highcharts.BBoxObject}
- * Object with x and y props for the position.
- */
- getElementPosition: function (element) {
- var el = element.element, div = this.chart.renderTo;
- if (div && el && el.getBoundingClientRect) {
- var rectEl = el.getBoundingClientRect(), rectDiv = div.getBoundingClientRect();
- return {
- x: rectEl.left - rectDiv.left,
- y: rectEl.top - rectDiv.top,
- width: rectEl.right - rectEl.left,
- height: rectEl.bottom - rectEl.top
- };
- }
- return { x: 0, y: 0, width: 1, height: 1 };
- },
- /**
- * @private
- * @param {Highcharts.HTMLElement} button
- * @param {Highcharts.BBoxObject} bBox
- */
- setProxyButtonStyle: function (button, bBox) {
- merge(true, button.style, {
- 'border-width': 0,
- 'background-color': 'transparent',
- cursor: 'pointer',
- outline: 'none',
- opacity: 0.001,
- filter: 'alpha(opacity=1)',
- '-ms-filter': 'progid:DXImageTransform.Microsoft.Alpha(Opacity=1)',
- zIndex: 999,
- overflow: 'hidden',
- padding: 0,
- margin: 0,
- display: 'block',
- position: 'absolute',
- width: (bBox.width || 1) + 'px',
- height: (bBox.height || 1) + 'px',
- left: (bBox.x || 0) + 'px',
- top: (bBox.y || 0) + 'px'
- });
- },
- /**
- * @private
- * @param {Highcharts.HTMLElement|Highcharts.HTMLDOMElement|
- * Highcharts.SVGDOMElement|Highcharts.SVGElement} source
- * @param {Highcharts.HTMLElement} button
- */
- proxyMouseEventsForButton: function (source, button) {
- var component = this;
- [
- 'click', 'touchstart', 'touchend', 'touchcancel', 'touchmove',
- 'mouseover', 'mouseenter', 'mouseleave', 'mouseout'
- ].forEach(function (evtType) {
- component.addEvent(button, evtType, function (e) {
- var clonedEvent = component.cloneMouseEvent(e);
- if (source) {
- component.fireEventOnWrappedOrUnwrappedElement(source, clonedEvent);
- }
- e.stopPropagation();
- e.preventDefault();
- });
- });
- },
- /**
- * Utility function to clone a mouse event for re-dispatching.
- * @private
- * @param {global.MouseEvent} e The event to clone.
- * @return {global.MouseEvent} The cloned event
- */
- cloneMouseEvent: function (e) {
- if (typeof win.MouseEvent === 'function') {
- return new win.MouseEvent(e.type, e);
- }
- // No MouseEvent support, try using initMouseEvent
- if (doc.createEvent) {
- var evt = doc.createEvent('MouseEvent');
- if (evt.initMouseEvent) {
- evt.initMouseEvent(e.type, e.bubbles, // #10561, #12161
- e.cancelable, e.view || win, e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget);
- return evt;
- }
- }
- return getFakeMouseEvent(e.type);
- },
- /**
- * Remove traces of the component.
- * @private
- */
- destroyBase: function () {
- removeElement(this.chart.a11yProxyContainer);
- this.domElementProvider.destroyCreatedElements();
- this.eventProvider.removeAddedEvents();
- }
- };
- extend(AccessibilityComponent.prototype, functionsToOverrideByDerivedClasses);
- return AccessibilityComponent;
- });
- _registerModule(_modules, 'modules/accessibility/KeyboardNavigation.js', [_modules['parts/Globals.js'], _modules['modules/accessibility/utils/htmlUtilities.js'], _modules['modules/accessibility/KeyboardNavigationHandler.js'], _modules['modules/accessibility/utils/EventProvider.js']], function (H, HTMLUtilities, KeyboardNavigationHandler, EventProvider) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Main keyboard navigation handling.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var merge = H.merge, win = H.win, doc = win.document;
- var getElement = HTMLUtilities.getElement;
- /* eslint-disable valid-jsdoc */
- /**
- * The KeyboardNavigation class, containing the overall keyboard navigation
- * logic for the chart.
- *
- * @requires module:modules/accessibility
- *
- * @private
- * @class
- * @param {Highcharts.Chart} chart
- * Chart object
- * @param {object} components
- * Map of component names to AccessibilityComponent objects.
- * @name Highcharts.KeyboardNavigation
- */
- function KeyboardNavigation(chart, components) {
- this.init(chart, components);
- }
- KeyboardNavigation.prototype = {
- /**
- * Initialize the class
- * @private
- * @param {Highcharts.Chart} chart
- * Chart object
- * @param {object} components
- * Map of component names to AccessibilityComponent objects.
- */
- init: function (chart, components) {
- var keyboardNavigation = this, e = this.eventProvider = new EventProvider();
- this.chart = chart;
- this.components = components;
- this.modules = [];
- this.currentModuleIx = 0;
- // Add keydown event
- e.addEvent(chart.renderTo, 'keydown', function (e) {
- keyboardNavigation.onKeydown(e);
- });
- // Add mouseup event on doc
- e.addEvent(doc, 'mouseup', function () {
- keyboardNavigation.onMouseUp();
- });
- // Run an update to get all modules
- this.update();
- // Init first module
- if (this.modules.length) {
- this.modules[0].init(1);
- }
- },
- /**
- * Update the modules for the keyboard navigation.
- * @param {Array<string>} [order]
- * Array specifying the tab order of the components.
- */
- update: function (order) {
- var a11yOptions = this.chart.options.accessibility, keyboardOptions = a11yOptions && a11yOptions.keyboardNavigation, components = this.components;
- this.updateContainerTabindex();
- if (keyboardOptions &&
- keyboardOptions.enabled &&
- order &&
- order.length) {
- // We (still) have keyboard navigation. Update module list
- this.modules = order.reduce(function (modules, componentName) {
- var navModules = components[componentName].getKeyboardNavigation();
- return modules.concat(navModules);
- }, [
- // Add an empty module at the start of list, to allow users to
- // tab into the chart.
- new KeyboardNavigationHandler(this.chart, {
- init: function () { }
- })
- ]);
- this.updateExitAnchor();
- }
- else {
- this.modules = [];
- this.currentModuleIx = 0;
- this.removeExitAnchor();
- }
- },
- /**
- * Reset chart navigation state if we click outside the chart and it's
- * not already reset.
- * @private
- */
- onMouseUp: function () {
- if (!this.keyboardReset &&
- !(this.chart.pointer && this.chart.pointer.chartPosition)) {
- var chart = this.chart, curMod = this.modules &&
- this.modules[this.currentModuleIx || 0];
- if (curMod && curMod.terminate) {
- curMod.terminate();
- }
- if (chart.focusElement) {
- chart.focusElement.removeFocusBorder();
- }
- this.currentModuleIx = 0;
- this.keyboardReset = true;
- }
- },
- /**
- * Function to run on keydown
- * @private
- * @param {global.KeyboardEvent} ev
- * Browser keydown event.
- */
- onKeydown: function (ev) {
- var e = ev || win.event, preventDefault, curNavModule = this.modules && this.modules.length &&
- this.modules[this.currentModuleIx];
- // Used for resetting nav state when clicking outside chart
- this.keyboardReset = false;
- // If there is a nav module for the current index, run it.
- // Otherwise, we are outside of the chart in some direction.
- if (curNavModule) {
- var response = curNavModule.run(e);
- if (response === curNavModule.response.success) {
- preventDefault = true;
- }
- else if (response === curNavModule.response.prev) {
- preventDefault = this.prev();
- }
- else if (response === curNavModule.response.next) {
- preventDefault = this.next();
- }
- if (preventDefault) {
- e.preventDefault();
- e.stopPropagation();
- }
- }
- },
- /**
- * Go to previous module.
- * @private
- */
- prev: function () {
- return this.move(-1);
- },
- /**
- * Go to next module.
- * @private
- */
- next: function () {
- return this.move(1);
- },
- /**
- * Move to prev/next module.
- * @private
- * @param {number} direction
- * Direction to move. +1 for next, -1 for prev.
- * @return {boolean}
- * True if there was a valid module in direction.
- */
- move: function (direction) {
- var curModule = this.modules && this.modules[this.currentModuleIx];
- if (curModule && curModule.terminate) {
- curModule.terminate(direction);
- }
- // Remove existing focus border if any
- if (this.chart.focusElement) {
- this.chart.focusElement.removeFocusBorder();
- }
- this.currentModuleIx += direction;
- var newModule = this.modules && this.modules[this.currentModuleIx];
- if (newModule) {
- if (newModule.validate && !newModule.validate()) {
- return this.move(direction); // Invalid module, recurse
- }
- if (newModule.init) {
- newModule.init(direction); // Valid module, init it
- return true;
- }
- }
- // No module
- this.currentModuleIx = 0; // Reset counter
- // Set focus to chart or exit anchor depending on direction
- if (direction > 0) {
- this.exiting = true;
- this.exitAnchor.focus();
- }
- else {
- this.chart.renderTo.focus();
- }
- return false;
- },
- /**
- * We use an exit anchor to move focus out of chart whenever we want, by
- * setting focus to this div and not preventing the default tab action. We
- * also use this when users come back into the chart by tabbing back, in
- * order to navigate from the end of the chart.
- * @private
- */
- updateExitAnchor: function () {
- var endMarkerId = 'highcharts-end-of-chart-marker-' + this.chart.index, endMarker = getElement(endMarkerId);
- this.removeExitAnchor();
- if (endMarker) {
- this.makeElementAnExitAnchor(endMarker);
- this.exitAnchor = endMarker;
- }
- else {
- this.createExitAnchor();
- }
- },
- /**
- * Chart container should have tabindex if navigation is enabled.
- * @private
- */
- updateContainerTabindex: function () {
- var a11yOptions = this.chart.options.accessibility, keyboardOptions = a11yOptions && a11yOptions.keyboardNavigation, shouldHaveTabindex = !(keyboardOptions && keyboardOptions.enabled === false), container = this.chart.container, curTabindex = container.getAttribute('tabIndex');
- if (shouldHaveTabindex && !curTabindex) {
- container.setAttribute('tabindex', '0');
- }
- else if (!shouldHaveTabindex && curTabindex === '0') {
- container.removeAttribute('tabindex');
- }
- },
- /**
- * @private
- */
- makeElementAnExitAnchor: function (el) {
- el.setAttribute('class', 'highcharts-exit-anchor');
- el.setAttribute('tabindex', '0');
- el.setAttribute('aria-hidden', false);
- // Handle focus
- this.addExitAnchorEventsToEl(el);
- },
- /**
- * Add new exit anchor to the chart.
- *
- * @private
- */
- createExitAnchor: function () {
- var chart = this.chart, exitAnchor = this.exitAnchor = doc.createElement('div');
- // Hide exit anchor
- merge(true, exitAnchor.style, {
- position: 'absolute',
- width: '1px',
- height: '1px',
- zIndex: 0,
- overflow: 'hidden',
- outline: 'none'
- });
- chart.renderTo.appendChild(exitAnchor);
- this.makeElementAnExitAnchor(exitAnchor);
- },
- /**
- * @private
- */
- removeExitAnchor: function () {
- if (this.exitAnchor && this.exitAnchor.parentNode) {
- this.exitAnchor.parentNode
- .removeChild(this.exitAnchor);
- delete this.exitAnchor;
- }
- },
- /**
- * @private
- */
- addExitAnchorEventsToEl: function (element) {
- var chart = this.chart, keyboardNavigation = this;
- this.eventProvider.addEvent(element, 'focus', function (ev) {
- var e = ev || win.event, curModule, focusComesFromChart = (e.relatedTarget &&
- chart.container.contains(e.relatedTarget)), comingInBackwards = !(focusComesFromChart || keyboardNavigation.exiting);
- if (comingInBackwards) {
- chart.renderTo.focus();
- e.preventDefault();
- // Move to last valid keyboard nav module
- // Note the we don't run it, just set the index
- if (keyboardNavigation.modules &&
- keyboardNavigation.modules.length) {
- keyboardNavigation.currentModuleIx =
- keyboardNavigation.modules.length - 1;
- curModule = keyboardNavigation.modules[keyboardNavigation.currentModuleIx];
- // Validate the module
- if (curModule &&
- curModule.validate && !curModule.validate()) {
- // Invalid. Try moving backwards to find next valid.
- keyboardNavigation.prev();
- }
- else if (curModule) {
- // We have a valid module, init it
- curModule.init(-1);
- }
- }
- }
- else {
- // Don't skip the next focus, we only skip once.
- keyboardNavigation.exiting = false;
- }
- });
- },
- /**
- * Remove all traces of keyboard navigation.
- * @private
- */
- destroy: function () {
- this.removeExitAnchor();
- this.eventProvider.removeAddedEvents();
- if (this.chart.container.getAttribute('tabindex') === '0') {
- this.chart.container.removeAttribute('tabindex');
- }
- }
- };
- return KeyboardNavigation;
- });
- _registerModule(_modules, 'modules/accessibility/components/LegendComponent.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js'], _modules['modules/accessibility/AccessibilityComponent.js'], _modules['modules/accessibility/KeyboardNavigationHandler.js'], _modules['modules/accessibility/utils/htmlUtilities.js']], function (H, U, AccessibilityComponent, KeyboardNavigationHandler, HTMLUtilities) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Accessibility component for chart legend.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var extend = U.extend;
- var stripHTMLTags = HTMLUtilities.stripHTMLTagsFromString, removeElement = HTMLUtilities.removeElement;
- /* eslint-disable no-invalid-this, valid-jsdoc */
- /**
- * @private
- */
- function scrollLegendToItem(legend, itemIx) {
- var itemPage = legend.allItems[itemIx].pageIx, curPage = legend.currentPage;
- if (typeof itemPage !== 'undefined' && itemPage + 1 !== curPage) {
- legend.scroll(1 + itemPage - curPage);
- }
- }
- /**
- * @private
- */
- function shouldDoLegendA11y(chart) {
- var items = chart.legend && chart.legend.allItems, legendA11yOptions = (chart.options.legend.accessibility || {});
- return !!(items && items.length &&
- !(chart.colorAxis && chart.colorAxis.length) &&
- legendA11yOptions.enabled !== false);
- }
- /**
- * Highlight legend item by index.
- *
- * @private
- * @function Highcharts.Chart#highlightLegendItem
- *
- * @param {number} ix
- *
- * @return {boolean}
- */
- H.Chart.prototype.highlightLegendItem = function (ix) {
- var items = this.legend.allItems, oldIx = this.highlightedLegendItemIx;
- if (items[ix]) {
- if (items[oldIx]) {
- H.fireEvent(items[oldIx].legendGroup.element, 'mouseout');
- }
- scrollLegendToItem(this.legend, ix);
- this.setFocusToElement(items[ix].legendItem, items[ix].a11yProxyElement);
- H.fireEvent(items[ix].legendGroup.element, 'mouseover');
- return true;
- }
- return false;
- };
- // Keep track of pressed state for legend items
- H.addEvent(H.Legend, 'afterColorizeItem', function (e) {
- var chart = this.chart, a11yOptions = chart.options.accessibility, legendItem = e.item;
- if (a11yOptions.enabled && legendItem && legendItem.a11yProxyElement) {
- legendItem.a11yProxyElement.setAttribute('aria-pressed', e.visible ? 'false' : 'true');
- }
- });
- /**
- * The LegendComponent class
- *
- * @private
- * @class
- * @name Highcharts.LegendComponent
- */
- var LegendComponent = function () { };
- LegendComponent.prototype = new AccessibilityComponent();
- extend(LegendComponent.prototype, /** @lends Highcharts.LegendComponent */ {
- /**
- * Init the component
- * @private
- */
- init: function () {
- var component = this;
- this.addEvent(H.Legend, 'afterScroll', function () {
- if (this.chart === component.chart) {
- component.updateProxies();
- }
- });
- },
- /**
- * @private
- */
- updateLegendItemProxyVisibility: function () {
- var legend = this.chart.legend, items = legend.allItems || [], curPage = legend.currentPage || 1;
- items.forEach(function (item) {
- var itemPage = item.pageIx || 0, hide = itemPage !== curPage - 1;
- if (item.a11yProxyElement) {
- item.a11yProxyElement.style.visibility = hide ?
- 'hidden' : 'visible';
- }
- });
- },
- /**
- * The legend needs updates on every render, in order to update positioning
- * of the proxy overlays.
- */
- onChartRender: function () {
- var component = this;
- // Ignore render after proxy clicked. No need to destroy it, and
- // destroying also kills focus.
- if (this.legendProxyButtonClicked) {
- delete component.legendProxyButtonClicked;
- return;
- }
- this.updateProxies();
- },
- /**
- * @private
- */
- updateProxies: function () {
- removeElement(this.legendProxyGroup);
- if (shouldDoLegendA11y(this.chart)) {
- this.addLegendProxyGroup();
- this.proxyLegendItems();
- this.updateLegendItemProxyVisibility();
- }
- },
- /**
- * @private
- */
- addLegendProxyGroup: function () {
- var a11yOptions = this.chart.options.accessibility, groupLabel = this.chart.langFormat('accessibility.legend.legendLabel', {}), groupRole = a11yOptions.landmarkVerbosity === 'all' ?
- 'region' : null;
- this.legendProxyGroup = this.addProxyGroup({
- 'aria-label': groupLabel,
- 'role': groupRole
- });
- },
- /**
- * @private
- */
- proxyLegendItems: function () {
- var component = this, items = (this.chart.legend &&
- this.chart.legend.allItems || []);
- items.forEach(function (item) {
- if (item.legendItem && item.legendItem.element) {
- component.proxyLegendItem(item);
- }
- });
- },
- /**
- * @private
- * @param {Highcharts.BubbleLegend|Highcharts.Point|Highcharts.Series} item
- */
- proxyLegendItem: function (item) {
- var component = this, itemLabel = this.chart.langFormat('accessibility.legend.legendItem', {
- chart: this.chart,
- itemName: stripHTMLTags(item.name)
- }), attribs = {
- tabindex: -1,
- 'aria-pressed': !item.visible,
- 'aria-label': itemLabel
- },
- // Keep track of when we should ignore next render
- preClickEvent = function () {
- component.legendProxyButtonClicked = true;
- },
- // Considers useHTML
- proxyPositioningElement = item.legendGroup.div ?
- item.legendItem : item.legendGroup;
- item.a11yProxyElement = this.createProxyButton(item.legendItem, this.legendProxyGroup, attribs, proxyPositioningElement, preClickEvent);
- },
- /**
- * Get keyboard navigation handler for this component.
- * @return {Highcharts.KeyboardNavigationHandler}
- */
- getKeyboardNavigation: function () {
- var keys = this.keyCodes, component = this, chart = this.chart;
- return new KeyboardNavigationHandler(chart, {
- keyCodeMap: [
- [
- [keys.left, keys.right, keys.up, keys.down],
- function (keyCode) {
- return component.onKbdArrowKey(this, keyCode);
- }
- ],
- [
- [keys.enter, keys.space],
- function () {
- return component.onKbdClick(this);
- }
- ]
- ],
- validate: function () {
- return component.shouldHaveLegendNavigation();
- },
- init: function (direction) {
- return component.onKbdNavigationInit(direction);
- }
- });
- },
- /**
- * @private
- * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler
- * @param {number} keyCode
- * @return {number}
- * Response code
- */
- onKbdArrowKey: function (keyboardNavigationHandler, keyCode) {
- var keys = this.keyCodes, response = keyboardNavigationHandler.response, chart = this.chart, a11yOptions = chart.options.accessibility, numItems = chart.legend.allItems.length, direction = (keyCode === keys.left || keyCode === keys.up) ? -1 : 1;
- var res = chart.highlightLegendItem(this.highlightedLegendItemIx + direction);
- if (res) {
- this.highlightedLegendItemIx += direction;
- return response.success;
- }
- if (numItems > 1 &&
- a11yOptions.keyboardNavigation.wrapAround) {
- keyboardNavigationHandler.init(direction);
- return response.success;
- }
- // No wrap, move
- return response[direction > 0 ? 'next' : 'prev'];
- },
- /**
- * @private
- * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler
- * @return {number}
- * Response code
- */
- onKbdClick: function (keyboardNavigationHandler) {
- var legendItem = this.chart.legend.allItems[this.highlightedLegendItemIx];
- if (legendItem && legendItem.a11yProxyElement) {
- H.fireEvent(legendItem.a11yProxyElement, 'click');
- }
- return keyboardNavigationHandler.response.success;
- },
- /**
- * @private
- * @return {boolean|undefined}
- */
- shouldHaveLegendNavigation: function () {
- var chart = this.chart, legendOptions = chart.options.legend || {}, hasLegend = chart.legend && chart.legend.allItems, hasColorAxis = chart.colorAxis && chart.colorAxis.length, legendA11yOptions = (legendOptions.accessibility || {});
- return !!(hasLegend &&
- chart.legend.display &&
- !hasColorAxis &&
- legendA11yOptions.enabled &&
- legendA11yOptions.keyboardNavigation &&
- legendA11yOptions.keyboardNavigation.enabled);
- },
- /**
- * @private
- * @param {number} direction
- */
- onKbdNavigationInit: function (direction) {
- var chart = this.chart, lastIx = chart.legend.allItems.length - 1, ixToHighlight = direction > 0 ? 0 : lastIx;
- chart.highlightLegendItem(ixToHighlight);
- this.highlightedLegendItemIx = ixToHighlight;
- }
- });
- return LegendComponent;
- });
- _registerModule(_modules, 'modules/accessibility/components/MenuComponent.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js'], _modules['modules/accessibility/AccessibilityComponent.js'], _modules['modules/accessibility/KeyboardNavigationHandler.js'], _modules['modules/accessibility/utils/chartUtilities.js'], _modules['modules/accessibility/utils/htmlUtilities.js']], function (H, U, AccessibilityComponent, KeyboardNavigationHandler, ChartUtilities, HTMLUtilities) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Accessibility component for exporting menu.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var extend = U.extend;
- var unhideChartElementFromAT = ChartUtilities.unhideChartElementFromAT;
- var removeElement = HTMLUtilities.removeElement, getFakeMouseEvent = HTMLUtilities.getFakeMouseEvent;
- /* eslint-disable no-invalid-this, valid-jsdoc */
- /**
- * Show the export menu and focus the first item (if exists).
- *
- * @private
- * @function Highcharts.Chart#showExportMenu
- */
- H.Chart.prototype.showExportMenu = function () {
- if (this.exportSVGElements && this.exportSVGElements[0]) {
- var el = this.exportSVGElements[0].element;
- if (el.onclick) {
- el.onclick(getFakeMouseEvent('click'));
- }
- }
- };
- /**
- * @private
- * @function Highcharts.Chart#hideExportMenu
- */
- H.Chart.prototype.hideExportMenu = function () {
- var chart = this, exportList = chart.exportDivElements;
- if (exportList && chart.exportContextMenu) {
- // Reset hover states etc.
- exportList.forEach(function (el) {
- if (el.className === 'highcharts-menu-item' && el.onmouseout) {
- el.onmouseout(getFakeMouseEvent('mouseout'));
- }
- });
- chart.highlightedExportItemIx = 0;
- // Hide the menu div
- chart.exportContextMenu.hideMenu();
- // Make sure the chart has focus and can capture keyboard events
- chart.container.focus();
- }
- };
- /**
- * Highlight export menu item by index.
- *
- * @private
- * @function Highcharts.Chart#highlightExportItem
- *
- * @param {number} ix
- *
- * @return {boolean}
- */
- H.Chart.prototype.highlightExportItem = function (ix) {
- var listItem = this.exportDivElements && this.exportDivElements[ix], curHighlighted = this.exportDivElements &&
- this.exportDivElements[this.highlightedExportItemIx], hasSVGFocusSupport;
- if (listItem &&
- listItem.tagName === 'LI' &&
- !(listItem.children && listItem.children.length)) {
- // Test if we have focus support for SVG elements
- hasSVGFocusSupport = !!(this.renderTo.getElementsByTagName('g')[0] || {}).focus;
- // Only focus if we can set focus back to the elements after
- // destroying the menu (#7422)
- if (listItem.focus && hasSVGFocusSupport) {
- listItem.focus();
- }
- if (curHighlighted && curHighlighted.onmouseout) {
- curHighlighted.onmouseout(getFakeMouseEvent('mouseout'));
- }
- if (listItem.onmouseover) {
- listItem.onmouseover(getFakeMouseEvent('mouseover'));
- }
- this.highlightedExportItemIx = ix;
- return true;
- }
- return false;
- };
- /**
- * Try to highlight the last valid export menu item.
- *
- * @private
- * @function Highcharts.Chart#highlightLastExportItem
- * @return {boolean}
- */
- H.Chart.prototype.highlightLastExportItem = function () {
- var chart = this, i;
- if (chart.exportDivElements) {
- i = chart.exportDivElements.length;
- while (i--) {
- if (chart.highlightExportItem(i)) {
- return true;
- }
- }
- }
- return false;
- };
- /**
- * @private
- * @param {Highcharts.Chart} chart
- */
- function exportingShouldHaveA11y(chart) {
- var exportingOpts = chart.options.exporting;
- return !!(exportingOpts &&
- exportingOpts.enabled !== false &&
- exportingOpts.accessibility &&
- exportingOpts.accessibility.enabled &&
- chart.exportSVGElements &&
- chart.exportSVGElements[0] &&
- chart.exportSVGElements[0].element);
- }
- /**
- * The MenuComponent class
- *
- * @private
- * @class
- * @name Highcharts.MenuComponent
- */
- var MenuComponent = function () { };
- MenuComponent.prototype = new AccessibilityComponent();
- extend(MenuComponent.prototype, /** @lends Highcharts.MenuComponent */ {
- /**
- * Init the component
- */
- init: function () {
- var chart = this.chart, component = this;
- this.addEvent(chart, 'exportMenuShown', function () {
- component.onMenuShown();
- });
- this.addEvent(chart, 'exportMenuHidden', function () {
- component.onMenuHidden();
- });
- },
- /**
- * @private
- */
- onMenuHidden: function () {
- var menu = this.chart.exportContextMenu;
- if (menu) {
- menu.setAttribute('aria-hidden', 'true');
- }
- this.setExportButtonExpandedState('false');
- },
- /**
- * @private
- */
- onMenuShown: function () {
- var chart = this.chart, menu = chart.exportContextMenu;
- if (menu) {
- this.addAccessibleContextMenuAttribs();
- unhideChartElementFromAT(chart, menu);
- }
- this.setExportButtonExpandedState('true');
- },
- /**
- * @private
- * @param {string} stateStr
- */
- setExportButtonExpandedState: function (stateStr) {
- var button = this.exportButtonProxy;
- if (button) {
- button.setAttribute('aria-expanded', stateStr);
- }
- },
- /**
- * Called on each render of the chart. We need to update positioning of the
- * proxy overlay.
- */
- onChartRender: function () {
- var chart = this.chart, a11yOptions = chart.options.accessibility;
- // Always start with a clean slate
- removeElement(this.exportProxyGroup);
- // Set screen reader properties on export menu
- if (exportingShouldHaveA11y(chart)) {
- // Proxy button and group
- this.exportProxyGroup = this.addProxyGroup(
- // Wrap in a region div if verbosity is high
- a11yOptions.landmarkVerbosity === 'all' ? {
- 'aria-label': chart.langFormat('accessibility.exporting.exportRegionLabel', { chart: chart }),
- 'role': 'region'
- } : {});
- var button = (this.chart.exportSVGElements[0]);
- this.exportButtonProxy = this.createProxyButton(button, this.exportProxyGroup, {
- 'aria-label': chart.langFormat('accessibility.exporting.menuButtonLabel', { chart: chart }),
- 'aria-expanded': 'false'
- });
- }
- },
- /**
- * @private
- */
- addAccessibleContextMenuAttribs: function () {
- var chart = this.chart, exportList = chart.exportDivElements;
- if (exportList && exportList.length) {
- // Set tabindex on the menu items to allow focusing by script
- // Set role to give screen readers a chance to pick up the contents
- exportList.forEach(function (item) {
- if (item.tagName === 'LI' &&
- !(item.children && item.children.length)) {
- item.setAttribute('tabindex', -1);
- }
- else {
- item.setAttribute('aria-hidden', 'true');
- }
- });
- // Set accessibility properties on parent div
- var parentDiv = exportList[0].parentNode;
- parentDiv.removeAttribute('aria-hidden');
- parentDiv.setAttribute('aria-label', chart.langFormat('accessibility.exporting.chartMenuLabel', { chart: chart }));
- }
- },
- /**
- * Get keyboard navigation handler for this component.
- * @return {Highcharts.KeyboardNavigationHandler}
- */
- getKeyboardNavigation: function () {
- var keys = this.keyCodes, chart = this.chart, component = this;
- return new KeyboardNavigationHandler(chart, {
- keyCodeMap: [
- // Arrow prev handler
- [
- [keys.left, keys.up],
- function () {
- return component.onKbdPrevious(this);
- }
- ],
- // Arrow next handler
- [
- [keys.right, keys.down],
- function () {
- return component.onKbdNext(this);
- }
- ],
- // Click handler
- [
- [keys.enter, keys.space],
- function () {
- return component.onKbdClick(this);
- }
- ],
- // ESC handler
- [
- [keys.esc],
- function () {
- return this.response.prev;
- }
- ]
- ],
- // Only run exporting navigation if exporting support exists and is
- // enabled on chart
- validate: function () {
- return chart.exportChart &&
- chart.options.exporting.enabled !== false &&
- chart.options.exporting.accessibility.enabled !==
- false;
- },
- // Show export menu
- init: function (direction) {
- chart.showExportMenu();
- if (direction < 0) {
- chart.highlightLastExportItem();
- }
- else {
- chart.highlightExportItem(0);
- }
- },
- // Hide the menu
- terminate: function () {
- chart.hideExportMenu();
- }
- });
- },
- /**
- * @private
- * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler
- * @return {number}
- * Response code
- */
- onKbdPrevious: function (keyboardNavigationHandler) {
- var chart = this.chart, a11yOptions = chart.options.accessibility, response = keyboardNavigationHandler.response, i = chart.highlightedExportItemIx || 0;
- // Try to highlight prev item in list. Highlighting e.g.
- // separators will fail.
- while (i--) {
- if (chart.highlightExportItem(i)) {
- return response.success;
- }
- }
- // We failed, so wrap around or move to prev module
- if (a11yOptions.keyboardNavigation.wrapAround) {
- chart.highlightLastExportItem();
- return response.success;
- }
- return response.prev;
- },
- /**
- * @private
- * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler
- * @return {number}
- * Response code
- */
- onKbdNext: function (keyboardNavigationHandler) {
- var chart = this.chart, a11yOptions = chart.options.accessibility, response = keyboardNavigationHandler.response, i = (chart.highlightedExportItemIx || 0) + 1;
- // Try to highlight next item in list. Highlighting e.g.
- // separators will fail.
- for (; i < chart.exportDivElements.length; ++i) {
- if (chart.highlightExportItem(i)) {
- return response.success;
- }
- }
- // We failed, so wrap around or move to next module
- if (a11yOptions.keyboardNavigation.wrapAround) {
- chart.highlightExportItem(0);
- return response.success;
- }
- return response.next;
- },
- /**
- * @private
- * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler
- * @return {number}
- * Response code
- */
- onKbdClick: function (keyboardNavigationHandler) {
- var chart = this.chart;
- this.fakeClickEvent(chart.exportDivElements[chart.highlightedExportItemIx]);
- return keyboardNavigationHandler.response.success;
- }
- });
- return MenuComponent;
- });
- _registerModule(_modules, 'modules/accessibility/components/SeriesComponent/SeriesKeyboardNavigation.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js'], _modules['modules/accessibility/KeyboardNavigationHandler.js'], _modules['modules/accessibility/utils/EventProvider.js'], _modules['modules/accessibility/utils/chartUtilities.js']], function (H, U, KeyboardNavigationHandler, EventProvider, ChartUtilities) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Handle keyboard navigation for series.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var extend = U.extend, defined = U.defined;
- var getPointFromXY = ChartUtilities.getPointFromXY, getSeriesFromName = ChartUtilities.getSeriesFromName;
- /* eslint-disable no-invalid-this, valid-jsdoc */
- /*
- * Set for which series types it makes sense to move to the closest point with
- * up/down arrows, and which series types should just move to next series.
- */
- H.Series.prototype.keyboardMoveVertical = true;
- ['column', 'pie'].forEach(function (type) {
- if (H.seriesTypes[type]) {
- H.seriesTypes[type].prototype.keyboardMoveVertical = false;
- }
- });
- /**
- * Get the index of a point in a series. This is needed when using e.g. data
- * grouping.
- *
- * @private
- * @function getPointIndex
- *
- * @param {Highcharts.AccessibilityPoint} point
- * The point to find index of.
- *
- * @return {number|undefined}
- * The index in the series.points array of the point.
- */
- function getPointIndex(point) {
- var index = point.index, points = point.series.points, i = points.length;
- if (points[index] !== point) {
- while (i--) {
- if (points[i] === point) {
- return i;
- }
- }
- }
- else {
- return index;
- }
- }
- /**
- * Determine if series navigation should be skipped
- *
- * @private
- * @function isSkipSeries
- *
- * @param {Highcharts.Series} series
- *
- * @return {boolean|number|undefined}
- */
- function isSkipSeries(series) {
- var a11yOptions = series.chart.options.accessibility, seriesNavOptions = a11yOptions.keyboardNavigation.seriesNavigation, seriesA11yOptions = series.options.accessibility || {}, seriesKbdNavOptions = seriesA11yOptions.keyboardNavigation;
- return seriesKbdNavOptions && seriesKbdNavOptions.enabled === false ||
- seriesA11yOptions.enabled === false ||
- series.options.enableMouseTracking === false || // #8440
- !series.visible ||
- // Skip all points in a series where pointNavigationEnabledThreshold is
- // reached
- (seriesNavOptions.pointNavigationEnabledThreshold &&
- seriesNavOptions.pointNavigationEnabledThreshold <=
- series.points.length);
- }
- /**
- * Determine if navigation for a point should be skipped
- *
- * @private
- * @function isSkipPoint
- *
- * @param {Highcharts.Point} point
- *
- * @return {boolean|number|undefined}
- */
- function isSkipPoint(point) {
- var a11yOptions = point.series.chart.options.accessibility;
- return point.isNull &&
- a11yOptions.keyboardNavigation.seriesNavigation.skipNullPoints ||
- point.visible === false ||
- isSkipSeries(point.series);
- }
- /**
- * Get the point in a series that is closest (in pixel distance) to a reference
- * point. Optionally supply weight factors for x and y directions.
- *
- * @private
- * @function getClosestPoint
- *
- * @param {Highcharts.Point} point
- * @param {Highcharts.Series} series
- * @param {number} [xWeight]
- * @param {number} [yWeight]
- *
- * @return {Highcharts.Point|undefined}
- */
- function getClosestPoint(point, series, xWeight, yWeight) {
- var minDistance = Infinity, dPoint, minIx, distance, i = series.points.length, hasUndefinedPosition = function (point) {
- return !(defined(point.plotX) && defined(point.plotY));
- };
- if (hasUndefinedPosition(point)) {
- return;
- }
- while (i--) {
- dPoint = series.points[i];
- if (hasUndefinedPosition(dPoint)) {
- continue;
- }
- distance = (point.plotX - dPoint.plotX) *
- (point.plotX - dPoint.plotX) *
- (xWeight || 1) +
- (point.plotY - dPoint.plotY) *
- (point.plotY - dPoint.plotY) *
- (yWeight || 1);
- if (distance < minDistance) {
- minDistance = distance;
- minIx = i;
- }
- }
- return defined(minIx) ? series.points[minIx] : void 0;
- }
- /**
- * Highlights a point (show tooltip and display hover state).
- *
- * @private
- * @function Highcharts.Point#highlight
- *
- * @return {Highcharts.Point}
- * This highlighted point.
- */
- H.Point.prototype.highlight = function () {
- var chart = this.series.chart;
- if (!this.isNull) {
- this.onMouseOver(); // Show the hover marker and tooltip
- }
- else {
- if (chart.tooltip) {
- chart.tooltip.hide(0);
- }
- // Don't call blur on the element, as it messes up the chart div's focus
- }
- // We focus only after calling onMouseOver because the state change can
- // change z-index and mess up the element.
- if (this.graphic) {
- chart.setFocusToElement(this.graphic);
- }
- chart.highlightedPoint = this;
- return this;
- };
- /**
- * Function to highlight next/previous point in chart.
- *
- * @private
- * @function Highcharts.Chart#highlightAdjacentPoint
- *
- * @param {boolean} next
- * Flag for the direction.
- *
- * @return {Highcharts.Point|boolean}
- * Returns highlighted point on success, false on failure (no adjacent
- * point to highlight in chosen direction).
- */
- H.Chart.prototype.highlightAdjacentPoint = function (next) {
- var chart = this, series = chart.series, curPoint = chart.highlightedPoint, curPointIndex = curPoint && getPointIndex(curPoint) || 0, curPoints = (curPoint && curPoint.series.points), lastSeries = chart.series && chart.series[chart.series.length - 1], lastPoint = lastSeries && lastSeries.points &&
- lastSeries.points[lastSeries.points.length - 1], newSeries, newPoint;
- // If no points, return false
- if (!series[0] || !series[0].points) {
- return false;
- }
- if (!curPoint) {
- // No point is highlighted yet. Try first/last point depending on move
- // direction
- newPoint = next ? series[0].points[0] : lastPoint;
- }
- else {
- // We have a highlighted point.
- // Grab next/prev point & series
- newSeries = series[curPoint.series.index + (next ? 1 : -1)];
- newPoint = curPoints[curPointIndex + (next ? 1 : -1)];
- if (!newPoint && newSeries) {
- // Done with this series, try next one
- newPoint = newSeries.points[next ? 0 : newSeries.points.length - 1];
- }
- // If there is no adjacent point, we return false
- if (!newPoint) {
- return false;
- }
- }
- // Recursively skip points
- if (isSkipPoint(newPoint)) {
- // If we skip this whole series, move to the end of the series before we
- // recurse, just to optimize
- newSeries = newPoint.series;
- if (isSkipSeries(newSeries)) {
- chart.highlightedPoint = next ?
- newSeries.points[newSeries.points.length - 1] :
- newSeries.points[0];
- }
- else {
- // Otherwise, just move one point
- chart.highlightedPoint = newPoint;
- }
- // Retry
- return chart.highlightAdjacentPoint(next);
- }
- // There is an adjacent point, highlight it
- return newPoint.highlight();
- };
- /**
- * Highlight first valid point in a series. Returns the point if successfully
- * highlighted, otherwise false. If there is a highlighted point in the series,
- * use that as starting point.
- *
- * @private
- * @function Highcharts.Series#highlightFirstValidPoint
- *
- * @return {boolean|Highcharts.Point}
- */
- H.Series.prototype.highlightFirstValidPoint = function () {
- var curPoint = this.chart.highlightedPoint, start = (curPoint && curPoint.series) === this ?
- getPointIndex(curPoint) :
- 0, points = this.points, len = points.length;
- if (points && len) {
- for (var i = start; i < len; ++i) {
- if (!isSkipPoint(points[i])) {
- return points[i].highlight();
- }
- }
- for (var j = start; j >= 0; --j) {
- if (!isSkipPoint(points[j])) {
- return points[j].highlight();
- }
- }
- }
- return false;
- };
- /**
- * Highlight next/previous series in chart. Returns false if no adjacent series
- * in the direction, otherwise returns new highlighted point.
- *
- * @private
- * @function Highcharts.Chart#highlightAdjacentSeries
- *
- * @param {boolean} down
- *
- * @return {Highcharts.Point|boolean}
- */
- H.Chart.prototype.highlightAdjacentSeries = function (down) {
- var chart = this, newSeries, newPoint, adjacentNewPoint, curPoint = chart.highlightedPoint, lastSeries = chart.series && chart.series[chart.series.length - 1], lastPoint = lastSeries && lastSeries.points &&
- lastSeries.points[lastSeries.points.length - 1];
- // If no point is highlighted, highlight the first/last point
- if (!chart.highlightedPoint) {
- newSeries = down ? (chart.series && chart.series[0]) : lastSeries;
- newPoint = down ?
- (newSeries && newSeries.points && newSeries.points[0]) : lastPoint;
- return newPoint ? newPoint.highlight() : false;
- }
- newSeries = chart.series[curPoint.series.index + (down ? -1 : 1)];
- if (!newSeries) {
- return false;
- }
- // We have a new series in this direction, find the right point
- // Weigh xDistance as counting much higher than Y distance
- newPoint = getClosestPoint(curPoint, newSeries, 4);
- if (!newPoint) {
- return false;
- }
- // New series and point exists, but we might want to skip it
- if (isSkipSeries(newSeries)) {
- // Skip the series
- newPoint.highlight();
- adjacentNewPoint = chart.highlightAdjacentSeries(down); // Try recurse
- if (!adjacentNewPoint) {
- // Recurse failed
- curPoint.highlight();
- return false;
- }
- // Recurse succeeded
- return adjacentNewPoint;
- }
- // Highlight the new point or any first valid point back or forwards from it
- newPoint.highlight();
- return newPoint.series.highlightFirstValidPoint();
- };
- /**
- * Highlight the closest point vertically.
- *
- * @private
- * @function Highcharts.Chart#highlightAdjacentPointVertical
- *
- * @param {boolean} down
- *
- * @return {Highcharts.Point|boolean}
- */
- H.Chart.prototype.highlightAdjacentPointVertical = function (down) {
- var curPoint = this.highlightedPoint, minDistance = Infinity, bestPoint;
- if (!defined(curPoint.plotX) || !defined(curPoint.plotY)) {
- return false;
- }
- this.series.forEach(function (series) {
- if (isSkipSeries(series)) {
- return;
- }
- series.points.forEach(function (point) {
- if (!defined(point.plotY) || !defined(point.plotX) ||
- point === curPoint) {
- return;
- }
- var yDistance = point.plotY - curPoint.plotY, width = Math.abs(point.plotX - curPoint.plotX), distance = Math.abs(yDistance) * Math.abs(yDistance) +
- width * width * 4; // Weigh horizontal distance highly
- // Reverse distance number if axis is reversed
- if (series.yAxis.reversed) {
- yDistance *= -1;
- }
- if (yDistance <= 0 && down || yDistance >= 0 && !down || // Chk dir
- distance < 5 || // Points in same spot => infinite loop
- isSkipPoint(point)) {
- return;
- }
- if (distance < minDistance) {
- minDistance = distance;
- bestPoint = point;
- }
- });
- });
- return bestPoint ? bestPoint.highlight() : false;
- };
- /**
- * @private
- * @param {Highcharts.Chart} chart
- * @return {Highcharts.Point|boolean}
- */
- function highlightFirstValidPointInChart(chart) {
- var res = false;
- delete chart.highlightedPoint;
- res = chart.series.reduce(function (acc, cur) {
- return acc || cur.highlightFirstValidPoint();
- }, false);
- return res;
- }
- /**
- * @private
- * @param {Highcharts.Chart} chart
- * @return {Highcharts.Point|boolean}
- */
- function highlightLastValidPointInChart(chart) {
- var numSeries = chart.series.length, i = numSeries, res = false;
- while (i--) {
- chart.highlightedPoint = chart.series[i].points[chart.series[i].points.length - 1];
- // Highlight first valid point in the series will also
- // look backwards. It always starts from currently
- // highlighted point.
- res = chart.series[i].highlightFirstValidPoint();
- if (res) {
- break;
- }
- }
- return res;
- }
- /**
- * @private
- * @param {Highcharts.Chart} chart
- */
- function updateChartFocusAfterDrilling(chart) {
- highlightFirstValidPointInChart(chart);
- if (chart.focusElement) {
- chart.focusElement.removeFocusBorder();
- }
- }
- /**
- * @private
- * @class
- * @name Highcharts.SeriesKeyboardNavigation
- */
- function SeriesKeyboardNavigation(chart, keyCodes) {
- this.keyCodes = keyCodes;
- this.chart = chart;
- }
- extend(SeriesKeyboardNavigation.prototype, /** @lends Highcharts.SeriesKeyboardNavigation */ {
- /**
- * Init the keyboard navigation
- */
- init: function () {
- var keyboardNavigation = this, chart = this.chart, e = this.eventProvider = new EventProvider();
- e.addEvent(H.Series, 'destroy', function () {
- return keyboardNavigation.onSeriesDestroy(this);
- });
- e.addEvent(chart, 'afterDrilldown', function () {
- updateChartFocusAfterDrilling(this);
- });
- e.addEvent(chart, 'drilldown', function (e) {
- var point = e.point, series = point.series;
- keyboardNavigation.lastDrilledDownPoint = {
- x: point.x,
- y: point.y,
- seriesName: series ? series.name : ''
- };
- });
- e.addEvent(chart, 'drillupall', function () {
- setTimeout(function () {
- keyboardNavigation.onDrillupAll();
- }, 10);
- });
- },
- onDrillupAll: function () {
- // After drillup we want to find the point that was drilled down to and
- // highlight it.
- var last = this.lastDrilledDownPoint, chart = this.chart, series = last && getSeriesFromName(chart, last.seriesName), point;
- if (last && series && defined(last.x) && defined(last.y)) {
- point = getPointFromXY(series, last.x, last.y);
- }
- // Container focus can be lost on drillup due to deleted elements.
- if (chart.container) {
- chart.container.focus();
- }
- if (point && point.highlight) {
- point.highlight();
- }
- if (chart.focusElement) {
- chart.focusElement.removeFocusBorder();
- }
- },
- /**
- * @return {Highcharts.KeyboardNavigationHandler}
- */
- getKeyboardNavigationHandler: function () {
- var keyboardNavigation = this, keys = this.keyCodes, chart = this.chart, inverted = chart.inverted;
- return new KeyboardNavigationHandler(chart, {
- keyCodeMap: [
- [inverted ? [keys.up, keys.down] : [keys.left, keys.right],
- function (keyCode) {
- return keyboardNavigation.onKbdSideways(this, keyCode);
- }],
- [inverted ? [keys.left, keys.right] : [keys.up, keys.down],
- function (keyCode) {
- return keyboardNavigation.onKbdVertical(this, keyCode);
- }],
- [[keys.enter, keys.space],
- function () {
- if (chart.highlightedPoint) {
- chart.highlightedPoint.firePointEvent('click');
- }
- return this.response.success;
- }]
- ],
- init: function (dir) {
- return keyboardNavigation.onHandlerInit(this, dir);
- },
- terminate: function () {
- return keyboardNavigation.onHandlerTerminate();
- }
- });
- },
- /**
- * @private
- * @param {Highcharts.KeyboardNavigationHandler} handler
- * @param {number} keyCode
- * @return {number}
- * response
- */
- onKbdSideways: function (handler, keyCode) {
- var keys = this.keyCodes, isNext = keyCode === keys.right || keyCode === keys.down;
- return this.attemptHighlightAdjacentPoint(handler, isNext);
- },
- /**
- * @private
- * @param {Highcharts.KeyboardNavigationHandler} handler
- * @param {number} keyCode
- * @return {number}
- * response
- */
- onKbdVertical: function (handler, keyCode) {
- var chart = this.chart, keys = this.keyCodes, isNext = keyCode === keys.down || keyCode === keys.right, navOptions = chart.options.accessibility.keyboardNavigation
- .seriesNavigation;
- // Handle serialized mode, act like left/right
- if (navOptions.mode && navOptions.mode === 'serialize') {
- return this.attemptHighlightAdjacentPoint(handler, isNext);
- }
- // Normal mode, move between series
- var highlightMethod = (chart.highlightedPoint &&
- chart.highlightedPoint.series.keyboardMoveVertical) ?
- 'highlightAdjacentPointVertical' :
- 'highlightAdjacentSeries';
- chart[highlightMethod](isNext);
- return handler.response.success;
- },
- /**
- * @private
- * @param {Highcharts.KeyboardNavigationHandler} handler
- * @param {number} initDirection
- * @return {number}
- * response
- */
- onHandlerInit: function (handler, initDirection) {
- var chart = this.chart;
- if (initDirection > 0) {
- highlightFirstValidPointInChart(chart);
- }
- else {
- highlightLastValidPointInChart(chart);
- }
- return handler.response.success;
- },
- /**
- * @private
- */
- onHandlerTerminate: function () {
- var chart = this.chart;
- if (chart.tooltip) {
- chart.tooltip.hide(0);
- }
- delete chart.highlightedPoint;
- },
- /**
- * Function that attempts to highlight next/prev point. Handles wrap around.
- * @private
- * @param {Highcharts.KeyboardNavigationHandler} handler
- * @param {boolean} directionIsNext
- * @return {number}
- * response
- */
- attemptHighlightAdjacentPoint: function (handler, directionIsNext) {
- var chart = this.chart, wrapAround = chart.options.accessibility.keyboardNavigation
- .wrapAround, highlightSuccessful = chart.highlightAdjacentPoint(directionIsNext);
- if (!highlightSuccessful) {
- if (wrapAround) {
- return handler.init(directionIsNext ? 1 : -1);
- }
- return handler.response[directionIsNext ? 'next' : 'prev'];
- }
- return handler.response.success;
- },
- /**
- * @private
- */
- onSeriesDestroy: function (series) {
- var chart = this.chart, currentHighlightedPointDestroyed = chart.highlightedPoint &&
- chart.highlightedPoint.series === series;
- if (currentHighlightedPointDestroyed) {
- delete chart.highlightedPoint;
- if (chart.focusElement) {
- chart.focusElement.removeFocusBorder();
- }
- }
- },
- /**
- * @private
- */
- destroy: function () {
- this.eventProvider.removeAddedEvents();
- }
- });
- return SeriesKeyboardNavigation;
- });
- _registerModule(_modules, 'modules/accessibility/components/SeriesComponent/SeriesDescriber.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js'], _modules['modules/accessibility/utils/htmlUtilities.js'], _modules['modules/accessibility/utils/chartUtilities.js']], function (H, U, HTMLUtilities, ChartUtilities) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Place desriptions on a series and its points.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var numberFormat = H.numberFormat, find = H.find;
- var isNumber = U.isNumber, pick = U.pick, defined = U.defined;
- var stripHTMLTags = HTMLUtilities.stripHTMLTagsFromString, reverseChildNodes = HTMLUtilities.reverseChildNodes;
- var getAxisDescription = ChartUtilities.getAxisDescription, getSeriesFirstPointElement = ChartUtilities.getSeriesFirstPointElement, getSeriesA11yElement = ChartUtilities.getSeriesA11yElement, unhideChartElementFromAT = ChartUtilities.unhideChartElementFromAT;
- /* eslint-disable valid-jsdoc */
- /**
- * @private
- */
- function findFirstPointWithGraphic(point) {
- var sourcePointIndex = point.index;
- if (!point.series || !point.series.data || !defined(sourcePointIndex)) {
- return null;
- }
- return find(point.series.data, function (p) {
- return !!(p &&
- typeof p.index !== 'undefined' &&
- p.index > sourcePointIndex &&
- p.graphic &&
- p.graphic.element);
- }) || null;
- }
- /**
- * @private
- */
- function makeDummyElement(point, pos) {
- var renderer = point.series.chart.renderer, dummy = renderer.rect(pos.x, pos.y, 1, 1);
- dummy.attr({
- 'class': 'highcharts-a11y-dummy-point',
- fill: 'none',
- 'fill-opacity': 0,
- 'stroke-opacity': 0,
- opacity: 0
- });
- return dummy;
- }
- /**
- * @private
- * @param {Highcharts.Point} point
- * @return {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement|undefined}
- */
- function addDummyPointElement(point) {
- var series = point.series, firstPointWithGraphic = findFirstPointWithGraphic(point), firstGraphic = firstPointWithGraphic && firstPointWithGraphic.graphic, parentGroup = firstGraphic ?
- firstGraphic.parentGroup :
- series.graph || series.group, dummyPos = firstPointWithGraphic ? {
- x: pick(point.plotX, firstPointWithGraphic.plotX, 0),
- y: pick(point.plotY, firstPointWithGraphic.plotY, 0)
- } : {
- x: pick(point.plotX, 0),
- y: pick(point.plotY, 0)
- }, dummyElement = makeDummyElement(point, dummyPos);
- if (parentGroup && parentGroup.element) {
- point.graphic = dummyElement;
- dummyElement.add(parentGroup);
- // Move to correct pos in DOM
- parentGroup.element.insertBefore(dummyElement.element, firstGraphic ? firstGraphic.element : null);
- return dummyElement.element;
- }
- }
- /**
- * @private
- * @param {Highcharts.Series} series
- * @return {boolean}
- */
- function hasMorePointsThanDescriptionThreshold(series) {
- var chartA11yOptions = series.chart.options.accessibility, threshold = (chartA11yOptions.series.pointDescriptionEnabledThreshold);
- return !!(threshold !== false &&
- series.points &&
- series.points.length >= threshold);
- }
- /**
- * @private
- * @param {Highcharts.Series} series
- * @return {boolean}
- */
- function shouldSetScreenReaderPropsOnPoints(series) {
- var seriesA11yOptions = series.options.accessibility || {};
- return !hasMorePointsThanDescriptionThreshold(series) &&
- !seriesA11yOptions.exposeAsGroupOnly;
- }
- /**
- * @private
- * @param {Highcharts.Series} series
- * @return {boolean}
- */
- function shouldSetKeyboardNavPropsOnPoints(series) {
- var chartA11yOptions = series.chart.options.accessibility, seriesNavOptions = chartA11yOptions.keyboardNavigation.seriesNavigation;
- return !!(series.points && (series.points.length <
- seriesNavOptions.pointNavigationEnabledThreshold ||
- seriesNavOptions.pointNavigationEnabledThreshold === false));
- }
- /**
- * @private
- * @param {Highcharts.Series} series
- * @return {boolean}
- */
- function shouldDescribeSeriesElement(series) {
- var chart = series.chart, chartOptions = chart.options.chart || {}, chartHas3d = chartOptions.options3d && chartOptions.options3d.enabled, hasMultipleSeries = chart.series.length > 1, describeSingleSeriesOption = chart.options.accessibility.series.describeSingleSeries, exposeAsGroupOnlyOption = (series.options.accessibility || {}).exposeAsGroupOnly, noDescribe3D = chartHas3d && hasMultipleSeries;
- return !noDescribe3D && (hasMultipleSeries || describeSingleSeriesOption ||
- exposeAsGroupOnlyOption || hasMorePointsThanDescriptionThreshold(series));
- }
- /**
- * @private
- * @param {Highcharts.Point} point
- * @param {number} value
- * @return {string}
- */
- function pointNumberToString(point, value) {
- var chart = point.series.chart, a11yPointOptions = chart.options.accessibility.point || {}, tooltipOptions = point.series.tooltipOptions || {}, lang = chart.options.lang;
- if (isNumber(value)) {
- return numberFormat(value, a11yPointOptions.valueDecimals ||
- tooltipOptions.valueDecimals ||
- -1, lang.decimalPoint, lang.accessibility.thousandsSep || lang.thousandsSep);
- }
- return value;
- }
- /**
- * @private
- * @param {Highcharts.Series} series
- * @return {string}
- */
- function getSeriesDescriptionText(series) {
- var seriesA11yOptions = series.options.accessibility || {}, descOpt = seriesA11yOptions.description;
- return descOpt && series.chart.langFormat('accessibility.series.description', {
- description: descOpt,
- series: series
- }) || '';
- }
- /**
- * @private
- * @param {Highcharts.series} series
- * @param {string} axisCollection
- * @return {string}
- */
- function getSeriesAxisDescriptionText(series, axisCollection) {
- var axis = series[axisCollection];
- return series.chart.langFormat('accessibility.series.' + axisCollection + 'Description', {
- name: getAxisDescription(axis),
- series: series
- });
- }
- /**
- * Get accessible time description for a point on a datetime axis.
- *
- * @private
- * @function Highcharts.Point#getTimeDescription
- * @param {Highcharts.Point} point
- * @return {string|undefined}
- * The description as string.
- */
- function getPointA11yTimeDescription(point) {
- var series = point.series, chart = series.chart, a11yOptions = chart.options.accessibility.point || {}, hasDateXAxis = series.xAxis && series.xAxis.isDatetimeAxis;
- if (hasDateXAxis) {
- var tooltipDateFormat = H.Tooltip.prototype.getXDateFormat.call({
- getDateFormat: H.Tooltip.prototype.getDateFormat,
- chart: chart
- }, point, chart.options.tooltip, series.xAxis), dateFormat = a11yOptions.dateFormatter &&
- a11yOptions.dateFormatter(point) ||
- a11yOptions.dateFormat ||
- tooltipDateFormat;
- return chart.time.dateFormat(dateFormat, point.x, void 0);
- }
- }
- /**
- * @private
- * @param {Highcharts.Point} point
- * @return {string}
- */
- function getPointXDescription(point) {
- var timeDesc = getPointA11yTimeDescription(point), xAxis = point.series.xAxis || {}, pointCategory = xAxis.categories && defined(point.category) &&
- ('' + point.category).replace('<br/>', ' '), canUseId = point.id && point.id.indexOf('highcharts-') < 0, fallback = 'x, ' + point.x;
- return point.name || timeDesc || pointCategory ||
- (canUseId ? point.id : fallback);
- }
- /**
- * @private
- * @param {Highcharts.Point} point
- * @param {string} prefix
- * @param {string} suffix
- * @return {string}
- */
- function getPointArrayMapValueDescription(point, prefix, suffix) {
- var pre = prefix || '', suf = suffix || '', keyToValStr = function (key) {
- var num = pointNumberToString(point, pick(point[key], point.options[key]));
- return key + ': ' + pre + num + suf;
- }, pointArrayMap = point.series.pointArrayMap;
- return pointArrayMap.reduce(function (desc, key) {
- return desc + (desc.length ? ', ' : '') + keyToValStr(key);
- }, '');
- }
- /**
- * @private
- * @param {Highcharts.Point} point
- * @return {string}
- */
- function getPointValueDescription(point) {
- var series = point.series, a11yPointOpts = series.chart.options.accessibility.point || {}, tooltipOptions = series.tooltipOptions || {}, valuePrefix = a11yPointOpts.valuePrefix ||
- tooltipOptions.valuePrefix || '', valueSuffix = a11yPointOpts.valueSuffix ||
- tooltipOptions.valueSuffix || '', fallbackKey = (typeof point.value !==
- 'undefined' ?
- 'value' : 'y'), fallbackDesc = pointNumberToString(point, point[fallbackKey]);
- if (point.isNull) {
- return series.chart.langFormat('accessibility.series.nullPointValue', {
- point: point
- });
- }
- if (series.pointArrayMap) {
- return getPointArrayMapValueDescription(point, valuePrefix, valueSuffix);
- }
- return valuePrefix + fallbackDesc + valueSuffix;
- }
- /**
- * Return string with information about point.
- * @private
- * @return {string}
- */
- function defaultPointDescriptionFormatter(point) {
- var series = point.series, chart = series.chart, description = point.options && point.options.accessibility &&
- point.options.accessibility.description, showXDescription = pick(series.xAxis &&
- series.xAxis.options.accessibility &&
- series.xAxis.options.accessibility.enabled, !chart.angular), xDesc = getPointXDescription(point), valueDesc = getPointValueDescription(point), indexText = defined(point.index) ? (point.index + 1) + '. ' : '', xDescText = showXDescription ? xDesc + ', ' : '', valText = valueDesc + '.', userDescText = description ? ' ' + description : '', seriesNameText = chart.series.length > 1 && series.name ?
- ' ' + series.name + '.' : '';
- return indexText + xDescText + valText + userDescText + seriesNameText;
- }
- /**
- * Set a11y props on a point element
- * @private
- * @param {Highcharts.Point} point
- * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} pointElement
- */
- function setPointScreenReaderAttribs(point, pointElement) {
- var series = point.series, a11yPointOptions = series.chart.options.accessibility.point || {}, seriesA11yOptions = series.options.accessibility || {}, label = stripHTMLTags(seriesA11yOptions.pointDescriptionFormatter &&
- seriesA11yOptions.pointDescriptionFormatter(point) ||
- a11yPointOptions.descriptionFormatter &&
- a11yPointOptions.descriptionFormatter(point) ||
- defaultPointDescriptionFormatter(point));
- pointElement.setAttribute('role', 'img');
- pointElement.setAttribute('aria-label', label);
- }
- /**
- * Add accessible info to individual point elements of a series
- * @private
- * @param {Highcharts.Series} series
- */
- function describePointsInSeries(series) {
- var setScreenReaderProps = shouldSetScreenReaderPropsOnPoints(series), setKeyboardProps = shouldSetKeyboardNavPropsOnPoints(series);
- if (setScreenReaderProps || setKeyboardProps) {
- series.points.forEach(function (point) {
- var shouldAddDummyPoint = point.isNull, pointEl = point.graphic && point.graphic.element ||
- shouldAddDummyPoint && addDummyPointElement(point);
- if (pointEl) {
- // We always set tabindex, as long as we are setting
- // props.
- pointEl.setAttribute('tabindex', '-1');
- if (setScreenReaderProps) {
- setPointScreenReaderAttribs(point, pointEl);
- }
- else {
- pointEl.setAttribute('aria-hidden', true);
- }
- }
- });
- }
- }
- /**
- * Return string with information about series.
- * @private
- * @return {string}
- */
- function defaultSeriesDescriptionFormatter(series) {
- var chart = series.chart, chartTypes = chart.types || [], description = getSeriesDescriptionText(series), shouldDescribeAxis = function (coll) {
- return chart[coll] && chart[coll].length > 1 && series[coll];
- }, xAxisInfo = getSeriesAxisDescriptionText(series, 'xAxis'), yAxisInfo = getSeriesAxisDescriptionText(series, 'yAxis'), summaryContext = {
- name: series.name || '',
- ix: series.index + 1,
- numSeries: chart.series && chart.series.length,
- numPoints: series.points && series.points.length,
- series: series
- }, combinationSuffix = chartTypes.length > 1 ? 'Combination' : '', summary = chart.langFormat('accessibility.series.summary.' + series.type + combinationSuffix, summaryContext) || chart.langFormat('accessibility.series.summary.default' + combinationSuffix, summaryContext);
- return summary + (description ? ' ' + description : '') + (shouldDescribeAxis('yAxis') ? ' ' + yAxisInfo : '') + (shouldDescribeAxis('xAxis') ? ' ' + xAxisInfo : '');
- }
- /**
- * Set a11y props on a series element
- * @private
- * @param {Highcharts.Series} series
- * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} seriesElement
- */
- function describeSeriesElement(series, seriesElement) {
- var seriesA11yOptions = series.options.accessibility || {}, a11yOptions = series.chart.options.accessibility, landmarkVerbosity = a11yOptions.landmarkVerbosity;
- // Handle role attribute
- if (seriesA11yOptions.exposeAsGroupOnly) {
- seriesElement.setAttribute('role', 'img');
- }
- else if (landmarkVerbosity === 'all') {
- seriesElement.setAttribute('role', 'region');
- } /* else do not add role */
- seriesElement.setAttribute('tabindex', '-1');
- seriesElement.setAttribute('aria-label', stripHTMLTags(a11yOptions.series.descriptionFormatter &&
- a11yOptions.series.descriptionFormatter(series) ||
- defaultSeriesDescriptionFormatter(series)));
- }
- /**
- * Put accessible info on series and points of a series.
- * @param {Highcharts.Series} series The series to add info on.
- */
- function describeSeries(series) {
- var chart = series.chart, firstPointEl = getSeriesFirstPointElement(series), seriesEl = getSeriesA11yElement(series);
- if (seriesEl) {
- // For some series types the order of elements do not match the
- // order of points in series. In that case we have to reverse them
- // in order for AT to read them out in an understandable order
- if (seriesEl.lastChild === firstPointEl) {
- reverseChildNodes(seriesEl);
- }
- describePointsInSeries(series);
- unhideChartElementFromAT(chart, seriesEl);
- if (shouldDescribeSeriesElement(series)) {
- describeSeriesElement(series, seriesEl);
- }
- else {
- seriesEl.setAttribute('aria-label', '');
- }
- }
- }
- var SeriesDescriber = {
- describeSeries: describeSeries,
- defaultPointDescriptionFormatter: defaultPointDescriptionFormatter,
- defaultSeriesDescriptionFormatter: defaultSeriesDescriptionFormatter,
- getPointA11yTimeDescription: getPointA11yTimeDescription,
- getPointXDescription: getPointXDescription,
- getPointValueDescription: getPointValueDescription
- };
- return SeriesDescriber;
- });
- _registerModule(_modules, 'modules/accessibility/components/SeriesComponent/NewDataAnnouncer.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js'], _modules['modules/accessibility/utils/htmlUtilities.js'], _modules['modules/accessibility/utils/chartUtilities.js'], _modules['modules/accessibility/components/SeriesComponent/SeriesDescriber.js'], _modules['modules/accessibility/utils/EventProvider.js'], _modules['modules/accessibility/utils/DOMElementProvider.js']], function (H, U, HTMLUtilities, ChartUtilities, SeriesDescriber, EventProvider, DOMElementProvider) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Handle announcing new data for a chart.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var extend = U.extend, defined = U.defined;
- var visuallyHideElement = HTMLUtilities.visuallyHideElement;
- var getChartTitle = ChartUtilities.getChartTitle;
- var defaultPointDescriptionFormatter = SeriesDescriber
- .defaultPointDescriptionFormatter, defaultSeriesDescriptionFormatter = SeriesDescriber
- .defaultSeriesDescriptionFormatter;
- /* eslint-disable no-invalid-this, valid-jsdoc */
- /**
- * @private
- */
- function chartHasAnnounceEnabled(chart) {
- return !!chart.options.accessibility.announceNewData.enabled;
- }
- /**
- * @private
- */
- function findPointInDataArray(point) {
- var candidates = point.series.data.filter(function (candidate) {
- return point.x === candidate.x && point.y === candidate.y;
- });
- return candidates.length === 1 ? candidates[0] : point;
- }
- /**
- * Get array of unique series from two arrays
- * @private
- */
- function getUniqueSeries(arrayA, arrayB) {
- var uniqueSeries = (arrayA || []).concat(arrayB || [])
- .reduce(function (acc, cur) {
- acc[cur.name + cur.index] = cur;
- return acc;
- }, {});
- return Object.keys(uniqueSeries).map(function (ix) {
- return uniqueSeries[ix];
- });
- }
- /**
- * @private
- * @class
- */
- var NewDataAnnouncer = function (chart) {
- this.chart = chart;
- };
- extend(NewDataAnnouncer.prototype, {
- /**
- * Initialize the new data announcer.
- */
- init: function () {
- this.lastAnnouncementTime = 0;
- this.dirty = {
- allSeries: {}
- };
- this.eventProvider = new EventProvider();
- this.domElementProvider = new DOMElementProvider();
- this.announceRegion = this.addAnnounceRegion();
- this.addEventListeners();
- },
- /**
- * Remove traces of announcer.
- */
- destroy: function () {
- this.eventProvider.removeAddedEvents();
- this.domElementProvider.destroyCreatedElements();
- },
- /**
- * Add the announcement live region to the DOM.
- * @private
- */
- addAnnounceRegion: function () {
- var chart = this.chart, div = this.domElementProvider.createElement('div'), announceOptions = (chart.options.accessibility.announceNewData);
- div.setAttribute('aria-hidden', false);
- div.setAttribute('aria-live', announceOptions.interruptUser ? 'assertive' : 'polite');
- visuallyHideElement(div);
- chart.renderTo.insertBefore(div, chart.renderTo.firstChild);
- return div;
- },
- /**
- * Add event listeners for the announcer
- * @private
- */
- addEventListeners: function () {
- var announcer = this, chart = this.chart, e = this.eventProvider;
- e.addEvent(chart, 'afterDrilldown', function () {
- announcer.lastAnnouncementTime = 0;
- });
- e.addEvent(H.Series, 'updatedData', function () {
- announcer.onSeriesUpdatedData(this);
- });
- e.addEvent(chart, 'afterAddSeries', function (e) {
- announcer.onSeriesAdded(e.series);
- });
- e.addEvent(H.Series, 'addPoint', function (e) {
- announcer.onPointAdded(e.point);
- });
- e.addEvent(chart, 'redraw', function () {
- announcer.announceDirtyData();
- });
- },
- /**
- * On new data in the series, make sure we add it to the dirty list.
- * @private
- * @param {Highcharts.Series} series
- */
- onSeriesUpdatedData: function (series) {
- var chart = this.chart;
- if (series.chart === chart && chartHasAnnounceEnabled(chart)) {
- this.dirty.hasDirty = true;
- this.dirty.allSeries[series.name + series.index] = series;
- }
- },
- /**
- * On new data series added, update dirty list.
- * @private
- * @param {Highcharts.Series} series
- */
- onSeriesAdded: function (series) {
- if (chartHasAnnounceEnabled(this.chart)) {
- this.dirty.hasDirty = true;
- this.dirty.allSeries[series.name + series.index] = series;
- // Add it to newSeries storage unless we already have one
- this.dirty.newSeries = defined(this.dirty.newSeries) ?
- void 0 : series;
- }
- },
- /**
- * On new point added, update dirty list.
- * @private
- * @param {Highcharts.Point} point
- */
- onPointAdded: function (point) {
- var chart = point.series.chart;
- if (this.chart === chart && chartHasAnnounceEnabled(chart)) {
- // Add it to newPoint storage unless we already have one
- this.dirty.newPoint = defined(this.dirty.newPoint) ?
- void 0 : point;
- }
- },
- /**
- * Gather what we know and announce the data to user.
- * @private
- */
- announceDirtyData: function () {
- var chart = this.chart, announcer = this;
- if (chart.options.accessibility.announceNewData &&
- this.dirty.hasDirty) {
- var newPoint = this.dirty.newPoint;
- // If we have a single new point, see if we can find it in the
- // data array. Otherwise we can only pass through options to
- // the description builder, and it is a bit sparse in info.
- if (newPoint) {
- newPoint = findPointInDataArray(newPoint);
- }
- this.queueAnnouncement(Object.keys(this.dirty.allSeries).map(function (ix) {
- return announcer.dirty.allSeries[ix];
- }), this.dirty.newSeries, newPoint);
- // Reset
- this.dirty = {
- allSeries: {}
- };
- }
- },
- /**
- * Announce to user that there is new data.
- * @private
- * @param {Array<Highcharts.Series>} dirtySeries
- * Array of series with new data.
- * @param {Highcharts.Series} [newSeries]
- * If a single new series was added, a reference to this series.
- * @param {Highcharts.Point} [newPoint]
- * If a single point was added, a reference to this point.
- */
- queueAnnouncement: function (dirtySeries, newSeries, newPoint) {
- var chart = this.chart, annOptions = (chart.options.accessibility.announceNewData);
- if (annOptions.enabled) {
- var announcer = this, now = +new Date(), dTime = now - this.lastAnnouncementTime, time = Math.max(0, annOptions.minAnnounceInterval - dTime),
- // Add series from previously queued announcement.
- allSeries = getUniqueSeries(this.queuedAnnouncement && this.queuedAnnouncement.series, dirtySeries);
- // Build message and announce
- var message = this.buildAnnouncementMessage(allSeries, newSeries, newPoint);
- if (message) {
- // Is there already one queued?
- if (this.queuedAnnouncement) {
- clearTimeout(this.queuedAnnouncementTimer);
- }
- // Build the announcement
- this.queuedAnnouncement = {
- time: now,
- message: message,
- series: allSeries
- };
- // Queue the announcement
- announcer.queuedAnnouncementTimer = setTimeout(function () {
- if (announcer && announcer.announceRegion) {
- announcer.lastAnnouncementTime = +new Date();
- announcer.liveRegionSpeak(announcer.queuedAnnouncement.message);
- delete announcer.queuedAnnouncement;
- delete announcer.queuedAnnouncementTimer;
- }
- }, time);
- }
- }
- },
- /**
- * Speak a message using the announcer live region.
- * @private
- * @param {string} message
- */
- liveRegionSpeak: function (message) {
- var announcer = this;
- this.announceRegion.innerHTML = message;
- // Delete contents after a little while to avoid user finding the live
- // region in the DOM.
- if (this.clearAnnouncementContainerTimer) {
- clearTimeout(this.clearAnnouncementContainerTimer);
- }
- this.clearAnnouncementContainerTimer = setTimeout(function () {
- announcer.announceRegion.innerHTML = '';
- delete announcer.clearAnnouncementContainerTimer;
- }, 1000);
- },
- /**
- * Get announcement message for new data.
- * @private
- * @param {Array<Highcharts.Series>} dirtySeries
- * Array of series with new data.
- * @param {Highcharts.Series} [newSeries]
- * If a single new series was added, a reference to this series.
- * @param {Highcharts.Point} [newPoint]
- * If a single point was added, a reference to this point.
- *
- * @return {string|null}
- * The announcement message to give to user.
- */
- buildAnnouncementMessage: function (dirtySeries, newSeries, newPoint) {
- var chart = this.chart, annOptions = chart.options.accessibility.announceNewData;
- // User supplied formatter?
- if (annOptions.announcementFormatter) {
- var formatterRes = annOptions.announcementFormatter(dirtySeries, newSeries, newPoint);
- if (formatterRes !== false) {
- return formatterRes.length ? formatterRes : null;
- }
- }
- // Default formatter - use lang options
- var multiple = H.charts && H.charts.length > 1 ? 'Multiple' : 'Single', langKey = newSeries ? 'newSeriesAnnounce' + multiple :
- newPoint ? 'newPointAnnounce' + multiple : 'newDataAnnounce', chartTitle = getChartTitle(chart);
- return chart.langFormat('accessibility.announceNewData.' + langKey, {
- chartTitle: chartTitle,
- seriesDesc: newSeries ?
- defaultSeriesDescriptionFormatter(newSeries) :
- null,
- pointDesc: newPoint ?
- defaultPointDescriptionFormatter(newPoint) :
- null,
- point: newPoint,
- series: newSeries
- });
- }
- });
- return NewDataAnnouncer;
- });
- _registerModule(_modules, 'modules/accessibility/components/SeriesComponent/forcedMarkers.js', [_modules['parts/Globals.js']], function (H) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Handle forcing series markers.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var merge = H.merge;
- /* eslint-disable no-invalid-this, valid-jsdoc */
- /**
- * @private
- */
- function isWithinDescriptionThreshold(series) {
- var a11yOptions = series.chart.options.accessibility;
- return series.points.length <
- a11yOptions.series.pointDescriptionEnabledThreshold ||
- a11yOptions.series.pointDescriptionEnabledThreshold === false;
- }
- /**
- * @private
- */
- function isWithinNavigationThreshold(series) {
- var navOptions = series.chart.options.accessibility
- .keyboardNavigation.seriesNavigation;
- return series.points.length <
- navOptions.pointNavigationEnabledThreshold ||
- navOptions.pointNavigationEnabledThreshold === false;
- }
- /**
- * @private
- */
- function shouldForceMarkers(series) {
- var chartA11yEnabled = series.chart.options.accessibility.enabled, seriesA11yEnabled = (series.options.accessibility &&
- series.options.accessibility.enabled) !== false, withinDescriptionThreshold = isWithinDescriptionThreshold(series), withinNavigationThreshold = isWithinNavigationThreshold(series);
- return chartA11yEnabled && seriesA11yEnabled &&
- (withinDescriptionThreshold || withinNavigationThreshold);
- }
- /**
- * @private
- */
- function unforceMarkerOptions(series) {
- var resetMarkerOptions = series.resetA11yMarkerOptions;
- merge(true, series.options, {
- marker: {
- enabled: resetMarkerOptions.enabled,
- states: {
- normal: {
- opacity: resetMarkerOptions.states &&
- resetMarkerOptions.states.normal &&
- resetMarkerOptions.states.normal.opacity
- }
- }
- }
- });
- }
- /**
- * @private
- */
- function forceZeroOpacityMarkerOptions(options) {
- merge(true, options, {
- marker: {
- enabled: true,
- states: {
- normal: {
- opacity: 0
- }
- }
- }
- });
- }
- /**
- * @private
- */
- function getPointMarkerOpacity(pointOptions) {
- return pointOptions.marker.states &&
- pointOptions.marker.states.normal &&
- pointOptions.marker.states.normal.opacity || 1;
- }
- /**
- * @private
- */
- function forceDisplayPointMarker(pointOptions) {
- merge(true, pointOptions.marker, {
- states: {
- normal: {
- opacity: getPointMarkerOpacity(pointOptions)
- }
- }
- });
- }
- /**
- * @private
- */
- function handleForcePointMarkers(points) {
- var i = points.length;
- while (i--) {
- var pointOptions = points[i].options;
- if (pointOptions.marker) {
- if (pointOptions.marker.enabled) {
- forceDisplayPointMarker(pointOptions);
- }
- else {
- forceZeroOpacityMarkerOptions(pointOptions);
- }
- }
- }
- }
- /**
- * @private
- */
- function addForceMarkersEvents() {
- /**
- * Keep track of forcing markers.
- * @private
- */
- H.addEvent(H.Series, 'render', function () {
- var series = this, options = series.options;
- if (shouldForceMarkers(series)) {
- if (options.marker && options.marker.enabled === false) {
- series.a11yMarkersForced = true;
- forceZeroOpacityMarkerOptions(series.options);
- }
- if (series._hasPointMarkers && series.points && series.points.length) {
- handleForcePointMarkers(series.points);
- }
- }
- else if (series.a11yMarkersForced && series.resetMarkerOptions) {
- delete series.a11yMarkersForced;
- unforceMarkerOptions(series);
- }
- });
- /**
- * Keep track of options to reset markers to if no longer forced.
- * @private
- */
- H.addEvent(H.Series, 'afterSetOptions', function (e) {
- this.resetA11yMarkerOptions = merge(e.options.marker || {}, this.userOptions.marker || {});
- });
- }
- return addForceMarkersEvents;
- });
- _registerModule(_modules, 'modules/accessibility/components/SeriesComponent/SeriesComponent.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js'], _modules['modules/accessibility/AccessibilityComponent.js'], _modules['modules/accessibility/components/SeriesComponent/SeriesKeyboardNavigation.js'], _modules['modules/accessibility/components/SeriesComponent/NewDataAnnouncer.js'], _modules['modules/accessibility/components/SeriesComponent/forcedMarkers.js'], _modules['modules/accessibility/utils/chartUtilities.js'], _modules['modules/accessibility/components/SeriesComponent/SeriesDescriber.js']], function (H, U, AccessibilityComponent, SeriesKeyboardNavigation, NewDataAnnouncer, addForceMarkersEvents, ChartUtilities, SeriesDescriber) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Accessibility component for series and points.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var extend = U.extend;
- var hideSeriesFromAT = ChartUtilities.hideSeriesFromAT;
- var describeSeries = SeriesDescriber.describeSeries;
- // Expose functionality to users
- H.SeriesAccessibilityDescriber = SeriesDescriber;
- // Handle forcing markers
- addForceMarkersEvents();
- /* eslint-disable no-invalid-this, valid-jsdoc */
- /**
- * The SeriesComponent class
- *
- * @private
- * @class
- * @name Highcharts.SeriesComponent
- */
- var SeriesComponent = function () { };
- SeriesComponent.prototype = new AccessibilityComponent();
- extend(SeriesComponent.prototype, /** @lends Highcharts.SeriesComponent */ {
- /**
- * Init the component.
- */
- init: function () {
- this.newDataAnnouncer = new NewDataAnnouncer(this.chart);
- this.newDataAnnouncer.init();
- this.keyboardNavigation = new SeriesKeyboardNavigation(this.chart, this.keyCodes);
- this.keyboardNavigation.init();
- this.hideTooltipFromATWhenShown();
- this.hideSeriesLabelsFromATWhenShown();
- },
- /**
- * @private
- */
- hideTooltipFromATWhenShown: function () {
- var component = this;
- this.addEvent(H.Tooltip, 'refresh', function () {
- if (this.chart === component.chart &&
- this.label &&
- this.label.element) {
- this.label.element.setAttribute('aria-hidden', true);
- }
- });
- },
- /**
- * @private
- */
- hideSeriesLabelsFromATWhenShown: function () {
- this.addEvent(this.chart, 'afterDrawSeriesLabels', function () {
- this.series.forEach(function (series) {
- if (series.labelBySeries) {
- series.labelBySeries.attr('aria-hidden', true);
- }
- });
- });
- },
- /**
- * Called on chart render. It is necessary to do this for render in case
- * markers change on zoom/pixel density.
- */
- onChartRender: function () {
- var chart = this.chart;
- chart.series.forEach(function (series) {
- var shouldDescribeSeries = (series.options.accessibility &&
- series.options.accessibility.enabled) !== false &&
- series.visible;
- if (shouldDescribeSeries) {
- describeSeries(series);
- }
- else {
- hideSeriesFromAT(series);
- }
- });
- },
- /**
- * Get keyboard navigation handler for this component.
- * @return {Highcharts.KeyboardNavigationHandler}
- */
- getKeyboardNavigation: function () {
- return this.keyboardNavigation.getKeyboardNavigationHandler();
- },
- /**
- * Remove traces
- */
- destroy: function () {
- this.newDataAnnouncer.destroy();
- this.keyboardNavigation.destroy();
- }
- });
- return SeriesComponent;
- });
- _registerModule(_modules, 'modules/accessibility/components/ZoomComponent.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js'], _modules['modules/accessibility/AccessibilityComponent.js'], _modules['modules/accessibility/KeyboardNavigationHandler.js'], _modules['modules/accessibility/utils/chartUtilities.js'], _modules['modules/accessibility/utils/htmlUtilities.js']], function (H, U, AccessibilityComponent, KeyboardNavigationHandler, ChartUtilities, HTMLUtilities) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Accessibility component for chart zoom.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var extend = U.extend, pick = U.pick;
- var unhideChartElementFromAT = ChartUtilities.unhideChartElementFromAT;
- var setElAttrs = HTMLUtilities.setElAttrs, removeElement = HTMLUtilities.removeElement;
- /* eslint-disable no-invalid-this, valid-jsdoc */
- /**
- * @private
- */
- function chartHasMapZoom(chart) {
- return !!(chart.mapZoom &&
- chart.mapNavButtons &&
- chart.mapNavButtons.length);
- }
- /**
- * Pan along axis in a direction (1 or -1), optionally with a defined
- * granularity (number of steps it takes to walk across current view)
- *
- * @private
- * @function Highcharts.Axis#panStep
- *
- * @param {number} direction
- * @param {number} [granularity]
- */
- H.Axis.prototype.panStep = function (direction, granularity) {
- var gran = granularity || 3, extremes = this.getExtremes(), step = (extremes.max - extremes.min) / gran * direction, newMax = extremes.max + step, newMin = extremes.min + step, size = newMax - newMin;
- if (direction < 0 && newMin < extremes.dataMin) {
- newMin = extremes.dataMin;
- newMax = newMin + size;
- }
- else if (direction > 0 && newMax > extremes.dataMax) {
- newMax = extremes.dataMax;
- newMin = newMax - size;
- }
- this.setExtremes(newMin, newMax);
- };
- /**
- * The ZoomComponent class
- *
- * @private
- * @class
- * @name Highcharts.ZoomComponent
- */
- var ZoomComponent = function () { };
- ZoomComponent.prototype = new AccessibilityComponent();
- extend(ZoomComponent.prototype, /** @lends Highcharts.ZoomComponent */ {
- /**
- * Initialize the component
- */
- init: function () {
- var component = this, chart = this.chart;
- [
- 'afterShowResetZoom', 'afterDrilldown', 'drillupall'
- ].forEach(function (eventType) {
- component.addEvent(chart, eventType, function () {
- component.updateProxyOverlays();
- });
- });
- },
- /**
- * Called when chart is updated
- */
- onChartUpdate: function () {
- var chart = this.chart, component = this;
- // Make map zoom buttons accessible
- if (chart.mapNavButtons) {
- chart.mapNavButtons.forEach(function (button, i) {
- unhideChartElementFromAT(chart, button.element);
- component.setMapNavButtonAttrs(button.element, 'accessibility.zoom.mapZoom' + (i ? 'Out' : 'In'));
- });
- }
- },
- /**
- * @private
- * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} button
- * @param {string} labelFormatKey
- */
- setMapNavButtonAttrs: function (button, labelFormatKey) {
- var chart = this.chart, label = chart.langFormat(labelFormatKey, { chart: chart });
- setElAttrs(button, {
- tabindex: -1,
- role: 'button',
- 'aria-label': label
- });
- },
- /**
- * Update the proxy overlays on every new render to ensure positions are
- * correct.
- */
- onChartRender: function () {
- this.updateProxyOverlays();
- },
- /**
- * Update proxy overlays, recreating the buttons.
- */
- updateProxyOverlays: function () {
- var chart = this.chart;
- // Always start with a clean slate
- removeElement(this.drillUpProxyGroup);
- removeElement(this.resetZoomProxyGroup);
- if (chart.resetZoomButton) {
- this.recreateProxyButtonAndGroup(chart.resetZoomButton, 'resetZoomProxyButton', 'resetZoomProxyGroup', chart.langFormat('accessibility.zoom.resetZoomButton', { chart: chart }));
- }
- if (chart.drillUpButton) {
- this.recreateProxyButtonAndGroup(chart.drillUpButton, 'drillUpProxyButton', 'drillUpProxyGroup', chart.langFormat('accessibility.drillUpButton', {
- chart: chart,
- buttonText: chart.getDrilldownBackText()
- }));
- }
- },
- /**
- * @private
- * @param {Highcharts.SVGElement} buttonEl
- * @param {string} buttonProp
- * @param {string} groupProp
- * @param {string} label
- */
- recreateProxyButtonAndGroup: function (buttonEl, buttonProp, groupProp, label) {
- removeElement(this[groupProp]);
- this[groupProp] = this.addProxyGroup();
- this[buttonProp] = this.createProxyButton(buttonEl, this[groupProp], { 'aria-label': label, tabindex: -1 });
- },
- /**
- * Get keyboard navigation handler for map zoom.
- * @private
- * @return {Highcharts.KeyboardNavigationHandler} The module object
- */
- getMapZoomNavigation: function () {
- var keys = this.keyCodes, chart = this.chart, component = this;
- return new KeyboardNavigationHandler(chart, {
- keyCodeMap: [
- [
- [keys.up, keys.down, keys.left, keys.right],
- function (keyCode) {
- return component.onMapKbdArrow(this, keyCode);
- }
- ],
- [
- [keys.tab],
- function (_keyCode, e) {
- return component.onMapKbdTab(this, e);
- }
- ],
- [
- [keys.space, keys.enter],
- function () {
- return component.onMapKbdClick(this);
- }
- ]
- ],
- validate: function () {
- return chartHasMapZoom(chart);
- },
- init: function (direction) {
- return component.onMapNavInit(direction);
- }
- });
- },
- /**
- * @private
- * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler
- * @param {number} keyCode
- * @return {number} Response code
- */
- onMapKbdArrow: function (keyboardNavigationHandler, keyCode) {
- var keys = this.keyCodes, panAxis = (keyCode === keys.up || keyCode === keys.down) ?
- 'yAxis' : 'xAxis', stepDirection = (keyCode === keys.left || keyCode === keys.up) ?
- -1 : 1;
- this.chart[panAxis][0].panStep(stepDirection);
- return keyboardNavigationHandler.response.success;
- },
- /**
- * @private
- * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler
- * @param {global.KeyboardEvent} event
- * @return {number} Response code
- */
- onMapKbdTab: function (keyboardNavigationHandler, event) {
- var button, chart = this.chart, response = keyboardNavigationHandler.response, isBackwards = event.shiftKey, isMoveOutOfRange = isBackwards && !this.focusedMapNavButtonIx ||
- !isBackwards && this.focusedMapNavButtonIx;
- // Deselect old
- chart.mapNavButtons[this.focusedMapNavButtonIx].setState(0);
- if (isMoveOutOfRange) {
- chart.mapZoom(); // Reset zoom
- return response[isBackwards ? 'prev' : 'next'];
- }
- // Select other button
- this.focusedMapNavButtonIx += isBackwards ? -1 : 1;
- button = chart.mapNavButtons[this.focusedMapNavButtonIx];
- chart.setFocusToElement(button.box, button.element);
- button.setState(2);
- return response.success;
- },
- /**
- * @private
- * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler
- * @return {number} Response code
- */
- onMapKbdClick: function (keyboardNavigationHandler) {
- this.fakeClickEvent(this.chart.mapNavButtons[this.focusedMapNavButtonIx]
- .element);
- return keyboardNavigationHandler.response.success;
- },
- /**
- * @private
- * @param {number} direction
- */
- onMapNavInit: function (direction) {
- var chart = this.chart, zoomIn = chart.mapNavButtons[0], zoomOut = chart.mapNavButtons[1], initialButton = direction > 0 ? zoomIn : zoomOut;
- chart.setFocusToElement(initialButton.box, initialButton.element);
- initialButton.setState(2);
- this.focusedMapNavButtonIx = direction > 0 ? 0 : 1;
- },
- /**
- * Get keyboard navigation handler for a simple chart button. Provide the
- * button reference for the chart, and a function to call on click.
- *
- * @private
- * @param {string} buttonProp The property on chart referencing the button.
- * @return {Highcharts.KeyboardNavigationHandler} The module object
- */
- simpleButtonNavigation: function (buttonProp, proxyProp, onClick) {
- var keys = this.keyCodes, component = this, chart = this.chart;
- return new KeyboardNavigationHandler(chart, {
- keyCodeMap: [
- [
- [keys.tab, keys.up, keys.down, keys.left, keys.right],
- function (keyCode, e) {
- var isBackwards = keyCode === keys.tab && e.shiftKey ||
- keyCode === keys.left || keyCode === keys.up;
- // Arrow/tab => just move
- return this.response[isBackwards ? 'prev' : 'next'];
- }
- ],
- [
- [keys.space, keys.enter],
- function () {
- var res = onClick(this, chart);
- return pick(res, this.response.success);
- }
- ]
- ],
- validate: function () {
- var hasButton = (chart[buttonProp] &&
- chart[buttonProp].box &&
- component[proxyProp]);
- return hasButton;
- },
- init: function () {
- chart.setFocusToElement(chart[buttonProp].box, component[proxyProp]);
- }
- });
- },
- /**
- * Get keyboard navigation handlers for this component.
- * @return {Array<Highcharts.KeyboardNavigationHandler>}
- * List of module objects
- */
- getKeyboardNavigation: function () {
- return [
- this.simpleButtonNavigation('resetZoomButton', 'resetZoomProxyButton', function (_handler, chart) {
- chart.zoomOut();
- }),
- this.simpleButtonNavigation('drillUpButton', 'drillUpProxyButton', function (handler, chart) {
- chart.drillUp();
- return handler.response.prev;
- }),
- this.getMapZoomNavigation()
- ];
- }
- });
- return ZoomComponent;
- });
- _registerModule(_modules, 'modules/accessibility/components/RangeSelectorComponent.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js'], _modules['modules/accessibility/AccessibilityComponent.js'], _modules['modules/accessibility/KeyboardNavigationHandler.js'], _modules['modules/accessibility/utils/chartUtilities.js'], _modules['modules/accessibility/utils/htmlUtilities.js']], function (H, U, AccessibilityComponent, KeyboardNavigationHandler, ChartUtilities, HTMLUtilities) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Accessibility component for the range selector.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var extend = U.extend;
- var unhideChartElementFromAT = ChartUtilities.unhideChartElementFromAT;
- var setElAttrs = HTMLUtilities.setElAttrs;
- /* eslint-disable no-invalid-this, valid-jsdoc */
- /**
- * @private
- */
- function shouldRunInputNavigation(chart) {
- var inputVisible = (chart.rangeSelector &&
- chart.rangeSelector.inputGroup &&
- chart.rangeSelector.inputGroup.element
- .getAttribute('visibility') !== 'hidden');
- return (inputVisible &&
- chart.options.rangeSelector.inputEnabled !== false &&
- chart.rangeSelector.minInput &&
- chart.rangeSelector.maxInput);
- }
- /**
- * Highlight range selector button by index.
- *
- * @private
- * @function Highcharts.Chart#highlightRangeSelectorButton
- *
- * @param {number} ix
- *
- * @return {boolean}
- */
- H.Chart.prototype.highlightRangeSelectorButton = function (ix) {
- var buttons = this.rangeSelector.buttons, curSelectedIx = this.highlightedRangeSelectorItemIx;
- // Deselect old
- if (typeof curSelectedIx !== 'undefined' && buttons[curSelectedIx]) {
- buttons[curSelectedIx].setState(this.oldRangeSelectorItemState || 0);
- }
- // Select new
- this.highlightedRangeSelectorItemIx = ix;
- if (buttons[ix]) {
- this.setFocusToElement(buttons[ix].box, buttons[ix].element);
- this.oldRangeSelectorItemState = buttons[ix].state;
- buttons[ix].setState(2);
- return true;
- }
- return false;
- };
- /**
- * The RangeSelectorComponent class
- *
- * @private
- * @class
- * @name Highcharts.RangeSelectorComponent
- */
- var RangeSelectorComponent = function () { };
- RangeSelectorComponent.prototype = new AccessibilityComponent();
- extend(RangeSelectorComponent.prototype, /** @lends Highcharts.RangeSelectorComponent */ {
- /**
- * Called on first render/updates to the chart, including options changes.
- */
- onChartUpdate: function () {
- var chart = this.chart, component = this, rangeSelector = chart.rangeSelector;
- if (!rangeSelector) {
- return;
- }
- if (rangeSelector.buttons && rangeSelector.buttons.length) {
- rangeSelector.buttons.forEach(function (button) {
- unhideChartElementFromAT(chart, button.element);
- component.setRangeButtonAttrs(button);
- });
- }
- // Make sure input boxes are accessible and focusable
- if (rangeSelector.maxInput && rangeSelector.minInput) {
- ['minInput', 'maxInput'].forEach(function (key, i) {
- var input = rangeSelector[key];
- if (input) {
- unhideChartElementFromAT(chart, input);
- component.setRangeInputAttrs(input, 'accessibility.rangeSelector.' + (i ? 'max' : 'min') +
- 'InputLabel');
- }
- });
- }
- },
- /**
- * @private
- * @param {Highcharts.SVGElement} button
- */
- setRangeButtonAttrs: function (button) {
- var chart = this.chart, label = chart.langFormat('accessibility.rangeSelector.buttonText', {
- chart: chart,
- buttonText: button.text && button.text.textStr
- });
- setElAttrs(button.element, {
- tabindex: -1,
- role: 'button',
- 'aria-label': label
- });
- },
- /**
- * @private
- */
- setRangeInputAttrs: function (input, langKey) {
- var chart = this.chart;
- setElAttrs(input, {
- tabindex: -1,
- role: 'textbox',
- 'aria-label': chart.langFormat(langKey, { chart: chart })
- });
- },
- /**
- * Get navigation for the range selector buttons.
- * @private
- * @return {Highcharts.KeyboardNavigationHandler} The module object.
- */
- getRangeSelectorButtonNavigation: function () {
- var chart = this.chart, keys = this.keyCodes, component = this;
- return new KeyboardNavigationHandler(chart, {
- keyCodeMap: [
- [
- [keys.left, keys.right, keys.up, keys.down],
- function (keyCode) {
- return component.onButtonNavKbdArrowKey(this, keyCode);
- }
- ],
- [
- [keys.enter, keys.space],
- function () {
- return component.onButtonNavKbdClick(this);
- }
- ]
- ],
- validate: function () {
- var hasRangeSelector = chart.rangeSelector &&
- chart.rangeSelector.buttons &&
- chart.rangeSelector.buttons.length;
- return hasRangeSelector;
- },
- init: function (direction) {
- var lastButtonIx = (chart.rangeSelector.buttons.length - 1);
- chart.highlightRangeSelectorButton(direction > 0 ? 0 : lastButtonIx);
- }
- });
- },
- /**
- * @private
- * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler
- * @param {number} keyCode
- * @return {number} Response code
- */
- onButtonNavKbdArrowKey: function (keyboardNavigationHandler, keyCode) {
- var response = keyboardNavigationHandler.response, keys = this.keyCodes, chart = this.chart, wrapAround = chart.options.accessibility
- .keyboardNavigation.wrapAround, direction = (keyCode === keys.left || keyCode === keys.up) ? -1 : 1, didHighlight = chart.highlightRangeSelectorButton(chart.highlightedRangeSelectorItemIx + direction);
- if (!didHighlight) {
- if (wrapAround) {
- keyboardNavigationHandler.init(direction);
- return response.success;
- }
- return response[direction > 0 ? 'next' : 'prev'];
- }
- return response.success;
- },
- /**
- * @private
- */
- onButtonNavKbdClick: function (keyboardNavigationHandler) {
- var response = keyboardNavigationHandler.response, chart = this.chart, wasDisabled = chart.oldRangeSelectorItemState === 3;
- if (!wasDisabled) {
- this.fakeClickEvent(chart.rangeSelector.buttons[chart.highlightedRangeSelectorItemIx].element);
- }
- return response.success;
- },
- /**
- * Get navigation for the range selector input boxes.
- * @private
- * @return {Highcharts.KeyboardNavigationHandler}
- * The module object.
- */
- getRangeSelectorInputNavigation: function () {
- var chart = this.chart, keys = this.keyCodes, component = this;
- return new KeyboardNavigationHandler(chart, {
- keyCodeMap: [
- [
- [
- keys.tab, keys.up, keys.down
- ], function (keyCode, e) {
- var direction = (keyCode === keys.tab && e.shiftKey ||
- keyCode === keys.up) ? -1 : 1;
- return component.onInputKbdMove(this, direction);
- }
- ]
- ],
- validate: function () {
- return shouldRunInputNavigation(chart);
- },
- init: function (direction) {
- component.onInputNavInit(direction);
- },
- terminate: function () {
- component.onInputNavTerminate();
- }
- });
- },
- /**
- * @private
- * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler
- * @param {number} direction
- * @return {number} Response code
- */
- onInputKbdMove: function (keyboardNavigationHandler, direction) {
- var chart = this.chart, response = keyboardNavigationHandler.response, newIx = chart.highlightedInputRangeIx =
- chart.highlightedInputRangeIx + direction, newIxOutOfRange = newIx > 1 || newIx < 0;
- if (newIxOutOfRange) {
- return response[direction > 0 ? 'next' : 'prev'];
- }
- chart.rangeSelector[newIx ? 'maxInput' : 'minInput'].focus();
- return response.success;
- },
- /**
- * @private
- * @param {number} direction
- */
- onInputNavInit: function (direction) {
- var chart = this.chart, buttonIxToHighlight = direction > 0 ? 0 : 1;
- chart.highlightedInputRangeIx = buttonIxToHighlight;
- chart.rangeSelector[buttonIxToHighlight ? 'maxInput' : 'minInput'].focus();
- },
- /**
- * @private
- */
- onInputNavTerminate: function () {
- var rangeSel = (this.chart.rangeSelector || {});
- if (rangeSel.maxInput) {
- rangeSel.hideInput('max');
- }
- if (rangeSel.minInput) {
- rangeSel.hideInput('min');
- }
- },
- /**
- * Get keyboard navigation handlers for this component.
- * @return {Array<Highcharts.KeyboardNavigationHandler>}
- * List of module objects.
- */
- getKeyboardNavigation: function () {
- return [
- this.getRangeSelectorButtonNavigation(),
- this.getRangeSelectorInputNavigation()
- ];
- }
- });
- return RangeSelectorComponent;
- });
- _registerModule(_modules, 'modules/accessibility/components/InfoRegionsComponent.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js'], _modules['modules/accessibility/AccessibilityComponent.js'], _modules['modules/accessibility/utils/chartUtilities.js'], _modules['modules/accessibility/utils/htmlUtilities.js']], function (H, U, AccessibilityComponent, ChartUtilities, HTMLUtilities) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Accessibility component for chart info region and table.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var doc = H.win.document, format = H.format;
- var extend = U.extend, pick = U.pick;
- var unhideChartElementFromAT = ChartUtilities.unhideChartElementFromAT, getChartTitle = ChartUtilities.getChartTitle, getAxisDescription = ChartUtilities.getAxisDescription;
- var addClass = HTMLUtilities.addClass, setElAttrs = HTMLUtilities.setElAttrs, escapeStringForHTML = HTMLUtilities.escapeStringForHTML, stripHTMLTagsFromString = HTMLUtilities.stripHTMLTagsFromString, getElement = HTMLUtilities.getElement, visuallyHideElement = HTMLUtilities.visuallyHideElement;
- /* eslint-disable no-invalid-this, valid-jsdoc */
- /**
- * @private
- */
- function getTypeDescForMapChart(chart, formatContext) {
- return formatContext.mapTitle ?
- chart.langFormat('accessibility.chartTypes.mapTypeDescription', formatContext) :
- chart.langFormat('accessibility.chartTypes.unknownMap', formatContext);
- }
- /**
- * @private
- */
- function getTypeDescForCombinationChart(chart, formatContext) {
- return chart.langFormat('accessibility.chartTypes.combinationChart', formatContext);
- }
- /**
- * @private
- */
- function getTypeDescForEmptyChart(chart, formatContext) {
- return chart.langFormat('accessibility.chartTypes.emptyChart', formatContext);
- }
- /**
- * @private
- */
- function buildTypeDescriptionFromSeries(chart, types, context) {
- var firstType = types[0], typeExplaination = chart.langFormat('accessibility.seriesTypeDescriptions.' + firstType, context), multi = chart.series && chart.series.length < 2 ? 'Single' : 'Multiple';
- return (chart.langFormat('accessibility.chartTypes.' + firstType + multi, context) ||
- chart.langFormat('accessibility.chartTypes.default' + multi, context)) + (typeExplaination ? ' ' + typeExplaination : '');
- }
- /**
- * @private
- */
- function getTableSummary(chart) {
- return chart.langFormat('accessibility.table.tableSummary', { chart: chart });
- }
- /**
- * @private
- */
- function stripEmptyHTMLTags(str) {
- return str.replace(/<(\w+)[^>]*?>\s*<\/\1>/g, '');
- }
- /**
- * @private
- */
- function enableSimpleHTML(str) {
- return str
- .replace(/<(h[1-7]|p|div)>/g, '<$1>')
- .replace(/</(h[1-7]|p|div|a|button)>/g, '</$1>')
- .replace(/<(div|a|button) id="([a-zA-Z\-0-9#]*?)">/g, '<$1 id="$2">');
- }
- /**
- * @private
- */
- function stringToSimpleHTML(str) {
- return stripEmptyHTMLTags(enableSimpleHTML(escapeStringForHTML(str)));
- }
- /**
- * Return simplified explaination of chart type. Some types will not be familiar
- * to most users, but in those cases we try to add an explaination of the type.
- *
- * @private
- * @function Highcharts.Chart#getTypeDescription
- * @param {Array<string>} types The series types in this chart.
- * @return {string} The text description of the chart type.
- */
- H.Chart.prototype.getTypeDescription = function (types) {
- var firstType = types[0], firstSeries = this.series && this.series[0] || {}, formatContext = {
- numSeries: this.series.length,
- numPoints: firstSeries.points && firstSeries.points.length,
- chart: this,
- mapTitle: firstSeries.mapTitle
- };
- if (!firstType) {
- return getTypeDescForEmptyChart(this, formatContext);
- }
- if (firstType === 'map') {
- return getTypeDescForMapChart(this, formatContext);
- }
- if (this.types.length > 1) {
- return getTypeDescForCombinationChart(this, formatContext);
- }
- return buildTypeDescriptionFromSeries(this, types, formatContext);
- };
- /**
- * The InfoRegionsComponent class
- *
- * @private
- * @class
- * @name Highcharts.InfoRegionsComponent
- */
- var InfoRegionsComponent = function () { };
- InfoRegionsComponent.prototype = new AccessibilityComponent();
- extend(InfoRegionsComponent.prototype, /** @lends Highcharts.InfoRegionsComponent */ {
- /**
- * Init the component
- * @private
- */
- init: function () {
- var chart = this.chart, component = this;
- this.initRegionsDefinitions();
- this.addEvent(chart, 'afterGetTable', function (e) {
- component.onDataTableCreated(e);
- });
- this.addEvent(chart, 'afterViewData', function (tableDiv) {
- component.dataTableDiv = tableDiv;
- // Use small delay to give browsers & AT time to register new table
- setTimeout(function () {
- component.focusDataTable();
- }, 300);
- });
- },
- /**
- * @private
- */
- initRegionsDefinitions: function () {
- var component = this;
- this.screenReaderSections = {
- before: {
- element: null,
- buildContent: function (chart) {
- var formatter = chart.options.accessibility
- .screenReaderSection.beforeChartFormatter;
- return formatter ? formatter(chart) :
- component.defaultBeforeChartFormatter(chart);
- },
- insertIntoDOM: function (el, chart) {
- chart.renderTo.insertBefore(el, chart.renderTo.firstChild);
- },
- afterInserted: function () {
- if (typeof component.dataTableButtonId !== 'undefined') {
- component.initDataTableButton(component.dataTableButtonId);
- }
- }
- },
- after: {
- element: null,
- buildContent: function (chart) {
- var formatter = chart.options.accessibility.screenReaderSection
- .afterChartFormatter;
- return formatter ? formatter(chart) :
- component.defaultAfterChartFormatter();
- },
- insertIntoDOM: function (el, chart) {
- chart.renderTo.insertBefore(el, chart.container.nextSibling);
- }
- }
- };
- },
- /**
- * Called on first render/updates to the chart, including options changes.
- */
- onChartUpdate: function () {
- var component = this;
- this.linkedDescriptionElement = this.getLinkedDescriptionElement();
- this.setLinkedDescriptionAttrs();
- Object.keys(this.screenReaderSections).forEach(function (regionKey) {
- component.updateScreenReaderSection(regionKey);
- });
- },
- /**
- * @private
- */
- getLinkedDescriptionElement: function () {
- var chartOptions = this.chart.options, linkedDescOption = chartOptions.accessibility.linkedDescription;
- if (!linkedDescOption) {
- return;
- }
- if (typeof linkedDescOption !== 'string') {
- return linkedDescOption;
- }
- var query = format(linkedDescOption, this.chart), queryMatch = doc.querySelectorAll(query);
- if (queryMatch.length === 1) {
- return queryMatch[0];
- }
- },
- /**
- * @private
- */
- setLinkedDescriptionAttrs: function () {
- var el = this.linkedDescriptionElement;
- if (el) {
- el.setAttribute('aria-hidden', 'true');
- addClass(el, 'highcharts-linked-description');
- }
- },
- /**
- * @private
- * @param {string} regionKey The name/key of the region to update
- */
- updateScreenReaderSection: function (regionKey) {
- var chart = this.chart, region = this.screenReaderSections[regionKey], content = region.buildContent(chart), sectionDiv = region.element = (region.element || this.createElement('div')), hiddenDiv = (sectionDiv.firstChild || this.createElement('div'));
- this.setScreenReaderSectionAttribs(sectionDiv, regionKey);
- hiddenDiv.innerHTML = content;
- sectionDiv.appendChild(hiddenDiv);
- region.insertIntoDOM(sectionDiv, chart);
- visuallyHideElement(hiddenDiv);
- unhideChartElementFromAT(chart, hiddenDiv);
- if (region.afterInserted) {
- region.afterInserted();
- }
- },
- /**
- * @private
- * @param {Highcharts.HTMLDOMElement} sectionDiv The section element
- * @param {string} regionKey Name/key of the region we are setting attrs for
- */
- setScreenReaderSectionAttribs: function (sectionDiv, regionKey) {
- var labelLangKey = ('accessibility.screenReaderSection.' + regionKey + 'RegionLabel'), chart = this.chart, labelText = chart.langFormat(labelLangKey, { chart: chart }), sectionId = 'highcharts-screen-reader-region-' + regionKey + '-' +
- chart.index;
- setElAttrs(sectionDiv, {
- id: sectionId,
- 'aria-label': labelText
- });
- // Sections are wrapped to be positioned relatively to chart in case
- // elements inside are tabbed to.
- sectionDiv.style.position = 'relative';
- if (chart.options.accessibility.landmarkVerbosity === 'all' &&
- labelText) {
- sectionDiv.setAttribute('role', 'region');
- }
- },
- /**
- * @private
- * @return {string}
- */
- defaultBeforeChartFormatter: function () {
- var chart = this.chart, format = chart.options.accessibility
- .screenReaderSection.beforeChartFormat, axesDesc = this.getAxesDescription(), dataTableButtonId = 'hc-linkto-highcharts-data-table-' +
- chart.index, context = {
- chartTitle: getChartTitle(chart),
- typeDescription: this.getTypeDescriptionText(),
- chartSubtitle: this.getSubtitleText(),
- chartLongdesc: this.getLongdescText(),
- xAxisDescription: axesDesc.xAxis,
- yAxisDescription: axesDesc.yAxis,
- viewTableButton: chart.getCSV ?
- this.getDataTableButtonText(dataTableButtonId) : ''
- }, formattedString = H.i18nFormat(format, context, chart);
- this.dataTableButtonId = dataTableButtonId;
- return stringToSimpleHTML(formattedString);
- },
- /**
- * @private
- * @return {string}
- */
- defaultAfterChartFormatter: function () {
- var chart = this.chart, format = chart.options.accessibility
- .screenReaderSection.afterChartFormat, context = {
- endOfChartMarker: this.getEndOfChartMarkerText()
- }, formattedString = H.i18nFormat(format, context, chart);
- return stringToSimpleHTML(formattedString);
- },
- /**
- * @private
- * @return {string}
- */
- getLinkedDescription: function () {
- var el = this.linkedDescriptionElement, content = el && el.innerHTML || '';
- return stripHTMLTagsFromString(content);
- },
- /**
- * @private
- * @return {string}
- */
- getLongdescText: function () {
- var chartOptions = this.chart.options, captionOptions = chartOptions.caption, captionText = captionOptions && captionOptions.text, linkedDescription = this.getLinkedDescription();
- return (chartOptions.accessibility.description ||
- linkedDescription ||
- captionText ||
- '');
- },
- /**
- * @private
- * @return {string}
- */
- getTypeDescriptionText: function () {
- var chart = this.chart;
- return chart.types ?
- chart.options.accessibility.typeDescription ||
- chart.getTypeDescription(chart.types) : '';
- },
- /**
- * @private
- * @param {string} buttonId
- * @return {string}
- */
- getDataTableButtonText: function (buttonId) {
- var chart = this.chart, buttonText = chart.langFormat('accessibility.table.viewAsDataTableButtonText', { chart: chart, chartTitle: getChartTitle(chart) });
- return '<a id="' + buttonId + '">' + buttonText + '</a>';
- },
- /**
- * @private
- * @return {string}
- */
- getSubtitleText: function () {
- var subtitle = (this.chart.options.subtitle);
- return stripHTMLTagsFromString(subtitle && subtitle.text || '');
- },
- /**
- * @private
- * @return {string}
- */
- getEndOfChartMarkerText: function () {
- var chart = this.chart, markerText = chart.langFormat('accessibility.screenReaderSection.endOfChartMarker', { chart: chart }), id = 'highcharts-end-of-chart-marker-' + chart.index;
- return '<div id="' + id + '">' + markerText + '</div>';
- },
- /**
- * @private
- * @param {Highcharts.Dictionary<string>} e
- */
- onDataTableCreated: function (e) {
- var chart = this.chart;
- if (chart.options.accessibility.enabled) {
- if (this.viewDataTableButton) {
- this.viewDataTableButton.setAttribute('aria-expanded', 'true');
- }
- e.html = e.html.replace('<table ', '<table tabindex="0" summary="' + getTableSummary(chart) + '"');
- }
- },
- /**
- * @private
- */
- focusDataTable: function () {
- var tableDiv = this.dataTableDiv, table = tableDiv && tableDiv.getElementsByTagName('table')[0];
- if (table && table.focus) {
- table.focus();
- }
- },
- /**
- * Set attribs and handlers for default viewAsDataTable button if exists.
- * @private
- * @param {string} tableButtonId
- */
- initDataTableButton: function (tableButtonId) {
- var el = this.viewDataTableButton = getElement(tableButtonId), chart = this.chart, tableId = tableButtonId.replace('hc-linkto-', '');
- if (el) {
- setElAttrs(el, {
- role: 'button',
- tabindex: '-1',
- 'aria-expanded': !!getElement(tableId),
- href: '#' + tableId
- });
- el.onclick = chart.options.accessibility
- .screenReaderSection.onViewDataTableClick ||
- function () {
- chart.viewData();
- };
- }
- },
- /**
- * Return object with text description of each of the chart's axes.
- * @private
- * @return {Highcharts.Dictionary<string>}
- */
- getAxesDescription: function () {
- var chart = this.chart, shouldDescribeColl = function (collectionKey, defaultCondition) {
- var axes = chart[collectionKey];
- return axes.length > 1 || axes[0] &&
- pick(axes[0].options.accessibility &&
- axes[0].options.accessibility.enabled, defaultCondition);
- }, hasNoMap = !!chart.types && chart.types.indexOf('map') < 0, hasCartesian = !!chart.hasCartesianSeries, showXAxes = shouldDescribeColl('xAxis', !chart.angular && hasCartesian && hasNoMap), showYAxes = shouldDescribeColl('yAxis', hasCartesian && hasNoMap), desc = {};
- if (showXAxes) {
- desc.xAxis = this.getAxisDescriptionText('xAxis');
- }
- if (showYAxes) {
- desc.yAxis = this.getAxisDescriptionText('yAxis');
- }
- return desc;
- },
- /**
- * @private
- * @param {string} collectionKey
- * @return {string}
- */
- getAxisDescriptionText: function (collectionKey) {
- var component = this, chart = this.chart, axes = chart[collectionKey];
- return chart.langFormat('accessibility.axis.' + collectionKey + 'Description' + (axes.length > 1 ? 'Plural' : 'Singular'), {
- chart: chart,
- names: axes.map(function (axis) {
- return getAxisDescription(axis);
- }),
- ranges: axes.map(function (axis) {
- return component.getAxisRangeDescription(axis);
- }),
- numAxes: axes.length
- });
- },
- /**
- * Return string with text description of the axis range.
- * @private
- * @param {Highcharts.Axis} axis The axis to get range desc of.
- * @return {string} A string with the range description for the axis.
- */
- getAxisRangeDescription: function (axis) {
- var axisOptions = axis.options || {};
- // Handle overridden range description
- if (axisOptions.accessibility &&
- typeof axisOptions.accessibility.rangeDescription !== 'undefined') {
- return axisOptions.accessibility.rangeDescription;
- }
- // Handle category axes
- if (axis.categories) {
- return this.getCategoryAxisRangeDesc(axis);
- }
- // Use time range, not from-to?
- if (axis.isDatetimeAxis && (axis.min === 0 || axis.dataMin === 0)) {
- return this.getAxisTimeLengthDesc(axis);
- }
- // Just use from and to.
- // We have the range and the unit to use, find the desc format
- return this.getAxisFromToDescription(axis);
- },
- /**
- * @private
- * @param {Highcharts.Axis} axis
- * @return {string}
- */
- getCategoryAxisRangeDesc: function (axis) {
- var chart = this.chart;
- if (axis.dataMax && axis.dataMin) {
- return chart.langFormat('accessibility.axis.rangeCategories', {
- chart: chart,
- axis: axis,
- numCategories: axis.dataMax - axis.dataMin + 1
- });
- }
- return '';
- },
- /**
- * @private
- * @param {Highcharts.Axis} axis
- * @return {string}
- */
- getAxisTimeLengthDesc: function (axis) {
- var chart = this.chart, range = {}, rangeUnit = 'Seconds';
- range.Seconds = ((axis.max || 0) - (axis.min || 0)) / 1000;
- range.Minutes = range.Seconds / 60;
- range.Hours = range.Minutes / 60;
- range.Days = range.Hours / 24;
- ['Minutes', 'Hours', 'Days'].forEach(function (unit) {
- if (range[unit] > 2) {
- rangeUnit = unit;
- }
- });
- var rangeValue = range[rangeUnit].toFixed(rangeUnit !== 'Seconds' &&
- rangeUnit !== 'Minutes' ? 1 : 0 // Use decimals for days/hours
- );
- // We have the range and the unit to use, find the desc format
- return chart.langFormat('accessibility.axis.timeRange' + rangeUnit, {
- chart: chart,
- axis: axis,
- range: rangeValue.replace('.0', '')
- });
- },
- /**
- * @private
- * @param {Highcharts.Axis} axis
- * @return {string}
- */
- getAxisFromToDescription: function (axis) {
- var chart = this.chart, dateRangeFormat = chart.options.accessibility
- .screenReaderSection.axisRangeDateFormat, format = function (axisKey) {
- return axis.isDatetimeAxis ? chart.time.dateFormat(dateRangeFormat, axis[axisKey]) : axis[axisKey];
- };
- return chart.langFormat('accessibility.axis.rangeFromTo', {
- chart: chart,
- axis: axis,
- rangeFrom: format('min'),
- rangeTo: format('max')
- });
- }
- });
- return InfoRegionsComponent;
- });
- _registerModule(_modules, 'modules/accessibility/components/ContainerComponent.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js'], _modules['modules/accessibility/utils/htmlUtilities.js'], _modules['modules/accessibility/utils/chartUtilities.js'], _modules['modules/accessibility/AccessibilityComponent.js']], function (H, U, HTMLUtilities, ChartUtilities, AccessibilityComponent) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Accessibility component for chart container.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var doc = H.win.document;
- var extend = U.extend;
- var stripHTMLTags = HTMLUtilities.stripHTMLTagsFromString;
- var unhideChartElementFromAT = ChartUtilities.unhideChartElementFromAT, getChartTitle = ChartUtilities.getChartTitle;
- /* eslint-disable valid-jsdoc */
- /**
- * The ContainerComponent class
- *
- * @private
- * @class
- * @name Highcharts.ContainerComponent
- */
- var ContainerComponent = function () { };
- ContainerComponent.prototype = new AccessibilityComponent();
- extend(ContainerComponent.prototype, /** @lends Highcharts.ContainerComponent */ {
- /**
- * Called on first render/updates to the chart, including options changes.
- */
- onChartUpdate: function () {
- this.handleSVGTitleElement();
- this.setSVGContainerLabel();
- this.setGraphicContainerAttrs();
- this.setRenderToAttrs();
- this.makeCreditsAccessible();
- },
- /**
- * @private
- */
- handleSVGTitleElement: function () {
- var chart = this.chart, titleId = 'highcharts-title-' + chart.index, titleContents = stripHTMLTags(chart.langFormat('accessibility.svgContainerTitle', {
- chartTitle: getChartTitle(chart)
- }));
- if (titleContents.length) {
- var titleElement = this.svgTitleElement =
- this.svgTitleElement || doc.createElementNS('http://www.w3.org/2000/svg', 'title');
- titleElement.textContent = titleContents;
- titleElement.id = titleId;
- chart.renderTo.insertBefore(titleElement, chart.renderTo.firstChild);
- }
- },
- /**
- * @private
- */
- setSVGContainerLabel: function () {
- var chart = this.chart, svgContainerLabel = stripHTMLTags(chart.langFormat('accessibility.svgContainerLabel', {
- chartTitle: getChartTitle(chart)
- }));
- if (chart.renderer.box && svgContainerLabel.length) {
- chart.renderer.box.setAttribute('aria-label', svgContainerLabel);
- }
- },
- /**
- * @private
- */
- setGraphicContainerAttrs: function () {
- var chart = this.chart, label = chart.langFormat('accessibility.graphicContainerLabel', {
- chartTitle: getChartTitle(chart)
- });
- if (label.length) {
- chart.container.setAttribute('aria-label', label);
- }
- },
- /**
- * @private
- */
- setRenderToAttrs: function () {
- var chart = this.chart;
- if (chart.options.accessibility.landmarkVerbosity !== 'disabled') {
- chart.renderTo.setAttribute('role', 'region');
- }
- else {
- chart.renderTo.removeAttribute('role');
- }
- chart.renderTo.setAttribute('aria-label', chart.langFormat('accessibility.chartContainerLabel', {
- title: getChartTitle(chart),
- chart: chart
- }));
- },
- /**
- * @private
- */
- makeCreditsAccessible: function () {
- var chart = this.chart, credits = chart.credits;
- if (credits) {
- if (credits.textStr) {
- credits.element.setAttribute('aria-label', stripHTMLTags(chart.langFormat('accessibility.credits', { creditsStr: credits.textStr })));
- }
- unhideChartElementFromAT(chart, credits.element);
- }
- },
- /**
- * Accessibility disabled/chart destroyed.
- */
- destroy: function () {
- this.chart.renderTo.setAttribute('aria-hidden', true);
- }
- });
- return ContainerComponent;
- });
- _registerModule(_modules, 'modules/accessibility/high-contrast-mode.js', [_modules['parts/Globals.js']], function (H) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Handling for Windows High Contrast Mode.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var isMS = H.isMS, win = H.win, doc = win.document;
- var whcm = {
- /**
- * Detect WHCM in the browser.
- *
- * @function Highcharts#isHighContrastModeActive
- * @private
- * @return {boolean} Returns true if the browser is in High Contrast mode.
- */
- isHighContrastModeActive: function () {
- if (win.matchMedia &&
- isMS &&
- /Edge\/\d./i.test(win.navigator.userAgent)) {
- // Use media query for Edge
- return win.matchMedia('(-ms-high-contrast: active)').matches;
- }
- if (isMS && win.getComputedStyle) {
- // Test BG image for IE
- var testDiv = doc.createElement('div');
- testDiv.style.backgroundImage = 'url(#)';
- doc.body.appendChild(testDiv);
- var bi = (testDiv.currentStyle ||
- win.getComputedStyle(testDiv)).backgroundImage;
- doc.body.removeChild(testDiv);
- return bi === 'none';
- }
- // Not used for other browsers
- return false;
- },
- /**
- * Force high contrast theme for the chart. The default theme is defined in
- * a separate file.
- *
- * @function Highcharts#setHighContrastTheme
- * @private
- * @param {Highcharts.AccessibilityChart} chart The chart to set the theme of.
- * @return {void}
- */
- setHighContrastTheme: function (chart) {
- // We might want to add additional functionality here in the future for
- // storing the old state so that we can reset the theme if HC mode is
- // disabled. For now, the user will have to reload the page.
- chart.highContrastModeActive = true;
- // Apply theme to chart
- var theme = (chart.options.accessibility.highContrastTheme);
- chart.update(theme, false);
- // Force series colors (plotOptions is not enough)
- chart.series.forEach(function (s) {
- var plotOpts = theme.plotOptions[s.type] || {};
- s.update({
- color: plotOpts.color || 'windowText',
- colors: [plotOpts.color || 'windowText'],
- borderColor: plotOpts.borderColor || 'window'
- });
- // Force point colors if existing
- s.points.forEach(function (p) {
- if (p.options && p.options.color) {
- p.update({
- color: plotOpts.color || 'windowText',
- borderColor: plotOpts.borderColor || 'window'
- }, false);
- }
- });
- });
- // The redraw for each series and after is required for 3D pie
- // (workaround)
- chart.redraw();
- }
- };
- return whcm;
- });
- _registerModule(_modules, 'modules/accessibility/high-contrast-theme.js', [], function () {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Default theme for Windows High Contrast Mode.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var theme = {
- chart: {
- backgroundColor: 'window'
- },
- title: {
- style: {
- color: 'windowText'
- }
- },
- subtitle: {
- style: {
- color: 'windowText'
- }
- },
- colorAxis: {
- minColor: 'windowText',
- maxColor: 'windowText',
- stops: []
- },
- colors: ['windowText'],
- xAxis: {
- gridLineColor: 'windowText',
- labels: {
- style: {
- color: 'windowText'
- }
- },
- lineColor: 'windowText',
- minorGridLineColor: 'windowText',
- tickColor: 'windowText',
- title: {
- style: {
- color: 'windowText'
- }
- }
- },
- yAxis: {
- gridLineColor: 'windowText',
- labels: {
- style: {
- color: 'windowText'
- }
- },
- lineColor: 'windowText',
- minorGridLineColor: 'windowText',
- tickColor: 'windowText',
- title: {
- style: {
- color: 'windowText'
- }
- }
- },
- tooltip: {
- backgroundColor: 'window',
- borderColor: 'windowText',
- style: {
- color: 'windowText'
- }
- },
- plotOptions: {
- series: {
- lineColor: 'windowText',
- fillColor: 'window',
- borderColor: 'windowText',
- edgeColor: 'windowText',
- borderWidth: 1,
- dataLabels: {
- connectorColor: 'windowText',
- color: 'windowText',
- style: {
- color: 'windowText',
- textOutline: 'none'
- }
- },
- marker: {
- lineColor: 'windowText',
- fillColor: 'windowText'
- }
- },
- pie: {
- color: 'window',
- colors: ['window'],
- borderColor: 'windowText',
- borderWidth: 1
- },
- boxplot: {
- fillColor: 'window'
- },
- candlestick: {
- lineColor: 'windowText',
- fillColor: 'window'
- },
- errorbar: {
- fillColor: 'window'
- }
- },
- legend: {
- backgroundColor: 'window',
- itemStyle: {
- color: 'windowText'
- },
- itemHoverStyle: {
- color: 'windowText'
- },
- itemHiddenStyle: {
- color: '#555'
- },
- title: {
- style: {
- color: 'windowText'
- }
- }
- },
- credits: {
- style: {
- color: 'windowText'
- }
- },
- labels: {
- style: {
- color: 'windowText'
- }
- },
- drilldown: {
- activeAxisLabelStyle: {
- color: 'windowText'
- },
- activeDataLabelStyle: {
- color: 'windowText'
- }
- },
- navigation: {
- buttonOptions: {
- symbolStroke: 'windowText',
- theme: {
- fill: 'window'
- }
- }
- },
- rangeSelector: {
- buttonTheme: {
- fill: 'window',
- stroke: 'windowText',
- style: {
- color: 'windowText'
- },
- states: {
- hover: {
- fill: 'window',
- stroke: 'windowText',
- style: {
- color: 'windowText'
- }
- },
- select: {
- fill: '#444',
- stroke: 'windowText',
- style: {
- color: 'windowText'
- }
- }
- }
- },
- inputBoxBorderColor: 'windowText',
- inputStyle: {
- backgroundColor: 'window',
- color: 'windowText'
- },
- labelStyle: {
- color: 'windowText'
- }
- },
- navigator: {
- handles: {
- backgroundColor: 'window',
- borderColor: 'windowText'
- },
- outlineColor: 'windowText',
- maskFill: 'transparent',
- series: {
- color: 'windowText',
- lineColor: 'windowText'
- },
- xAxis: {
- gridLineColor: 'windowText'
- }
- },
- scrollbar: {
- barBackgroundColor: '#444',
- barBorderColor: 'windowText',
- buttonArrowColor: 'windowText',
- buttonBackgroundColor: 'window',
- buttonBorderColor: 'windowText',
- rifleColor: 'windowText',
- trackBackgroundColor: 'window',
- trackBorderColor: 'windowText'
- }
- };
- return theme;
- });
- _registerModule(_modules, 'modules/accessibility/options/options.js', [], function () {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Default options for accessibility.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- /**
- * Formatter callback for the accessibility announcement.
- *
- * @callback Highcharts.AccessibilityAnnouncementFormatter
- *
- * @param {Array<Highcharts.Series>} updatedSeries
- * Array of all series that received updates. If an announcement is already
- * queued, the series that received updates for that announcement are also
- * included in this array.
- *
- * @param {Highcharts.Series} [addedSeries]
- * This is provided if {@link Highcharts.Chart#addSeries} was called, and there
- * is a new series. In that case, this argument is a reference to the new
- * series.
- *
- * @param {Highcharts.Point} [addedPoint]
- * This is provided if {@link Highcharts.Series#addPoint} was called, and there
- * is a new point. In that case, this argument is a reference to the new point.
- *
- * @return {false|string}
- * The function should return a string with the text to announce to the user.
- * Return empty string to not announce anything. Return `false` to use the
- * default announcement format.
- */
- /**
- * @interface Highcharts.PointAccessibilityOptionsObject
- */ /**
- * Provide a description of the data point, announced to screen readers.
- * @name Highcharts.PointAccessibilityOptionsObject#description
- * @type {string|undefined}
- * @requires modules/accessibility
- * @since 7.1.0
- */
- /* *
- * @interface Highcharts.PointOptionsObject in parts/Point.ts
- */ /**
- * @name Highcharts.PointOptionsObject#accessibility
- * @type {Highcharts.PointAccessibilityOptionsObject|undefined}
- * @requires modules/accessibility
- * @since 7.1.0
- */
- /**
- * @callback Highcharts.ScreenReaderClickCallbackFunction
- *
- * @param {global.MouseEvent} evt
- * Mouse click event
- *
- * @return {void}
- */
- /**
- * Creates a formatted string for the screen reader module.
- *
- * @callback Highcharts.ScreenReaderFormatterCallbackFunction<T>
- *
- * @param {T} context
- * Context to format
- *
- * @return {string}
- * Formatted string for the screen reader module.
- */
- var options = {
- /**
- * Options for configuring accessibility for the chart. Requires the
- * [accessibility module](https://code.highcharts.com/modules/accessibility.js)
- * to be loaded. For a description of the module and information
- * on its features, see
- * [Highcharts Accessibility](http://www.highcharts.com/docs/chart-concepts/accessibility).
- *
- * @since 5.0.0
- * @requires modules/accessibility
- * @optionparent accessibility
- */
- accessibility: {
- /**
- * Enable accessibility functionality for the chart.
- *
- * @since 5.0.0
- */
- enabled: true,
- /**
- * Accessibility options for the screen reader information sections
- * added before and after the chart.
- *
- * @since 8.0.0
- */
- screenReaderSection: {
- /**
- * Function to run upon clicking the "View as Data Table" link in
- * the screen reader region.
- *
- * By default Highcharts will insert and set focus to a data table
- * representation of the chart.
- *
- * @type {Highcharts.ScreenReaderClickCallbackFunction}
- * @since 8.0.0
- * @apioption accessibility.screenReaderSection.onViewDataTableClick
- */
- /**
- * A formatter function to create the HTML contents of the hidden
- * screen reader information region before the chart. Receives one
- * argument, `chart`, referring to the chart object. Should return a
- * string with the HTML content of the region. By default this
- * returns an automatic description of the chart based on
- * [beforeChartFormat](#accessibility.screenReaderSection.beforeChartFormat).
- *
- * @type {Highcharts.ScreenReaderFormatterCallbackFunction<Highcharts.Chart>}
- * @since 8.0.0
- * @apioption accessibility.screenReaderSection.beforeChartFormatter
- */
- /**
- * Format for the screen reader information region before the chart.
- * Supported HTML tags are `<h1-7>`, `<p>`, `<div>`, `<a>`, and
- * `<button>`. Attributes are not supported, except for id on
- * `<div>`, `<a>`, and `<button>`. Id is required on `<a>` and
- * `<button>` in the format `<tag id="abcd">`. Numbers, lower- and
- * uppercase letters, "-" and "#" are valid characters in IDs.
- *
- * @since 8.0.0
- */
- beforeChartFormat: '<h5>{chartTitle}</h5>' +
- '<div>{typeDescription}</div>' +
- '<div>{chartSubtitle}</div>' +
- '<div>{chartLongdesc}</div>' +
- '<div>{xAxisDescription}</div>' +
- '<div>{yAxisDescription}</div>' +
- '<div>{viewTableButton}</div>',
- /**
- * A formatter function to create the HTML contents of the hidden
- * screen reader information region after the chart. Analogous to
- * [beforeChartFormatter](#accessibility.screenReaderSection.beforeChartFormatter).
- *
- * @type {Highcharts.ScreenReaderFormatterCallbackFunction<Highcharts.Chart>}
- * @since 8.0.0
- * @apioption accessibility.screenReaderSection.afterChartFormatter
- */
- /**
- * Format for the screen reader information region after the chart.
- * Analogous to [beforeChartFormat](#accessibility.screenReaderSection.beforeChartFormat).
- *
- * @since 8.0.0
- */
- afterChartFormat: '{endOfChartMarker}',
- /**
- * Date format to use to describe range of datetime axes.
- *
- * For an overview of the replacement codes, see
- * [dateFormat](/class-reference/Highcharts#dateFormat).
- *
- * @see [point.dateFormat](#accessibility.point.dateFormat)
- *
- * @since 8.0.0
- */
- axisRangeDateFormat: '%Y-%m-%d %H:%M:%S'
- },
- /**
- * Accessibility options global to all data series. Individual series
- * can also have specific [accessibility options](#plotOptions.series.accessibility)
- * set.
- *
- * @since 8.0.0
- */
- series: {
- /**
- * Formatter function to use instead of the default for series
- * descriptions. Receives one argument, `series`, referring to the
- * series to describe. Should return a string with the description
- * of the series for a screen reader user. If `false` is returned,
- * the default formatter will be used for that series.
- *
- * @see [series.description](#plotOptions.series.description)
- *
- * @type {Highcharts.ScreenReaderFormatterCallbackFunction<Highcharts.Series>}
- * @since 8.0.0
- * @apioption accessibility.series.descriptionFormatter
- */
- /**
- * Whether or not to add series descriptions to charts with a single
- * series.
- *
- * @since 8.0.0
- */
- describeSingleSeries: false,
- /**
- * When a series contains more points than this, we no longer expose
- * information about individual points to screen readers.
- *
- * Set to `false` to disable.
- *
- * @type {boolean|number}
- * @since 8.0.0
- */
- pointDescriptionEnabledThreshold: 200
- },
- /**
- * Amount of landmarks/regions to create for screen reader users. More
- * landmarks can make navigation with screen readers easier, but can
- * be distracting if there are lots of charts on the page. Three modes
- * are available:
- * - `all`: Adds regions for all series, legend, menu, information
- * region.
- * - `one`: Adds a single landmark per chart.
- * - `disabled`: No landmarks are added.
- *
- * @since 7.1.0
- * @validvalue ["all", "one", "disabled"]
- */
- landmarkVerbosity: 'all',
- /**
- * Link the chart to an HTML element describing the contents of the
- * chart.
- *
- * It is always recommended to describe charts using visible text, to
- * improve SEO as well as accessibility for users with disabilities.
- * This option lets an HTML element with a description be linked to the
- * chart, so that screen reader users can connect the two.
- *
- * By setting this option to a string, Highcharts runs the string as an
- * HTML selector query on the entire document. If there is only a single
- * match, this element is linked to the chart. The content of the linked
- * element will be included in the chart description for screen reader
- * users.
- *
- * By default, the chart looks for an adjacent sibling element with the
- * `highcharts-description` class.
- *
- * The feature can be disabled by setting the option to an empty string,
- * or overridden by providing the
- * [accessibility.description](#accessibility.description) option.
- * Alternatively, the HTML element to link can be passed in directly as
- * an HTML node.
- *
- * If you need the description to be part of the exported image,
- * consider using the [caption](#caption) feature.
- *
- * If you need the description to be hidden visually, use the
- * [accessibility.description](#accessibility.description) option.
- *
- * @see [caption](#caption)
- * @see [description](#accessibility.description)
- * @see [typeDescription](#accessibility.typeDescription)
- *
- * @sample highcharts/accessibility/accessible-line
- * Accessible line chart
- *
- * @type {string|Highcharts.HTMLDOMElement}
- * @since 8.0.0
- */
- linkedDescription: '*[data-highcharts-chart="{index}"] + .highcharts-description',
- /**
- * A hook for adding custom components to the accessibility module.
- * Should be an object mapping component names to instances of classes
- * inheriting from the Highcharts.AccessibilityComponent base class.
- * Remember to add the component to the
- * [keyboardNavigation.order](#accessibility.keyboardNavigation.order)
- * for the keyboard navigation to be usable.
- *
- * @sample highcharts/accessibility/custom-component
- * Custom accessibility component
- *
- * @type {*}
- * @since 7.1.0
- * @apioption accessibility.customComponents
- */
- /**
- * Theme to apply to the chart when Windows High Contrast Mode is
- * detected. By default, a high contrast theme matching the high
- * contrast system system colors is used.
- *
- * @type {*}
- * @since 7.1.3
- * @apioption accessibility.highContrastTheme
- */
- /**
- * A text description of the chart.
- *
- * **Note: Prefer using [linkedDescription](#accessibility.linkedDescription)
- * or [caption](#caption.text) instead.**
- *
- * If the Accessibility module is loaded, this option is included by
- * default as a long description of the chart in the hidden screen
- * reader information region.
- *
- * Note: Since Highcharts now supports captions and linked descriptions,
- * it is preferred to define the description using those methods, as a
- * visible caption/description benefits all users. If the
- * `accessibility.description` option is defined, the linked description
- * is ignored, and the caption is hidden from screen reader users.
- *
- * @see [linkedDescription](#accessibility.linkedDescription)
- * @see [caption](#caption)
- * @see [typeDescription](#accessibility.typeDescription)
- *
- * @type {string}
- * @since 5.0.0
- * @apioption accessibility.description
- */
- /**
- * A text description of the chart type.
- *
- * If the Accessibility module is loaded, this will be included in the
- * description of the chart in the screen reader information region.
- *
- * Highcharts will by default attempt to guess the chart type, but for
- * more complex charts it is recommended to specify this property for
- * clarity.
- *
- * @type {string}
- * @since 5.0.0
- * @apioption accessibility.typeDescription
- */
- /**
- * Options for descriptions of individual data points.
- *
- * @since 8.0.0
- * @apioption accessibility.point
- */
- /**
- * Date format to use for points on datetime axes when describing them
- * to screen reader users.
- *
- * Defaults to the same format as in tooltip.
- *
- * For an overview of the replacement codes, see
- * [dateFormat](/class-reference/Highcharts#dateFormat).
- *
- * @see [dateFormatter](#accessibility.point.dateFormatter)
- *
- * @type {string}
- * @since 8.0.0
- * @apioption accessibility.point.dateFormat
- */
- /**
- * Formatter function to determine the date/time format used with
- * points on datetime axes when describing them to screen reader users.
- * Receives one argument, `point`, referring to the point to describe.
- * Should return a date format string compatible with
- * [dateFormat](/class-reference/Highcharts#dateFormat).
- *
- * @see [dateFormat](#accessibility.point.dateFormat)
- *
- * @type {Highcharts.ScreenReaderFormatterCallbackFunction<Highcharts.Point>}
- * @since 8.0.0
- * @apioption accessibility.point.dateFormatter
- */
- /**
- * Prefix to add to the values in the point descriptions. Uses
- * [tooltip.valuePrefix](#tooltip.valuePrefix) if not defined.
- *
- * @type {string}
- * @since 8.0.0
- * @apioption accessibility.point.valuePrefix
- */
- /**
- * Suffix to add to the values in the point descriptions. Uses
- * [tooltip.valueSuffix](#tooltip.valueSuffix) if not defined.
- *
- * @type {string}
- * @since 8.0.0
- * @apioption accessibility.point.valueSuffix
- */
- /**
- * Decimals to use for the values in the point descriptions. Uses
- * [tooltip.valueDecimals](#tooltip.valueDecimals) if not defined.
- *
- * @type {number}
- * @since 8.0.0
- * @apioption accessibility.point.valueDecimals
- */
- /**
- * Formatter function to use instead of the default for point
- * descriptions.
- * Receives one argument, `point`, referring to the point to describe.
- * Should return a string with the description of the point for a screen
- * reader user. If `false` is returned, the default formatter will be
- * used for that point.
- *
- * @see [point.accessibility.description](#series.line.data.accessibility.description)
- *
- * @type {Highcharts.ScreenReaderFormatterCallbackFunction<Highcharts.Point>}
- * @since 8.0.0
- * @apioption accessibility.point.descriptionFormatter
- */
- /**
- * Options for keyboard navigation.
- *
- * @declare Highcharts.KeyboardNavigationOptionsObject
- * @since 5.0.0
- */
- keyboardNavigation: {
- /**
- * Enable keyboard navigation for the chart.
- *
- * @since 5.0.0
- */
- enabled: true,
- /**
- * Options for the focus border drawn around elements while
- * navigating through them.
- *
- * @sample highcharts/accessibility/custom-focus
- * Custom focus ring
- *
- * @declare Highcharts.KeyboardNavigationFocusBorderOptionsObject
- * @since 6.0.3
- */
- focusBorder: {
- /**
- * Enable/disable focus border for chart.
- *
- * @since 6.0.3
- */
- enabled: true,
- /**
- * Hide the browser's default focus indicator.
- *
- * @since 6.0.4
- */
- hideBrowserFocusOutline: true,
- /**
- * Style options for the focus border drawn around elements
- * while navigating through them. Note that some browsers in
- * addition draw their own borders for focused elements. These
- * automatic borders can not be styled by Highcharts.
- *
- * In styled mode, the border is given the
- * `.highcharts-focus-border` class.
- *
- * @type {Highcharts.CSSObject}
- * @since 6.0.3
- */
- style: {
- /** @internal */
- color: '#335cad',
- /** @internal */
- lineWidth: 2,
- /** @internal */
- borderRadius: 3
- },
- /**
- * Focus border margin around the elements.
- *
- * @since 6.0.3
- */
- margin: 2
- },
- /**
- * Order of tab navigation in the chart. Determines which elements
- * are tabbed to first. Available elements are: `series`, `zoom`,
- * `rangeSelector`, `chartMenu`, `legend`. In addition, any custom
- * components can be added here.
- *
- * @type {Array<string>}
- * @since 7.1.0
- */
- order: ['series', 'zoom', 'rangeSelector', 'legend', 'chartMenu'],
- /**
- * Whether or not to wrap around when reaching the end of arrow-key
- * navigation for an element in the chart.
- * @since 7.1.0
- */
- wrapAround: true,
- /**
- * Options for the keyboard navigation of data points and series.
- *
- * @declare Highcharts.KeyboardNavigationSeriesNavigationOptionsObject
- * @since 8.0.0
- */
- seriesNavigation: {
- /**
- * Set the keyboard navigation mode for the chart. Can be
- * "normal" or "serialize". In normal mode, left/right arrow
- * keys move between points in a series, while up/down arrow
- * keys move between series. Up/down navigation acts
- * intelligently to figure out which series makes sense to move
- * to from any given point.
- *
- * In "serialize" mode, points are instead navigated as a single
- * list. Left/right behaves as in "normal" mode. Up/down arrow
- * keys will behave like left/right. This can be useful for
- * unifying navigation behavior with/without screen readers
- * enabled.
- *
- * @type {string}
- * @default normal
- * @since 8.0.0
- * @validvalue ["normal", "serialize"]
- * @apioption accessibility.keyboardNavigation.seriesNavigation.mode
- */
- /**
- * Skip null points when navigating through points with the
- * keyboard.
- *
- * @since 8.0.0
- */
- skipNullPoints: true,
- /**
- * When a series contains more points than this, we no longer
- * allow keyboard navigation for it.
- *
- * Set to `false` to disable.
- *
- * @type {boolean|number}
- * @since 8.0.0
- */
- pointNavigationEnabledThreshold: false
- }
- },
- /**
- * Options for announcing new data to screen reader users. Useful
- * for dynamic data applications and drilldown.
- *
- * Keep in mind that frequent announcements will not be useful to
- * users, as they won't have time to explore the new data. For these
- * applications, consider making snapshots of the data accessible, and
- * do the announcements in batches.
- *
- * @declare Highcharts.AccessibilityAnnounceNewDataOptionsObject
- * @since 7.1.0
- */
- announceNewData: {
- /**
- * Optional formatter callback for the announcement. Receives
- * up to three arguments. The first argument is always an array
- * of all series that received updates. If an announcement is
- * already queued, the series that received updates for that
- * announcement are also included in this array. The second
- * argument is provided if `chart.addSeries` was called, and
- * there is a new series. In that case, this argument is a
- * reference to the new series. The third argument, similarly,
- * is provided if `series.addPoint` was called, and there is a
- * new point. In that case, this argument is a reference to the
- * new point.
- *
- * The function should return a string with the text to announce
- * to the user. Return empty string to not announce anything.
- * Return `false` to use the default announcement format.
- *
- * @sample highcharts/accessibility/custom-dynamic
- * High priority live alerts
- *
- * @type {Highcharts.AccessibilityAnnouncementFormatter}
- * @apioption accessibility.announceNewData.announcementFormatter
- */
- /**
- * Enable announcing new data to screen reader users
- * @sample highcharts/accessibility/accessible-dynamic
- * Dynamic data accessible
- */
- enabled: false,
- /**
- * Minimum interval between announcements in milliseconds. If
- * new data arrives before this amount of time has passed, it is
- * queued for announcement. If another new data event happens
- * while an announcement is queued, the queued announcement is
- * dropped, and the latest announcement is queued instead. Set
- * to 0 to allow all announcements, but be warned that frequent
- * announcements are disturbing to users.
- */
- minAnnounceInterval: 5000,
- /**
- * Choose whether or not the announcements should interrupt the
- * screen reader. If not enabled, the user will be notified once
- * idle. It is recommended not to enable this setting unless
- * there is a specific reason to do so.
- */
- interruptUser: false
- }
- },
- /**
- * Accessibility options for a data point.
- *
- * @declare Highcharts.PointAccessibilityOptionsObject
- * @since 7.1.0
- * @apioption series.line.data.accessibility
- */
- /**
- * Provide a description of the data point, announced to screen readers.
- *
- * @type {string}
- * @since 7.1.0
- * @apioption series.line.data.accessibility.description
- */
- /**
- * Accessibility options for a series.
- *
- * @declare Highcharts.SeriesAccessibilityOptionsObject
- * @since 7.1.0
- * @requires modules/accessibility
- * @apioption plotOptions.series.accessibility
- */
- /**
- * Enable/disable accessibility functionality for a specific series.
- *
- * @type {boolean}
- * @since 7.1.0
- * @apioption plotOptions.series.accessibility.enabled
- */
- /**
- * Provide a description of the series, announced to screen readers.
- *
- * @type {string}
- * @since 7.1.0
- * @apioption plotOptions.series.accessibility.description
- */
- /**
- * Formatter function to use instead of the default for point
- * descriptions. Same as `accessibility.point.descriptionFormatter`, but for
- * a single series.
- *
- * @see [accessibility.point.descriptionFormatter](#accessibility.point.descriptionFormatter)
- *
- * @type {Highcharts.ScreenReaderFormatterCallbackFunction<Highcharts.Point>}
- * @since 7.1.0
- * @apioption plotOptions.series.accessibility.pointDescriptionFormatter
- */
- /**
- * Expose only the series element to screen readers, not its points.
- *
- * @type {boolean}
- * @since 7.1.0
- * @apioption plotOptions.series.accessibility.exposeAsGroupOnly
- */
- /**
- * Keyboard navigation for a series
- *
- * @declare Highcharts.SeriesAccessibilityKeyboardNavigationOptionsObject
- * @since 7.1.0
- * @apioption plotOptions.series.accessibility.keyboardNavigation
- */
- /**
- * Enable/disable keyboard navigation support for a specific series.
- *
- * @type {boolean}
- * @since 7.1.0
- * @apioption plotOptions.series.accessibility.keyboardNavigation.enabled
- */
- /**
- * Accessibility options for an axis. Requires the accessibility module.
- *
- * @declare Highcharts.AxisAccessibilityOptionsObject
- * @since 7.1.0
- * @requires modules/accessibility
- * @apioption xAxis.accessibility
- */
- /**
- * Enable axis accessibility features, including axis information in the
- * screen reader information region. If this is disabled on the xAxis, the
- * x values are not exposed to screen readers for the individual data points
- * by default.
- *
- * @type {boolean}
- * @since 7.1.0
- * @apioption xAxis.accessibility.enabled
- */
- /**
- * Description for an axis to expose to screen reader users.
- *
- * @type {string}
- * @since 7.1.0
- * @apioption xAxis.accessibility.description
- */
- /**
- * Range description for an axis. Overrides the default range description.
- * Set to empty to disable range description for this axis.
- *
- * @type {string}
- * @since 7.1.0
- * @apioption xAxis.accessibility.rangeDescription
- */
- legend: {
- /**
- * Accessibility options for the legend. Requires the Accessibility
- * module.
- *
- * @since 7.1.0
- * @requires modules/accessibility
- * @apioption legend.accessibility
- */
- accessibility: {
- /**
- * Enable accessibility support for the legend.
- *
- * @since 7.1.0
- * @apioption legend.accessibility.enabled
- */
- enabled: true,
- /**
- * Options for keyboard navigation for the legend.
- *
- * @since 7.1.0
- * @requires modules/accessibility
- * @apioption legend.accessibility.keyboardNavigation
- */
- keyboardNavigation: {
- /**
- * Enable keyboard navigation for the legend.
- *
- * @see [accessibility.keyboardNavigation](#accessibility.keyboardNavigation.enabled)
- *
- * @since 7.1.0
- * @apioption legend.accessibility.keyboardNavigation.enabled
- */
- enabled: true
- }
- }
- },
- exporting: {
- /**
- * Accessibility options for the exporting menu. Requires the
- * Accessibility module.
- *
- * @since 7.1.0
- * @requires modules/accessibility
- * @apioption exporting.accessibility
- */
- accessibility: {
- /**
- * Enable accessibility support for the export menu.
- *
- * @since 7.1.0
- * @apioption exporting.accessibility.enabled
- */
- enabled: true
- }
- }
- };
- return options;
- });
- _registerModule(_modules, 'modules/accessibility/options/langOptions.js', [], function () {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Default lang/i18n options for accessibility.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var langOptions = {
- /**
- * Configure the accessibility strings in the chart. Requires the
- * [accessibility module](https://code.highcharts.com/modules/accessibility.js)
- * to be loaded. For a description of the module and information on its
- * features, see
- * [Highcharts Accessibility](https://www.highcharts.com/docs/chart-concepts/accessibility).
- *
- * For more dynamic control over the accessibility functionality, see
- * [accessibility.pointDescriptionFormatter](#accessibility.pointDescriptionFormatter),
- * [accessibility.seriesDescriptionFormatter](#accessibility.seriesDescriptionFormatter),
- * and
- * [accessibility.screenReaderSectionFormatter](#accessibility.screenReaderSectionFormatter).
- *
- * @since 6.0.6
- * @optionparent lang.accessibility
- */
- accessibility: {
- defaultChartTitle: 'Chart',
- chartContainerLabel: '{title}. Highcharts interactive chart.',
- svgContainerLabel: 'Interactive chart',
- drillUpButton: '{buttonText}',
- credits: 'Chart credits: {creditsStr}',
- /**
- * Thousands separator to use when formatting numbers for screen
- * readers. Note that many screen readers will not handle space as a
- * thousands separator, and will consider "11 700" as two numbers.
- *
- * Set to `null` to use the separator defined in
- * [lang.thousandsSep](lang.thousandsSep).
- *
- * @since 7.1.0
- */
- thousandsSep: ',',
- /**
- * Title element text for the chart SVG element. Leave this
- * empty to disable adding the title element. Browsers will display
- * this content when hovering over elements in the chart. Assistive
- * technology may use this element to label the chart.
- *
- * @since 6.0.8
- */
- svgContainerTitle: '',
- /**
- * Set a label on the container wrapping the SVG.
- *
- * @see [chartContainerLabel](#lang.accessibility.chartContainerLabel)
- *
- * @since 8.0.0
- */
- graphicContainerLabel: '',
- /**
- * Language options for the screen reader information sections added
- * before and after the charts.
- *
- * @since 8.0.0
- */
- screenReaderSection: {
- beforeRegionLabel: 'Chart screen reader information.',
- afterRegionLabel: '',
- /**
- * Label for the end of the chart. Announced by screen readers.
- *
- * @since 8.0.0
- */
- endOfChartMarker: 'End of interactive chart.'
- },
- /**
- * Language options for accessibility of the legend.
- *
- * @since 8.0.0
- */
- legend: {
- legendLabel: 'Toggle series visibility',
- legendItem: 'Toggle visibility of {itemName}'
- },
- /**
- * Chart and map zoom accessibility language options.
- *
- * @since 8.0.0
- */
- zoom: {
- mapZoomIn: 'Zoom chart',
- mapZoomOut: 'Zoom out chart',
- resetZoomButton: 'Reset zoom'
- },
- /**
- * Range selector language options for accessibility.
- *
- * @since 8.0.0
- */
- rangeSelector: {
- minInputLabel: 'Select start date.',
- maxInputLabel: 'Select end date.',
- buttonText: 'Select range {buttonText}'
- },
- /**
- * Accessibility language options for the data table.
- *
- * @since 8.0.0
- */
- table: {
- viewAsDataTableButtonText: 'View as data table. {chartTitle}',
- tableSummary: 'Table representation of chart.'
- },
- /**
- * Default announcement for new data in charts. If addPoint or
- * addSeries is used, and only one series/point is added, the
- * `newPointAnnounce` and `newSeriesAnnounce` strings are used.
- * The `...Single` versions will be used if there is only one chart
- * on the page, and the `...Multiple` versions will be used if there
- * are multiple charts on the page. For all other new data events,
- * the `newDataAnnounce` string will be used.
- *
- * @since 7.1.0
- */
- announceNewData: {
- newDataAnnounce: 'Updated data for chart {chartTitle}',
- newSeriesAnnounceSingle: 'New data series: {seriesDesc}',
- newPointAnnounceSingle: 'New data point: {pointDesc}',
- newSeriesAnnounceMultiple: 'New data series in chart {chartTitle}: {seriesDesc}',
- newPointAnnounceMultiple: 'New data point in chart {chartTitle}: {pointDesc}'
- },
- /**
- * Descriptions of lesser known series types. The relevant
- * description is added to the screen reader information region
- * when these series types are used.
- *
- * @since 6.0.6
- */
- seriesTypeDescriptions: {
- boxplot: 'Box plot charts are typically used to display ' +
- 'groups of statistical data. Each data point in the ' +
- 'chart can have up to 5 values: minimum, lower quartile, ' +
- 'median, upper quartile, and maximum.',
- arearange: 'Arearange charts are line charts displaying a ' +
- 'range between a lower and higher value for each point.',
- areasplinerange: 'These charts are line charts displaying a ' +
- 'range between a lower and higher value for each point.',
- bubble: 'Bubble charts are scatter charts where each data ' +
- 'point also has a size value.',
- columnrange: 'Columnrange charts are column charts ' +
- 'displaying a range between a lower and higher value for ' +
- 'each point.',
- errorbar: 'Errorbar series are used to display the ' +
- 'variability of the data.',
- funnel: 'Funnel charts are used to display reduction of data ' +
- 'in stages.',
- pyramid: 'Pyramid charts consist of a single pyramid with ' +
- 'item heights corresponding to each point value.',
- waterfall: 'A waterfall chart is a column chart where each ' +
- 'column contributes towards a total end value.'
- },
- /**
- * Chart type description strings. This is added to the chart
- * information region.
- *
- * If there is only a single series type used in the chart, we use
- * the format string for the series type, or default if missing.
- * There is one format string for cases where there is only a single
- * series in the chart, and one for multiple series of the same
- * type.
- *
- * @since 6.0.6
- */
- chartTypes: {
- /* eslint-disable max-len */
- emptyChart: 'Empty chart',
- mapTypeDescription: 'Map of {mapTitle} with {numSeries} data series.',
- unknownMap: 'Map of unspecified region with {numSeries} data series.',
- combinationChart: 'Combination chart with {numSeries} data series.',
- defaultSingle: 'Chart with {numPoints} data {#plural(numPoints, points, point)}.',
- defaultMultiple: 'Chart with {numSeries} data series.',
- splineSingle: 'Line chart with {numPoints} data {#plural(numPoints, points, point)}.',
- splineMultiple: 'Line chart with {numSeries} lines.',
- lineSingle: 'Line chart with {numPoints} data {#plural(numPoints, points, point)}.',
- lineMultiple: 'Line chart with {numSeries} lines.',
- columnSingle: 'Bar chart with {numPoints} {#plural(numPoints, bars, bar)}.',
- columnMultiple: 'Bar chart with {numSeries} data series.',
- barSingle: 'Bar chart with {numPoints} {#plural(numPoints, bars, bar)}.',
- barMultiple: 'Bar chart with {numSeries} data series.',
- pieSingle: 'Pie chart with {numPoints} {#plural(numPoints, slices, slice)}.',
- pieMultiple: 'Pie chart with {numSeries} pies.',
- scatterSingle: 'Scatter chart with {numPoints} {#plural(numPoints, points, point)}.',
- scatterMultiple: 'Scatter chart with {numSeries} data series.',
- boxplotSingle: 'Boxplot with {numPoints} {#plural(numPoints, boxes, box)}.',
- boxplotMultiple: 'Boxplot with {numSeries} data series.',
- bubbleSingle: 'Bubble chart with {numPoints} {#plural(numPoints, bubbles, bubble)}.',
- bubbleMultiple: 'Bubble chart with {numSeries} data series.'
- },
- /**
- * Axis description format strings.
- *
- * @since 6.0.6
- */
- axis: {
- /* eslint-disable max-len */
- xAxisDescriptionSingular: 'The chart has 1 X axis displaying {names[0]}. {ranges[0]}',
- xAxisDescriptionPlural: 'The chart has {numAxes} X axes displaying {#each(names, -1) }and {names[-1]}.',
- yAxisDescriptionSingular: 'The chart has 1 Y axis displaying {names[0]}. {ranges[0]}',
- yAxisDescriptionPlural: 'The chart has {numAxes} Y axes displaying {#each(names, -1) }and {names[-1]}.',
- timeRangeDays: 'Range: {range} days.',
- timeRangeHours: 'Range: {range} hours.',
- timeRangeMinutes: 'Range: {range} minutes.',
- timeRangeSeconds: 'Range: {range} seconds.',
- rangeFromTo: 'Range: {rangeFrom} to {rangeTo}.',
- rangeCategories: 'Range: {numCategories} categories.'
- },
- /**
- * Exporting menu format strings for accessibility module.
- *
- * @since 6.0.6
- */
- exporting: {
- chartMenuLabel: 'Chart menu',
- menuButtonLabel: 'View chart menu',
- exportRegionLabel: 'Chart menu'
- },
- /**
- * Lang configuration for different series types. For more dynamic
- * control over the series element descriptions, see
- * [accessibility.seriesDescriptionFormatter](#accessibility.seriesDescriptionFormatter).
- *
- * @since 6.0.6
- */
- series: {
- /**
- * Lang configuration for the series main summary. Each series
- * type has two modes:
- *
- * 1. This series type is the only series type used in the
- * chart
- *
- * 2. This is a combination chart with multiple series types
- *
- * If a definition does not exist for the specific series type
- * and mode, the 'default' lang definitions are used.
- *
- * @since 6.0.6
- */
- summary: {
- /* eslint-disable max-len */
- 'default': '{name}, series {ix} of {numSeries} with {numPoints} data {#plural(numPoints, points, point)}.',
- defaultCombination: '{name}, series {ix} of {numSeries} with {numPoints} data {#plural(numPoints, points, point)}.',
- line: '{name}, line {ix} of {numSeries} with {numPoints} data {#plural(numPoints, points, point)}.',
- lineCombination: '{name}, series {ix} of {numSeries}. Line with {numPoints} data {#plural(numPoints, points, point)}.',
- spline: '{name}, line {ix} of {numSeries} with {numPoints} data {#plural(numPoints, points, point)}.',
- splineCombination: '{name}, series {ix} of {numSeries}. Line with {numPoints} data {#plural(numPoints, points, point)}.',
- column: '{name}, bar series {ix} of {numSeries} with {numPoints} {#plural(numPoints, bars, bar)}.',
- columnCombination: '{name}, series {ix} of {numSeries}. Bar series with {numPoints} {#plural(numPoints, bars, bar)}.',
- bar: '{name}, bar series {ix} of {numSeries} with {numPoints} {#plural(numPoints, bars, bar)}.',
- barCombination: '{name}, series {ix} of {numSeries}. Bar series with {numPoints} {#plural(numPoints, bars, bar)}.',
- pie: '{name}, pie {ix} of {numSeries} with {numPoints} {#plural(numPoints, slices, slice)}.',
- pieCombination: '{name}, series {ix} of {numSeries}. Pie with {numPoints} {#plural(numPoints, slices, slice)}.',
- scatter: '{name}, scatter plot {ix} of {numSeries} with {numPoints} {#plural(numPoints, points, point)}.',
- scatterCombination: '{name}, series {ix} of {numSeries}, scatter plot with {numPoints} {#plural(numPoints, points, point)}.',
- boxplot: '{name}, boxplot {ix} of {numSeries} with {numPoints} {#plural(numPoints, boxes, box)}.',
- boxplotCombination: '{name}, series {ix} of {numSeries}. Boxplot with {numPoints} {#plural(numPoints, boxes, box)}.',
- bubble: '{name}, bubble series {ix} of {numSeries} with {numPoints} {#plural(numPoints, bubbles, bubble)}.',
- bubbleCombination: '{name}, series {ix} of {numSeries}. Bubble series with {numPoints} {#plural(numPoints, bubbles, bubble)}.',
- map: '{name}, map {ix} of {numSeries} with {numPoints} {#plural(numPoints, areas, area)}.',
- mapCombination: '{name}, series {ix} of {numSeries}. Map with {numPoints} {#plural(numPoints, areas, area)}.',
- mapline: '{name}, line {ix} of {numSeries} with {numPoints} data {#plural(numPoints, points, point)}.',
- maplineCombination: '{name}, series {ix} of {numSeries}. Line with {numPoints} data {#plural(numPoints, points, point)}.',
- mapbubble: '{name}, bubble series {ix} of {numSeries} with {numPoints} {#plural(numPoints, bubbles, bubble)}.',
- mapbubbleCombination: '{name}, series {ix} of {numSeries}. Bubble series with {numPoints} {#plural(numPoints, bubbles, bubble)}.'
- },
- /**
- * User supplied description text. This is added after the main
- * summary if present.
- *
- * @since 6.0.6
- */
- description: '{description}',
- /**
- * xAxis description for series if there are multiple xAxes in
- * the chart.
- *
- * @since 6.0.6
- */
- xAxisDescription: 'X axis, {name}',
- /**
- * yAxis description for series if there are multiple yAxes in
- * the chart.
- *
- * @since 6.0.6
- */
- yAxisDescription: 'Y axis, {name}',
- /**
- * Description for the value of null points.
- *
- * @since 8.0.0
- */
- nullPointValue: 'No value'
- }
- }
- };
- return langOptions;
- });
- _registerModule(_modules, 'modules/accessibility/options/deprecatedOptions.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Default options for accessibility.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- /* eslint-disable max-len */
- /*
- * List of deprecated options:
- *
- * chart.description -> accessibility.description
- * chart.typeDescription -> accessibility.typeDescription
- * series.description -> series.accessibility.description
- * series.exposeElementToA11y -> series.accessibility.exposeAsGroupOnly
- * series.pointDescriptionFormatter ->
- * series.accessibility.pointDescriptionFormatter
- * series.skipKeyboardNavigation ->
- * series.accessibility.keyboardNavigation.enabled
- * point.description -> point.accessibility.description !!!! WARNING: No longer deprecated and handled, removed for HC8.
- * axis.description -> axis.accessibility.description
- *
- * accessibility.pointDateFormat -> accessibility.point.dateFormat
- * accessibility.addTableShortcut -> Handled by screenReaderSection.beforeChartFormat
- * accessibility.pointDateFormatter -> accessibility.point.dateFormatter
- * accessibility.pointDescriptionFormatter -> accessibility.point.descriptionFormatter
- * accessibility.pointDescriptionThreshold -> accessibility.series.pointDescriptionEnabledThreshold
- * accessibility.pointNavigationThreshold -> accessibility.keyboardNavigation.seriesNavigation.pointNavigationEnabledThreshold
- * accessibility.pointValueDecimals -> accessibility.point.valueDecimals
- * accessibility.pointValuePrefix -> accessibility.point.valuePrefix
- * accessibility.pointValueSuffix -> accessibility.point.valueSuffix
- * accessibility.screenReaderSectionFormatter -> accessibility.screenReaderSection.beforeChartFormatter
- * accessibility.describeSingleSeries -> accessibility.series.describeSingleSeries
- * accessibility.seriesDescriptionFormatter -> accessibility.series.descriptionFormatter
- * accessibility.onTableAnchorClick -> accessibility.screenReaderSection.onViewDataTableClick
- * accessibility.axisRangeDateFormat -> accessibility.screenReaderSection.axisRangeDateFormat
- * accessibility.keyboardNavigation.skipNullPoints -> accessibility.keyboardNavigation.seriesNavigation.skipNullPoints
- * accessibility.keyboardNavigation.mode -> accessibility.keyboardNavigation.seriesNavigation.mode
- *
- * lang.accessibility.chartHeading -> no longer used, remove
- * lang.accessibility.legendItem -> lang.accessibility.legend.legendItem
- * lang.accessibility.legendLabel -> lang.accessibility.legend.legendLabel
- * lang.accessibility.mapZoomIn -> lang.accessibility.zoom.mapZoomIn
- * lang.accessibility.mapZoomOut -> lang.accessibility.zoom.mapZoomOut
- * lang.accessibility.resetZoomButton -> lang.accessibility.zoom.resetZoomButton
- * lang.accessibility.screenReaderRegionLabel -> lang.accessibility.screenReaderSection.beforeRegionLabel
- * lang.accessibility.rangeSelectorButton -> lang.accessibility.rangeSelector.buttonText
- * lang.accessibility.rangeSelectorMaxInput -> lang.accessibility.rangeSelector.maxInputLabel
- * lang.accessibility.rangeSelectorMinInput -> lang.accessibility.rangeSelector.minInputLabel
- * lang.accessibility.svgContainerEnd -> lang.accessibility.screenReaderSection.endOfChartMarker
- * lang.accessibility.viewAsDataTable -> lang.accessibility.table.viewAsDataTableButtonText
- * lang.accessibility.tableSummary -> lang.accessibility.table.tableSummary
- *
- */
- /* eslint-enable max-len */
- var error = H.error;
- var pick = U.pick;
- /* eslint-disable valid-jsdoc */
- /**
- * Warn user that a deprecated option was used.
- * @private
- * @param {Highcharts.Chart} chart
- * @param {string} oldOption
- * @param {string} newOption
- * @return {void}
- */
- function warn(chart, oldOption, newOption) {
- error('Highcharts: Deprecated option ' + oldOption +
- ' used. This will be removed from future versions of Highcharts. Use ' +
- newOption + ' instead.', false, chart);
- }
- /**
- * Set a new option on a root prop, where the option is defined as an array of
- * suboptions.
- * @private
- * @param root
- * @param {Array<string>} optionAsArray
- * @param {*} val
- * @return {void}
- */
- function traverseSetOption(root, optionAsArray, val) {
- var opt = root, prop, i = 0;
- for (; i < optionAsArray.length - 1; ++i) {
- prop = optionAsArray[i];
- opt = opt[prop] = pick(opt[prop], {});
- }
- opt[optionAsArray[optionAsArray.length - 1]] = val;
- }
- /**
- * If we have a clear root option node for old and new options and a mapping
- * between, we can use this generic function for the copy and warn logic.
- */
- function deprecateFromOptionsMap(chart, rootOldAsArray, rootNewAsArray, mapToNewOptions) {
- /**
- * @private
- */
- function getChildProp(root, propAsArray) {
- return propAsArray.reduce(function (acc, cur) {
- return acc[cur];
- }, root);
- }
- var rootOld = getChildProp(chart.options, rootOldAsArray), rootNew = getChildProp(chart.options, rootNewAsArray);
- Object.keys(mapToNewOptions).forEach(function (oldOptionKey) {
- var val = rootOld[oldOptionKey];
- if (typeof val !== 'undefined') {
- traverseSetOption(rootNew, mapToNewOptions[oldOptionKey], val);
- warn(chart, rootOldAsArray.join('.') + '.' + oldOptionKey, rootNewAsArray.join('.') + '.' +
- mapToNewOptions[oldOptionKey].join('.'));
- }
- });
- }
- /**
- * @private
- */
- function copyDeprecatedChartOptions(chart) {
- var chartOptions = chart.options.chart || {}, a11yOptions = chart.options.accessibility || {};
- ['description', 'typeDescription'].forEach(function (prop) {
- if (chartOptions[prop]) {
- a11yOptions[prop] = chartOptions[prop];
- warn(chart, 'chart.' + prop, 'accessibility.' + prop);
- }
- });
- }
- /**
- * @private
- */
- function copyDeprecatedAxisOptions(chart) {
- chart.axes.forEach(function (axis) {
- var opts = axis.options;
- if (opts && opts.description) {
- opts.accessibility = opts.accessibility || {};
- opts.accessibility.description = opts.description;
- warn(chart, 'axis.description', 'axis.accessibility.description');
- }
- });
- }
- /**
- * @private
- */
- function copyDeprecatedSeriesOptions(chart) {
- // Map of deprecated series options. New options are defined as
- // arrays of paths under series.options.
- var oldToNewSeriesOptions = {
- description: ['accessibility', 'description'],
- exposeElementToA11y: ['accessibility', 'exposeAsGroupOnly'],
- pointDescriptionFormatter: [
- 'accessibility', 'pointDescriptionFormatter'
- ],
- skipKeyboardNavigation: [
- 'accessibility', 'keyboardNavigation', 'enabled'
- ]
- };
- chart.series.forEach(function (series) {
- // Handle series wide options
- Object.keys(oldToNewSeriesOptions).forEach(function (oldOption) {
- var optionVal = series.options[oldOption];
- if (typeof optionVal !== 'undefined') {
- // Set the new option
- traverseSetOption(series.options, oldToNewSeriesOptions[oldOption],
- // Note that skipKeyboardNavigation has inverted option
- // value, since we set enabled rather than disabled
- oldOption === 'skipKeyboardNavigation' ?
- !optionVal : optionVal);
- warn(chart, 'series.' + oldOption, 'series.' +
- oldToNewSeriesOptions[oldOption].join('.'));
- }
- });
- });
- }
- /**
- * @private
- */
- function copyDeprecatedTopLevelAccessibilityOptions(chart) {
- deprecateFromOptionsMap(chart, ['accessibility'], ['accessibility'], {
- pointDateFormat: ['point', 'dateFormat'],
- pointDateFormatter: ['point', 'dateFormatter'],
- pointDescriptionFormatter: ['point', 'descriptionFormatter'],
- pointDescriptionThreshold: ['series',
- 'pointDescriptionEnabledThreshold'],
- pointNavigationThreshold: ['keyboardNavigation', 'seriesNavigation',
- 'pointNavigationEnabledThreshold'],
- pointValueDecimals: ['point', 'valueDecimals'],
- pointValuePrefix: ['point', 'valuePrefix'],
- pointValueSuffix: ['point', 'valueSuffix'],
- screenReaderSectionFormatter: ['screenReaderSection',
- 'beforeChartFormatter'],
- describeSingleSeries: ['series', 'describeSingleSeries'],
- seriesDescriptionFormatter: ['series', 'descriptionFormatter'],
- onTableAnchorClick: ['screenReaderSection', 'onViewDataTableClick'],
- axisRangeDateFormat: ['screenReaderSection', 'axisRangeDateFormat']
- });
- }
- /**
- * @private
- */
- function copyDeprecatedKeyboardNavigationOptions(chart) {
- deprecateFromOptionsMap(chart, ['accessibility', 'keyboardNavigation'], ['accessibility', 'keyboardNavigation', 'seriesNavigation'], {
- skipNullPoints: ['skipNullPoints'],
- mode: ['mode']
- });
- }
- /**
- * @private
- */
- function copyDeprecatedLangOptions(chart) {
- deprecateFromOptionsMap(chart, ['lang', 'accessibility'], ['lang', 'accessibility'], {
- legendItem: ['legend', 'legendItem'],
- legendLabel: ['legend', 'legendLabel'],
- mapZoomIn: ['zoom', 'mapZoomIn'],
- mapZoomOut: ['zoom', 'mapZoomOut'],
- resetZoomButton: ['zoom', 'resetZoomButton'],
- screenReaderRegionLabel: ['screenReaderSection',
- 'beforeRegionLabel'],
- rangeSelectorButton: ['rangeSelector', 'buttonText'],
- rangeSelectorMaxInput: ['rangeSelector', 'maxInputLabel'],
- rangeSelectorMinInput: ['rangeSelector', 'minInputLabel'],
- svgContainerEnd: ['screenReaderSection', 'endOfChartMarker'],
- viewAsDataTable: ['table', 'viewAsDataTableButtonText'],
- tableSummary: ['table', 'tableSummary']
- });
- }
- /**
- * Copy options that are deprecated over to new options. Logs warnings to
- * console if deprecated options are used.
- *
- * @private
- */
- function copyDeprecatedOptions(chart) {
- copyDeprecatedChartOptions(chart);
- copyDeprecatedAxisOptions(chart);
- if (chart.series) {
- copyDeprecatedSeriesOptions(chart);
- }
- copyDeprecatedTopLevelAccessibilityOptions(chart);
- copyDeprecatedKeyboardNavigationOptions(chart);
- copyDeprecatedLangOptions(chart);
- }
- return copyDeprecatedOptions;
- });
- _registerModule(_modules, 'modules/accessibility/a11y-i18n.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
- /* *
- *
- * Accessibility module - internationalization support
- *
- * (c) 2010-2019 Highsoft AS
- * Author: Øystein Moseng
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var pick = U.pick;
- /* eslint-disable valid-jsdoc */
- /**
- * String trim that works for IE6-8 as well.
- *
- * @private
- * @function stringTrim
- *
- * @param {string} str
- * The input string
- *
- * @return {string}
- * The trimmed string
- */
- function stringTrim(str) {
- return str.trim && str.trim() || str.replace(/^\s+|\s+$/g, '');
- }
- /**
- * i18n utility function. Format a single array or plural statement in a format
- * string. If the statement is not an array or plural statement, returns the
- * statement within brackets. Invalid array statements return an empty string.
- *
- * @private
- * @function formatExtendedStatement
- *
- * @param {string} statement
- *
- * @param {Highcharts.Dictionary<*>} ctx
- * Context to apply to the format string.
- *
- * @return {string}
- */
- function formatExtendedStatement(statement, ctx) {
- var eachStart = statement.indexOf('#each('), pluralStart = statement.indexOf('#plural('), indexStart = statement.indexOf('['), indexEnd = statement.indexOf(']'), arr, result;
- // Dealing with an each-function?
- if (eachStart > -1) {
- var eachEnd = statement.slice(eachStart).indexOf(')') + eachStart, preEach = statement.substring(0, eachStart), postEach = statement.substring(eachEnd + 1), eachStatement = statement.substring(eachStart + 6, eachEnd), eachArguments = eachStatement.split(','), lenArg = Number(eachArguments[1]), len;
- result = '';
- arr = ctx[eachArguments[0]];
- if (arr) {
- lenArg = isNaN(lenArg) ? arr.length : lenArg;
- len = lenArg < 0 ?
- arr.length + lenArg :
- Math.min(lenArg, arr.length); // Overshoot
- // Run through the array for the specified length
- for (var i = 0; i < len; ++i) {
- result += preEach + arr[i] + postEach;
- }
- }
- return result.length ? result : '';
- }
- // Dealing with a plural-function?
- if (pluralStart > -1) {
- var pluralEnd = statement.slice(pluralStart).indexOf(')') + pluralStart, pluralStatement = statement.substring(pluralStart + 8, pluralEnd), pluralArguments = pluralStatement.split(','), num = Number(ctx[pluralArguments[0]]);
- switch (num) {
- case 0:
- result = pick(pluralArguments[4], pluralArguments[1]);
- break;
- case 1:
- result = pick(pluralArguments[2], pluralArguments[1]);
- break;
- case 2:
- result = pick(pluralArguments[3], pluralArguments[1]);
- break;
- default:
- result = pluralArguments[1];
- }
- return result ? stringTrim(result) : '';
- }
- // Array index
- if (indexStart > -1) {
- var arrayName = statement.substring(0, indexStart), ix = Number(statement.substring(indexStart + 1, indexEnd)), val;
- arr = ctx[arrayName];
- if (!isNaN(ix) && arr) {
- if (ix < 0) {
- val = arr[arr.length + ix];
- // Handle negative overshoot
- if (typeof val === 'undefined') {
- val = arr[0];
- }
- }
- else {
- val = arr[ix];
- // Handle positive overshoot
- if (typeof val === 'undefined') {
- val = arr[arr.length - 1];
- }
- }
- }
- return typeof val !== 'undefined' ? val : '';
- }
- // Standard substitution, delegate to H.format or similar
- return '{' + statement + '}';
- }
- /**
- * i18n formatting function. Extends Highcharts.format() functionality by also
- * handling arrays and plural conditionals. Arrays can be indexed as follows:
- *
- * - Format: 'This is the first index: {myArray[0]}. The last: {myArray[-1]}.'
- *
- * - Context: { myArray: [0, 1, 2, 3, 4, 5] }
- *
- * - Result: 'This is the first index: 0. The last: 5.'
- *
- *
- * They can also be iterated using the #each() function. This will repeat the
- * contents of the bracket expression for each element. Example:
- *
- * - Format: 'List contains: {#each(myArray)cm }'
- *
- * - Context: { myArray: [0, 1, 2] }
- *
- * - Result: 'List contains: 0cm 1cm 2cm '
- *
- *
- * The #each() function optionally takes a length parameter. If positive, this
- * parameter specifies the max number of elements to iterate through. If
- * negative, the function will subtract the number from the length of the array.
- * Use this to stop iterating before the array ends. Example:
- *
- * - Format: 'List contains: {#each(myArray, -1) }and {myArray[-1]}.'
- *
- * - Context: { myArray: [0, 1, 2, 3] }
- *
- * - Result: 'List contains: 0, 1, 2, and 3.'
- *
- *
- * Use the #plural() function to pick a string depending on whether or not a
- * context object is 1. Arguments are #plural(obj, plural, singular). Example:
- *
- * - Format: 'Has {numPoints} {#plural(numPoints, points, point}.'
- *
- * - Context: { numPoints: 5 }
- *
- * - Result: 'Has 5 points.'
- *
- *
- * Optionally there are additional parameters for dual and none: #plural(obj,
- * plural, singular, dual, none). Example:
- *
- * - Format: 'Has {#plural(numPoints, many points, one point, two points,
- * none}.'
- *
- * - Context: { numPoints: 2 }
- *
- * - Result: 'Has two points.'
- *
- *
- * The dual or none parameters will take precedence if they are supplied.
- *
- * @requires modules/accessibility
- *
- * @function Highcharts.i18nFormat
- *
- * @param {string} formatString
- * The string to format.
- *
- * @param {Highcharts.Dictionary<*>} context
- * Context to apply to the format string.
- *
- * @param {Highcharts.Chart} chart
- * A `Chart` instance with a time object and numberFormatter, passed on
- * to H.format().
- *
- * @return {string}
- * The formatted string.
- */
- H.i18nFormat = function (formatString, context, chart) {
- var getFirstBracketStatement = function (sourceStr, offset) {
- var str = sourceStr.slice(offset || 0), startBracket = str.indexOf('{'), endBracket = str.indexOf('}');
- if (startBracket > -1 && endBracket > startBracket) {
- return {
- statement: str.substring(startBracket + 1, endBracket),
- begin: offset + startBracket + 1,
- end: offset + endBracket
- };
- }
- }, tokens = [], bracketRes, constRes, cursor = 0;
- // Tokenize format string into bracket statements and constants
- do {
- bracketRes = getFirstBracketStatement(formatString, cursor);
- constRes = formatString.substring(cursor, bracketRes && bracketRes.begin - 1);
- // If we have constant content before this bracket statement, add it
- if (constRes.length) {
- tokens.push({
- value: constRes,
- type: 'constant'
- });
- }
- // Add the bracket statement
- if (bracketRes) {
- tokens.push({
- value: bracketRes.statement,
- type: 'statement'
- });
- }
- cursor = bracketRes ? bracketRes.end + 1 : cursor + 1;
- } while (bracketRes);
- // Perform the formatting. The formatArrayStatement function returns the
- // statement in brackets if it is not an array statement, which means it
- // gets picked up by H.format below.
- tokens.forEach(function (token) {
- if (token.type === 'statement') {
- token.value = formatExtendedStatement(token.value, context);
- }
- });
- // Join string back together and pass to H.format to pick up non-array
- // statements.
- return H.format(tokens.reduce(function (acc, cur) {
- return acc + cur.value;
- }, ''), context, chart);
- };
- /**
- * Apply context to a format string from lang options of the chart.
- *
- * @requires modules/accessibility
- *
- * @function Highcharts.Chart#langFormat
- *
- * @param {string} langKey
- * Key (using dot notation) into lang option structure.
- *
- * @param {Highcharts.Dictionary<*>} context
- * Context to apply to the format string.
- *
- * @return {string}
- * The formatted string.
- */
- H.Chart.prototype.langFormat = function (langKey, context) {
- var keys = langKey.split('.'), formatString = this.options.lang, i = 0;
- for (; i < keys.length; ++i) {
- formatString = formatString && formatString[keys[i]];
- }
- return typeof formatString === 'string' ?
- H.i18nFormat(formatString, context, this) : '';
- };
- });
- _registerModule(_modules, 'modules/accessibility/focusBorder.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Extend SVG and Chart classes with focus border capabilities.
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var addEvent = H.addEvent;
- var extend = U.extend, pick = U.pick;
- /* eslint-disable no-invalid-this, valid-jsdoc */
- /*
- * Add focus border functionality to SVGElements. Draws a new rect on top of
- * element around its bounding box. This is used by multiple components.
- */
- extend(H.SVGElement.prototype, {
- /**
- * @private
- * @function Highcharts.SVGElement#addFocusBorder
- *
- * @param {number} margin
- *
- * @param {Highcharts.CSSObject} style
- */
- addFocusBorder: function (margin, style) {
- // Allow updating by just adding new border
- if (this.focusBorder) {
- this.removeFocusBorder();
- }
- // Add the border rect
- var bb = this.getBBox(), pad = pick(margin, 3);
- bb.x += this.translateX ? this.translateX : 0;
- bb.y += this.translateY ? this.translateY : 0;
- this.focusBorder = this.renderer.rect(bb.x - pad, bb.y - pad, bb.width + 2 * pad, bb.height + 2 * pad, parseInt((style && style.borderRadius || 0).toString(), 10))
- .addClass('highcharts-focus-border')
- .attr({
- zIndex: 99
- })
- .add(this.parentGroup);
- if (!this.renderer.styledMode) {
- this.focusBorder.attr({
- stroke: style && style.stroke,
- 'stroke-width': style && style.strokeWidth
- });
- }
- },
- /**
- * @private
- * @function Highcharts.SVGElement#removeFocusBorder
- */
- removeFocusBorder: function () {
- if (this.focusBorder) {
- this.focusBorder.destroy();
- delete this.focusBorder;
- }
- }
- });
- /**
- * Set chart's focus to an SVGElement. Calls focus() on it, and draws the focus
- * border. This is used by multiple components.
- *
- * @private
- * @function Highcharts.Chart#setFocusToElement
- *
- * @param {Highcharts.SVGElement} svgElement
- * Element to draw the border around.
- *
- * @param {SVGDOMElement|HTMLDOMElement} [focusElement]
- * If supplied, it draws the border around svgElement and sets the focus
- * to focusElement.
- */
- H.Chart.prototype.setFocusToElement = function (svgElement, focusElement) {
- var focusBorderOptions = this.options.accessibility.keyboardNavigation.focusBorder, browserFocusElement = focusElement || svgElement.element;
- // Set browser focus if possible
- if (browserFocusElement &&
- browserFocusElement.focus) {
- // If there is no focusin-listener, add one to work around Edge issue
- // where Narrator is not reading out points despite calling focus().
- if (!(browserFocusElement.hcEvents &&
- browserFocusElement.hcEvents.focusin)) {
- addEvent(browserFocusElement, 'focusin', function () { });
- }
- browserFocusElement.focus();
- // Hide default focus ring
- if (focusBorderOptions.hideBrowserFocusOutline) {
- browserFocusElement.style.outline = 'none';
- }
- }
- if (focusBorderOptions.enabled) {
- // Remove old focus border
- if (this.focusElement) {
- this.focusElement.removeFocusBorder();
- }
- // Draw focus border (since some browsers don't do it automatically)
- svgElement.addFocusBorder(focusBorderOptions.margin, {
- stroke: focusBorderOptions.style.color,
- strokeWidth: focusBorderOptions.style.lineWidth,
- borderRadius: focusBorderOptions.style.borderRadius
- });
- this.focusElement = svgElement;
- }
- };
- });
- _registerModule(_modules, 'modules/accessibility/accessibility.js', [_modules['modules/accessibility/utils/chartUtilities.js'], _modules['parts/Globals.js'], _modules['modules/accessibility/KeyboardNavigationHandler.js'], _modules['parts/Utilities.js'], _modules['modules/accessibility/AccessibilityComponent.js'], _modules['modules/accessibility/KeyboardNavigation.js'], _modules['modules/accessibility/components/LegendComponent.js'], _modules['modules/accessibility/components/MenuComponent.js'], _modules['modules/accessibility/components/SeriesComponent/SeriesComponent.js'], _modules['modules/accessibility/components/ZoomComponent.js'], _modules['modules/accessibility/components/RangeSelectorComponent.js'], _modules['modules/accessibility/components/InfoRegionsComponent.js'], _modules['modules/accessibility/components/ContainerComponent.js'], _modules['modules/accessibility/high-contrast-mode.js'], _modules['modules/accessibility/high-contrast-theme.js'], _modules['modules/accessibility/options/options.js'], _modules['modules/accessibility/options/langOptions.js'], _modules['modules/accessibility/options/deprecatedOptions.js']], function (ChartUtilities, H, KeyboardNavigationHandler, U, AccessibilityComponent, KeyboardNavigation, LegendComponent, MenuComponent, SeriesComponent, ZoomComponent, RangeSelectorComponent, InfoRegionsComponent, ContainerComponent, whcm, highContrastTheme, defaultOptions, defaultLangOptions, copyDeprecatedOptions) {
- /* *
- *
- * (c) 2009-2019 Øystein Moseng
- *
- * Accessibility module for Highcharts
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var extend = U.extend;
- var addEvent = H.addEvent, doc = H.win.document, merge = H.merge, fireEvent = H.fireEvent;
- // Add default options
- merge(true, H.defaultOptions, defaultOptions, {
- accessibility: {
- highContrastTheme: highContrastTheme
- },
- lang: defaultLangOptions
- });
- // Expose functionality on Highcharts namespace
- H.A11yChartUtilities = ChartUtilities;
- H.KeyboardNavigationHandler = KeyboardNavigationHandler;
- H.AccessibilityComponent = AccessibilityComponent;
- /* eslint-disable no-invalid-this, valid-jsdoc */
- /**
- * The Accessibility class
- *
- * @private
- * @requires module:modules/accessibility
- *
- * @class
- * @name Highcharts.Accessibility
- *
- * @param {Highcharts.Chart} chart
- * Chart object
- */
- function Accessibility(chart) {
- this.init(chart);
- }
- Accessibility.prototype = {
- /**
- * Initialize the accessibility class
- * @private
- * @param {Highcharts.Chart} chart
- * Chart object
- */
- init: function (chart) {
- this.chart = chart;
- // Abort on old browsers
- if (!doc.addEventListener || !chart.renderer.isSVG) {
- chart.renderTo.setAttribute('aria-hidden', true);
- return;
- }
- // Copy over any deprecated options that are used. We could do this on
- // every update, but it is probably not needed.
- copyDeprecatedOptions(chart);
- this.initComponents();
- this.keyboardNavigation = new KeyboardNavigation(chart, this.components);
- this.update();
- },
- /**
- * @private
- */
- initComponents: function () {
- var chart = this.chart, a11yOptions = chart.options.accessibility;
- this.components = {
- container: new ContainerComponent(),
- infoRegions: new InfoRegionsComponent(),
- legend: new LegendComponent(),
- chartMenu: new MenuComponent(),
- rangeSelector: new RangeSelectorComponent(),
- series: new SeriesComponent(),
- zoom: new ZoomComponent()
- };
- if (a11yOptions.customComponents) {
- extend(this.components, a11yOptions.customComponents);
- }
- var components = this.components;
- // Refactor to use Object.values if we polyfill
- Object.keys(components).forEach(function (componentName) {
- components[componentName].initBase(chart);
- components[componentName].init();
- });
- },
- /**
- * Update all components.
- */
- update: function () {
- var components = this.components, chart = this.chart, a11yOptions = chart.options.accessibility;
- fireEvent(chart, 'beforeA11yUpdate');
- // Update the chart type list as this is used by multiple modules
- chart.types = this.getChartTypes();
- // Update markup
- Object.keys(components).forEach(function (componentName) {
- components[componentName].onChartUpdate();
- fireEvent(chart, 'afterA11yComponentUpdate', {
- name: componentName,
- component: components[componentName]
- });
- });
- // Update keyboard navigation
- this.keyboardNavigation.update(a11yOptions.keyboardNavigation.order);
- // Handle high contrast mode
- if (!chart.highContrastModeActive && // Only do this once
- whcm.isHighContrastModeActive()) {
- whcm.setHighContrastTheme(chart);
- }
- fireEvent(chart, 'afterA11yUpdate');
- },
- /**
- * Destroy all elements.
- */
- destroy: function () {
- var chart = this.chart || {};
- // Destroy components
- var components = this.components;
- Object.keys(components).forEach(function (componentName) {
- components[componentName].destroy();
- components[componentName].destroyBase();
- });
- // Kill keyboard nav
- if (this.keyboardNavigation) {
- this.keyboardNavigation.destroy();
- }
- // Hide container from screen readers if it exists
- if (chart.renderTo) {
- chart.renderTo.setAttribute('aria-hidden', true);
- }
- // Remove focus border if it exists
- if (chart.focusElement) {
- chart.focusElement.removeFocusBorder();
- }
- },
- /**
- * Return a list of the types of series we have in the chart.
- * @private
- */
- getChartTypes: function () {
- var types = {};
- this.chart.series.forEach(function (series) {
- types[series.type] = 1;
- });
- return Object.keys(types);
- }
- };
- /**
- * @private
- */
- H.Chart.prototype.updateA11yEnabled = function () {
- var a11y = this.accessibility, accessibilityOptions = this.options.accessibility;
- if (accessibilityOptions && accessibilityOptions.enabled) {
- if (a11y) {
- a11y.update();
- }
- else {
- this.accessibility = a11y = new Accessibility(this);
- }
- }
- else if (a11y) {
- // Destroy if after update we have a11y and it is disabled
- if (a11y.destroy) {
- a11y.destroy();
- }
- delete this.accessibility;
- }
- else {
- // Just hide container
- this.renderTo.setAttribute('aria-hidden', true);
- }
- };
- // Handle updates to the module and send render updates to components
- addEvent(H.Chart, 'render', function (e) {
- // Update/destroy
- if (this.a11yDirty && this.renderTo) {
- delete this.a11yDirty;
- this.updateA11yEnabled();
- }
- var a11y = this.accessibility;
- if (a11y) {
- Object.keys(a11y.components).forEach(function (componentName) {
- a11y.components[componentName].onChartRender();
- });
- }
- });
- // Update with chart/series/point updates
- addEvent(H.Chart, 'update', function (e) {
- // Merge new options
- var newOptions = e.options.accessibility;
- if (newOptions) {
- // Handle custom component updating specifically
- if (newOptions.customComponents) {
- this.options.accessibility.customComponents =
- newOptions.customComponents;
- delete newOptions.customComponents;
- }
- merge(true, this.options.accessibility, newOptions);
- // Recreate from scratch
- if (this.accessibility && this.accessibility.destroy) {
- this.accessibility.destroy();
- delete this.accessibility;
- }
- }
- // Mark dirty for update
- this.a11yDirty = true;
- });
- // Mark dirty for update
- addEvent(H.Point, 'update', function () {
- if (this.series.chart.accessibility) {
- this.series.chart.a11yDirty = true;
- }
- });
- ['addSeries', 'init'].forEach(function (event) {
- addEvent(H.Chart, event, function () {
- this.a11yDirty = true;
- });
- });
- ['update', 'updatedData', 'remove'].forEach(function (event) {
- addEvent(H.Series, event, function () {
- if (this.chart.accessibility) {
- this.chart.a11yDirty = true;
- }
- });
- });
- // Direct updates (events happen after render)
- [
- 'afterDrilldown', 'drillupall'
- ].forEach(function (event) {
- addEvent(H.Chart, event, function () {
- if (this.accessibility) {
- this.accessibility.update();
- }
- });
- });
- // Destroy with chart
- addEvent(H.Chart, 'destroy', function () {
- if (this.accessibility) {
- this.accessibility.destroy();
- }
- });
- });
- _registerModule(_modules, 'masters/modules/accessibility.src.js', [], function () {
- });
- }));
|