1/** 2 * Swiss Bike Park - Interactive Map 3 * sbpim 4 * box: swissbikepark-2020 5 * author: sandra 6 * 7 * description: 8 * this script adds interactivity to a inline svg map (in code part). 9 * there is no interactivity on mobile/tablet, only on desktop >1024. 10 * When clicked on a number on a map, the corresponding popup opens and the track 11 * is highlighted. 12 */ 13sbpim = { 14 15 init: function() { 16 imContainer = document.querySelector('.interactiveMap') 17 if (!imContainer) { 18 return 19 } 20 imNumberContainer = imContainer.querySelector('.iM__background') 21 imNumbers = imContainer.querySelectorAll('.iM__background .num') 22 imPopupsContainer = imContainer.querySelector('.iM__popups') 23 imCloseLinks = imContainer.querySelectorAll('.iM__close') 24 activeClassName = 'is-active' 25 scrollbarOffset = imContainer.getBoundingClientRect().left 26 supportsNativeSmoothScroll = 'scrollBehavior' in document.documentElement.style 27 28 sbpim.addNumbersToPopup() 29 sbpim.setupListeners() 30 }, 31 32 setupListeners: function() { 33 imNumbers.forEach(function(num){ 34 num.addEventListener('click', sbpim.handleNumClick) 35 }) 36 37 imCloseLinks.forEach(function(link){ 38 link.addEventListener('click', sbpim.closeAll) 39 }) 40 41 window.addEventListener('resize', function(event) { 42 if (sbpim.isInteractive()) { 43 sbpim.positionPopups() 44 } 45 }) 46 47 document.addEventListener('keyup', function (event) { 48 var key = event.key || event.keyCode 49 if (key === 'Escape' || key === 'Esc' || key === 27) { 50 sbpim.closeAll() 51 } 52 }) 53 }, 54 55 handleNumClick: function() { 56 var num = this 57 if (!sbpim.isInteractive()) { 58 var popup = imPopupsContainer.querySelector('.iM__popup--'+num.dataset.number) 59 var yOffset = document.querySelector('.section--header').getHeight() 60 const y = popup.getBoundingClientRect().top + window.pageYOffset - yOffset - 16 61 62 //window.scrollTo({top: y, behavior: 'smooth'}); 63 64 if (supportsNativeSmoothScroll) { 65 console.log('nativeSmoothScrollTo') 66 sbpim.nativeSmoothScrollTo(y); 67 } else { 68 console.log('old scroll') 69 sbpim.smoothScrollTo(y, 600); 70 } 71 return 72 } 73 sbpim.closeAll() 74 imPopupsContainer.querySelector('.iM__popup--'+num.dataset.number).classList.add(activeClassName) 75 imContainer.querySelector('.track--'+num.dataset.number).classList.add(activeClassName) 76 }, 77 78 positionPopups: function() { 79 var containerOffsetTop = imContainer.getBoundingClientRect().top 80 imNumbers.forEach(function(num){ 81 var numBounding = num.getBoundingClientRect() 82 var popup = imPopupsContainer.querySelector('.iM__popup--'+num.dataset.number) 83 var popupNumber = imPopupsContainer.querySelector('.iM__number--'+num.dataset.number) 84 var top = numBounding.top + (numBounding.height * 0.5) - containerOffsetTop 85 var left = numBounding.left + (numBounding.width * 0.5) - scrollbarOffset 86 if(numBounding.left > (window.innerWidth / 2) && num.dataset.number != 11) { 87 popup.classList.add('iM__popup--right') 88 } 89 popup.style.top = top + 'px' 90 popup.style.left = left + 'px' 91 92 sbpim.setNodeDimensions(popupNumber, numBounding) 93 }) 94 }, 95 96 addNumbersToPopup: function() { 97 imPopupsContainer.children.forEach(function(popup) { 98 var id = popup.dataset.popup 99 var numBounding = imNumberContainer.querySelector('.num--'+ id).getBoundingClientRect() 100 101 var img = document.createElement('img') 102 img.setAttribute('src', '/images/nums/num-'+ id +'.svg') 103 img.setAttribute('alt', id) 104 img.classList.add('iM__number', 'iM__number--' + id) 105 if(numBounding.left > (window.innerWidth / 2) && id != 11) { 106 img.classList.add('iM__number--right') 107 } 108 sbpim.setNodeDimensions(img, numBounding) 109 110 img.addEventListener('click', sbpim.closeAll) 111 popup.appendChild(img) 112 113 }) 114 sbpim.positionPopups() 115 }, 116 117 closeAll: function() { 118 imContainer.querySelectorAll('.'+activeClassName).forEach(function(n) {n.classList.remove(activeClassName)}) 119 }, 120 121 setNodeDimensions: function(node, nodeBounding) { 122 node.style.height = nodeBounding.height+'px' 123 node.style.width = nodeBounding.width+'px' 124 }, 125 126 isInteractive: function() { 127 return (window.innerWidth >= 1024) 128 }, 129 130 // polyfilled smooth scrolling for IE, Edge & Safari 131 smoothScrollTo: function(to, duration) { 132 var element = document.scrollingElement || document.documentElement, 133 start = element.scrollTop, 134 change = to - start, 135 startDate = +new Date() 136 137 // t = current time 138 // b = start value 139 // c = change in value 140 // d = duration 141 var easeInOutQuad = function(t, b, c, d) { 142 t /= d/2 143 if (t < 1) return c/2*t*t + b 144 t-- 145 return -c/2 * (t*(t-2) - 1) + b 146 }; 147 148 var animateScroll = function() { 149 const currentDate = +new Date() 150 const currentTime = currentDate - startDate 151 element.scrollTop = parseInt(easeInOutQuad(currentTime, start, change, duration)) 152 if(currentTime < duration) { 153 requestAnimationFrame(animateScroll) 154 } 155 else { 156 element.scrollTop = to 157 } 158 } 159 animateScroll(); 160 }, 161 162 nativeSmoothScrollTo: function(y) { 163 window.scroll({ 164 behavior: 'smooth', 165 top: y 166 }) 167 } 168} 169 170document.addEventListener("DOMContentLoaded", sbpim.init)
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.