{"version":3,"sources":["interactive-map.js"],"names":["window","addEventListener","cnfsdInteractiveMApLoaded","maps","document","querySelectorAll","mapConfig","partialAttributeName","fillColourDefault","strokeColourDefault","interactiveFillColourInactive","interactiveFillColourActive","InteractiveMapDefaultSetter","static","path","InteractiveMapHelpers","updatePathColourHelper","setAttribute","mapElement","classList","add","callback","attribute","attributes","attributeName","name","attributeValue","value","toLowerCase","includes","colour","interactivePathsObject","matchingAttribute","Object","entries","find","key","paths","Array","isArray","forEach","region","replaceAll","index","tabIndex","element","isVisible","style","visibility","display","InteractiveMapInitialisation","constructor","map","this","mapContainer","setMapTitle","interactivePaths","jsonData","handleJsonData","initialiseInteractiveMap","eventHandlerInstance","initialiseInteractivePaths","querySelector","setMapTabIndex","InteractiveMapEventHandler","jsonURL","getAttribute","fetch","then","response","json","data","catch","error","console","JSON","parse","log","handlePageResizing","mapTitleElement","mapTitleValue","innerHTML","remove","allPaths","from","setDefaultPathColours","findMatchingAttributeHelper","createInteractivePathObject","matchingEntry","matchingKey","push","setInteractivePathStateInactiveState","interactionType","tabbingActivated","selectedPath","tabbablePaths","initialiseInteractivePathInstance","initialiseResizeInstance","initialiseListeners","pathInteractionInstance","resizeInstance","InteractiveMapPathInteractionHandler","InteractiveMapResizeHandler","handleTooltipOnResize","debounceResizeHandler","e","handlePathInteraction","stopPropagation","handleMapKeyPressListener","handleFocusOutOfMap","tooltipData","length","setFocusAttributes","setPathFocusEListener","setPathTabIndexHelper","target","blur","removeEventListener","parsedRegion","regionParser","dataEntries","val","join","keys","handleMapPathFocused","checkTargetIsSVG","SVGPathElement","SVGPolygonElement","self","setTimeout","handlePathNotInteracted","contains","createPlotObject","clientX","clientY","checkForMatchingEntry","mutationController","selectedRegion","removeFocusInteractionFromPaths","setDefaultMapAttributes","tooltip","container","box","title","content","plot","plotLine","themeProductColour","SelectedRegion","SelectedPaths","previouslySelectedPaths","tooltipManagerInstance","setInteractionPathColour","initObservation","initTooltipInstance","productUIColour","getComputedStyle","body","getPropertyValue","MutationObserver","mutations","mutation","type","toggleTooltipVisibility","offsetHeight","handlePathColourChange","handleTooltipCreation","observe","InteractiveMapTooltipManager","plotPosition","x","undefined","y","previouslySelectedPathHandler","newlySelectedRegion","getSelectedPaths","newPathSelected","removePaths","selectedPaths","removeCurrentlySelectedPaths","pathLooperHelper","findSelectedRegionByAttributeHelper","matchingRegion","resetPathInteraction","createTooltip","toggleElementVisibility","toggleElementDisplay","toggleTooltipDisplay","displayed","newPathColour","styleData","tooltipMargin","getStyleData","styleString","pathElem","updateTooltipPosition","setTooltipData","setTooltipBoxTitle","pathRect","getBoundingClientRect","mapRect","halfofPathHeight","height","positionRelativeToParent","left","top","getPlotPosition","checkPathRelativePosition","positionTooltipPoint","getPlotCenter","width","offsetWidth","handlePathBelowMapCenter","handlePathAboveMapCenter","positionTooltipBoxX","yPosition","positionTooltipBoxY","lineHeight","positionTooltipLine","boxYPosition","halfOfBoxHeight","lineStartPoint","isAbove","bottom","xPlot","plotPositionX","tooltipWidth","quarterTooltipWidth","xPosition","contentHTML","createSpanWithStyles","text","styles","prop","valueObj","valueString","styledText","stylesToAdd","regex","RegExp","replace","match","valueHTML","isResizing","debounce","func","delay","timeoutId","args","clearTimeout","mapInstances","mapSVG","mapInstance"],"mappings":"AACAA,OAAAC,iBAAA,QAAA,KAEA,QAAA,IAAAD,OAAAE,0BACA,OAGA,MAAAC,EAAAC,SAAAC,iBAAA,wBACA,IAAAF,EAAA,OAEA,MAAAG,EAAA,CACAC,qBAAA,cACAC,kBAAA,UACAC,oBAAA,UACAC,8BAAA,UACAC,4BAAA,WAKA,MAAAC,EAGAC,6BAAAC,GACAC,EAAAC,uBAAAF,EAAAR,EAAAE,mBACAM,EAAAG,aAAA,SAAAX,EAAAG,oBACA,CAGAI,+BAAAK,GACAA,EAAAD,aAAA,YAAA,UACAC,EAAAD,aAAA,aAAA,wCACA,CAGAJ,4CAAAC,GACAC,EAAAC,uBAAAF,EAAAR,EAAAI,+BACAI,EAAAK,UAAAC,IAAA,cACA,EAIA,MAAAL,EAGAF,mCAAA,CAAAC,EAAAO,KACA,IAAA,MAAAC,KAAAR,EAAAS,WAAA,CACA,MAAAC,EAAAF,EAAAG,KACAC,EAAAJ,EAAAK,MAEAH,EAAAI,cAAAC,SAAAvB,EAAAC,qBAAAqB,gBACAP,EAAAK,EAAAZ,EAEA,GAGAD,8BAAAC,EAAAgB,GACAhB,GAAAA,EAAAG,aAAA,OAAAa,EACA,CAGAjB,2CAAA,CAAAkB,EAAAC,IACAC,OAAAC,QAAAH,GAAAI,MAAA,EAAAC,KAAAA,IAAAJ,IAGAnB,wBAAA,CAAAwB,EAAAhB,EAAAS,KACAO,GAAAhB,IAEAiB,MAAAC,QAAAF,GACAA,EAAAG,SAAA1B,IACAO,EAAAP,EAAAgB,GAAA,KAAA,IAGAT,EAAAgB,EAAAP,GAAA,MACA,EAGAjB,oBAAA4B,GACAA,EAAAC,WAAA,IAAA,KAGA7B,6BAAA,CAAAC,EAAA6B,KACA7B,EAAA8B,SAAAD,GAGA9B,+BAAA,CAAAgC,EAAAC,KAEAD,EAAAE,MAAAC,WADAF,EACA,UAEA,QACA,EAIAjC,4BAAA,CAAAgC,EAAAC,KAEAD,EAAAE,MAAAE,QADAH,EACA,QAEA,MACA,EAMA,MAAAI,EACAC,YAAAC,GACAC,KAAAC,aAAAF,EACAC,KAAAnC,WAEAmC,KAAAE,cAEAF,KAAAG,iBAAA,CAAA,EAEAH,KAAAI,SACAJ,KAAAK,iBAEAL,KAAAI,UAAAJ,KAAAM,yBAAAN,KAAAI,UAEAJ,KAAAO,oBACA,CAEAD,yBAAAF,GACAA,IAGAJ,KAAAI,WAAAJ,KAAAI,SAAAA,GAEAJ,KAAAQ,6BAEAR,KAAAG,mBAEAH,KAAAnC,WAAAmC,KAAAC,aAAAQ,cAAA,yCACAT,KAAAU,eAAAV,KAAAnC,YACAmC,KAAAO,qBAAA,IAAAI,EAAAX,KAAAC,aAAAD,KAAAnC,WAAAmC,KAAAG,mBACA,CAGAE,eAAA,KACA,MAAAO,EAAAZ,KAAAC,aAAAY,aAAA,gBACAT,EAAAJ,KAAAC,aAAAY,aAAA,iBAEAD,EAEAE,MAAAF,GACAG,MAAAC,GAAAA,EAAAC,SACAF,MAAAG,IACAlB,KAAAM,yBAAAY,EAAA,IAEAC,OAAAC,IACAC,QAAAD,MAAA,qCAAAA,EAAA,IAEAhB,EAEAJ,KAAAI,SAAAkB,KAAAC,MAAAnB,GAEAiB,QAAAG,IAAA,wCACA,EAIAC,mBAAA,KACAzB,KAAAG,kBAEAH,KAAAO,qBAAAkB,oBAAA,EAGAvB,YAAA,KAEA,MAAAwB,EAAA1B,KAAAC,aAAAQ,cAAA,+BACAkB,EAAA3B,KAAAC,aAAAY,aAAA,kBAGAa,GAAAC,IACAD,EAAAE,UAAAD,EACAD,EAAA5D,UAAA+D,OAAA,UACA,EAIArB,2BAAA,KACA,MAAAsB,EAAA9B,KAAAC,aAAAjD,iBAAA,iBAGAiC,MAAA8C,KAAAD,GAAA3C,SAAA1B,IACAF,EAAAyE,sBAAAvE,GACAC,EAAAuE,4BAAAxE,EAAAuC,KAAAkC,4BAAA,GACA,EAIAA,4BAAA,CAAAjE,EAAAR,KAEA,MAAA0E,EAAAvD,OAAAC,QAAAmB,KAAAI,UAAAtB,MAAA,EAAAC,KAAAA,IAAAd,IAEA,IAAAkE,EAAA,OAEA,MAAAC,EAAA9D,GAAA6D,EAGAnC,KAAAG,iBAAAiC,GAOAnD,MAAAC,QAAAc,KAAAG,iBAAAiC,GAAApD,OAEAgB,KAAAG,iBAAAiC,GAAApD,MAAAqD,KAAA5E,GAGAuC,KAAAG,iBAAAiC,GAAApD,MAAA,CAAAgB,KAAAG,iBAAAiC,GAAApD,MAAAvB,IAVAuC,KAAAG,iBAAAiC,GAAA,CAAA,EAEApC,KAAAG,iBAAAiC,GAAA,MAAA3E,EACAuC,KAAAG,iBAAAiC,GAAA,YAAA9D,GAYAf,EAAA+E,qCAAA7E,EAAA,EAGAiD,eAAA7C,IACAA,GACAA,EAAAD,aAAA,WAAA,EAAA,EAQA,MAAA+C,EACAb,YAAAC,EAAAlC,EAAAsC,GACAH,KAAAC,aAAAF,EACAC,KAAAnC,WAAAA,EACAmC,KAAAG,iBAAAA,EAEAH,KAAAuC,gBACAvC,KAAAwC,iBAEAxC,KAAAyC,aAEAzC,KAAA0C,cAAA,GAEA1C,KAAA2C,kCAAA5C,EAAAlC,EAAAsC,GAEAH,KAAA4C,yBAAA/E,GAEAmC,KAAA6C,oBAAAhF,GAEAmC,KAAA8C,wBACA9C,KAAA+C,cACA,CAGAJ,kCAAA,CAAA1C,EAAApC,EAAAsC,KAEAH,KAAA8C,wBAAA,IAAAE,EAAA/C,EAAApC,EAAAsC,EAAA,EAGAyC,yBAAA/E,GACAmC,KAAA+C,eAAA,IAAAE,EAAApF,EAAAmC,KAAA8C,wBACA,CAEArB,mBAAA,KACAzB,KAAA+C,eAAAG,wBACAlD,KAAA+C,eAAAI,uBAAA,EAGAN,oBAAAhF,IAEAA,EAAAjB,iBAAA,aAAAwG,IACApD,KAAAuC,gBAAA,QACAvC,KAAAqD,sBAAAD,GACAA,EAAAE,iBAAA,IACA,GAEAzF,EAAAjB,iBAAA,SAAA,KACAiB,EAAAjB,iBAAA,UAAAoD,KAAAuD,0BAAA,GACA,EAGAA,0BAAAH,IAEA,GAAA,UAAAA,EAAArE,IAAA,CAEAiB,KAAAwC,kBAAA,EACAxC,KAAAuC,gBAAA,WAGAvC,KAAAnC,WAAAD,aAAA,aAAA,iCACAoC,KAAAnC,WAAAC,UAAAC,IAAA,WAGAhB,SAAAH,iBAAA,UAAAoD,KAAAwD,qBAGA,IAAAd,EAAA,GACA,IAAA,MAAA3D,GAAAC,MAAAA,EAAAyE,YAAAA,MAAA7E,OAAAC,QAAAmB,KAAAG,kBAAA,CAEA,MAAA1C,EAAAwB,MAAAC,QAAAF,GAAAA,EAAA,GAAAA,EAEA,IAAAgB,KAAA0C,cAAAlE,SAAAf,GAAA,CACAiF,EAAAL,KAAA5E,GAEA,MAAA6B,EAAAoD,EAAAgB,OAEA1D,KAAA2D,mBAAAlG,EAAA6B,EAAAmE,EAAA1E,GACAiB,KAAA4D,sBAAAnG,EACA,CAGAC,EAAAmG,sBAAApG,EAAA,EACA,CAEAuC,KAAA0C,cAAAA,EAEAU,EAAAU,OAAAC,OACA/D,KAAAnC,WAAAmG,oBAAA,UAAAhE,KAAAuD,0BACA,GAIAI,mBAAA,CAAAlG,EAAA6B,EAAAmE,EAAArE,KACA,MAAA6E,EAAAvG,EAAAwG,aAAA9E,GAEA+E,EAAA,GAAAvF,OAAAC,QAAA4E,GAAA1D,KAAA,EAAAhB,EAAAqF,KAAA,GAAArF,MAAAqF,EAAA9F,UAAA+F,KAAA,QAGA5G,EAAAG,aAAA,aAAA,WAAAqG,MAAAE,GAAAA,KAGA1G,EAAAG,aAAA,gBAAA0B,GACA7B,EAAAG,aAAA,eAAAgB,OAAA0F,KAAAtE,KAAAG,kBAAAuD,QAGAjG,EAAAG,aAAA,YAAA,EAAA,EAIAgG,sBAAAnG,IACAA,EAAAb,iBAAA,QAAAoD,KAAAuE,qBAAA,EAGAA,qBAAAnB,IACA,aAAApD,KAAAuC,gBACAvC,KAAAqD,sBAAAD,GAGApD,KAAAuC,gBAAA,UACA,EAGAiC,iBAAAhF,GACAA,aAAAiF,gBAAAjF,aAAAkF,kBAIArB,sBAAAD,IACA,MAAAuB,EAAA3E,KAEA4E,YAAA,WAGA,IAAAD,EAAAH,iBAAApB,EAAAU,QAKA,OAHAa,EAAAnC,mBAAAmC,EAAApC,gBAAA,iBAEAoC,EAAA7B,wBAAA+B,wBAAAzB,EAAAU,QAKAV,EAAAU,OAAAhG,UAAAgH,SAAA,gBAQAH,EAAAnC,mBAAAY,EAAAU,OAAAjD,aAAA,cAAA8D,EAAApC,gBAAA,YAEAoC,EAAA7B,wBAAAiC,iBAAA3B,EAAA4B,QAAA5B,EAAA6B,SAEAvH,EAAAuE,4BAAAmB,EAAAU,OAAAa,EAAA7B,wBAAAoC,uBAGAP,EAAA7B,wBAAAqC,oBAAA,EAEAR,EAAA1E,aAAArC,aAAA,uBAAA+G,EAAA7B,wBAAAsC,iBAfAT,EAAAnC,mBAAAmC,EAAApC,gBAAA,WAgBA,GAAA,EAAA,EAIA8C,gCAAA,KACA,IAAArF,KAAA0C,cAAAgB,QAEA1D,KAAA0C,cAAAvD,SAAA1B,IAEAC,EAAAmG,sBAAApG,GAAA,EAAA,GACA,EAIA+F,oBAAAJ,IAEApD,KAAAnC,WAAAiH,SAAA1B,EAAAU,UAEA9D,KAAAnC,WAAAC,UAAA+D,OAAA,WAGA7B,KAAAqF,kCAGA9H,EAAA+H,wBAAAtF,KAAAnC,YAGAmC,KAAAuC,gBAAA,KACAvC,KAAAwC,kBAAA,EAEAxC,KAAA8C,wBAAA+B,wBAAA,MAGA9H,SAAAiH,oBAAA,UAAAhE,KAAAwD,qBAAA,EAKA,MAAAR,EACAlD,YAAAC,EAAAlC,EAAAsC,GACAH,KAAAC,aAAAF,EACAC,KAAAnC,WAAAA,EACAmC,KAAAG,iBAAAA,EAEAH,KAAAuF,QAAA,CACAC,UAAA,KACAC,IAAA,KACAC,MAAA,KACAC,QAAA,KACAC,KAAA,KACAC,SAAA,MAGA7F,KAAA8F,mBAEA9F,KAAAmF,oBAAA,EAEAnF,KAAA+F,eACA/F,KAAAgG,cACAhG,KAAAyD,YAEAzD,KAAAiG,wBAEAjG,KAAAkG,uBAEAlG,KAAAmG,2BACAnG,KAAAoG,gBAAArG,GACAC,KAAAqG,qBACA,CAEAF,yBAAA,KACA,MAAAG,EAAAC,iBAAAxJ,SAAAyJ,MAAAC,iBAAA,0BACAzG,KAAA8F,mBAAA,YAAAQ,GAAAA,EAAA,UAAAA,CAAA,EAGAF,gBAAAnG,IAEA,IAAAyG,kBAAAC,IACAA,EAAAxH,SAAAyH,IACA,GAAA,eAAAA,EAAAC,MAAA,yBAAAD,EAAAzI,cAAA,CACA,MAAAiB,EAAAa,EAAAY,aAAA,wBAGA,IAAAzB,EAAA,OAAAY,KAAA8G,wBAAA,cAAA,GAGA,GAAA,IAAA9G,KAAAnC,WAAAkJ,aAAA,OAIA/G,KAAAmF,qBACAnF,KAAA+E,mBACA/E,KAAAkF,sBAAA9F,IAIAY,KAAAgH,yBAGAhH,KAAAiH,wBAGAjH,KAAAmF,oBAAA,CACA,IACA,IAGA+B,QAAAjH,EAAA,CAAA/B,YAAA,GAAA,EAGAmI,oBAAA,KAEA,MAAAd,EAAAvF,KAAAC,aAAAQ,cAAA,iCAEA8E,IAEAvF,KAAAuF,QAAAC,UAAAD,EACAvF,KAAAuF,QAAAE,IAAAF,EAAA9E,cAAA,2CACAT,KAAAuF,QAAAG,MAAAH,EAAA9E,cAAA,kDACAT,KAAAuF,QAAAI,QAAAJ,EAAA9E,cAAA,oDACAT,KAAAuF,QAAAK,KAAAL,EAAA9E,cAAA,uCACAT,KAAAuF,QAAAM,SAAAN,EAAA9E,cAAA,4CAEAT,KAAAkG,uBAAA,IAAAiB,EAAAnH,KAAAC,aAAAD,KAAAnC,WAAAmC,KAAAuF,SAAA,EAGAR,iBAAA,CAAAC,EAAAC,KAEA,IAAAjF,KAAAkG,uBAAA,OAEA,IAAAkB,EAAA,CACAC,OAAAC,EACAC,OAAAD,GAGAtC,GAAAC,IAEAmC,EAAAC,EAAArC,EACAoC,EAAAG,EAAAtC,GAGAjF,KAAAkG,uBAAAkB,aAAAA,CAAA,EAIAI,8BAAAC,IAEA,MAAAxB,EAAAjG,KAAA0H,mBAGA,OAAAzB,IAGAjG,KAAA2H,gBAAAF,IAAAzH,KAAAoF,eAEApF,KAAA2H,gBAEA3H,KAAA4H,YAAA3B,GAGAjG,KAAAiG,wBAAAjG,KAAA6H,cAIA7H,KAAA2H,gBAAA,EAIAD,iBAAA,KACA,GAAA1H,KAAAoF,eAAA,OAAApF,KAAAG,iBAAAH,KAAAoF,gBAAApG,KAAA,EAGA8I,6BAAA,KACA9H,KAAA4H,YAAA5H,KAAA6H,eACA7H,KAAA6H,cAAA,IAAA,EAGAD,YAAA3B,IACArB,YAAA,WACAlH,EAAAqK,iBAAA9B,EAAAvI,EAAAC,uBAAAV,EAAAI,8BACA,GAAA,EAAA,EAIA6H,sBAAA9F,IACA,MAAA+C,EAAAzE,EAAAsK,oCAAAhI,KAAAG,iBAAAf,GACA,IAAA+C,EAAA,OAEA,MAAA8F,GAAAjJ,MAAAA,EAAAyE,YAAAA,IAAAtB,EAEAnC,KAAAwH,8BAAAS,IAIAjI,KAAA6H,cAAA7I,EACAgB,KAAAoF,eAAA6C,EACAjI,KAAAyD,YAAAA,GAEAzD,KAAAkI,sBACA,EAIAA,qBAAA,KACAlI,KAAA6H,cAAA,KACA7H,KAAAoF,eAAA,KACApF,KAAAyD,YAAA,KACAzD,KAAA8G,wBAAA,cAAA,EAAA,EAGAG,sBAAA,KAEA,MAAAtC,EAAA3E,KAEA4E,YAAA,WACA,IAAAD,EAAAkD,gBAAAlD,EAAAuB,uBAAA,OAEA,IAAAzD,EACAxD,MAAAC,QAAAyF,EAAAkD,iBAAApF,EAAAkC,EAAAkD,cAAA,IACAlD,EAAAuB,uBAAAiC,cAAA1F,GAAAkC,EAAAkD,cAAAlD,EAAAlB,YAAAkB,EAAAS,eACA,GAAA,EAAA,EAIAP,wBAAAf,IAEA,GAAA,OAAA9D,KAAAoF,eAAA,OAGA,MAAAK,IAAAA,EAAAG,KAAAA,EAAAC,SAAAA,GAAA7F,KAAAuF,QACA,GACAzB,IAAA2B,GACAA,EAAAX,SAAAhB,IACAA,IAAA8B,GACA9B,IAAA+B,EACA,OAGA7F,KAAA8G,wBAAA,cAAA,GAGA,MAAAb,EAAAjG,KAAA0H,mBACAzB,GAAAjG,KAAA4H,YAAA3B,GAGAjG,KAAAoF,eAAA,KACApF,KAAAC,aAAArC,aAAA,uBAAA,GAAA,EAGAkJ,wBAAA,CAAAD,EAAAlH,KAEA,eAAAkH,GAAAnJ,EAAA0K,wBAAApI,KAAAuF,QAAAC,UAAA7F,GAEA,YAAAkH,GAAAnJ,EAAA2K,qBAAArI,KAAAuF,QAAAC,UAAA7F,EAAA,EAIA2I,qBAAAC,IACA7K,EAAA0K,wBAAApI,KAAAuF,QAAAC,UAAA+C,EAAA,EAIAvB,uBAAA,KACA,IAAAwB,EACAxJ,EAAAgB,KAAA6H,cAEA7H,KAAA6H,cACAW,EAAAxI,KAAA8F,oBAAA7I,EAAAK,6BAEAkL,EAAAvL,EAAAI,8BACA2B,EAAAgB,KAAAiG,wBACAjG,KAAAiG,wBAAA,MAIAvI,EAAAqK,iBAAA/I,EAAAtB,EAAAC,uBAAA6K,EAAA,EAKA,MAAArB,EACArH,YAAAC,EAAAlC,EAAA0H,GACAvF,KAAAC,aAAAF,EACAC,KAAAnC,WAAAA,EACAmC,KAAAuF,QAAAA,EAEAvF,KAAAyI,UAEAzI,KAAA0I,cAAA,GAEA1I,KAAAoH,aAAA,CACAC,OAAAC,EACAC,OAAAD,GAGAtH,KAAA2I,cACA,CAEAA,aAAA,KACA,MAAAC,EAAA5I,KAAAC,aAAAY,aAAA,uBACA+H,IAAA5I,KAAAyI,UAAAnH,KAAAC,MAAAqH,GAAA,EAGAT,cAAA,CAAAU,EAAA3H,EAAA9B,KACAY,KAAA8I,sBAAAD,GACA7I,KAAA+I,eAAA7H,GACAlB,KAAAgJ,mBAAA5J,EAAA,EAGA0J,sBAAAD,IACA,MAAAlE,EAAA3E,KAEA4E,YAAA,KAGA,MAAAqE,EAAAJ,EAAAK,wBACAC,EAAAxE,EAAA9G,WAAAqL,wBACAE,EAAAH,EAAAI,OAAA,EAGAC,EAAA,CACAC,KAAAN,EAAAM,KAAAJ,EAAAI,KACAC,IAAAP,EAAAO,IAAAL,EAAAK,KAGApC,EAAAzC,EAAA8E,gBAAAR,EAAAK,EAAAF,EAAAD,GAGAxE,EAAA+E,0BAAAtC,EAAAkC,EAAAF,EAAAH,EAAAE,GAGAxE,EAAAgF,qBAAAvC,GAEA1J,EAAA0K,wBAAAzD,EAAAY,QAAAC,WAAA,EAAA,GAEA,EAAA,EAGAiE,gBAAA,CAAAR,EAAAK,EAAAF,EAAAD,KACA,MAAA9B,EAAAA,EAAAE,EAAAA,GAAAvH,KAAA4J,gBAEA,IAAAxC,EAAA,CACAC,EAAA,EACAE,EAAA,GAaA,OAVAvH,KAAAoH,aAAAC,GAAArH,KAAAoH,aAAAG,GAEAH,EAAAC,EAAArH,KAAAoH,aAAAC,EAAA8B,EAAAI,KAAAlC,EACAD,EAAAG,EAAAvH,KAAAoH,aAAAG,EAAA4B,EAAAK,IAAAjC,IAGAH,EAAAC,EAAAiC,EAAAC,KAAAN,EAAAY,MAAA,EAAAxC,EACAD,EAAAG,EAAA+B,EAAAE,KAAAJ,EAAA7B,IAGAH,CAAA,EAGAwC,cAAA,KAEA,CACAvC,EAAArH,KAAAuF,QAAAK,KAAAkE,YAAA,EACAvC,EAAAvH,KAAAuF,QAAAK,KAAAmB,aAAA,IAMA2C,0BAAA,CAAAtC,EAAAkC,EAAAF,EAAAH,EAAAE,KAEAG,EAAAE,IAAAxJ,KAAAnC,WAAAkJ,aAAA,EAEA/G,KAAA+J,yBAAA3C,EAAAkC,EAAAF,EAAAH,EAAAE,GAEAnJ,KAAAgK,yBAAA5C,EAAAkC,EAAAF,EAAAH,EAAAE,EACA,EAGAa,yBAAA,CAAA5C,EAAAkC,EAAAF,EAAAH,EAAAE,KAEAnJ,KAAAiK,oBAAAX,EAAAC,KAAAnC,EAAAC,EAAA8B,GAEA,MAAAe,EAAA9C,EAAAG,EAAA6B,EAAApJ,KAAA0I,cACA1I,KAAAmK,oBAAAD,GAAA,GAGA,MAAAE,EAAAhB,EAAApJ,KAAA0I,cACA1I,KAAAqK,oBAAAjD,EAAAG,EAAAH,EAAAC,EAAA+C,EAAA,EAGAL,yBAAA,CAAA3C,EAAAkC,EAAAF,EAAAH,EAAAE,KAIA,MAAAmB,EAAAnB,EAAAE,QAAAjC,EAAAG,EAAA6B,GACApJ,KAAAiK,oBAAAX,EAAAC,KAAAnC,EAAAC,EAAA8B,GACAnJ,KAAAmK,oBAAAG,GAAA,GAGA,MAAAC,EAAAvK,KAAAuF,QAAAE,IAAAsB,aAAA,EACAyD,EAAApD,EAAAG,EAAA6B,EAAAmB,EACAH,EAAAhB,EAAAmB,EAEAvK,KAAAqK,oBAAAG,EAAApD,EAAAC,EAAA+C,EAAA,EAGAD,oBAAA,CAAAD,EAAAO,KAEAA,GACAzK,KAAAuF,QAAAE,IAAA/F,MAAA8J,IAAA,GAAAU,MACAlK,KAAAuF,QAAAE,IAAA/F,MAAAgL,OAAA,SAEA1K,KAAAuF,QAAAE,IAAA/F,MAAA8J,IAAA,OACAxJ,KAAAuF,QAAAE,IAAA/F,MAAAgL,OAAA,GAAAR,MACA,EAGAD,oBAAA,CAAAU,EAAAC,EAAAzB,KACA,MAAA0B,EAAA7K,KAAAuF,QAAAE,IAAAqE,YAGAgB,EAAAD,EAAA,EAGAF,EAAAxB,EAAAU,MAAA,EAEA7J,KAAAuF,QAAAE,IAAA/F,MAAA6J,KAAAqB,EAAA,EAAAE,EAAA,KAGAH,EAAAE,EAAA1B,EAAAU,MAAA,EAEA7J,KAAAuF,QAAAE,IAAA/F,MAAA6J,KAAAqB,EAAAC,EAAA,EAAA,KAGA7K,KAAAuF,QAAAE,IAAA/F,MAAA6J,KAAAqB,EAAAE,EAAA,IAEA,EAGAnB,qBAAAvC,IAEApH,KAAAuF,QAAAK,KAAAlG,MAAA8J,IAAA,GAAApC,EAAAG,MAEAvH,KAAAuF,QAAAK,KAAAlG,MAAA6J,KAAA,GAAAnC,EAAAC,KAAA,EAGAgD,oBAAA,CAAAH,EAAAa,EAAAX,KAEApK,KAAAuF,QAAAM,SAAAnG,MAAA8J,IAAA,GAAAU,MACAlK,KAAAuF,QAAAM,SAAAnG,MAAA2J,OAAA,GAAAe,MAEApK,KAAAuF,QAAAM,SAAAnG,MAAA6J,KAAA,GAAAwB,EAAA/K,KAAAuF,QAAAK,KAAAkE,YAAA,KAAA,EAGAf,eAAA7H,IAEA,IAAA8J,EAAA,GAEA,MAAAC,EAAA,CAAAC,EAAAC,IAGA,gBADAA,EAAAvM,OAAAC,QAAAsM,GAAApL,KAAA,EAAAqL,EAAAhH,KAAA,GAAAgH,MAAAhH,MAAAC,KAAA,MAAA,OACA6G,WAIA,IAAA,MAAAnM,KAAAmC,EAAA,CACA,MAAAmK,EAAAnK,EAAAnC,GAGA,GAAA,OAAAsM,GAAA,iBAAAA,EAAA,CAEA,IAAAC,EAAAD,EAAA/M,MAEA+M,EAAAE,YACAF,EAAAE,WAAApM,SAAA,EAAAb,QAAAoB,YAGA,MAAA8L,EAAAxL,KAAAyI,WAAAzI,KAAAyI,UAAA/I,GAAAM,KAAAyI,UAAA/I,GAAAA,EAEA,GAAA8L,EAAA,CAEA,MAAAC,EAAA,IAAAC,OAAA,IAAApN,KAAA,KACAgN,EAAAA,EAAAK,QAAAF,GAAAG,GAAAX,EAAAW,EAAAJ,IACA,KAKA,MAAAA,EAAAxL,KAAAyI,WAAAzI,KAAAyI,UAAA4C,EAAA3L,OAAAM,KAAAyI,UAAA4C,EAAA3L,OAAA2L,EAAA3L,MAEA,IAAAmM,EAGAA,EAFAL,EAEAP,EAAAK,EAAAE,GAEA,SAAAF,WAGAN,GAAAa,CACA,CACA,CAEA7L,KAAAuF,QAAAI,QAAA/D,UAAAoJ,CAAA,EAGAhC,mBAAA5J,IAEAY,KAAAuF,QAAAG,MAAA9D,UAAAlE,EAAAwG,aAAA9E,EAAA,EAOA,MAAA6D,EACAnD,YAAAC,EAAA+C,GACA9C,KAAAnC,WAAAkC,EACAC,KAAA8C,wBAAAA,EAEA9C,KAAA8L,UACA,CAEAC,SAAA,CAAAC,EAAAC,KAEA,IAAAC,EACA,OAAA,YAAAC,GACAC,aAAAF,GACAA,EAAAtH,YAAA,KACAoH,KAAAG,EAAA,GACAF,EACA,CAAA,EAIA/I,sBAAA,KACAlD,KAAA8L,aAGA9L,KAAA8L,YAAA,EAGA9L,KAAA8C,wBAAAgE,wBAAA,WAAA,GAAA,EAGA3D,sBAAAnD,KAAA+L,UAAA,KAGA,GAFA/L,KAAA8C,wBAAAgE,wBAAA,WAAA,GAEA,GAAA9G,KAAAnC,WAAAkJ,aAGA,OAFA/G,KAAA8C,wBAAAgF,oCACA9H,KAAA8C,wBAAAgE,wBAAA,cAAA,GAMA9G,KAAA8C,wBAAAsC,iBAGApF,KAAA8C,wBAAAiC,mBAGA/E,KAAA8C,wBAAAmE,yBAIAjH,KAAA8L,YAAA,CAAA,GACA,KAIA,MAAAO,EAAA,GACAvP,EAAAqC,SAAAmN,IACA,MAAAvM,EAAA,IAAAF,EAAAyM,GACAD,EAAAhK,KAAAtC,EAAA,IAGApD,OAAAC,iBAAA,UAAA,KACAyP,EAAAlN,SAAAoN,IACAA,EAAA9K,oBAAA,GACA,IAGA,oBAAA5E,4BACAF,OAAAE,2BAAA,EACA","file":"cms2-interactive-map.min.js","sourcesContent":["\r\nwindow.addEventListener('load', () => {\r\n\r\n if (typeof window.cnfsdInteractiveMApLoaded !== 'undefined') {\r\n\t\treturn;\r\n\t}\r\n\r\n const maps = document.querySelectorAll('.mod-interactive-map');\r\n if (!maps) return;\r\n \r\n const mapConfig = {\r\n partialAttributeName: 'data-map-id',\r\n fillColourDefault: '#AFAEAE',\r\n strokeColourDefault: '#1F1F1F',\r\n interactiveFillColourInactive: '#E5E5E5',\r\n interactiveFillColourActive: '#58AAE0'\r\n }\r\n\r\n\r\n\r\n class InteractiveMapDefaultSetter {\r\n\r\n // SET PATHS DEFAULT\r\n static setDefaultPathColours(path) {\r\n InteractiveMapHelpers.updatePathColourHelper(path, mapConfig.fillColourDefault)\r\n path.setAttribute('stroke', mapConfig.strokeColourDefault);\r\n }\r\n\r\n // SET ATTRIBUTES TO DEFAULT\r\n static setDefaultMapAttributes(mapElement) {\r\n mapElement.setAttribute('aria-live', 'polite');\r\n mapElement.setAttribute('aria-label', 'Press enter to interact with the map.');\r\n }\r\n\r\n //SET THE DEFAULT COLOUR OF INTERACTIVE REGIONS\r\n static setInteractivePathStateInactiveState(path) {\r\n InteractiveMapHelpers.updatePathColourHelper(path, mapConfig.interactiveFillColourInactive)\r\n path.classList.add('interactive');\r\n } \r\n }\r\n\r\n\r\n class InteractiveMapHelpers {\r\n\r\n // LOOP THROUGH PATH ATTRIBUTES AND MATCH ANY DATA-MAP-ID{ANYTHING} ATTRIBUTES\r\n static findMatchingAttributeHelper = (path, callback) => {\r\n for (const attribute of path.attributes) {\r\n const attributeName = attribute.name;\r\n const attributeValue = attribute.value;\r\n\r\n if (attributeName.toLowerCase().includes(mapConfig.partialAttributeName.toLowerCase())) {\r\n callback(attributeValue, path);\r\n }\r\n }\r\n }\r\n\r\n static updatePathColourHelper(path, colour) {\r\n if (path) path.setAttribute('fill', colour);\r\n }\r\n\r\n\r\n static findSelectedRegionByAttributeHelper = (interactivePathsObject, matchingAttribute) => {\r\n return Object.entries(interactivePathsObject).find(([key]) => key === matchingAttribute);\r\n }\r\n\r\n static pathLooperHelper = (paths, callback, colour) => {\r\n if (!paths || !callback) return;\r\n\r\n if (Array.isArray(paths)) {\r\n paths.forEach(path => {\r\n callback(path, colour ?? null);\r\n })\r\n } else {\r\n callback(paths, colour ?? null);\r\n }\r\n }\r\n\r\n static regionParser = (region) => {\r\n return region.replaceAll('_', ' ');\r\n }\r\n\r\n static setPathTabIndexHelper = (path, index) => {\r\n path.tabIndex = index\r\n }\r\n\r\n static toggleElementVisibility = (element, isVisible) => {\r\n if (isVisible) {\r\n element.style.visibility = 'visible';\r\n } else {\r\n element.style.visibility = 'hidden';\r\n }\r\n }\r\n\r\n\r\n static toggleElementDisplay = (element, isVisible) => {\r\n if (isVisible) {\r\n element.style.display = 'block';\r\n } else {\r\n element.style.display = 'none';\r\n }\r\n }\r\n }\r\n\r\n\r\n\r\n class InteractiveMapInitialisation {\r\n constructor(map) {\r\n this.mapContainer = map;\r\n this.mapElement;\r\n\r\n this.setMapTitle();\r\n\r\n this.interactivePaths = {};\r\n\r\n this.jsonData;\r\n this.handleJsonData();\r\n\r\n if (this.jsonData) this.initialiseInteractiveMap(this.jsonData);\r\n \r\n this.eventHandlerInstance;\r\n }\r\n \r\n initialiseInteractiveMap(jsonData) {\r\n if (!jsonData) return;\r\n\r\n //SETS JSON DATA IF DOESN'T EXIST \r\n if (!this.jsonData) this.jsonData = jsonData\r\n\r\n this.initialiseInteractivePaths();\r\n\r\n if (!this.interactivePaths) return;\r\n\r\n this.mapElement = this.mapContainer.querySelector('.mod-interactive-map__inner-container');\r\n this.setMapTabIndex(this.mapElement);\r\n this.eventHandlerInstance = new InteractiveMapEventHandler(this.mapContainer, this.mapElement, this.interactivePaths);\r\n }\r\n\r\n\r\n handleJsonData = () => {\r\n const jsonURL = this.mapContainer.getAttribute('data-map-url');\r\n const jsonData = this.mapContainer.getAttribute('data-map-json');\r\n\r\n if (jsonURL) {\r\n // IF JSON ADDED AS A URL\r\n fetch(jsonURL)\r\n .then(response => response.json())\r\n .then(data => {\r\n this.initialiseInteractiveMap(data);\r\n })\r\n .catch(error => {\r\n console.error('Error fetching JSON data from URL:', error);\r\n });\r\n } else if (jsonData) {\r\n //IF JSON ADDED AS A HTML ATTRIBUTE\r\n this.jsonData = JSON.parse(jsonData);\r\n } else {\r\n console.log('No JSON data or URL found for the map');\r\n }\r\n\r\n }\r\n\r\n handlePageResizing = () => {\r\n if (!this.interactivePaths) return;\r\n\r\n this.eventHandlerInstance.handlePageResizing();\r\n }\r\n\r\n setMapTitle = () => {\r\n //GET THE MAP TITLE ELEMENT\r\n const mapTitleElement = this.mapContainer.querySelector('.mod-interactive-map__title');\r\n const mapTitleValue = this.mapContainer.getAttribute('data-map-title');\r\n\r\n //CHECK MAP TITLE ATTRIBUTE EXISTS, IF SO, SET TITLE TEXT & TO VISIBLE\r\n if (mapTitleElement && mapTitleValue) {\r\n mapTitleElement.innerHTML = mapTitleValue;\r\n mapTitleElement.classList.remove('hidden'); \r\n }\r\n }\r\n\r\n\r\n initialiseInteractivePaths = () => {\r\n const allPaths = this.mapContainer.querySelectorAll('path, polygon');\r\n\r\n //LOOP THROUGH ALL PATHS AND PASS ATTRIBUTE MATCHER HELPER THE PATH AND CALLBACK FUNCTION (TO CREATE PATH THE OBJECT)\r\n Array.from(allPaths).forEach(path => {\r\n InteractiveMapDefaultSetter.setDefaultPathColours(path)\r\n InteractiveMapHelpers.findMatchingAttributeHelper(path, this.createInteractivePathObject);\r\n });\r\n }\r\n\r\n\r\n createInteractivePathObject = (attribute, path) => {\r\n //CHECKS IF PATH HAS MATCHING ATTRIBUTE WITH KEY IN DATA\r\n const matchingEntry = Object.entries(this.jsonData).find(([key]) => key === attribute);\r\n\r\n if (!matchingEntry) return;\r\n\r\n const [matchingKey, value] = matchingEntry;\r\n\r\n //IF KEY DOESN'T EXIST, SET EMPTY OBJECT\r\n if (!this.interactivePaths[matchingKey]) {\r\n //CREATE KEY\r\n this.interactivePaths[matchingKey] = {};\r\n //CREATE NEW KEYS FOR PATHS & DATA AND SET VALUES\r\n this.interactivePaths[matchingKey]['paths'] = path;\r\n this.interactivePaths[matchingKey]['tooltipData'] = value;\r\n } else {\r\n if (Array.isArray(this.interactivePaths[matchingKey].paths)) {\r\n //IF PATH VALUE IS ALREADY, PUSH INTO ARRAY \r\n this.interactivePaths[matchingKey].paths.push(path);\r\n } else {\r\n //ELSE CREATE NEW ARRAY FOR MATCHING KEY\r\n this.interactivePaths[matchingKey].paths = [this.interactivePaths[matchingKey].paths, path];\r\n }\r\n }\r\n\r\n //SET INTERACTIVE COLOUR TO EACH PATH\r\n InteractiveMapDefaultSetter.setInteractivePathStateInactiveState(path);\r\n }\r\n\r\n setMapTabIndex = (mapElement) => {\r\n if (!mapElement) return;\r\n mapElement.setAttribute('tabIndex', 0);\r\n }\r\n }\r\n\r\n\r\n\r\n\r\n\r\n class InteractiveMapEventHandler {\r\n constructor(map, mapElement, interactivePaths) {\r\n this.mapContainer = map;\r\n this.mapElement = mapElement;\r\n this.interactivePaths = interactivePaths;\r\n\r\n this.interactionType;\r\n this.tabbingActivated;\r\n\r\n this.selectedPath;\r\n\r\n this.tabbablePaths = [];\r\n\r\n this.initialiseInteractivePathInstance(map, mapElement, interactivePaths);\r\n\r\n this.initialiseResizeInstance(mapElement);\r\n\r\n this.initialiseListeners(mapElement);\r\n\r\n this.pathInteractionInstance;\r\n this.resizeInstance;\r\n }\r\n\r\n\r\n initialiseInteractivePathInstance = (mapContainer, mapElement, interactivePaths) => {\r\n //SET UP INTERACTIVE PATH HANDLER INSTANCE\r\n this.pathInteractionInstance = new InteractiveMapPathInteractionHandler(mapContainer, mapElement, interactivePaths);\r\n }\r\n\r\n initialiseResizeInstance(mapElement) {\r\n this.resizeInstance = new InteractiveMapResizeHandler(mapElement, this.pathInteractionInstance);\r\n }\r\n\r\n handlePageResizing = () => {\r\n this.resizeInstance.handleTooltipOnResize();\r\n this.resizeInstance.debounceResizeHandler();\r\n }\r\n\r\n initialiseListeners = (mapElement) => {\r\n //CLICK EVENT\r\n mapElement.addEventListener('mousedown', (e) => {\r\n this.interactionType = 'mouse';\r\n this.handlePathInteraction(e);\r\n e.stopPropagation();\r\n }, true);\r\n\r\n mapElement.addEventListener('focus', () => {\r\n mapElement.addEventListener('keydown', this.handleMapKeyPressListener);\r\n });\r\n }\r\n \r\n handleMapKeyPressListener = (e) => {\r\n\r\n if (e.key === 'Enter') {\r\n\r\n this.tabbingActivated = true;\r\n this.interactionType = 'keyboard';\r\n\r\n //LET USER KNOW THEY ARE IN THE MAP\r\n this.mapElement.setAttribute('aria-label', 'You are now in the mapElement');\r\n this.mapElement.classList.add('focused');\r\n\r\n //ATTACH E LISTENER TO DOCUMENT TO CHECK WHEN FOCUS LEAVES THE MAP\r\n document.addEventListener('focusin', this.handleFocusOutOfMap);\r\n\r\n\r\n let tabbablePaths = [];\r\n for (const [key, { paths, tooltipData }] of Object.entries(this.interactivePaths)) {\r\n\r\n const path = Array.isArray(paths) ? paths[0] : paths;\r\n\r\n if (!this.tabbablePaths.includes(path)) {\r\n tabbablePaths.push(path);\r\n\r\n const index = tabbablePaths.length;\r\n\r\n this.setFocusAttributes(path, index, tooltipData, key);\r\n this.setPathFocusEListener(path);\r\n }\r\n\r\n //SETS TAB INDEX TO 0 TO ENABLE PATHS TO BE TABBABLE\r\n InteractiveMapHelpers.setPathTabIndexHelper(path, 0);\r\n }\r\n\r\n this.tabbablePaths = tabbablePaths;\r\n\r\n e.target.blur();\r\n this.mapElement.removeEventListener('keydown', this.handleMapKeyPressListener);\r\n }\r\n }\r\n\r\n\r\n setFocusAttributes = (path, index, tooltipData, region) => {\r\n const parsedRegion = InteractiveMapHelpers.regionParser(region);\r\n\r\n const dataEntries = `${Object.entries(tooltipData).map(([key, val]) => `${key}: ${val.value}`).join(', ')}`\r\n\r\n //SET ARIA LABELS\r\n path.setAttribute('aria-label', `Region: ${parsedRegion}, ${dataEntries ?? dataEntries}`);\r\n\r\n //TELLS USER HOW MANY REGIONS IN MAP AND WHAT ONE THEY'RE ON\r\n path.setAttribute('aria-posinset', index);\r\n path.setAttribute('aria-setsize', Object.keys(this.interactivePaths).length);\r\n\r\n //USED TO HANDLE CLICK INTERFERANCE WITHIN HANDLE PATH INTERACTION FUNCTION\r\n path.setAttribute('tabbable', true);\r\n\r\n }\r\n\r\n setPathFocusEListener = (path) => {\r\n path.addEventListener('focus', this.handleMapPathFocused);\r\n }\r\n\r\n handleMapPathFocused = (e) => {\r\n if (this.interactionType === 'keyboard') {\r\n this.handlePathInteraction(e);\r\n } else {\r\n //SETS THE INTERACTION TYPE BACK TO KEYBOARD (FUNCTION ONLY RAN WHEN USER TABBING)\r\n this.interactionType = 'keyboard';\r\n }\r\n }\r\n\r\n checkTargetIsSVG = (element) => {\r\n return element instanceof SVGPathElement || element instanceof SVGPolygonElement;\r\n }\r\n\r\n\r\n handlePathInteraction = (e) => {\r\n const self = this;\r\n\r\n setTimeout(function() {\r\n //CHECKS IF SVG\r\n\r\n if (!self.checkTargetIsSVG(e.target)) {\r\n //SETS THE INTERACTION TYPE BACK TO KEYBOARD IF THE USER WAS TABBING\r\n if (self.tabbingActivated) self.interactionType = 'keyboard';\r\n\r\n self.pathInteractionInstance.handlePathNotInteracted(e.target);\r\n return; \r\n }\r\n\r\n //IF A USER CLICKS AN AREA THAT IS NOT TABBABLE, DO NOT SET ANYTHING\r\n if (!e.target.classList.contains('interactive')) {\r\n //RESET THE INTERACTION TYPE TO KEYBOARD IF THE USER WAS TABBING\r\n if (self.tabbingActivated) self.interactionType = 'keyboard';\r\n return;\r\n }\r\n\r\n \r\n //SETS INTERACTION TYPE BACK TO KEYBOARD IF THE USER HAS CLICKED THE MAP WHILST TABBING\r\n if (self.tabbingActivated && !e.target.getAttribute('tabbable')) self.interactionType = 'keyboard';\r\n\r\n self.pathInteractionInstance.createPlotObject(e.clientX, e.clientY)\r\n\r\n InteractiveMapHelpers.findMatchingAttributeHelper(e.target, self.pathInteractionInstance.checkForMatchingEntry);\r\n\r\n //SET MUTATION CONTROLLER TO FALSE SO THAT THE UPDATE TO DATA-SELECTED-REGION DOESN'T RUN CHECKFORMATCHINGENTRY TWICE\r\n self.pathInteractionInstance.mutationController = true;\r\n\r\n self.mapContainer.setAttribute('data-selected-region', self.pathInteractionInstance.selectedRegion);\r\n }, 0)\r\n }\r\n\r\n\r\n removeFocusInteractionFromPaths = () => {\r\n if (this.tabbablePaths.length === 0) return;\r\n \r\n this.tabbablePaths.forEach(path => {\r\n //SETS TAB INDEX TO 0 TO ENABLE PATHS TO BE TABBABLE\r\n InteractiveMapHelpers.setPathTabIndexHelper(path, -1);\r\n })\r\n }\r\n\r\n\r\n handleFocusOutOfMap = (e) => {\r\n //FUNCTION RESETS MAP TO DEFAULT WHEN USER TABS OUT OF MAP\r\n if (this.mapElement.contains(e.target)) return;\r\n\r\n this.mapElement.classList.remove('focused');\r\n\r\n //RESET MAP INTERACTION STATE (SO USER IS NOT FORCED INTO TABBING THROUGH MAP AGAIN)\r\n this.removeFocusInteractionFromPaths();\r\n\r\n //SET BACK TO DEFAULT ATTRIBUTES\r\n InteractiveMapDefaultSetter.setDefaultMapAttributes(this.mapElement);\r\n\r\n //RESET VARIABLES\r\n this.interactionType = null;\r\n this.tabbingActivated = false;\r\n\r\n this.pathInteractionInstance.handlePathNotInteracted(null);\r\n\r\n //REMOVE FOCUS E-LISTENER FROM DOCUMENT\r\n document.removeEventListener('focusin', this.handleFocusOutOfMap);\r\n }\r\n }\r\n\r\n\r\n class InteractiveMapPathInteractionHandler {\r\n constructor (map, mapElement, interactivePaths) {\r\n this.mapContainer = map;\r\n this.mapElement = mapElement;\r\n this.interactivePaths = interactivePaths;\r\n\r\n this.tooltip = {\r\n container: null,\r\n box: null,\r\n title: null,\r\n content: null,\r\n plot: null,\r\n plotLine: null\r\n }\r\n\r\n this.themeProductColour;\r\n\r\n this.mutationController = false;\r\n\r\n this.SelectedRegion;\r\n this.SelectedPaths;\r\n this.tooltipData;\r\n\r\n this.previouslySelectedPaths;\r\n\r\n this.tooltipManagerInstance;\r\n\r\n this.setInteractionPathColour();\r\n this.initObservation(map);\r\n this.initTooltipInstance();\r\n }\r\n\r\n setInteractionPathColour = () => {\r\n const productUIColour = getComputedStyle(document.body).getPropertyValue('--themeUiProductColour');\r\n this.themeProductColour = productUIColour !== \"#efefef\" || !productUIColour ? productUIColour : '#58aae0';\r\n }\r\n\r\n initObservation = (mapContainer) => {\r\n //OBSERVES EACH MAP ON PAGE FOR CHANGES IN THE DATA-SELECTED-REGION ATTRIBUTE\r\n const observer = new MutationObserver((mutations) => {\r\n mutations.forEach((mutation) => {\r\n if (mutation.type === 'attributes' && mutation.attributeName === 'data-selected-region') {\r\n const region = mapContainer.getAttribute('data-selected-region');\r\n\r\n\r\n if (!region) return this.toggleTooltipVisibility('visibility', false);\r\n\r\n //IF MAP HEIGHT IS 0, EXIT (HANDLES TAB)\r\n if (this.mapElement.offsetHeight === 0) return;\r\n\r\n\r\n //IF INTERACTION WAS NOT BY CLICK CHECK FOR MATCH\r\n if (!this.mutationController) {\r\n this.createPlotObject();\r\n this.checkForMatchingEntry(region);\r\n }\r\n\r\n //CHANGE PATH COLOUR\r\n this.handlePathColourChange(); \r\n\r\n //SET TOOLTIP DATA;\r\n this.handleTooltipCreation();\r\n\r\n //RESET CONTROLLER\r\n this.mutationController = false;\r\n }\r\n });\r\n });\r\n\r\n observer.observe(mapContainer, {attributes: true});\r\n }\r\n\r\n initTooltipInstance = () => {\r\n //GET TOOLTIP\r\n const tooltip = this.mapContainer.querySelector('.mod-interactive-map__tooltip');\r\n\r\n if (!tooltip) return;\r\n\r\n this.tooltip.container = tooltip;\r\n this.tooltip.box = tooltip.querySelector('.mod-interactive-map__tooltip__info-box');\r\n this.tooltip.title = tooltip.querySelector('.mod-interactive-map__tooltip__info-box__title');\r\n this.tooltip.content = tooltip.querySelector('.mod-interactive-map__tooltip__info-box__content');\r\n this.tooltip.plot = tooltip.querySelector('.mod-interactive-map__tooltip__plot');\r\n this.tooltip.plotLine = tooltip.querySelector('.mod-interactive-map__tooltip__plot-line');\r\n\r\n this.tooltipManagerInstance = new InteractiveMapTooltipManager(this.mapContainer, this.mapElement, this.tooltip);\r\n }\r\n\r\n createPlotObject = (clientX, clientY) => {\r\n\r\n if (!this.tooltipManagerInstance) return;\r\n\r\n let plotPosition = {\r\n x: undefined,\r\n y: undefined\r\n }\r\n\r\n if (clientX && clientY) {\r\n //IF USER MOUSE CLICKED\r\n plotPosition.x = clientX;\r\n plotPosition.y = clientY;\r\n }\r\n\r\n this.tooltipManagerInstance.plotPosition = plotPosition;\r\n }\r\n\r\n\r\n previouslySelectedPathHandler = (newlySelectedRegion) => {\r\n //GET PREVIOUSLY SELECTED PATHS\r\n const previouslySelectedPaths = this.getSelectedPaths();\r\n\r\n //IF THERE ARE NO PRIOR PATHS SELECTED, RETURN TRUE\r\n if (!previouslySelectedPaths) return true;\r\n\r\n //IF NEWLY SELECTED REGION IS DIFFERENT AS CURRENT REGION, DIFFERENT SELECTED PATHS WILL BE TRUE, ELSE IS FALSE\r\n this.newPathSelected = newlySelectedRegion !== this.selectedRegion;\r\n\r\n if (this.newPathSelected) {\r\n //CALL FUNCTION TO DESELECT PREVIOUS PATHS\r\n this.removePaths(previouslySelectedPaths);\r\n } else {\r\n //STORE PREVIOUSLY SELECTED PATHS AS BEING REMOVED\r\n this.previouslySelectedPaths = this.selectedPaths;\r\n }\r\n\r\n //RETURN TRUE/FALSE\r\n return this.newPathSelected;\r\n }\r\n\r\n \r\n getSelectedPaths = () => {\r\n if (this.selectedRegion) return this.interactivePaths[this.selectedRegion].paths;\r\n }\r\n\r\n removeCurrentlySelectedPaths = () => {\r\n this.removePaths(this.selectedPaths);\r\n this.selectedPaths = null;\r\n }\r\n\r\n removePaths = (previouslySelectedPaths) => {\r\n setTimeout(function() {\r\n InteractiveMapHelpers.pathLooperHelper(previouslySelectedPaths, InteractiveMapHelpers.updatePathColourHelper, mapConfig.interactiveFillColourInactive);\r\n }, 0);\r\n }\r\n\r\n\r\n checkForMatchingEntry = (region) => {\r\n const matchingEntry = InteractiveMapHelpers.findSelectedRegionByAttributeHelper(this.interactivePaths, region);\r\n if (!matchingEntry) return;\r\n\r\n const [matchingRegion, {paths, tooltipData}] = matchingEntry;\r\n\r\n const newPathSelected = this.previouslySelectedPathHandler(matchingRegion);\r\n\r\n //IF NEW PATH, SET PATHS REGION AND TOOLTIP, ELSE REMOVE THEM\r\n if (newPathSelected) {\r\n this.selectedPaths = paths;\r\n this.selectedRegion = matchingRegion;\r\n this.tooltipData = tooltipData;\r\n } else {\r\n this.resetPathInteraction();\r\n }\r\n }\r\n\r\n\r\n resetPathInteraction = () => {\r\n this.selectedPaths = null;\r\n this.selectedRegion = null;\r\n this.tooltipData = null;\r\n this.toggleTooltipVisibility('visibility', false);\r\n }\r\n\r\n handleTooltipCreation = () => {\r\n //PASSES ALL DATA REQUIRED TO CREATE TOOLTIP TO TOOLTIP INSTANCE\r\n const self = this;\r\n\r\n setTimeout(function() {\r\n if (!self.selectedPaths || !self.tooltipManagerInstance) return;\r\n\r\n let selectedPath;\r\n if (Array.isArray(self.selectedPaths)) selectedPath = self.selectedPaths[0];\r\n self.tooltipManagerInstance.createTooltip(selectedPath || self.selectedPaths, self.tooltipData, self.selectedRegion);\r\n }, 0)\r\n }\r\n\r\n\r\n handlePathNotInteracted = (target) => {\r\n //IF NO REGION SELECTED, EXIT FUNCTION\r\n if (this.selectedRegion === null) return;\r\n\r\n //IF TOOLTIP CLICKED, DO NOTHING\r\n const { box, plot, plotLine } = this.tooltip;\r\n if (\r\n target === box || \r\n box.contains(target) ||\r\n target === plot || \r\n target === plotLine\r\n ) return;\r\n\r\n //REMOVE TOOLTIP\r\n this.toggleTooltipVisibility('visibility', false);\r\n \r\n //REMOVE COLOUR FROM PREVIOUS AREA\r\n const previouslySelectedPaths = this.getSelectedPaths();\r\n if (previouslySelectedPaths) this.removePaths(previouslySelectedPaths);\r\n\r\n //REMOVE SELECTED REGION\r\n this.selectedRegion = null;\r\n this.mapContainer.setAttribute('data-selected-region', '');\r\n }\r\n\r\n toggleTooltipVisibility = (type, visibility) => {\r\n\r\n if (type === 'visibility') InteractiveMapHelpers.toggleElementVisibility(this.tooltip.container, visibility);\r\n\r\n if (type === 'display') InteractiveMapHelpers.toggleElementDisplay(this.tooltip.container, visibility);\r\n \r\n }\r\n\r\n toggleTooltipDisplay = (displayed) => {\r\n InteractiveMapHelpers.toggleElementVisibility(this.tooltip.container, displayed);\r\n }\r\n\r\n\r\n handlePathColourChange = () => {\r\n let newPathColour;\r\n let paths = this.selectedPaths;\r\n\r\n if (this.selectedPaths) {\r\n newPathColour = this.themeProductColour ?? mapConfig.interactiveFillColourActive;\r\n } else {\r\n newPathColour = mapConfig.interactiveFillColourInactive;\r\n paths = this.previouslySelectedPaths;\r\n this.previouslySelectedPaths = null;\r\n }\r\n\r\n //SET PATH COLOUR TO NEW PATH COLOUR\r\n InteractiveMapHelpers.pathLooperHelper(paths, InteractiveMapHelpers.updatePathColourHelper, newPathColour);\r\n }\r\n }\r\n\r\n\r\n class InteractiveMapTooltipManager {\r\n constructor(map, mapElement, tooltip) {\r\n this.mapContainer = map\r\n this.mapElement = mapElement;\r\n this.tooltip = tooltip;\r\n\r\n this.styleData;\r\n\r\n this.tooltipMargin = 20;\r\n\r\n this.plotPosition = {\r\n x: undefined,\r\n y: undefined\r\n };\r\n\r\n this.getStyleData();\r\n }\r\n\r\n getStyleData = () => {\r\n const styleString = this.mapContainer.getAttribute('data-tooltip-styles');\r\n if (styleString) this.styleData = JSON.parse(styleString);\r\n }\r\n\r\n createTooltip = (pathElem, data, region) => {\r\n this.updateTooltipPosition(pathElem);\r\n this.setTooltipData(data);\r\n this.setTooltipBoxTitle(region);\r\n }\r\n\r\n updateTooltipPosition = (pathElem) => {\r\n const self = this;\r\n\r\n setTimeout(() => {\r\n //FUNCTION THAT STARTS POSITIONING THE TOOLTIP\r\n\r\n const pathRect = pathElem.getBoundingClientRect();\r\n const mapRect = self.mapElement.getBoundingClientRect();\r\n const halfofPathHeight = pathRect.height / 2;\r\n\r\n //PATH POSITION RELATIVE TO MAP SVG\r\n const positionRelativeToParent = {\r\n left: pathRect.left - mapRect.left,\r\n top: pathRect.top - mapRect.top,\r\n };\r\n\r\n const plotPosition = self.getPlotPosition(pathRect, positionRelativeToParent, halfofPathHeight, mapRect);\r\n\r\n //IF TOOLTIP SHOULD GO ABOVE/BELOW PATH\r\n self.checkPathRelativePosition(plotPosition, positionRelativeToParent, halfofPathHeight, pathRect, mapRect);\r\n\r\n //PASS COORDS (X,Y) FOR TOOLTIP POINT \r\n self.positionTooltipPoint(plotPosition);\r\n\r\n InteractiveMapHelpers.toggleElementVisibility(self.tooltip.container, true);\r\n\r\n }, 0);\r\n }\r\n\r\n getPlotPosition = (pathRect, positionRelativeToParent, halfofPathHeight, mapRect) => {\r\n const {x, y} = this.getPlotCenter();\r\n\r\n let plotPosition = {\r\n x: 0,\r\n y: 0\r\n };\r\n\r\n if (this.plotPosition.x && this.plotPosition.y) {\r\n // USES X AND Y FOR WHERE USER HAS CLICKED\r\n plotPosition.x = this.plotPosition.x - mapRect.left - x;\r\n plotPosition.y = this.plotPosition.y - mapRect.top - y;\r\n } else {\r\n //USES X AND Y FOR MIDDLE OF PATH (TABBING)\r\n plotPosition.x = positionRelativeToParent.left + (pathRect.width / 2) - x;\r\n plotPosition.y = positionRelativeToParent.top + (halfofPathHeight - y);\r\n }\r\n\r\n return plotPosition;\r\n }\r\n\r\n getPlotCenter = () => {\r\n //RETURNS THE EXACT CENTER OF THE PLOT POINT\r\n const tooltipCenter = {\r\n x: this.tooltip.plot.offsetWidth / 2,\r\n y: this.tooltip.plot.offsetHeight / 2\r\n }\r\n return tooltipCenter;\r\n }\r\n\r\n\r\n checkPathRelativePosition = (plotPosition, positionRelativeToParent, halfofPathHeight, pathRect, mapRect) => {\r\n //CHECKS IF PATH CLICKED IS ABOVE/ BELOW HALF WAY POINT OF MAP\r\n const pathBelowMapCenter = positionRelativeToParent.top > this.mapElement.offsetHeight / 2;\r\n if (pathBelowMapCenter) {\r\n this.handlePathBelowMapCenter(plotPosition,positionRelativeToParent, halfofPathHeight, pathRect, mapRect);\r\n } else {\r\n this.handlePathAboveMapCenter(plotPosition, positionRelativeToParent, halfofPathHeight, pathRect, mapRect);\r\n }\r\n }\r\n \r\n handlePathAboveMapCenter = (plotPosition, positionRelativeToParent, halfofPathHeight, pathRect, mapRect) => {\r\n //PASS Y POSITION AND VALUES FOR X POSITION CALCULATION FOR TOOLTIP BOX POSITION\r\n this.positionTooltipBoxX(positionRelativeToParent.left, plotPosition.x, mapRect);\r\n\r\n const yPosition = plotPosition.y + halfofPathHeight + this.tooltipMargin;\r\n this.positionTooltipBoxY(yPosition, true);\r\n\r\n //PASS HEIGHT, X AND Y COORDS FOR TOOLTIP LINE\r\n const lineHeight = halfofPathHeight + this.tooltipMargin;\r\n this.positionTooltipLine(plotPosition.y, plotPosition.x, lineHeight);\r\n }\r\n\r\n handlePathBelowMapCenter = (plotPosition ,positionRelativeToParent, halfofPathHeight, pathRect, mapRect) => {\r\n //PASS Y POSITION AND VALUES FOR X POSITION CALCULATION FOR TOOLTIP BOX POSITION\r\n \r\n //BOX POSITIONING\r\n const boxYPosition = mapRect.height - (plotPosition.y - halfofPathHeight)\r\n this.positionTooltipBoxX(positionRelativeToParent.left, plotPosition.x, mapRect);\r\n this.positionTooltipBoxY(boxYPosition, false);\r\n\r\n //LINE POSITIONING\r\n const halfOfBoxHeight = this.tooltip.box.offsetHeight /2,\r\n lineStartPoint = plotPosition.y - halfofPathHeight - halfOfBoxHeight,\r\n lineHeight = halfofPathHeight + halfOfBoxHeight;\r\n\r\n this.positionTooltipLine(lineStartPoint, plotPosition.x, lineHeight);\r\n }\r\n\r\n positionTooltipBoxY = (yPosition, isAbove) => {\r\n //SET Y POSITION OF POPUP BOX (STRING VALUES IN PIXELS)\r\n if (isAbove) {\r\n this.tooltip.box.style.top = `${yPosition}px`;\r\n this.tooltip.box.style.bottom = `auto`;\r\n } else {\r\n this.tooltip.box.style.top = `auto`;\r\n this.tooltip.box.style.bottom = `${yPosition}px`;\r\n }\r\n }\r\n\r\n positionTooltipBoxX = (xPlot, plotPositionX, mapRect) => {\r\n const tooltipWidth = this.tooltip.box.offsetWidth;\r\n\r\n //QUARTER WIDTH OF TOOLTIP FOR PADDING\r\n const quarterTooltipWidth = tooltipWidth / 4;\r\n\r\n //IF PATH IS ON RIGHT SIDE OF MAP\r\n if (xPlot > mapRect.width / 2) {\r\n //CHANGE THE LEFT OF THE TOOLTIP BOX TO THE RIGHT SIDE OF THE LINE\r\n this.tooltip.box.style.left = `${plotPositionX - (quarterTooltipWidth * 3)}px`;\r\n } else {\r\n //IF TOOLTIP GOING OFF SCREEN (5 FOR A BIT OF PADDING)\r\n if (xPlot + tooltipWidth > mapRect.width - 5) {\r\n //SET TOOLTIP BOX TO CENTER OF LINE\r\n this.tooltip.box.style.left = `${plotPositionX - (tooltipWidth / 2)}px`;\r\n } else {\r\n //CHANGE THE LEFT OF THE TOOLTIP BOX TO THE RIGHT SIDE OF THE LINE\r\n this.tooltip.box.style.left = `${plotPositionX - quarterTooltipWidth}px`;\r\n }\r\n }\r\n }\r\n\r\n positionTooltipPoint = (plotPosition) => {\r\n //SET Y POSITION OF POPUP BOX\r\n this.tooltip.plot.style.top = `${plotPosition.y}px`;\r\n //SET X POSITION OF POPUP BOX\r\n this.tooltip.plot.style.left = `${plotPosition.x}px`;\r\n }\r\n \r\n positionTooltipLine = (yPosition, xPosition, lineHeight) => {\r\n //SET TOOLTIP LINE HEIGHT & TOP \r\n this.tooltip.plotLine.style.top = `${yPosition}px`;\r\n this.tooltip.plotLine.style.height = `${lineHeight}px`;\r\n //X POSITION OF LINE IS X POSITION OF PLOT POINT PLUS HALF THE PLOT POINT WIDTH (MIDDLE OF PLOT)\r\n this.tooltip.plotLine.style.left = `${xPosition + (this.tooltip.plot.offsetWidth / 2 )}px`;\r\n }\r\n\r\n setTooltipData = (data) => {\r\n //ACCEPTS THE DATA TO BE ADDED TO THE TOOLTIP\r\n let contentHTML = '';\r\n\r\n const createSpanWithStyles = (text, styles) => {\r\n //LOOP THROUGH EACH ITEM IN STYLES OBJECT, SET KEY TO STYLE PROPERTY AND VALUE TO THE STYLE VALUE\r\n const styleString = styles ? Object.entries(styles).map(([prop, val]) => `${prop}: ${val}`).join('; ') : '';\r\n return `${text}`;\r\n };\r\n\r\n //FOR EACH KEY IN IN THE JSON IN THE REGION USER CLICKED\r\n for (const key in data) {\r\n const valueObj = data[key];\r\n \r\n //IF VALUE NOT NULL AND IS OBJECT\r\n if (valueObj !== null && typeof valueObj === 'object') {\r\n\r\n let valueString = valueObj.value;\r\n //IF STYLETEXT EXIST UPDATE VALUESTRING WITH NEW STYLED SPANS (IF MATCHES EXIST)\r\n if (valueObj.styledText) {\r\n valueObj.styledText.forEach(({ value, style }) => {\r\n \r\n //IF STYLE VALUE EXISTS IN STYLE DATA, SET STYLES TO ADD TO STYLE DATA VALUE ELSE SET TO STYLES\r\n const stylesToAdd = this.styleData && this.styleData[style] ? this.styleData[style] : style;\r\n\r\n if (stylesToAdd) {\r\n //MATCH DESIRED TEXT WITHIN ORIGINAL VALUE AND PASS TO CREATESPANFUNCTION\r\n const regex = new RegExp(`(${value})`, 'g');\r\n valueString = valueString.replace(regex, match => createSpanWithStyles(match, stylesToAdd));\r\n }\r\n });\r\n }\r\n\r\n //IF STYLE DATA OBJECT EXISTS, USE \r\n const stylesToAdd = this.styleData && this.styleData[valueObj.style] ? this.styleData[valueObj.style] : valueObj.style;\r\n\r\n let valueHTML;\r\n if (stylesToAdd) {\r\n //IF STYLE KEY EXISTS IN OBJ, PASS TO STYLING FUNCTION\r\n valueHTML = createSpanWithStyles(valueString, stylesToAdd);\r\n } else {\r\n valueHTML = `${valueString}`;\r\n }\r\n \r\n contentHTML += valueHTML;\r\n }\r\n }\r\n //UPDATE INNERHTML OF TOOLTIP\r\n this.tooltip.content.innerHTML = contentHTML;\r\n };\r\n\r\n setTooltipBoxTitle = (region) => {\r\n //SET TOOLTIP TITLE TO REGION\r\n this.tooltip.title.innerHTML = InteractiveMapHelpers.regionParser(region);\r\n }\r\n }\r\n\r\n \r\n\r\n\r\n class InteractiveMapResizeHandler {\r\n constructor(map, pathInteractionInstance) {\r\n this.mapElement = map;\r\n this.pathInteractionInstance = pathInteractionInstance;\r\n \r\n this.isResizing;\r\n }\r\n\r\n debounce = (func, delay) => {\r\n //DEBOUNCE FUNCTION FOR RESIZE\r\n let timeoutId;\r\n return function (...args) {\r\n clearTimeout(timeoutId);\r\n timeoutId = setTimeout(() => {\r\n func(...args);\r\n }, delay);\r\n };\r\n }\r\n\r\n\r\n handleTooltipOnResize = () => {\r\n if (this.isResizing) return;\r\n\r\n //RESIZE STARTING\r\n this.isResizing = true;\r\n\r\n //SET TOOLTIP TO DISPLAY NONE WHEN RESIZING (DOESN'T CAUSE OVERFLOW ISSUES WITH LARGE TOOLTIPS)\r\n this.pathInteractionInstance.toggleTooltipVisibility('display', false);\r\n }\r\n\r\n debounceResizeHandler = this.debounce(() => {\r\n this.pathInteractionInstance.toggleTooltipVisibility('display', true);\r\n\r\n if (this.mapElement.offsetHeight == 0) {\r\n this.pathInteractionInstance.removeCurrentlySelectedPaths();\r\n this.pathInteractionInstance.toggleTooltipVisibility('visibility', false);\r\n return;\r\n }\r\n\r\n\r\n //RECALC THE TOOLTIP POSITION ONCE RESIZE IS DONE\r\n if (this.pathInteractionInstance.selectedRegion) {\r\n\r\n //RESET PLOT POINT TO NULL SO THAT THE TOOLTIP CAN BE POSITIONED TO CENTER OF PATH ELEMENT\r\n this.pathInteractionInstance.createPlotObject();\r\n\r\n //SET TOOLTIP POSITION\r\n this.pathInteractionInstance.handleTooltipCreation();\r\n }\r\n\r\n //RESIZE FINISHED\r\n this.isResizing = false;\r\n }, 200);\r\n }\r\n\r\n\r\n const mapInstances = [];\r\n maps.forEach(mapSVG => {\r\n const map = new InteractiveMapInitialisation(mapSVG);\r\n mapInstances.push(map);\r\n });\r\n\r\n window.addEventListener('resize', () => {\r\n mapInstances.forEach(mapInstance => {\r\n mapInstance.handlePageResizing();\r\n });\r\n });\r\n\r\n if (typeof cnfsdInteractiveMApLoaded === 'undefined') {\r\n\t\twindow.cnfsdInteractiveMApLoaded = true;\r\n\t}\r\n});"]}