1/*! 2 * taxes.gov.az â interactive map 3 * Replaces the map handlers from main.js (they are detached below). 4 * 5 * Starts on DOM ready (jQuery ready runs after main.js's own ready handlers, 6 * because this file is included after it), so the map works as soon as the 7 * page is shown â without waiting for images, iframes and CDN scripts. 8 * A guard makes sure it runs only once even if the file is included twice. 9 */ 10(function () { 11 'use strict'; 12 13 function initTaxesMap() { 14 if (window.__taxesMapReady) { 15 return; 16 } 17 window.__taxesMapReady = true; 18 19 var $ = window.jQuery; 20 if (!$) { 21 return; 22 } 23 24 var $map = $('#taxes-map'); 25 if (!$map.length) { 26 return; 27 } 28 29 var tree = window.taxesMapTree || {}; 30 var $wrap = $('.map-interactive'); 31 var $popups = $('.popup-list .mypopup'); 32 var $select = $('.tmap-select'); 33 var svg = $map.closest('svg')[0]; 34 var CIRCLE_R = '3.5'; 35 var CIRCLE_R_ACTIVE = '5.5'; 36 var MOBILE_QUERY = '(max-width: 575px)'; 37 38 // Detach old handlers bound by main.js 39 $('.map-interactive .region-circle, .map-interactive .path-section').off('click'); 40 $('.popup-close').off('click'); 41 $('.select-region-mobil').off('change'); 42 43 function isMobile() { 44 return window.matchMedia && window.matchMedia(MOBILE_QUERY).matches; 45 } 46 47 48 /* ---------------------------------------------------------------------- 49 Mobile zoom (animated viewBox) 50 ---------------------------------------------------------------------- */ 51 52 var FULL_VIEW = svg ? [svg.viewBox.baseVal.x, svg.viewBox.baseVal.y, svg.viewBox.baseVal.width, svg.viewBox.baseVal.height] : null; 53 var viewAnim = null; 54 55 function getView() { 56 var b = svg.viewBox.baseVal; 57 return [b.x, b.y, b.width, b.height]; 58 } 59 60 function setView(v) { 61 svg.setAttribute('viewBox', v.join(' ')); 62 } 63 64 function animateView(to) { 65 if (!svg) { 66 return; 67 } 68 if (viewAnim) { 69 window.cancelAnimationFrame(viewAnim); 70 } 71 var from = getView(); 72 var start = null; 73 var duration = 450; 74 75 function step(ts) { 76 if (start === null) { 77 start = ts; 78 } 79 var p = Math.min(1, (ts - start) / duration); 80 var e = 1 - Math.pow(1 - p, 3); 81 setView(from.map(function (f, i) { 82 return f + (to[i] - f) * e; 83 })); 84 if (p < 1) { 85 viewAnim = window.requestAnimationFrame(step); 86 } 87 } 88 89 viewAnim = window.requestAnimationFrame(step); 90 } 91 92 // Bounding box of a region (shape + its labels) in SVG user units 93 function regionBox(code) { 94 var group = $map.find('.path-hover[data-atrr="' + code + '"]')[0]; 95 if (!group || !svg.getScreenCTM()) { 96 return null; 97 } 98 var r = group.getBoundingClientRect(); 99 var m = svg.getScreenCTM().inverse(); 100 var p1 = svg.createSVGPoint(); 101 var p2 = svg.createSVGPoint(); 102 p1.x = r.left; 103 p1.y = r.top; 104 p2.x = r.right; 105 p2.y = r.bottom; 106 p1 = p1.matrixTransform(m); 107 p2 = p2.matrixTransform(m); 108 return [p1.x, p1.y, p2.x - p1.x, p2.y - p1.y]; 109 } 110 111 function zoomToRegion(code) { 112 if (!svg || !isMobile()) { 113 return; 114 } 115 var b = regionBox(code); 116 if (!b) { 117 return; 118 } 119 var ratio = FULL_VIEW[2] / FULL_VIEW[3]; 120 var w = b[2] * 1.3; 121 var h = b[3] * 1.3; 122 123 if (w / h > ratio) { 124 h = w / ratio; 125 } else { 126 w = h * ratio; 127 } 128 129 // Limit the zoom so small regions (Bakı) do not become oversized 130 var minW = FULL_VIEW[2] / 4; 131 if (w < minW) { 132 w = minW; 133 h = w / ratio; 134 } 135 136 var cx = b[0] + b[2] / 2; 137 var cy = b[1] + b[3] / 2; 138 139 animateView([cx - w / 2, cy - h / 2, w, h]); 140 $wrap.addClass('tmap-zoomed'); 141 } 142 143 function zoomReset() { 144 if (!svg) { 145 return; 146 } 147 if ($wrap.hasClass('tmap-zoomed')) { 148 animateView(FULL_VIEW.slice()); 149 } 150 $wrap.removeClass('tmap-zoomed'); 151 } 152 153 154 /* ---------------------------------------------------------------------- 155 Popups and highlighting 156 ---------------------------------------------------------------------- */ 157 158 function findPopup(code) { 159 return $popups.filter(function () {
160 return $(this).attr('data-map-popup') === code; 161 }); 162 } 163 164 function regionOf(code, $el) { 165 if (tree[code]) { 166 return tree[code]; 167 } 168 if ($el && $el.length) { 169 var $group = $el.closest('.path-hover'); 170 if ($group.length) { 171 return $group.attr('data-atrr'); 172 } 173 } 174 return code; 175 } 176 177 function highlightRegion(regionCode) { 178 $map.find('.path-hover').removeClass('color-changed') 179 .filter('[data-atrr="' + regionCode + '"]').addClass('color-changed'); 180 } 181 182 function markDistrict(code) { 183 $map.find('.region-circle').attr('r', CIRCLE_R); 184 if (code) { 185 $map.find('.region-circle[data-id="' + code + '"]').attr('r', CIRCLE_R_ACTIVE); 186 } 187 } 188 189 // Map preview iframes are loaded only when their popup is opened 190 function loadMapPreview($popup) { 191 $popup.find('iframe[data-src]').each(function () { 192 var $frame = $(this); 193 $frame.attr('src', $frame.attr('data-src')).removeAttr('data-src'); 194 }); 195 } 196 197 function showPopup($popup) { 198 loadMapPreview($popup); 199 $popups.not($popup).stop(true, true).hide(); 200 $popup.stop(true, true).fadeIn(200).scrollTop(0); 201 } 202 203 function openCode(code, $el) { 204 if (!code) { 205 return; 206 } 207 208 var region = regionOf(code, $el); 209 var isDistrict = region !== code; 210 var $popup = findPopup(code); 211 212 // District without its own popup -> show its region popup 213 if (!$popup.length) { 214 $popup = findPopup(region); 215 } 216 217 highlightRegion(region); 218 markDistrict(isDistrict ? code : null); 219 220 if ($select.length) { 221 $select.val(region); 222 } 223 224 if (isMobile()) { 225 zoomToRegion(region); 226 $('html, body').stop(true).animate({ scrollTop: $wrap.offset().top - 12 }, 400); 227 } 228 229 if (!$popup.length) { 230 return; 231 } 232 233 showPopup($popup); 234 $wrap.addClass('map-click'); 235 236 if ($(window).width() <= 1180 && !isMobile()) { 237 $('html, body').stop(true).animate({ scrollTop: $popup.offset().top - 100 }, 600); 238 } 239 } 240 241 function closeAll() { 242 $popups.stop(true, true).fadeOut(150); 243 $map.find('.path-hover').removeClass('color-changed'); 244 markDistrict(null); 245 $wrap.removeClass('map-click'); 246 zoomReset(); 247 if ($select.length) { 248 $select.val(''); 249 } 250 } 251 252 253 /* ---------------------------------------------------------------------- 254 Events 255 ---------------------------------------------------------------------- */ 256 257 // District dots and labels 258 $map.on('click', '.region-circle, .path-section', function (e) { 259 e.stopPropagation(); 260 openCode($(this).attr('data-id'), $(this)); 261 }); 262 263 // Click on the region shape itself 264 $map.on('click', '.path-hover > path', function () { 265 openCode($(this).closest('.path-hover').attr('data-atrr')); 266 }); 267 268 // District links inside a popup 269 $(document).on('click', '.popup-list [data-map-link]', function (e) { 270 e.preventDefault(); 271 openCode($(this).attr('data-map-link')); 272 }); 273 274 $(document).on('click', '.popup-list .popup-close', function () { 275 closeAll(); 276 }); 277 278 $(document).on('keyup', function (e) { 279 if (e.key === 'Escape' || e.keyCode === 27) { 280 closeAll(); 281 } 282 }); 283 284 // Mobile region picker 285 $select.on('change', function () { 286 var code = $(this).val(); 287 if (code) { 288 openCode(code); 289 } else { 290 closeAll(); 291 } 292 }); 293 294 // Mobile "whole map" button 295 $('.tmap-reset').on('click', function () { 296 closeAll(); 297 }); 298 299 // Leaving the mobile layout (rotation / resize) restores the full map 300 var resizeTimer = null; 301 $(window).on('resize', function () { 302 window.clearTimeout(resizeTimer); 303 resizeTimer = window.setTimeout(function () { 304 if (!isMobile() && svg && $wrap.hasClass('tmap-zoomed')) {
305 setView(FULL_VIEW.slice()); 306 $wrap.removeClass('tmap-zoomed'); 307 } 308 }, 150); 309 }); 310 } 311 312 if (window.jQuery) { 313 window.jQuery(initTaxesMap); 314 } else { 315 window.addEventListener('load', initTaxesMap); 316 } 317})();
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.