1'use strict'; 2 3function _typeof(obj) { 4 '@babel/helpers - typeof'; 5 if (typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol') { 6 _typeof = function _typeof(obj) { 7 return typeof obj; 8 }; 9 } else { 10 _typeof = function _typeof(obj) { 11 return obj && 12 typeof Symbol === 'function' && 13 obj.constructor === Symbol && 14 obj !== Symbol.prototype 15 ? 'symbol' 16 : typeof obj; 17 }; 18 } 19 return _typeof(obj); 20} 21 22/** 23 * Geocluster function. Original: 24 * https://github.com/yetzt/node-geocluster 25 * and adapted to work with iMaps 26 */ 27function geocluster(elements, bias, defaults, tooltipTemplate) { 28 bias = parseFloat(bias); 29 if (!(this instanceof geocluster)) { 30 return new geocluster(elements, bias, defaults, tooltipTemplate); 31 } 32 return this._cluster(elements, bias, defaults, tooltipTemplate); 33} // degrees to radians 34 35geocluster.prototype._toRad = function (number) { 36 return (number * Math.PI) / 180; 37}; // geodetic distance approximation 38 39geocluster.prototype._dist = function (lat1, lon1, lat2, lon2) { 40 var dlat = this._toRad(lat2 - lat1); 41 42 var dlon = this._toRad(lon2 - lon1); 43 44 var a = 45 Math.sin(dlat / 2) * Math.sin(dlat / 2) + 46 Math.sin(dlon / 2) * 47 Math.sin(dlon / 2) * 48 Math.cos(this._toRad(lat1)) * 49 Math.cos(this._toRad(lat2)); 50 return Math.round(2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) * 6371 * 100) / 100; 51}; 52 53geocluster.prototype._centroid = function (set) { 54 var cetroidObj = Object.values(set).reduce( 55 function (accumulator, currentValue) { 56 return { 57 latitude: accumulator.latitude + currentValue.latitude, 58 longitude: accumulator.longitude + currentValue.longitude, 59 }; 60 }, 61 { 62 latitude: 0, 63 longitude: 0, 64 } 65 ); 66 cetroidObj = Object.values(cetroidObj).map(function (e) { 67 return e / Object.keys(set).length; 68 }); 69 return cetroidObj; 70}; 71 72geocluster.prototype._clean = function (data) { 73 return data.map(function (cluster) { 74 return [cluster.centroid, cluster.elements]; 75 }); 76}; 77 78geocluster.prototype._cluster = function (elements, bias, defaults, tooltipTemplate) { 79 var self = this, 80 clusterMapCollection = []; 81 var tempMarker; // set bias to 1 on default 82 83 if (typeof bias !== 'number' || isNaN(bias)) { 84 bias = 1; 85 } 86 87 // derive threshold from bias 88 var threshold = 10000 * bias; 89 var clusterMap = []; 90 91 // generate random initial cluster map 92 clusterMap.push({ 93 centroid: elements[Math.floor(0.5 * elements.length)], 94 elements: [], 95 fill: defaults.fill, 96 hover: defaults.hover, 97 radius: defaults.radius, 98 }); 99 100 // loop elements and distribute them to clusters 101 var changing = true; 102 103 while (changing === true) { 104 var newCluster = false; 105 var clusterChanged = false; // iterate over elements 106 107 elements.forEach(function (e) { 108 var closestDist = Infinity; 109 var closestCluster = null; // find closest cluster 110 111 clusterMap.forEach(function (cluster, ci) { 112 // distance to cluster 113 var dist = self._dist( 114 e.latitude, 115 e.longitude, 116 clusterMap[ci].centroid.latitude, 117 clusterMap[ci].centroid.longitude 118 ); 119 120 if (dist < closestDist) { 121 closestDist = dist; 122 closestCluster = ci; 123 } 124 }); // is the closest distance smaller than the stddev of elements? 125 126 if (closestDist < threshold || closestDist === 0) { 127 // put element into existing cluster 128 clusterMap[closestCluster].elements.push(e); 129 } else { 130 // create a new cluster with this element 131 clusterMap.push({ 132 centroid: e, 133 elements: [e], 134 }); 135 newCluster = true; 136 } 137 }); // delete empty clusters from clusterMap 138 139 clusterMap = clusterMap.filter(function (cluster) { 140 return cluster.elements.length > 0; 141 }); // calculate the clusters centroids and check for change 142 143 clusterMap.forEach(function (cluster, ci) { 144 var centroid = self._centroid(cluster.elements); 145 146 changing = false; 147 148 if ( 149 centroid.latitude !== cluster.centroid.latitude || 150 centroid.longitude !== cluster.centroid.longitude 151 ) { 152 clusterMap[ci].centroid = centroid; 153 clusterChanged = true; 154 } 155 });
155 // loop cycle if clusters have changed 156 157 if (!clusterChanged && !newCluster) { 158 changing = false; 159 } else { 160 // remove all elements from clusters and run again 161 if (changing) { 162 clusterMap = clusterMap.map(function (cluster) { 163 cluster.elements = []; 164 return cluster; 165 }); 166 } 167 } 168 } 169 170 clusterMap = clusterMap.map(function (cluster) { 171 if (cluster.elements.length === 1) { 172 clusterMapCollection.push(cluster.elements[0]); 173 } else { 174 tempMarker = { 175 id: '', 176 label: cluster.elements.length, 177 name: '', 178 value: cluster.elements.length, 179 cluster: true, 180 latitude: cluster.centroid[0], 181 longitude: cluster.centroid[1], 182 elements: cluster.elements, 183 content: '', 184 fill: defaults.fill, 185 hover: defaults.hover, 186 radius: defaults.radius, 187 action: '', 188 }; // in case we have a custom tooltipTemplate 189 190 if (tooltipTemplate) { 191 tempMarker.tooltipTemplate = tooltipTemplate; 192 } 193 194 clusterMapCollection.push(tempMarker); 195 } 196 }); // compress result 197 198 return clusterMapCollection; 199}; 200/* ROUTER */ 201var iMapsRouter = {}; 202 203iMapsRouter.getGeoFiles = function (regionClicked) { 204 var regionID = regionClicked.id.toString(), 205 regionName = regionClicked.name, 206 urlappend, 207 varappend, 208 geoFiles = {}, 209 continents = [ 210 'southAmerica', 211 'northAmerica', 212 'europe', 213 'middleEast', 214 'asia', 215 'oceania', 216 'africa', 217 'antarctica', 218 ]; // continents 219 220 if (continents.includes(regionID)) { 221 urlappend = 'region/world/'; 222 varappend = '_region_world_'; 223 } // us maps 224 else if (regionID.includes('US-')) { 225 urlappend = 'region/usa/'; 226 varappend = '_region_usa_'; 227 regionID = regionID.substr(-2).toLowerCase(); 228 } else { 229 urlappend = ''; 230 varappend = '_'; 231 regionID = regionName.toLowerCase().replace('united states', 'usa'); 232 } 233 234 geoFiles.src = 'https://cdn.amcharts.com/lib/4/geodata/' + urlappend + regionID + 'Low.js'; 235 geoFiles.map = 'am4geodata' + varappend + regionID + 'Low'; 236 geoFiles.title = regionName; 237 return geoFiles; 238}; 239 240iMapsRouter.getAllSrc = function () { 241 var sources = {}, 242 paths = { 243 main: '../../vendor/geodata', 244 usa: '../../vendor/geodata/region/usa', 245 world: '../../vendor/geodata/region/world', 246 }; 247 248 var fs = require('fs'); 249 250 Object.keys(paths).forEach(function (item) { 251 sources[item] = []; 252 fs.readdir(paths[item], function (err, files) { 253 files.forEach(function (file) { 254 sources[item].push(file); 255 }); 256 }); 257 }); 258 return sources; 259}; 260/** 261 * get map am4charts variable name based on name value 262 */ 263 264iMapsRouter.getVarByName = function (variable) { 265 if (typeof variable === 'undefined') { 266 return 'am4geodata_worldLow'; 267 } else if (variable.includes('custom')) { 268 return variable; 269 } 270 271 variable = variable.replace(/\//g, '_'); 272 return 'am4geodata_' + variable; 273}; 274 275iMapsRouter.getCleanMapName = function (mapName, id) { 276 if (typeof mapName === 'undefined') { 277 return false; 278 } 279 280 mapName = mapName.replace('Low', ''); 281 mapName = mapName.replace('High', ''); 282 283 if (mapName === 'custom') { 284 mapName += id; 285 } 286 287 return mapName; 288}; 289 290iMapsRouter.iso2cleanName = function (iso, mapID) { 291 var countries = iMapsRouter.getCountries(); 292 var continents = [ 293 'africa', 294 'antarctiva', 295 'asia', 296 'europe', 297 'middleEast', 298 'northAmerica', 299 'oceania', 300 'southAmerica', 301 'centralAmerica', 302 ]; 303 var tempIso; 304 var series = iMapsManager.maps[mapID].seriesIndex; 305 var match = false; 306 console.log('ISO: ' + iso); // exceptions 307 308 if ('VA' === iso) { 309 return 'vatican'; 310 } else if ('US' === iso) { 311 return 'usa'; 312 } else if (iso.includes('CA-')) { 313 return 'region/canada/' + iso.replace('CA-', '').toLowerCase(); 314 } else if (iso.includes('MX-')) { 315 return 'region/mexico/' + iso.replace('MX-', '').toLowerCase(); 316 } else if (continents.includes(iso)) { 317 return 'region/world/' + iso; 318 } else if (iso.includes('US-')) { 319 tempIso = [ 320 'region/usa/' + iso.replace('US-', '').toLowerCase(), 321 'region/usa/congressional/' + iso.replace('US-', '').toLowerCase(), 322 'region/usa/congressional2022/' + iso.replace('US-', '').toLowerCase(), 323 ]; 324 } else if ('GB' === iso) { 325 tempIso = ['uk', 'ukCountries', 'ukCounties']; 326 } else if ('BA' === iso) { 327 tempIso = ['bosniaHerzegovinaCantons', 'bosniaHerzegovina']; 328 } else if ('IL' === iso) { 329 tempIso = ['israel', 'israelPalestine']; 330 } else if ('SI' === iso) { 331 tempIso = ['sloveniaRegions', 'slovenia']; 332 } else if ('IN' === iso) { 333 tempIso = ['india2019', 'india', 'india2020']; 334 } else if ('AE' === iso) { 335 tempIso = ['unitedArabEmirates', 'uae']; 336 } else if ('FR' === iso) { 337 tempIso = ['franceDepartments', 'france']; 338 } else if ('MG' === iso) { 339 tempIso = ['madagascarProvince', 'madagascarRegion']; 340 } else if ('PT' === iso) { 341 tempIso = ['portugal', 'portugalRegions']; 342 } else if ('RS' === iso) { 343 tempIso = ['serbia', 'serbiaNoKosovo']; 344 } else if ('CD' === iso) { 345 tempIso = ['congoDR']; 346 } else if ('CG' === iso) { 347 tempIso = ['congo']; 348 } else if ('CZ' === iso) { 349 tempIso = ['czechRepublic', 'czechia']; 350 } else if ('MM' === iso) { 351 tempIso = ['myanmar']; 352 } // the rest 353 354 // this block needs reviewing.. if/else are a mess 355 if (Array.isArray(tempIso)) {
356 tempIso.forEach(function (item) { 357 if (series.hasOwnProperty(item)) { 358 match = item; 359 } 360 }); 361 362 if (match) { 363 return match; 364 } else { 365 if (countries.hasOwnProperty(iso)) { 366 return iMapsRouter.camelize(countries[iso]); 367 } 368 } 369 } else { 370 if (countries.hasOwnProperty(iso)) { 371 return iMapsRouter.camelize(countries[iso]); 372 } 373 } 374 return false; 375}; 376 377iMapsRouter.getCountries = function () { 378 var rawjson = 379 '{"AF":"Afghanistan","AX":"\xC5land Islands","AL":"Albania","DZ":"Algeria","AS":"American Samoa","AD":"Andorra","AO":"Angola","AI":"Anguilla","AQ":"Antarctica","AG":"Antigua & Barbuda","AR":"Argentina","AM":"Armenia","AW":"Aruba","AC":"Ascension Island","AU":"Australia","AT":"Austria","AZ":"Azerbaijan","BS":"Bahamas","BH":"Bahrain","BD":"Bangladesh","BB":"Barbados","BY":"Belarus","BE":"Belgium","BZ":"Belize","BJ":"Benin","BM":"Bermuda","BT":"Bhutan","BO":"Bolivia","BA":"Bosnia & Herzegovina","BW":"Botswana","BR":"Brazil","IO":"British Indian Ocean Territory","VG":"British Virgin Islands","BN":"Brunei","BG":"Bulgaria","BF":"Burkina Faso","BI":"Burundi","KH":"Cambodia","CM":"Cameroon","CA":"Canada","IC":"Canary Islands","CV":"Cape Verde","BQ":"Caribbean Netherlands","KY":"Cayman Islands","CF":"Central African Republic","EA":"Ceuta & Melilla","TD":"Chad","CL":"Chile","CN":"China","CX":"Christmas Island","CC":"Cocos (Keeling) Islands","CO":"Colombia","KM":"Comoros","CG":"Congo - Brazzaville","CD":"Congo - Kinshasa","CK":"Cook Islands","CR":"Costa Rica","CI":"C\xF4te d\u2019Ivoire","HR":"Croatia","CU":"Cuba","CW":"Cura\xE7ao","CY":"Cyprus","CZ":"Czechia","DK":"Denmark","DG":"Diego Garcia","DJ":"Djibouti","DM":"Dominica","DO":"Dominican Republic","EC":"Ecuador","EG":"Egypt","SV":"El Salvador","GQ":"Equatorial Guinea","ER":"Eritrea","EE":"Estonia","SZ":"Eswatini","ET":"Ethiopia","FK":"Falkland Islands","FO":"Faroe Islands","FJ":"Fiji","FI":"Finland","FR":"France","GF":"French Guiana","PF":"French Polynesia","TF":"French Southern Territories","GA":"Gabon","GM":"Gambia","GE":"Georgia","DE":"Germany","GH":"Ghana","GI":"Gibraltar","GR":"Greece","GL":"Greenland","GD":"Grenada","GP":"Guadeloupe","GU":"Guam","GT":"Guatemala","GG":"Guernsey","GN":"Guinea","GW":"Guinea-Bissau","GY":"Guyana","HT":"Haiti","HN":"Honduras","HK":"Hong Kong SAR China","HU":"Hungary","IS":"Iceland","IN":"India","ID":"Indonesia","IR":"Iran","IQ":"Iraq","IE":"Ireland","IM":"Isle of Man","IL":"Israel","IT":"Italy","JM":"Jamaica","JP":"Japan","JE":"Jersey","JO":"Jordan","KZ":"Kazakhstan","KE":"Kenya","KI":"Kiribati","XK":"Kosovo","KW":"Kuwait","KG":"Kyrgyzstan","LA":"Laos","LV":"Latvia","LB":"Lebanon","LS":"Lesotho","LR":"Liberia","LY":"Libya","LI":"Liechtenstein","LT":"Lithuania","LU":"Luxembourg","MO":"Macao SAR China","MG":"Madagascar","MW":"Malawi","MY":"Malaysia","MV":"Maldives","ML":"Mali","MT":"Malta","MH":"Marshall Islands","MQ":"Martinique","MR":"Mauritania","MU":"Mauritius","YT":"Mayotte","MX":"Mexico","FM":"Micronesia","MD":"Moldova","MC":"Monaco","MN":"Mongolia","ME":"Montenegro","MS":"Montserrat","MA":"Morocco","MZ":"Mozambique","MM":"Myanmar (Burma)","NA":"Namibia","NR":"Nauru","NP":"Nepal","NL":"Netherlands","NC":"New Caledonia","NZ":"New Zealand","NI":"Nicaragua","NE":"Niger","NG":"Nigeria","NU":"Niue","NF":"Norfolk Island","KP":"North Korea","MK":"North Macedonia","MP":"Northern Mariana Islands","NO":"Norway","OM":"Oman","PK":"Pakistan","PW":"Palau","PS":"Palestinian Territories","PA":"Panama","PG":"Papua New Guinea","PY":"Paraguay","PE":"Peru","PH":"Philippines","PN":"Pitcairn Islands","PL":"Poland","PT":"Portugal","XA":"Pseudo-Accents","XB":"Pseudo-Bidi","PR":"Puerto Rico","QA":"Qatar","RE":"R\xE9union","RO":"Romania","RU":"Russia","RW":"Rwanda","WS":"Samoa","SM":"San Marino","ST":"S\xE3o Tom\xE9 & Pr\xEDncipe","SA":"Saudi Arabia","SN":"Senegal","RS":"Serbia","SC":"Seychelles","SL":"Sierra Leone","SG":"Singapore","SX":"Sint Maarten","SK":"Slovakia","SI":"Slovenia","SB":"Solomon Islands","SO":"Somalia","ZA":"South Africa","GS":"South Georgia & South Sandwich Islands","KR":"South Korea","SS":"South Sudan","ES":"Spain","LK":"Sri Lanka","BL":"St Barth\xE9lemy","SH":"St Helena","KN":"St Kitts & Nevis","LC":"St Lucia","MF":"St Martin","PM":"St Pierre & Miquelon","VC":"St Vincent & Grenadines","SD":"Sudan","SR":"Suriname","SJ":"Svalbard & Jan Mayen","SE":"Sweden","CH":"Switzerland","SY":"Syria","TW":"Taiwan","TJ":"Tajikistan","TZ":"Tanzania","TH":"Thailand","TL":"Timor-Leste","TG":"Togo","TK":"Tokelau","TO":"Tonga","TT":"Trinidad & Tobago","TA":"Tristan da Cunha","TN":"Tunisia","TR":"Turkey","TM":"Turkmenistan","TC":"Turks & Caicos Islands","TV":"Tuvalu","UG":"Uganda","UA":"Ukraine","AE":"United Arab Emirates","GB":"United Kingdom","US":"United States","UY":"Uruguay","UM":"US Outlying Islands","VI":"US Virgin Islands","UZ":"Uzbekistan","VU":"Vanuatu","VA":"Vatican City","VE":"Venezuela","VN":"Vietnam","WF":"Wallis & Futuna","EH":"Western Sahara","YE":"Yemen","ZM":"Zambia","ZW":"Zimbabwe"}'; 380 return JSON.parse(rawjson); 381}; 382 383iMapsRouter.camelize = function (str) { 384 return str 385 .replace(/(?:^\w|[A-Z]|\b\w)/g, function (word, index) { 386 return index == 0 ? word.toLowerCase() : word.toUpperCase(); 387 }) 388 .replace(/\s+/g, ''); 389}; 390/** 391 * File that contains functions to prepare raw data that arrives in a javascript variable. 392 * 1) Convert color strings to color objects 393 * */ 394 395var iMapsModel = {}; 396 397iMapsModel.prepareData = function (fullData) { 398 if (!fullData) { 399 return fullData; 400 } 401 402 if (!Array.isArray(fullData)) { 403 return fullData; 404 } 405 406 fullData.forEach(function (data, index) { 407 fullData[index] = iMapsModel.iterateData(data); 408 409 if (Array.isArray(fullData[index].overlay) && fullData[index].overlay.length > 0) { 410 fullData[index].overlay.forEach(function (odata, ind) { 411 // if the overlay map is the same as base map, only include the active regions 412 if ( 413 fullData[index].overlay[ind].map === fullData[index].map && 414 !iMapsManager.bool(fullData[index].allowEmpty) 415 ) { 416 fullData[index].overlay[ind].include = iMapsModel.prepareOverlayInclude(odata); 417 } 418 419 fullData[index].overlay[ind] = iMapsModel.iterateData(odata); 420 }); 421 } 422 }); 423 return fullData; 424}; 425 426iMapsModel.prepareOverlayInclude = function (data) { 427 var includes = data.includes || ''; 428 429 if (data.regions) { 430 data.regions.forEach(function (region) { 431 includes += ',' + region.id; 432 }); 433 } 434 435 return includes; 436}; 437 438iMapsModel.iterateData = function (data) { 439 // check if there's a custom callback function to prepare the data 440 /* eslint-disable-next-line camelcase -- public API: site developers may define a global `igm_custom_filter` function to hook into map data before rendering. */ 441 if (typeof igm_custom_filter === 'function') { 442 data = igm_custom_filter(data); 443 } // check if there's a map specific custom callback function 444 445 var mapFunction = 'igm_custom_filter_' + data.id; 446 447 if (typeof window[mapFunction] === 'function') { 448 data = window[mapFunction](data); 449 } // create color objects 450 451 data = iMapsModel.prepareColor(data); 452 453 // convert exclude and includes to array 454 data = iMapsModel.prepareExcludeIncludes(data); 455 456 // convert coordinates to int 457 data = iMapsModel.coordinatesToInt(data); 458
459 // prepare entries that use defaults 460 data = iMapsModel.prepareEntriesData(data); 461 462 // prepare grouped regions 463 data = iMapsModel.prepareGroupedRegions(data); 464 465 //extract image source from imageMarkers 466 data = iMapsModel.prepareImageFields(data); 467 468 //prepare lines multiGeoLine format 469 data = iMapsModel.prepareMultiGeoLine(data); 470 return data; 471}; 472 473iMapsModel.prepareMultiGeoLine = function (data) { 474 if (Array.isArray(data.lines) && data.lines.length) { 475 //make sure we only get entries with geoline data 476 data.lines = data.lines.filter(function (line) { 477 if (Array.isArray(line.multiGeoLine) && line.multiGeoLine.length) { 478 return line; 479 } 480 }); 481 482 data.lines.map(function (line) { 483 // notice the arrow option needs to be reversed, because it controls the arrow.disabled option when rendered 484 line.arrow = typeof line.arrow !== 'undefined' ? iMapsManager.bool(line.arrow) : false; 485 line.arrowDisabled = !line.arrow; 486 line.multiGeoLine.map(function (geoLine) { 487 Object.assign(geoLine, geoLine.coordinates); 488 delete geoLine.coordinates; 489 }); 490 }); 491 } 492 493 return data; 494}; 495 496iMapsModel.prepareImageFields = function (data) { 497 // image markers 498 if (Array.isArray(data.imageMarkers) && Array.isArray(data.imageMarkers)) { 499 data.imageMarkers.map(function (marker) { 500 if ( 501 typeof marker.href === 'undefined' && 502 marker.image && 503 (Array.isArray(marker.image) || typeof marker.image === 'object') 504 ) { 505 marker.href = marker.image.url; 506 } 507 return marker; 508 }); 509 } 510 511 return data; 512}; 513 514iMapsModel.prepareGroupedRegions = function (data) { 515 var regions, tempRegion, group, groupIds, groupName; // regions 516 517 if (Array.isArray(data.regions) && data.regions.length) { 518 if (typeof data.regionGroups === 'undefined') { 519 data.regionGroups = []; 520 } 521 522 // if the option to group entries is enabled, cosider them as a group entry 523 if (iMapsManager.bool(data.regionsGroupHover)) { 524 data.regionGroups.push(data.regions); 525 return data; 526 } 527 528 data.regions.map(function (region, index) { 529 if (region.id && String(region.id).includes(',')) { 530 group = []; 531 groupIds = []; 532 regions = region.id.split(','); 533 groupName = region.name; 534 535 regions.forEach(function (reg) { 536 tempRegion = Object.assign({}, region); 537 tempRegion.id = reg.trim(); 538 539 // keep some original values 540 tempRegion.originalID = region.id; 541 tempRegion.groupName = groupName; 542 543 // delete the group name, to keep region name 544 delete tempRegion.name; 545 delete region.name; 546 547 // check if numeric 548 if (!isNaN(tempRegion.id)) { 549 // tempRegion.id = parseFloat( tempRegion.id ); 550 } 551 552 // check if not repeated 553 if (!groupIds.includes(tempRegion.id)) {
554 groupIds.push(tempRegion.id); 555 group.push(tempRegion); 556 } 557 }); 558 559 // add group to main data object 560 // finally add it to the main data object 561 data.regionGroups.push(group); 562 563 // remove this region from the default regions data set 564 data.regions.splice(index, -1); 565 } else { 566 return region; 567 } 568 }); 569 } 570 571 return data; 572}; 573 574iMapsModel.prepareTooltip = function (tooltipContent, options) { 575 var maxWidth, isMSIE, images, tooltipNode, range, tempDiv; 576 577 if (typeof options === 'undefined' || typeof tooltipContent === 'undefined') { 578 return tooltipContent; 579 } 580 581 maxWidth = 582 typeof options.maxWidth !== 'undefined' && options.maxWidth !== '' 583 ? parseInt(options.maxWidth) 584 : false; 585 isMSIE = iMapsModel.isMSIE(); // remove html tags for IE 586 587 if (isMSIE) { 588 return iMapsModel.removeHTMLtags(tooltipContent); 589 } // check for images 590 591 if (tooltipContent && tooltipContent.includes('<img')) { 592 // images 593 range = document.createRange(); // Make the parent of the first div in the document becomes the context node 594 595 range.selectNode(document.getElementsByTagName('div').item(0)); 596 tooltipNode = range.createContextualFragment(tooltipContent); 597 images = tooltipNode.querySelectorAll('img'); 598 599 if (images.length > 0) { 600 images.forEach(function (img) { 601 if (img.width !== 0 && img.style.width === '') { 602 img.style.width = img.width + 'px'; 603 } 604 605 if (img.height !== 0 && img.style.height === '') { 606 img.style.height = img.height + 'px'; 607 } 608 }); 609 tempDiv = document.createElement('div'); 610 tempDiv.appendChild(tooltipNode.cloneNode(true)); 611 tooltipContent = tempDiv.innerHTML; 612 } 613 } // tooltip 614 615 if (maxWidth && tooltipContent !== '' && !isMSIE) { 616 tooltipContent = 617 '<div class="imapsInnerTooltip" style="max-width:' + 618 maxWidth + 619 'px">' + 620 tooltipContent + 621 '</div>'; 622 } 623 624 return tooltipContent; 625}; 626 627iMapsModel.isMSIE = function () { 628 return window.navigator.userAgent.match(/(MSIE|Trident)/); 629}; 630 631iMapsModel.removeHTMLtags = function (str) { 632 if (str === null || str === '') { 633 return ''; 634 } else { 635 str = str.toString(); 636 } 637 return str.replace(/<[^>]*>/g, ''); 638}; 639 640iMapsModel.prepareEntriesData = function (data) { 641 if (data.heatMapMarkers && data.heatMapMarkers.enabled === '1') { 642 data.heatMapMarkers.minRadius = parseInt(data.heatMapMarkers.minRadius); 643 data.heatMapMarkers.maxRadius = parseInt(data.heatMapMarkers.maxRadius); 644 } 645 646 var mapID = data.id; // regions 647 648 if (Array.isArray(data.regions) && data.regions.length) { 649 data.regions.map(function (region) { 650 if (typeof region.useDefaults === 'undefined' || region.useDefaults === '1') { 651 Object.assign(region, data.regionDefaults); 652 } 653 654 if (typeof region.action !== 'undefined' && region.action === 'default') { 655 region.action = data.regionDefaults.action; 656 } 657 658 if ( 659 typeof data.regionDefaults.triggerClickOnHover !== 'undefined' && 660 data.regionDefaults.triggerClickOnHover === '1' 661 ) { 662 region.triggerClickOnHover = true; 663 } 664 665 if (typeof data.regionActiveState !== 'undefined' && data.regionActiveState.enabled === '1') { 666 region.activeState = true; 667 } 668 669 // auto labels properties 670 if ( 671 data.regionLabels && 672 data.regionLabels.source === 'custom' && 673 typeof data.regionLabels.customSource !== 'undefined' 674 ) { 675 if (data.regionLabels.customSource.includes('.')) { 676 region.autoLabel = data.regionLabels.customSource.split('.').reduce(function (obj, i) { 677 if (obj[i]) { 678 return obj[i]; 679 } 680 681 return 0; 682 }, region); 683 } else { 684 region.autoLabel = region[data.regionLabels.customSource]; 685 } 686 } 687 688 if (data.heatMapRegions && data.heatMapRegions.enabled === '1') { 689 // if it includes a reference with dot notation 690 if (data.heatMapRegions.source.includes('.')) { 691 region.heatMapRegionRef = data.heatMapRegions.source.split('.').reduce(function (obj, i) { 692 if (obj[i]) { 693 return obj[i]; 694 } 695 696 return 0; 697 }, region); 698 } 699 700 delete region.fill; 701 } // default action 702 703 // border hover - currently doesn't exist 704 if ( 705 typeof data.visual.borderColorHover !== 'undefined' && 706 data.visual.borderColorHover !== data.visual.borderColor 707 ) { 708 region.borderColorHover = data.visual.borderColorHover; 709 } // border width on hover - currently doesn't exist 710 711 if ( 712 typeof data.visual.borderWidthHover !== 'undefined' && 713 data.visual.borderWidthHover !== data.visual.borderWidth 714 ) { 715 region.borderWidthHover = data.visual.borderWidthHover; 716 } 717 718 region.tooltipContent = iMapsModel.prepareTooltip(region.tooltipContent, data.tooltip); 719 region.mapID = mapID; 720 721 // fix for value with "-" minus sign 722 if (region.value && _typeof(region.value) !== undefined && region.value !== '') { 723 region.val = region.value; 724 region.value = parseFloat(region.value); 725 } 726 727 return region; 728 }); // heatmap with dot notation 729 // if it includes a reference with dot notation 730 731 if (data.heatMapRegions && data.heatMapRegions.source.includes('.')) { 732 data.heatMapRegions.source = 'heatMapRegionRef'; 733 } 734 } // round markers 735 736 if (Array.isArray(data.roundMarkers) && data.roundMarkers.length) { 737 data.roundMarkers.map(function (marker) { 738 if (typeof marker.useDefaults === 'undefined' || marker.useDefaults === '1') { 739 Object.assign(marker, data.markerDefaults); 740 } 741 742 if (marker.coordinates) { 743 marker.latitude = marker.coordinates.latitude; 744 marker.longitude = marker.coordinates.longitude; //Object.assign(marker, marker.coordinates); 745 //delete marker.coordinates; 746 } // set name to be id 747 748 if (typeof marker.latitude === 'string') { 749 marker.latitude = parseFloat(marker.latitude); 750 } 751 if (typeof marker.longitude === 'string') { 752 marker.longitude = parseFloat(marker.latitude); 753 } 754 755 if (typeof marker.name === 'undefined') { 756 marker.name = marker.id; 757 } 758 759 if (data.roundMarkersMobileSize && parseInt(data.roundMarkersMobileSize) !== 100) { 760 if (window.innerWidth <= 780) {
761 marker.radius = 762 (parseFloat(marker.radius) * parseFloat(data.roundMarkersMobileSize)) / 100; 763 } 764 } 765 766 if (data.heatMapMarkers && data.heatMapMarkers.enabled === '1') { 767 if (!isNaN(marker.value)) { 768 marker.value = parseFloat(marker.value); 769 } // if it includes a reference with dot notation 770 771 if (data.heatMapMarkers.source.includes('.')) { 772 marker.heatMapMarkerRef = data.heatMapMarkers.source.split('.').reduce(function (obj, i) { 773 if (obj[i]) { 774 return obj[i]; 775 } 776 777 return 0; 778 }, marker); 779 } 780 781 delete marker.fill; 782 delete marker.radius; 783 } 784 785 // fix for value with "-" minus sign 786 if (marker.value && _typeof(marker.value) !== undefined && marker.value !== '') { 787 marker.val = marker.value; 788 marker.value = parseFloat(marker.value); 789 } 790 791 // default action 792 if (marker.action === 'default') { 793 marker.action = data.markerDefaults.action; 794 } 795 796 if ( 797 typeof data.markerDefaults.triggerClickOnHover !== 'undefined' && 798 data.markerDefaults.triggerClickOnHover === '1' 799 ) { 800 marker.triggerClickOnHover = true; 801 } 802 803 if ( 804 typeof data.triggerRegionHover !== 'undefined' && 805 data.triggerRegionHover.enabled === '1' 806 ) { 807 marker.triggerRegionHover = true; 808 } 809 810 marker.tooltipContent = iMapsModel.prepareTooltip(marker.tooltipContent, data.tooltip); 811 marker.mapID = mapID; 812 return marker; 813 }); // remove markers with empty coordinates 814 815 data.roundMarkers = data.roundMarkers.filter(function (marker) { 816 return typeof marker.latitude !== 'undefined' && marker.latitude !== '' && marker.name !== ''; 817 }); // heatmap with dot notation 818 // if it includes a reference with dot notation 819 820 if (data.heatMapMarkers && data.heatMapMarkers.source.includes('.')) { 821 data.heatMapMarkers.source = 'heatMapMarkerRef'; 822 } 823 } // icon markers 824 825 if (Array.isArray(data.iconMarkers) && data.iconMarkers.length) { 826 data.iconMarkers.map(function (marker) { 827 if (typeof marker.useDefaults === 'undefined' || marker.useDefaults === '1') { 828 Object.assign(marker, data.iconMarkerDefaults); 829 } 830 831 if (marker.coordinates) { 832 marker.latitude = marker.coordinates.latitude; 833 marker.longitude = marker.coordinates.longitude; //Object.assign(marker, marker.coordinates); 834 //delete marker.coordinates; 835 } // set name to be id 836 837 if (typeof marker.name === 'undefined') { 838 marker.name = marker.id; 839 } // default action 840 841 if (marker.action === 'default') { 842 marker.action = data.iconMarkerDefaults.action; 843 } 844 845 if ( 846 typeof data.iconMarkerDefaults.triggerClickOnHover !== 'undefined' && 847 data.iconMarkerDefaults.triggerClickOnHover === '1' 848 ) { 849 marker.triggerClickOnHover = true; 850 } 851 852 // Possible approach to resize icon marker on smaller screens, but won't resize on the fly 853 854 if (data.iconMarkersMobileSize && parseInt(data.iconMarkersMobileSize) !== 100) { 855 if (window.innerWidth <= 780) { 856 marker.scale = (parseFloat(marker.scale) * parseFloat(data.iconMarkersMobileSize)) / 100; 857 } 858 } 859 860 // solve issue with value parameter only accepting numbers 861 marker.val = marker.value; 862 marker.value = parseFloat(marker.value); 863 864 marker.tooltipContent = iMapsModel.prepareTooltip(marker.tooltipContent, data.tooltip); 865 marker.mapID = mapID; 866 return marker; 867 }); 868 } // image markers 869 870 if (Array.isArray(data.imageMarkers) && data.imageMarkers.length) { 871 data.imageMarkers.map(function (marker) { 872 if (typeof marker.useDefaults === 'undefined' || marker.useDefaults === '1') { 873 Object.assign(marker, data.imageMarkerDefaults); 874 } 875 876 if (marker.coordinates) { 877 marker.latitude = marker.coordinates.latitude; 878 marker.longitude = marker.coordinates.longitude; //Object.assign(marker, marker.coordinates); 879 //delete marker.coordinates; 880 } // set name to be id 881 882 if (typeof marker.nonScaling !== 'undefined') { 883 marker.nonScaling = iMapsManager.bool(marker.nonScaling); 884 } 885 886 if (typeof marker.size === 'undefined') { 887 marker.size = data.imageMarkerDefaults.size; 888 } 889 890 if (typeof marker.horizontalCenter === 'undefined') { 891 marker.horizontalCenter = data.imageMarkerDefaults.horizontalCenter; 892 } 893 894 if (typeof marker.verticalCenter === 'undefined') { 895 marker.verticalCenter = data.imageMarkerDefaults.verticalCenter; 896 } 897 898 if (typeof marker.name === 'undefined') { 899 marker.name = marker.id; 900 } 901 902 if (marker.action === 'default' || typeof marker.action === 'undefined') { 903 marker.action = data.imageMarkerDefaults.action; 904 } 905 906 if ( 907 typeof data.imageMarkerDefaults.triggerClickOnHover !== 'undefined' && 908 data.imageMarkerDefaults.triggerClickOnHover === '1' 909 ) { 910 marker.triggerClickOnHover = true; 911 } 912 913 // Possible approach to resize icon marker on smaller screens, but won't resize on the fly 914 915 if (data.imageMarkersMobileSize && parseInt(data.imageMarkersMobileSize) !== 100) { 916 if (window.innerWidth <= 780) { 917 marker.size = (parseFloat(marker.size) * parseFloat(data.imageMarkersMobileSize)) / 100; 918 } 919 } 920 921 // solve problem of value param only accepting numbers 922 marker.val = marker.value; 923 marker.value = parseFloat(marker.value); 924 925 marker.tooltipContent = iMapsModel.prepareTooltip(marker.tooltipContent, data.tooltip); 926 marker.mapID = mapID; 927 return marker; 928 }); 929 } // labels 930 931 if (Array.isArray(data.labels) && data.labels.length) { 932 data.labels.map(function (label) { 933 if (typeof label.useDefaults === 'undefined' || label.useDefaults === '1') { 934 Object.assign(label, data.labelDefaults); 935 Object.assign(label, data.labelPosition); 936 } 937 938 if (label.coordinates) { 939 Object.assign(label, label.coordinates); 940 delete label.coordinates; 941 } 942 943 if (label.action === 'default') { 944 label.action = data.labelDefaults.action; 945 } 946 947 if ( 948 typeof data.labelDefaults.triggerClickOnHover !== 'undefined' && 949 data.labelDefaults.triggerClickOnHover === '1' 950 ) { 951 label.triggerClickOnHover = true; 952 } 953 954 if (typeof label.size !== 'undefined') { 955 label.fontSize = label.size; 956 } // change font size on smaller screens 957 958 if (data.labelsMobileSize && parseInt(data.labelsMobileSize) !== 100) { 959 if (window.innerWidth <= 780) { 960 label.fontSize = (parseInt(label.fontSize) * parseInt(data.labelsMobileSize)) / 100; 961 label.size = label.fontSize; 962 } 963 } 964 965 label.tooltipContent = iMapsModel.prepareTooltip(label.tooltipContent, data.tooltip); 966 label.mapID = mapID; 967 return label; 968 }); 969 } // lines 970 971 if (Array.isArray(data.lines) && data.lines.length) { 972 data.lines.map(function (line) { 973 if (typeof line.useDefaults === 'undefined' || line.useDefaults === '1') { 974 Object.assign(line, data.lineDefaults); 975 } 976 977 line.curvature = parseFloat(line.curvature); 978 return line; 979 }); 980 } 981 982 return data; 983}; 984 985iMapsModel.prepareExcludeIncludes = function (data) { 986 if (typeof data.onlyIncludeActive !== 'undefined' && parseInt(data.onlyIncludeActive) === 1) { 987 data.include = []; 988 data.exclude = []; 989 990 if (data.regions) { 991 data.regions.forEach(function (region) { 992 data.include.push(region.id); 993 994 if (!isNaN(region.id)) { 995 data.include.push(parseInt(region.id)); 996 } 997 }); 998 } 999 1000 return data; 1001 } 1002 1003 if (data.exclude && typeof data.exclude === 'string' && data.exclude.trim().length) { 1004 data.exclude = data.exclude.split(',').map(function (item) { 1005 return item.trim(); 1006 }); 1007 } 1008 1009 if (data.include && data.include.trim().length) { 1010 data.include = data.include.split(',').map(function (item) { 1011 return item.trim(); 1012 }); 1013 1014 data.include.map(function (item) { 1015 if (!isNaN(item)) { 1016 data.include.push(parseInt(item)); 1017 } 1018 }); 1019 } 1020 1021 return data; 1022}; 1023 1024iMapsModel.coordinatesToInt = function (data) { 1025 var convertCoordinates = function convertCoordinates(key, obj) { 1026 obj[key].latitude = Number(obj[key].latitude); 1027 obj[key].longitude = Number(obj[key].longitude); 1028 },
1029 iterateObj = function iterateObj(Obj) { 1030 if (_typeof(Obj) !== 'object' || Obj === null) { 1031 return; 1032 } 1033 1034 Object.keys(Obj).map(function (key) { 1035 if (_typeof(Obj[key]) === 'object') { 1036 if (key === 'coordinates' || key === 'homeGeoPoint') { 1037 convertCoordinates(key, Obj); 1038 } else if (typeof Obj['className'] !== 'undefined') { 1039 return; 1040 } else { 1041 iterateObj(Obj[key]); 1042 } 1043 } 1044 }); 1045 }; 1046 1047 iterateObj(data); 1048 return data; 1049}; 1050 1051iMapsModel.prepareColor = function (data) { 1052 // prepare color fields 1053 var colorFields = [ 1054 'inactiveColor', 1055 'activeColor', 1056 'hoverColor', 1057 'hover', 1058 'inactiveHoverColor', 1059 'backgroundColor', 1060 'color', 1061 'minColor', 1062 'maxColor', 1063 'fill', 1064 'projectionBackgroundColor', 1065 'borderColor', 1066 'borderColorHover', 1067 ], 1068 createGradient = function createGradient(data) { 1069 var colours = data.split('|'); 1070 var gradient, gradientType, gradientOff
1070set; 1071 1072 gradientType = typeof igmGradientType !== 'undefined' ? igmGradientType : 'LinearGradient'; 1073 gradientOffset = 1074 typeof igmGradientOffset !== 'undefined' && Array.isArray(igmGradientOffset) 1075 ? igmGradientOffset 1076 : []; 1077 1078 gradient = new am4core[gradientType](); 1079 colours.forEach(function (color, index) { 1080 gradient.addColor(am4core.color(color), 1, gradientOffset[index]); 1081 }); 1082 1083 //rotation 1084 gradient.rotation = typeof igmGradientRotation !== 'undefined' ? igmGradientRotation : 0; 1085 return gradient; 1086 }, 1087 createPattern = function createPattern(data) { 1088 var url = data; 1089 // Create pattern 1090 var pattern = new am4core.Pattern(); 1091 pattern.width = 150; 1092 pattern.height = 150; 1093 pattern.strokeWidth = 0; 1094 pattern.stroke = am4core.color('#6699cc'); 1095 //pattern.patternUnits = 'objectBoundingBox'; // objectBoundingBox // userSpaceOnUse 1096 1097 var image = new am4core.Image(); 1098 image.href = url; 1099 image.width = 150; 1100 image.height = 150; 1101 image.x = 0; 1102 image.y = 0; 1103 image.verticalCenter = 'middle'; 1104 image.valign = 'middle'; 1105 pattern.addElement(image.element); 1106 pattern.addElement(image.element); 1107 pattern.addElement(image.element); 1108 return pattern; 1109 }, 1110 checkColor = function checkColor(key, obj) { 1111 if (colorFields.includes(key)) { 1112 if (obj[key].includes('|')) { 1113 obj[key] = createGradient(obj[key]); 1114 } else if (obj[key].startsWith('http')) { 1115 obj[key] = createPattern(obj[key]); 1116 } 1117 // on hover out, amcharts is not able to resolve transparent colours, in default states, so we prevent this 1118 // by setting an almost transparent colour 1119 else if (key === 'hover' && (obj[key] === 'transparent' || obj[key].endsWith(',0)'))) { 1120 obj[key] = am4core.color('rgba(0,0,0,0.001)'); 1121 } else if (obj[key] === 'transparent') { 1122 obj[key] = am4core.color('rgba(0,0,0,0)'); 1123 } else { 1124 obj[key] = am4core.color(obj[key]); 1125 } 1126 } 1127 },
1128 iterateObj = function iterateObj(Obj) { 1129 if (_typeof(Obj) !== 'object' || Obj === null) { 1130 return; 1131 } 1132 1133 Object.keys(Obj).map(function (key) { 1134 if (_typeof(Obj[key]) === 'object') { 1135 iterateObj(Obj[key]); 1136 } else if (typeof Obj['className'] !== 'undefined') { 1137 return; 1138 } else { 1139 checkColor(key, Obj); 1140 } 1141 }); 1142 }; 1143 1144 iterateObj(data); 1145 return data; 1146}; 1147 1148/** 1149 * Retrieves object with region codes and names from geojson 1150 */ 1151 1152iMapsModel.extractCodes = function (data) { 1153 var obj = {}; 1154 1155 for (var i = 0; i < data.features.length; i++) { 1156 obj[data.features[i].properties.id] = data.features[i].properties.name; 1157 } 1158 1159 return obj; 1160}; 1161 1162('use strict'); 1163/* jshint node: true */ 1164 1165/* global Promise */ 1166 1167/* jshint browser: true */ 1168 1169/* global am4maps */ 1170 1171/* global am4core */ 1172 1173/* global iMapsData */ 1174 1175/* global geocluster */ 1176 1177/* global iMapsRouter */ 1178 1179/* global iMaps */ 1180 1181/* jshint esversion:5 */ 1182 1183/* global iMapsActions */ 1184 1185/* 1186Model Object with methods and helpers to build the maps 1187*/ 1188 1189var iMapsManager = {}; 1190iMapsManager.maps = {}; 1191 1192iMapsManager.init = function (i) { 1193 var im = this; 1194 im.addMap(i); 1195}; 1196/** 1197 * Adds maps based on data index 1198 * 1199 */ 1200 1201iMapsManager.addMap = function (index) { 1202 var im = this, 1203 data = iMapsData.data[index], 1204 id = data.id, 1205 map, 1206 regionSeries, 1207 groupedSeries, 1208 markerSeries, 1209 labelSeries, 1210 customLegend, 1211 imageSeries, 1212 iconSeries, 1213 graticuleSeries, 1214 clusterSeries, 1215 mapVar, 1216 bgSeries, 1217 bgImage, 1218 aspRatioContainer, 1219 container = document.getElementById(data.container); 1220 1221 if (data.disabled) { 1222 return; 1223 } 1224 1225 if (container === null) { 1226 return; 1227 } 1228 1229 aspRatioContainer = container.closest('.map_aspect_ratio'); 1230 1231 // if map was already built 1232 if (typeof im.maps[id] !== 'undefined') { 1233 im.maps[id].map.dispose(); 1234 } 1235 1236 // map container size adjustment 1237 // if mobile 1238 if ( 1239 window.innerWidth <= 780 && 1240 typeof data.visual.paddingTop !== 'undefined' && 1241 data.visual.paddingTop !== '' 1242 ) { 1243 aspRatioContainer.style.paddingTop = String(data.visual.paddingTopMobile) + '%'; 1244 } else { 1245 aspRatioContainer.style.paddingTop = String(data.visual.paddingTop) + '%'; 1246 } 1247 1248 window.addEventListener('resize', function () { 1249 if ( 1250 window.innerWidth <= 780 && 1251 typeof data.visual.paddingTop !== 'undefined' && 1252 data.visual.paddingTop !== '' 1253 ) { 1254 aspRatioContainer.style.paddingTop = String(data.visual.paddingTopMobile) + '%'; 1255 } else { 1256 aspRatioContainer.style.paddingTop = String(data.visual.paddingTop) + '%'; 1257 } 1258 }); 1259 1260 if (data.visual.maxWidth !== '') { 1261 //container.closest(".map_box").style.maxWidth = String(data.visual.maxWidth) + "px"; 1262 } 1263 1264 if (data.visual.fontFamily !== '' && data.visual.fontFamily !== 'inherit') { 1265 container.closest('.map_box').style.fontFamily = data.visual.fontFamily; 1266 } 1267 1268 // create map and a shorter reference to it 1269 im.maps[id] = { 1270 map: am4core.create(data.container, am4maps.MapChart), 1271 series: [], 1272 clusterSeries: {}, 1273 seriesIndex: {}, 1274 seriesById: {}, 1275 data: data, 1276 allBaseSeries: [], 1277 labelSeries: [], 1278 baseRegionSeries: {}, 1279 groupedBaseRegionSeries: [], 1280 backgroundSeries: {}, 1281 }; 1282 map = im.maps[id].map; 1283 map.readerTitle = 'Interactive Map'; 1284 1285 clusterSeries = im.maps[id].clusterSeries; 1286 // ready event 1287 // on click map debug 1288 map.events.on('ready', function () { 1289 var event = new Event('mapready'); 1290 container.dispatchEvent(event); 1291 // we might move the event that triggers on ready to mapappeared because it doesn't work well with custom maps 1292 im.triggerOnReady(id, data); 1293 }); 1294 map.events.on('appeared', function () { 1295 var event = new Event('mapappeared'); 1296 container.dispatchEvent(event); 1297 im.triggerOnAppeared(id, data); 1298 container.classList.remove('map_loading'); 1299 }); 1300 1301 // locale 1302 if ( 1303 typeof iMapsData.options !== 'undefined' && 1304 typeof iMapsData.options.locale !== 'undefined' && 1305 iMapsData.options.locale && 1306 typeof window['am4lang_' + iMapsData.options.locale] !== 'undefined' 1307 ) { 1308 map.language.locale = window['am4lang_' + iMapsData.options.locale]; 1309 } // enable small map 1310 1311 if (data.zoom && data.zoom.smallMap && im.bool(data.zoom.smallMap)) { 1312 map.smallMap = new am4maps.SmallMap(); 1313 } // load map geodata 1314 1315 if (data.map === 'custom' || im.bool(data.useGeojson)) { 1316 map.geodataSource.url = data.mapURL; 1317 } else {
1318 mapVar = iMapsRouter.getVarByName(data.map); 1319 map.geodata = window[mapVar]; 1320 } 1321 1322 if ( 1323 typeof iMapsData.options !== 'undefined' && 1324 typeof iMapsData.options.lang !== 'undefined' && 1325 iMapsData.options.lang && 1326 typeof window['am4geodata_lang_' + iMapsData.options.lang] !== 'undefined' 1327 ) { 1328 map.geodataNames = window['am4geodata_lang_' + iMapsData.options.lang]; 1329 } 1330 1331 // projection - moved to the end of the function to fix issue with Albers not rendering correctly 1332 map.projection = new am4maps.projections[data.projection](); 1333 1334 // fix issues with USA territories map 1335 if (data.map.startsWith('usaTerritories')) { 1336 map.events.on('ready', function () { 1337 map.projection = new am4maps.projections[data.projection](); 1338 }); 1339 } 1340 1341 map.fontFamily = data.visual.fontFamily; 1342 1343 // export menu 1344 if (data.exportMenu && im.bool(data.exportMenu.enable)) { 1345 map.exporting.menu = new am4core.ExportMenu(); 1346 map.exporting.menu.items[0].icon = 1347 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiA8Zz4KICA8dGl0bGU+YmFja2dyb3VuZDwvdGl0bGU+CiAgPHJlY3QgeD0iLTEiIHk9Ii0xIiB3aWR0aD0iNS45NDQ3NzMiIGhlaWdodD0iNS45NDQ3NzMiIGlkPSJjYW52YXNfYmFja2dyb3VuZCIgZmlsbD0ibm9uZSIvPgogPC9nPgoKIDxnPgogIDx0aXRsZT5MYXllciAxPC90aXRsZT4KICA8cGF0aCBzdHJva2U9Im51bGwiIGQ9Im0xNC40MjcwMzEsMTUuNzQwNDAxcTAsLTAuMjU3NjQzIC0wLjE4ODI3NCwtMC40NDU5MTd0LTAuNDQ1OTE3LC0wLjE4ODI3NHQtMC40NDU5MTcsMC4xODgyNzR0LTAuMTg4Mjc0LDAuNDQ1OTE3dDAuMTg4Mjc0LDAuNDQ1OTE3dDAuNDQ1OTE3LDAuMTg4Mjc0dDAuNDQ1OTE3LC0wLjE4ODI3NHQwLjE4ODI3NCwtMC40NDU5MTd6bTIuNTM2NzgsMHEwLC0wLjI1NzY0MyAtMC4xODgyNzQsLTAuNDQ1OTE3dC0wLjQ0NTkxNywtMC4xODgyNzR0LTAuNDQ1OTE3LDAuMTg4Mjc0dC0wLjE4ODI3NCwwLjQ0NTkxN3QwLjE4ODI3NCwwLjQ0NTkxN3QwLjQ0NTkxNywwLjE4ODI3NHQwLjQ0NTkxNywtMC4xODgyNzR0MC4xODgyNzQsLTAuNDQ1OTE3em0xLjI2ODM5LC0yLjIxOTY4NWwwLDMuMTcwOTdxMCwwLjM5NjM3NCAtMC4yNzc0NjEsMC42NzM4MzR0LTAuNjczODM0LDAuMjc3NDYxbC0xNC41ODY0NywwcS0wLjM5NjM3NCwwIC0wLjY3MzgzNCwtMC4yNzc0NjF0LTAuMjc3NDYxLC0wLjY3MzgzNGwwLC0zLjE3MDk3cTAsLTAuMzk2Mzc0IDAuMjc3NDYxLC0wLjY3MzgzNHQwLjY3MzgzNCwtMC4yNzc0NjFsNC42MDc4MTYsMGwxLjMzNzc1MSwxLjM0NzY1OXEwLjU3NDczOCwwLjU1NDkyMSAxLjM0NzY1OSwwLjU1NDkyMXQxLjM0NzY1OSwtMC41NTQ5MjFsMS4zNDc2NTksLTEuMzQ3NjU5bDQuNTk3OTA4LDBxMC4zOTYzNzQsMCAwLjY3MzgzNCwwLjI3NzQ2MXQwLjI3NzQ2MSwwLjY3MzgzNGwwLjAwMDAxOCwwem0tMy4yMjA1MjMsLTUuNjM4MzlxMC4xNjg0NTYsMC40MDYyODIgLTAuMTM4NzMsMC42OTM2NTFsLTQuNDM5MzYsNC40MzkzNnEtMC4xNzgzNjUsMC4xODgyNzQgLTAuNDQ1OTE3LDAuMTg4Mjc0dC0wLjQ0NTkxNywtMC4xODgyNzRsLTQuNDM5MzYsLTQuNDM5MzZxLTAuMzA3MTg3LC0wLjI4NzM2OSAtMC4xMzg3MywtMC42OTM2NTFxMC4xNjg0NTYsLTAuMzg2NDY1IDAuNTg0NjQ3LC0wLjM4NjQ2NWwyLjUzNjc4LDBsMCwtNC40MzkzNnEwLC0wLjI1NzY0MyAwLjE4ODI3NCwtMC40NDU5MTd0MC40NDU5MTcsLTAuMTg4Mjc0bDIuNTM2NzgsMHEwLjI1NzY0MywwIDAuNDQ1OTE3LDAuMTg4Mjc0dDAuMTg4Mjc0LDAuNDQ1OTE3bDAsNC40MzkzNmwyLjUzNjc4LDBxMC40MTYxOTEsMCAwLjU4NDY0NywwLjM4NjQ2NXoiIGlkPSJzdmdfMSIvPgogPC9nPgo8L3N2Zz4='; 1348 map.exporting.menu.align = data.exportMenu.align ? data.exportMenu.align : 'right'; 1349 map.exporting.menu.verticalAlign = data.exportMenu.verticalAlign 1350 ? data.exportMenu.verticalAlign 1351 : 'top'; 1352 } 1353 1354 // touch devices options 1355 if (data.touchInterface) { 1356 if (im.bool(data.touchInterface.tapToActivate)) { 1357 map.tapToActivate = true; 1358 map.tapTimeout = data.touchInterface.tapTimeout; 1359 } 1360 1361 if (im.bool(data.touchInterface.dragGrip)) { 1362 map.dragGrip.disabled = false; 1363 map.dragGrip.autoHideDelay = data.touchInterface.dragGripAutoHideDelay; 1364 } 1365 } 1366 1367 // different map center 1368 //map.deltaLongitude = -10; 1369 // pan behaviours 1370 // map.panBehavior = "rotateLongLat"; 1371 // map.panBehavior = "rotateLong"; 1372 // map.deltaLatitude = -20; 1373 // map.padding(20, 20, 20, 20); 1374 // visual settings 1375 1376 map.background.fill = data.visual.backgroundColor; 1377 map.background.fillOpacity = data.visual.backgroundOpacity; 1378 1379 // iOS scroll issue fix - not working 1380 map.backgroundSeries.mapPolygons.template.focusable = false; 1381 map.background.focusable = false; 1382 map.backgroundSeries.focusable = false; 1383 1384 // background image 1385 if ( 1386 typeof data.visual.bgImage !== 'undefined' && 1387 typeof data.visual.bgImage.url !== 'undefined' && 1388 data.visual.bgImage.url !== '' 1389 ) { 1390 bgSeries = map.series.push(new am4maps.MapImageSeries()); 1391 bgSeries.toBack(); 1392 bgImage = bgSeries.mapImages.template.createChild(am4core.Image); 1393 bgImage.propertyFields.href = 'src'; 1394 bgImage.width = map.width; 1395 bgImage.height = map.height; 1396 bgSeries.data = [ 1397 { 1398 src: data.visual.bgImage.url, 1399 }, 1400 ]; 1401 1402 im.maps[id].backgroundSeries = bgSeries; 1403 } 1404 1405 map.exporting.backgroundColor = data.visual.backgroundColor; 1406 map.exporting.filePrefix = 'interactive_map'; 1407 map.exporting.useWebFonts = false;
1408 1409 // graticulate - grid lines 1410 if (data.projection === 'Orthographic' && data.grid) { 1411 graticuleSeries = map.series.push(new am4maps.GraticuleSeries()); 1412 graticuleSeries.mapLines.template.line.stroke = data.grid.color; 1413 graticuleSeries.mapLines.template.line.strokeOpacity = 1; 1414 graticuleSeries.fitExtent = false; 1415 map.backgroundSeries.mapPolygons.template.polygon.fillOpacity = 1; 1416 map.backgroundSeries.mapPolygons.template.polygon.fill = data.grid.projectionBackgroundColor; 1417 } 1418 1419 im.handleZoom(id); // Auto Legend 1420 1421 if (data.legend && im.bool(data.legend.enabled)) { 1422 map.legend = new am4maps.Legend(); // positioning 1423 1424 if (data.legend.position === 'top' || data.legend.position === 'bottom') { 1425 map.legend.contentAlign = data.legend.align; 1426 map.legend.valign = data.legend.position; 1427 } else { 1428 map.legend.position = data.legend.position; 1429 map.legend.align = data.legend.position; 1430 map.legend.valign = data.legend.valign; 1431 } 1432 1433 if (typeof data.legend.style !== 'undefined' && data.legend.style !== 'default') { 1434 im.setLegendStyle(id, map.legend, data.legend.style); 1435 } 1436 1437 if (_typeof(data.legend.fill) !== undefined) { 1438 map.legend.labels.template.fill = data.legend.fill; 1439 } // interactive 1440 1441 if (data.legend.clickable === 'false') { 1442 map.legend.itemContainers.template.interactionsEnabled = false; 1443 } 1444 1445 if (data.legend.clickable === 'toggle') { 1446 // do nothing, it's the default event 1447 // let's just clear the events, just in case. 1448 map.legend.itemContainers.template.events.on('hit', function () { 1449 iMapsManager.clearSelected(id); 1450 }); 1451 } 1452 1453 if (data.legend.clickable === 'select') { 1454 map.legend.itemContainers.template.togglable = false; 1455 map.legend.itemContainers.template.events.on('hit', function (ev) { 1456 iMapsManager.clearSelected(id); 1457 var select = []; 1458 var seriesType = im.getTargetSeriesType(ev.target.dataItem.dataContext); // currently only works for region series 1459 1460 if (seriesType === 'MapPolygonSeries') { 1461 ev.target.dataItem.dataContext.mapPolygons.each(function (polygon) { 1462 if (!polygon.dataItem.dataContext.madeFromGeoData) { 1463 polygon.setState('active'); 1464 polygon.isActive = true; 1465 polygon.isHover = false; 1466 select.push(polygon); 1467 } 1468 }); 1469 im.maps[id].selected = select; 1470 } 1471 }); 1472 map.legend.itemContainers.template.events.on('over', function (ev) { 1473 var seriesType = im.getTargetSeriesType(ev.target.dataItem.dataContext); 1474 var target = ''; 1475 1476 // bring this series to front 1477 ev.target.dataItem.dataContext.zIndex = Number.MAX_VALUE; 1478 ev.target.dataItem.dataContext.toFront(); 1479 1480 if (seriesType === 'MapImageSeries') { 1481 target = ev.target.dataItem.dataContext.mapImages; 1482 target.each(function (marker) { 1483 marker.setState('highlight'); 1484 }); 1485 } else if (seriesType === 'MapPolygonSeries') { 1486 target = ev.target.dataItem.dataContext.mapPolygons; 1487 target.each(function (polygon) { 1488 if (!polygon.dataItem.dataContext.madeFromGeoData) { 1489 polygon.setState('highlight'); 1490 } 1491 }); 1492 } else { 1493 return; 1494 } 1495 }); 1496 map.legend.itemContainers.template.events.on('out', function (ev) { 1497 var seriesType = im.getTargetSeriesType(ev.target.dataItem.dataContext); 1498 var target = ''; 1499 1500 if (seriesType === 'MapImageSeries') { 1501 target = ev.target.dataItem.dataContext.mapImages; 1502 target.each(function (marker) { 1503 marker.setState('default'); 1504 }); 1505 } else if (seriesType === 'MapPolygonSeries') { 1506 target = ev.target.dataItem.dataContext.mapPolygons; 1507 target.each(function (polygon) { 1508 if (!polygon.dataItem.dataContext.madeFromGeoData) { 1509 polygon.setState('default'); 1510 } 1511 }); 1512 } else { 1513 return; 1514 } 1515 }); 1516 } 1517 } 1518 1519 // Custom Legend 1520 if (data.customLegend && im.bool(data.customLegend.enabled)) { 1521 var customLegendType = 1522 typeof data.customLegend.type !== 'undefined' ? data.customLegend.type : 'internal'; 1523 1524 if ( 1525 data.customLegend.data && 1526 Array.isArray(data.customLegend.data) && 1527 customLegendType === 'internal' 1528 ) { 1529 customLegend = new am4maps.Legend(); 1530 customLegend.parent = map.chartContainer; 1531 customLegend.data = data.customLegend.data; 1532 1533 /* 1534 customLegend.data.map(function(entry){ 1535 entry.name = entry.name.replace(/&#(\d+);/g, function(match, dec) { 1536 return String.fromCharCode(dec); 1537 }); 1538 return entry; 1539 });*/ 1540 1541 if (typeof data.customLegend.style !== 'undefined' && data.customLegend.style !== 'default') { 1542 im.setLegendStyle(id, customLegend, data.customLegend.style); 1543 } // no interaction with mouse 1544 1545 customLegend.itemContainers.template.clickable = false;
1546 customLegend.itemContainers.template.focusable = false; 1547 customLegend.itemContainers.template.hoverable = false; 1548 customLegend.itemContainers.template.cursorOverStyle = am4core.MouseCursorStyle['default']; 1549 customLegend.labels.template.truncate = false; 1550 customLegend.labels.template.wrap = true; // positioning 1551 1552 if (data.customLegend.position === 'top' || data.customLegend.position === 'bottom') { 1553 customLegend.contentAlign = data.customLegend.align; 1554 customLegend.valign = data.customLegend.position; 1555 } else { 1556 customLegend.position = data.customLegend.position; 1557 customLegend.align = data.customLegend.position; 1558 customLegend.valign = data.customLegend.valign; 1559 } 1560 1561 if (_typeof(data.customLegend.fill) !== undefined) { 1562 customLegend.labels.template.fill = data.customLegend.fill; 1563 } 1564 } 1565 } 1566 1567 // Create Main Series 1568 regionSeries = im.pushRegionSeries(id, data); 1569 im.maps[id].baseRegionSeries = regionSeries; // Check for grouped regions 1570 1571 if (Array.isArray(data.regionGroups) && data.regionGroups.length) { 1572 groupedSeries = im.pushGroupSeries(id, data); 1573 im.maps[id].groupedBaseRegionSeries = groupedSeries; 1574 } // Overlay collections - we can add all series in the preset order 1575 1576 if (Array.isArray(data.overlay) && data.overlay.length) { 1577 data.overlay.forEach(function (mapObj) { 1578 im.pushSeries(id, mapObj); 1579 }); 1580 } // Create Other Series - we create them after the overlay to avoid overlap 1581 1582 if (Array.isArray(data.lines) && data.lines.length) { 1583 im.pushLineSeries(id, data); 1584 } 1585 1586 if (Array.isArray(data.roundMarkers) && data.roundMarkers.length) { 1587 markerSeries = im.pushRoundMarkerSeries(id, data); 1588 1589 if (data.clusterMarkers && im.bool(data.clusterMarkers.enabled)) { 1590 markerSeries.hidden = true; 1591 im.setupClusters(data, id); 1592 clusterSeries[id].zoomLevels[data.clusterMarkers.zoomLevel] = markerSeries; 1593 // we setup the main index series (zoom=1) to be visible 1594 // when doing it inside setupClusters function, there was a bug 1595 if (clusterSeries[id].zoomLevels[1]) { 1596 clusterSeries[id].zoomLevels[1].hidden = false; 1597 // we also add it to the base series here, since it wasn't working in the setupClusters function 1598 im.maps[id].allBaseSeries.push(clusterSeries[id].zoomLevels[1]); 1599 } 1600 } 1601 } 1602 1603 if (Array.isArray(data.imageMarkers) && data.imageMarkers.length) { 1604 imageSeries = im.pushImageMarkerSeries(id, data); //imageSeries.hiddenInLegend = true; 1605 1606 im.maps[id].allBaseSeries.push(imageSeries); 1607 } 1608 1609 if (Array.isArray(data.iconMarkers) && data.iconMarkers.length) { 1610 iconSeries = im.pushIconMarkerSeries(id, data); //iconSeries.hiddenInLegend = true; 1611 1612 im.maps[id].allBaseSeries.push(iconSeries); 1613 } 1614 1615 if (Array.isArray(data.labels) && data.labels.length) { 1616 labelSeries = im.pushLabelSeries(id, data); //labelSeries.hiddenInLegend = true; 1617 1618 im.maps[id].allBaseSeries.push(labelSeries); 1619 } // checks if we should display info and creates events. 1620 1621 im.handleInfoBox(id); // map.projection = new am4maps.projections[data.projection](); 1622}; 1623 1624iMapsManager.setLegendStyle = function (id, legend, style) { 1625 var sizes = { 1626 xsmall: 10, 1627 small: 13, 1628 regular: 16, 1629 large: 19, 1630 larger: 23, 1631 }; 1632 var legendSize = sizes[style]; 1633 var legendMarkerTemplate = legend.markers.template; 1634 legend.labels.template.fontSize = legendSize; 1635 legend.useDefaultMarker = true; 1636 legendMarkerTemplate.width = legendSize; 1637 legendMarkerTemplate.height = legendSize; 1638}; 1639 1640iMapsManager.handleZoom = function (id) { 1641 var im = this, 1642 map = im.maps[id].map, 1643 data = im.maps[id].data, 1644 defaultOffset = true, 1645 defaultZoom = true; // Viewport settings 1646 1647 // Zoom Level 1648 if (typeof data.viewport !== 'undefined' && parseFloat(data.viewport.zoomLevel) >= 1) { 1649 map.homeZoomLevel = parseFloat(data.viewport.zoomLevel); 1650 defaultZoom = false; // to make sure everything else is disabled by default 1651 1652 map.seriesContainer.resizable = false; 1653 map.seriesContainer.draggable = false;
1654 map.chartContainer.wheelable = false; 1655 } 1656 1657 // Home center point 1658 if ( 1659 typeof data.viewport !== 'undefined' && 1660 data.viewport.homeGeoPoint && 1661 data.viewport.homeGeoPoint.latitude !== 0 && 1662 data.viewport.homeGeoPoint.longitude !== 0 1663 ) { 1664 map.homeGeoPoint = data.viewport.homeGeoPoint; 1665 } 1666 1667 // delta Coordinates Offset 1668 if (typeof data.viewport !== 'undefined' && data.viewport.offset) { 1669 // only change if there are values, otherwise we might mess up projections (Albers) 1670 if (data.viewport.offset.longitude !== '' && data.viewport.offset.longitude !== '0') { 1671 defaultOffset = false; 1672 map.deltaLongitude = data.viewport.offset.longitude; 1673 } 1674 1675 if (data.viewport.offset.latitude !== '' && data.viewport.offset.latitude !== '0') { 1676 defaultOffset = false; 1677 map.deltaLatitude = data.viewport.offset.latitude; 1678 } 1679 1680 if (defaultOffset) { 1681 iMapsManager.latLongOffsetFix(data, map, defaultZoom); 1682 } 1683 } 1684 1685 // manual fixes for NZ and RU and Asia maps 1686 if (typeof data.viewport === 'undefined') { 1687 iMapsManager.latLongOffsetFix(data, map, defaultZoom); 1688 } 1689 1690 // default zoom behaviour 1691 if (typeof data.zoom === 'undefined') { 1692 // default zoom behaviour when we can't find zoom settings 1693 if (typeof data.zoomMaster !== 'undefined' && im.bool(data.zoomMaster)) { 1694 map.seriesContainer.draggable = true; 1695 map.seriesContainer.resizable = true; 1696 1697 // display zoom controls by default 1698 map.zoomControl = new am4maps.ZoomControl(); 1699 map.zoomControl.focusable = false; 1700 1701 // iOS fix 1702 map.zoomControl.exportable = false; 1703 if (map.zoomControl.children && map.zoomControl.children.values) { 1704 map.zoomControl.children.values.forEach(function (child) { 1705 child.focusable = false; 1706 }); 1707 } 1708 1709 map.zoomControl.align = 'right'; 1710 map.zoomControl.valign = 'bottom'; 1711 } else { 1712 map.seriesContainer.resizable = false; 1713 map.seriesContainer.draggable = false; 1714 } 1715 1716 map.seriesContainer.events.disableType('doublehit'); 1717 map.chartContainer.background.events.disableType('doublehit'); 1718 map.chartContainer.wheelable = false; 1719 return; 1720 } // disable drag in Orthographic and leave default for the rest 1721 1722 if (data.projection !== 'Orthographic') { 1723 map.seriesContainer.draggable = data.zoom ? im.bool(data.zoom.draggable) : false; 1724 map.seriesContainer.resizable = data.zoom ? im.bool(data.zoom.draggable) : false; // don't zoom out to center 1725 1726 if (im.bool(data.zoom.draggable)) { 1727 // in case we want to show the grab hand on mousehover also 1728 //map.seriesContainer.cursorOverStyle = am4core.MouseCursorStyle.grab; 1729 map.seriesContainer.cursorDownStyle = am4core.MouseCursorStyle.grabbing; 1730 } 1731 1732 // control zoom and pan behaviour 1733 map.centerMapOnZoomOut = false;
1734 map.maxPanOut = 0; 1735 1736 // zoom is enabled, only allow drag on mobile 1737 if ( 1738 im.bool(data.zoom.enabled) && 1739 !im.bool(data.zoom.draggable) && 1740 im.bool(data.zoom.mobileResizable) && 1741 /Mobi|Android/i.test(navigator.userAgent) 1742 ) { 1743 map.seriesContainer.draggable = true; 1744 map.seriesContainer.resizable = true; 1745 } 1746 } else { 1747 map.seriesContainer.draggable = false; 1748 map.seriesContainer.resizable = false; 1749 map.panBehavior = 'rotateLongLat'; 1750 } // disable zoom 1751 1752 if (!im.bool(data.zoom.enabled)) { 1753 map.maxZoomLevel = parseFloat(data.viewport.zoomLevel); 1754 map.seriesContainer.events.disableType('doublehit'); 1755 map.chartContainer.background.events.disableType('doublehit'); 1756 map.seriesContainer.draggable = false; 1757 map.seriesContainer.resizable = false; 1758 map.chartContainer.wheelable = false; 1759 } else { 1760 // mouse wheel zoom 1761 map.chartContainer.wheelable = im.bool(data.zoom.wheelable); // double click zoom 1762 1763 if (!im.bool(data.zoom.doubleHitZoom)) { 1764 map.seriesContainer.events.disableType('doublehit'); 1765 map.chartContainer.background.events.disableType('doublehit'); 1766 } 1767 1768 if (typeof data.zoom.maxZoomLevel !== 'undefined') { 1769 map.maxZoomLevel = parseInt(data.zoom.maxZoomLevel); 1770 } // Zoom Controls 1771 1772 if (im.bool(data.zoom.controls)) { 1773 map.zoomControl = new am4maps.ZoomControl(); 1774 1775 // iOS fix 1776 map.zoomControl.exportable = false; 1777 if (map.zoomControl.children && map.zoomControl.children.values) { 1778 map.zoomControl.children.values.forEach(function (child) { 1779 child.focusable = false; 1780 }); 1781 } 1782 1783 map.zoomControl.exportable = false; 1784 map.zoomControl.align = data.zoom.controlsPositions 1785 ? data.zoom.controlsPositions.align 1786 : 'right'; 1787 map.zoomControl.valign = data.zoom.controlsPositions 1788 ? data.zoom.controlsPositions.valign 1789 : 'bottom'; 1790 1791 if (typeof data.zoom.homeButton === 'undefined' || im.bool(data.zoom.homeButton)) { 1792 // home button 1793 var homeButton = new am4core.Button(); 1794 // iOS scroll fix 1795 homeButton.focusable = false; 1796 homeButton.events.on('hit', function () { 1797 map.goHome(); 1798 // in case drillDown is enabled, we hide everything else 1799 iMapsManager.resetDrilldown(id); 1800 // reset actions 1801 if ( 1802 typeof iMapsActions !== 'undefined' && 1803 typeof iMapsActions.resetActions !== 'undefined' 1804 ) { 1805 iMapsActions.resetActions(id); 1806 } 1807 }); 1808 homeButton.icon = new am4core.Sprite(); 1809 homeButton.padding(7, 5, 7, 5); 1810 homeButton.width = 30; 1811 homeButton.icon.path = 1812 'M16,8 L14,8 L14,16 L10,16 L10,10 L6,10 L6,16 L2,16 L2,8 L0,8 L8,0 L16,8 Z M16,8'; 1813 homeButton.marginBottom = 3; 1814 homeButton.parent = map.zoomControl; 1815 homeButton.insertBefore(map.zoomControl.plusButton); // fix for Firefox home button not being loaded correctly 1816 1817 map.events.on('inited', function () { 1818 homeButton.deepInvalidate(); 1819 }); 1820 } 1821 } // outside zoom controls 1822 1823 if (im.bool(data.zoom.externalControls)) { 1824 // add home button 1825 iMapsManager.handleExternalZoom(data.id); 1826 } 1827 } // full screen button 1828 1829 if (typeof data.fullScreen !== 'undefined' && im.bool(data.fullScreen.enabled)) { 1830 // full screen 1831 var fullScreenButton = map.chartContainer.createChild(am4core.Button); 1832 fullScreenButton.events.on('hit', function (ev) { 1833 var parentMap = document.querySelector('#map_' + ev.target.icon.mapID); 1834 var mainParent = parentMap.closest('.map_wrapper'); 1835 1836 // browser fullscreen 1837 iMapsManager.toggleFullscreen(mainParent); 1838 iMapsManager.isFullScreen = ev.target; 1839 }); 1840 1841 // Add button 1842 fullScreenButton.align = data.fullScreen.align; 1843 fullScreenButton.valign = data.fullScreen.valign; 1844 fullScreenButton.margin(5, 5, 5, 5); 1845 fullScreenButton.padding(5, 0, 5, 0); 1846 fullScreenButton.width = 30; 1847 fullScreenButton.icon = new am4core.Sprite(); 1848 fullScreenButton.icon.path = iMapsManager.library.icons.goFullIconPath; 1849 fullScreenButton.icon.isFullScreen = false;
1850 fullScreenButton.icon.mapID = id; // if mobile only, add class 1851 1852 if (im.bool(data.fullScreen.mobileOnly)) { 1853 fullScreenButton.id = '_fullscreen_button_only_mobile'; 1854 } else { 1855 fullScreenButton.id = '_fullscreen_button'; 1856 } 1857 1858 // Solution for Firefox issue with button container 1859 map.events.on('inited', function () { 1860 fullScreenButton.deepInvalidate(); 1861 }); 1862 } 1863 1864 // pan events? 1865 map.events.on('mappositionchanged', function () { 1866 // what to do here to have tooltips always display follow pan? 1867 }); 1868 1869 // zoom level changed events 1870 map.events.on('zoomlevelchanged', function (ev) { 1871 var clusterSeries = im.maps[id].clusterSeries, 1872 closest, 1873 zlevel = ev.target.zoomLevel, 1874 isDrill = im.bool(data.drillDownOnClick), 1875 // Check if data.liveFilter exists and has the property 'enabled' before accessing it 1876 isDrilling = im.maps[id].isDrilling, 1877 drilledTo = im.maps[id].drilledTo, 1878 activeMap = im.filteredMap, 1879 keepBase = false; 1880 1881 var hasLiveFilter = false; 1882 if (typeof data.liveFilter !== 'undefined') { 1883 var hasLiveFilter = im.bool(data.liveFilter.enabled); 1884 } 1885 1886 // for drilldown 1887 if (isDrill && typeof data.alwaysKeepBase !== 'undefined' && im.bool(data.alwaysKeepBase)) { 1888 keepBase = true; 1889 } 1890 1891 // for live filter 1892 // Added check to ensure data.liveFilter exists before checking its 'keepBase' property 1893 if (hasLiveFilter && data.liveFilter && im.bool(data.liveFilter.keepBase)) { 1894 keepBase = true; 1895 } 1896 1897 // where the magic happens to show/hide series from cluster markers 1898 if (clusterSeries && Object.keys(clusterSeries).length) { 1899 Object.keys(clusterSeries).forEach(function (key) { 1900 // if the drilldown or live filter are enabled 1901 if (isDrill || hasLiveFilter) { 1902 if ( 1903 //active map in live filter is the map the cluster belongs to 1904 (hasLiveFilter && parseInt(activeMap) === parseInt(clusterSeries[key].overlay)) || 1905 // current active map is the base map in the filter 1906 (hasLiveFilter && parseInt(activeMap) === parseInt(id)) || 1907 // there's a filter, but the keepBase is enabled, so clusters that are not overlay still display 1908 (hasLiveFilter && keepBase && !im.bool(clusterSeries[key].overlay)) || 1909 //map being drilled to is the map the cluster belongs to 1910 (isDrilling && 1911 drilledTo && 1912 parseInt(drilledTo) === parseInt(clusterSeries[key].overlay)) || 1913 //drilldown is enabled and cluster is from the base map and we are not drilling 1914 (isDrill && !im.bool(clusterSeries[key].overlay) && !keepBase && !drilledTo) || 1915 //drilldown is enabled, cluster is from base map and keepBase is enabled 1916 (isDrill && !im.bool(clusterSeries[key].overlay) && keepBase) 1917 ) { 1918 // first we get the closest zoom value compared to the current zom 1919 closest = im.getClosest(clusterSeries[key].zoomLevels, zlevel); 1920 Object.keys(clusterSeries[key].zoomLevels).forEach(function (zkey) { 1921 clusterSeries[key].zoomLevels[zkey].hide(); 1922 if (parseFloat(zkey) === closest) { 1923 clusterSeries[key].zoomLevels[zkey].show(); 1924 } else { 1925 clusterSeries[key].zoomLevels[zkey].hide(); 1926 } 1927 }); 1928 } else { 1929 // not drilling and not active map 1930 Object.keys(clusterSeries[key].zoomLevels).forEach(function (zkey) { 1931 clusterSeries[key].zoomLevels[zkey].hide(); 1932 }); 1933 } 1934 1935 return; 1936 } 1937 1938 // it's not a drilldown, proceed 1939 // we go through the series to show the closest one and hide the others 1940 closest = im.getClosest(clusterSeries[key].zoomLevels, zlevel); 1941 Object.keys(clusterSeries[key].zoomLevels).forEach(function (zkey) { 1942 // we hide them by default 1943 clusterSeries[key].zoomLevels[zkey].hide(); 1944 1945 if (parseFloat(zkey) === closest) { 1946 clusterSeries[key].zoomLevels[zkey].show(); 1947 } else { 1948 clusterSeries[key].zoomLevels[zkey].hide(); 1949 } 1950 }); 1951 }); 1952 } 1953 }); 1954}; 1955/** 1956 * Gets closest zoom level based on current zoom and array of zoom levels for cluster
1956s 1957 * @param {*} zoomLevels 1958 * @param {*} zlevel 1959 */ 1960 1961iMapsManager.getClosest = function (zoomLevels, zlevel) { 1962 var closest = Object.keys(zoomLevels).reduce(function (prev, curr) { 1963 prev = parseInt(prev); 1964 curr = parseInt(curr); 1965 return Math.abs(curr - zlevel) < Math.abs(prev - zlevel) ? curr : prev; 1966 }); 1967 return closest; 1968}; 1969 1970/* Reset drilldown behaviour */ 1971iMapsManager.resetDrilldown = function (id) { 1972 var im = this, 1973 data = im.maps[id].data, 1974 allCurrentSeries = im.maps[id].series, 1975 allBaseSeries = im.maps[id].allBaseSeries, 1976 bgSeries = im.maps[id].backgroundSeries; 1977 1978 if (im.bool(data.drillDownOnClick)) { 1979 for (var i = 0, len = allCurrentSeries.length; i < len; i++) { 1980 allCurrentSeries[i].hide(); //map.deltaLongitude = 0; 1981 } 1982 1983 for (var ib = 0, lenb = allBaseSeries.length; ib < lenb; ib++) { 1984 // this is messing the cluster markers on base map 1985 allBaseSeries[ib].show(); 1986 1987 // make sure there's a bg series 1988 if (bgSeries.mapPolygons) { 1989 bgSeries.show(); 1990 } 1991 } 1992 1993 iMapsManager.maps[id].drilledTo = false; 1994 iMapsManager.maps[id].isDrilling = false; 1995 } 1996}; 1997 1998/** Manually fix lat/long offset for some countries in default projections/values */ 1999 2000iMapsManager.latLongOffsetFix = function (data, mapObj, defaultZoom) { 2001 var mapSelected = data.map; 2002 var mapsFixInclude = [ 2003 'russiaLow', 2004 'russiaHigh', 2005 'russiaCrimeaLow', 2006 'russiaCrimeaHigh', 2007 'region/world/asiaLow', 2008 'region/world/asiaHigh', 2009 'region/world/asiaUltra', 2010 'region/world/asiaIndiaLow', 2011 'region/world/asiaIndiaHigh', 2012 'region/world/asiaIndiaUltra', 2013 ]; 2014 2015 // only do the fix if Russia is included 2016 2017 if (mapsFixInclude.includes(mapSelected) && data.exclude && !data.exclude.includes('RU')) { 2018 mapObj.deltaLongitude = -100; 2019 2020 if (defaultZoom) { 2021 mapObj.homeZoomLevel = 1.5; 2022 } 2023 } 2024 2025 if (mapSelected === 'newZealandLow' || mapSelected == 'newZealandHigh') { 2026 mapObj.deltaLongitude = 20; 2027 } 2028}; 2029/** 2030 * Push region series that are grouped together 2031 */ 2032 2033iMapsManager.pushGroupSeries = function (id, data) { 2034 var series = []; 2035 var regionSerie; 2036 data.regionGroups.forEach(function (group) { 2037 var newData = {}, 2038 include = group.map(function (a) { 2039 return a.id; 2040 }); 2041 2042 // let's get all the options from the main map and change the group option to true 2043 newData = Object.assign({}, data); 2044 newData.regionsGroupHover = true; 2045 newData.regions = group; 2046 newData.include = include; // include only the regions we're grouping 2047 regionSerie = iMapsManager.pushRegionSeries(id, newData, true); 2048 series.push(regionSerie); 2049 }); 2050 return series; 2051}; 2052/** 2053 * Push different series of overlay/child maps 2054 * int i - index of the map data 2055 * data - object with map data to push 2056 */ 2057 2058iMapsManager.pushSeries = function (id, data) { 2059 var im = this, 2060 regionSeries, 2061 markerSeries, 2062 labelSeries, 2063 lineSeries, 2064 iconSeries, 2065 imageSeries, 2066 groupedSeries, 2067 clusterSeries = im.maps[id].clusterSeries, 2068 parentData = im.maps[id].data, 2069 seriesIndex = im.maps[id].seriesIndex, 2070 seriesById = im.maps[id].seriesById, 2071 isDrill = im.bool(im.maps[id].data.drillDownOnClick), 2072 cleanMapName = iMapsRouter.getCleanMapName(data.map, data.id), 2073 defaultSeries = false; 2074 2075 if (false === cleanMapName) { 2076 return; 2077 } 2078 2079 if (typeof data.id === 'undefined') { 2080 return; 2081 } 2082 2083 seriesById[data.id] = []; 2084 2085 // check if it's set a map overlay by default 2086 if ( 2087 typeof parentData.liveFilter !== 'undefined' && 2088 parseInt(parentData.liveFilter['default']) !== parentData.id 2089 ) { 2090 defaultSeries = parseInt(parentData.liveFilter['default']); 2091 im.filteredMap = defaultSeries; 2092 } // setup series index 2093 2094 if (!Array.isArray(im.maps[id].seriesIndex[data.map])) { 2095 im.maps[id].seriesIndex[cleanMapName] = []; 2096 } 2097 2098 // to allow empty maps to overlay, we removed the check && data.regions.length and send empty array 2099 if (!Array.isArray(data.regions)) { 2100 data.regions = []; 2101 } 2102 2103 if (typeof parentData.allowEmpty === 'undefined') { 2104 parentData.allowEmpty = 0; 2105 } // in case we want empty maps to overlay, we remove this check. 2106 // in are not allowing the empty so that the live filter works better and markers are not hidden behind the map 2107 // reference: https://interactivegeomaps.com/feature/live-filter/ 2108 // but other overlays and empty maps might need to be added... 2109 2110 // we don't check if the regions.length exist, because maybe user wants to add an empty map, only to show divisions 2111 if (data.regions.length || im.bool(parentData.allowEmpty)) { 2112 // in case we don't allow empty, we only include the active regions 2113 if (!im.bool(parentData.allowEmpty)) { 2114 data.include = []; 2115 data.regions.forEach(function (region) { 2116 data.include.push(region.id); 2117 if (!isNaN(region.id)) { 2118 data.include.push(parseInt(region.id)); 2119 } 2120 }); 2121 } 2122 2123 regionSeries = iMapsManager.pushRegionSeries(id, data);
2124 seriesIndex[cleanMapName].push(regionSeries); 2125 seriesById[data.id].push(regionSeries); 2126 2127 if (isDrill) { 2128 regionSeries.hidden = true; 2129 regionSeries.mapID = data.id; 2130 } 2131 2132 // hide in case we have a live filter and this is not the default 2133 if ( 2134 parentData.liveFilter && 2135 im.bool(parentData.liveFilter.enabled) && 2136 defaultSeries && 2137 defaultSeries !== data.id 2138 ) { 2139 regionSeries.hidden = true; 2140 } 2141 } 2142 2143 // Check for grouped regions 2144 if (Array.isArray(data.regionGroups) && data.regionGroups.length) { 2145 groupedSeries = im.pushGroupSeries(id, data); 2146 groupedSeries.forEach(function (regionSerie) { 2147 seriesIndex[cleanMapName].push(regionSerie); 2148 seriesById[data.id].push(regionSerie); 2149 2150 if (isDrill) { 2151 regionSerie.hidden = true; 2152 regionSerie.mapID = data.id; 2153 } 2154 2155 // hide in case we have a live filter and this is not the default 2156 if ( 2157 parentData.liveFilter && 2158 im.bool(parentData.liveFilter.enabled) && 2159 defaultSeries && 2160 defaultSeries !== data.id 2161 ) { 2162 regionSerie.hidden = true; 2163 } 2164 }); 2165 } // let's add lines before markers, so that the markers then overlay the end of lines, in case 2166 2167 if (Array.isArray(data.lines) && data.lines.length) { 2168 lineSeries = iMapsManager.pushLineSeries(id, data); 2169 seriesIndex[cleanMapName].push(lineSeries); 2170 seriesById[data.id].push(lineSeries); 2171 2172 if (isDrill) { 2173 lineSeries.hidden = true; 2174 } // hide in case we have a live filter and this is not the default 2175 2176 if ( 2177 parentData.liveFilter && 2178 im.bool(parentData.liveFilter.enabled) && 2179 defaultSeries && 2180 defaultSeries !== data.id 2181 ) { 2182 lineSeries.hidden = true; 2183 } 2184 } 2185 2186 if (Array.isArray(data.roundMarkers) && data.roundMarkers.length) { 2187 markerSeries = iMapsManager.pushRoundMarkerSeries(id, data); 2188 seriesIndex[cleanMapName].push(markerSeries); 2189 seriesById[data.id].push(markerSeries); 2190 2191 if (isDrill) { 2192 markerSeries.hidden = true; 2193 markerSeries.mapID = data.id; 2194 } 2195 2196 // clusters in overlay maps 2197 if (data.clusterMarkers && im.bool(data.clusterMarkers.enabled)) { 2198 markerSeries.hidden = true; 2199 im.setupClusters(data, id, data.id); 2200 clusterSeries[data.id].zoomLevels[data.clusterMarkers.zoomLevel] = markerSeries; // we setup the main index series (zoom=1) to be visible 2201 // when doing it inside setupClusters function, there was a bug 2202 2203 if (!isDrill && clusterSeries[data.id].zoomLevels[1]) { 2204 clusterSeries[data.id].zoomLevels[1].hidden = false; 2205 2206 // if there's a live filter, double check - we hide them. 2207 // otherwise overlaid series with clusters were always displaying, even when they shouldn't 2208 if ( 2209 parentData.liveFilter && 2210 im.bool(parentData.liveFilter.enabled) && 2211 defaultSeries && 2212 defaultSeries !== data.id 2213 ) { 2214 clusterSeries[data.id].zoomLevels[1].hidden = true; 2215 } 2216 } 2217 } 2218 2219 // hide in case we have a live filter and this is not the default 2220 if ( 2221 parentData.liveFilter && 2222 im.bool(parentData.liveFilter.enabled) && 2223 defaultSeries && 2224 defaultSeries !== data.id 2225 ) { 2226 markerSeries.hidden = true; 2227 } 2228 } 2229 2230 if (Array.isArray(data.iconMarkers) && data.iconMarkers.length) { 2231 iconSeries = iMapsManager.pushIconMarkerSeries(id, data); 2232 seriesIndex[cleanMapName].push(iconSeries); 2233 seriesById[data.id].push(iconSeries); 2234 2235 if (isDrill) { 2236 iconSeries.hidden = true; 2237 } // hide in case we have a live filter and this is not the default 2238 2239 if ( 2240 parentData.liveFilter && 2241 im.bool(parentData.liveFilter.enabled) && 2242 defaultSeries && 2243 defaultSeries !== data.id 2244 ) { 2245 iconSeries.hidden = true; 2246 } 2247 } 2248 2249 if (Array.isArray(data.imageMarkers) && data.imageMarkers.length) { 2250 imageSeries = iMapsManager.pushImageMarkerSeries(id, data); 2251 seriesIndex[cleanMapName].push(imageSeries); 2252 seriesById[data.id].push(imageSeries); 2253 2254 if (isDrill) { 2255 imageSeries.hidden = true; 2256 } // hide in case we have a live filter and this is not the default 2257 2258 if ( 2259 parentData.liveFilter && 2260 im.bool(parentData.liveFilter.enabled) && 2261 defaultSeries && 2262 defaultSeries !== data.id 2263 ) { 2264 imageSeries.hidden = true; 2265 } 2266 } 2267 2268 if (Array.isArray(data.labels) && data.labels.length) { 2269 labelSeries = iMapsManager.pushLabelSeries(id, data); 2270 seriesIndex[cleanMapName].push(labelSeries); 2271 seriesById[data.id].push(labelSeries); 2272 2273 if (isDrill) { 2274 labelSeries.hidden = true; 2275 } // hide in case we have a live filter and this is not the default 2276 2277 if ( 2278 parentData.liveFilter && 2279 im.bool(parentData.liveFilter.enabled) && 2280 defaultSeries && 2281 defaultSeries !== data.id 2282 ) { 2283 labelSeries.hidden = true; 2284 } 2285 } 2286}; 2287 2288iMapsManager.pushRegionSeries = function (id, data, groupHover) { 2289 var im = this, 2290 map = im.maps[id].map, 2291 // shorter reference for the map 2292 regionSeries, 2293 tooltipConfig = data.tooltip || {}, 2294 regionTemplate, 2295 hover, 2296 active, 2297 highlight, 2298 mapVar, 2299 clkLabel, 2300 groupHover = groupHover || false; 2301 data = data || {}; 2302 regionSeries = map.series.push(new am4maps.MapPolygonSeries()); 2303 2304 if (data.map === 'custom' || im.bool(data.useGeojson)) { 2305 regionSeries.geodataSource.url = data.mapURL; 2306 } else {
2307 mapVar = iMapsRouter.getVarByName(data.map); 2308 regionSeries.geodata = window[mapVar]; 2309 } 2310 2311 regionSeries.name = 2312 data.regionLegend && data.regionLegend.title !== '' ? data.regionLegend.title : data.title; 2313 regionSeries.hiddenInLegend = data.regionLegend ? !im.bool(data.regionLegend.enabled) : true; // if it's a base series 2314 2315 // override hide in legend for scenarios where there are grouped entries for example 2316 if (data.regionLegend && data.regionLegend.enabled === 'onlyGroups' && groupHover) { 2317 regionSeries.hiddenInLegend = false; 2318 } 2319 2320 if (data.regionLegend && data.regionLegend.enabled === 'onlyGroups' && !groupHover) { 2321 regionSeries.hiddenInLegend = true; 2322 } 2323 2324 if (data.regionLegend && data.regionLegend.enabled === 'ignoreGroups' && groupHover) { 2325 regionSeries.hiddenInLegend = true; 2326 } 2327 2328 if (data.regionLegend && data.regionLegend.enabled === 'ignoreGroups' && !groupHover) { 2329 regionSeries.hiddenInLegend = false; 2330 } 2331 2332 if (id === data.id) { 2333 // add it as the baseSeries - which will contain all region base series 2334 if (typeof im.maps[id].baseSeries === 'undefined') { 2335 im.maps[id].baseSeries = []; 2336 } 2337 im.maps[id].baseSeries.push(regionSeries); 2338 im.maps[id].allBaseSeries.push(regionSeries); 2339 } 2340 2341 // Make map load polygon (like country names) data from GeoJSON 2342 regionSeries.useGeodata = true; // Exclude 2343 2344 if (Array.isArray(data.exclude) && data.exclude.length) { 2345 regionSeries.exclude = data.exclude; 2346 } // Include 2347 2348 if (Array.isArray(data.include) && data.include.length) { 2349 regionSeries.include = data.include; 2350 } // Setup Heatmap rules 2351 2352 if (data.heatMapRegions && im.bool(data.heatMapRegions.enabled)) { 2353 im.setupHeatMap(regionSeries, id, data); 2354 } // Data 2355 // if (Array.isArray(data.regions)) { 2356 2357 regionSeries.data = data.regions; // Configure series 2358 2359 if (groupHover) { 2360 regionSeries.groupHover = true; 2361 } 2362 2363 regionTemplate = regionSeries.mapPolygons.template; 2364 im.setupTooltip(id, regionSeries, data); // check for custom tooltip template 2365 2366 if ( 2367 typeof data.regionsTooltipTemplate !== 'undefined' && 2368 data.regionsTooltipTemplate.trim() !== '' 2369 ) { 2370 regionTemplate.tooltipText = data.regionsTooltipTemplate; 2371 regionTemplate.tooltipHTML = data.regionsTooltipTemplate; 2372 } else { 2373 regionTemplate.tooltipText = tooltipConfig.template 2374 ? tooltipConfig.template 2375 : '{tooltipContent}'; 2376 regionTemplate.tooltipHTML = tooltipConfig.template 2377 ? tooltipConfig.template 2378 : '{tooltipContent}'; 2379 } 2380 2381 regionTemplate.adapter.add('tooltipHTML', function (value, target) { 2382 if ( 2383 _typeof(target.dataItem.dataContext) === 'object' && 2384 typeof tooltipConfig.onlyWithData !== 'undefined' 2385 ) { 2386 // check if we don't return tooltip on empty regions 2387 if (im.bool(tooltipConfig.onlyWithData)) { 2388 if (target.dataItem.dataContext.madeFromGeoData === true) { 2389 target.tooltip.tooltipText = undefined; 2390 target.tooltip.tooltipHTML = undefined; 2391 return ''; 2392 } 2393 } 2394 } 2395 2396 if (value === '') { 2397 return value; 2398 } 2399 2400 return value.replace(/\\/g, ''); 2401 }); 2402 regionTemplate.adapter.add('tooltipText', function (value, target) { 2403 if ( 2404 _typeof(target.dataItem.dataContext) === 'object' && 2405 typeof tooltipConfig.onlyWithData !== 'undefined' 2406 ) { 2407 // check if we don't return tooltip on empty regions 2408 if (im.bool(tooltipConfig.onlyWithData)) { 2409 if (target.dataItem.dataContext.madeFromGeoData === true) { 2410 target.tooltip.tooltipText = undefined; 2411 target.tooltip.tooltipHTML = undefined; 2412 return ''; 2413 } 2414 } 2415 } 2416 2417 if (value === '') { 2418 return value; 2419 } 2420 2421 return value.replace(/\\/g, ''); 2422 }); // For legend color 2423 2424 regionSeries.fill = data.regionDefaults.fill; 2425 regionTemplate.fill = data.regionDefaults.inactiveColor; 2426 regionTemplate.stroke = data.visual.borderColor; 2427 regionTemplate.strokeWidth = data.visual.borderWidth; // fill 2428 2429 regionTemplate.propertyFields.fill = 'fill'; 2430 2431 // exploring adapter 2432 /* 2433 regionTemplate.adapter.add("fill", function(fill, target) { 2434 if(Array.isArray(fill)){ 2435 let gradient = new am4core.LinearGradient(); 2436 fill.forEach(function(color){
2437 gradient.addColor(am4core.color(color)); 2438 }); 2439 fill = gradient; 2440 } 2441 return fill; 2442 }); 2443 */ 2444 2445 // hover - only create if it's not a group hover series 2446 2447 if (!groupHover) { 2448 // also don't consider it on heatmaps with hover disabled 2449 if ( 2450 typeof data.heatMapRegions !== 'undefined' && 2451 im.bool(data.heatMapRegions.enabled) && 2452 im.bool(data.heatMapRegions.noHover) 2453 ) { 2454 // do nothing for now, we don't need hover, might implement something at some point 2455 } else { 2456 hover = regionTemplate.states.create('hover'); 2457 hover.propertyFields.fill = 'hover'; 2458 } 2459 //hover.propertyFields.strokeWidth = "borderWidthHover"; 2460 //hover.propertyFields.stroke = "borderColorHover"; 2461 } 2462 2463 // active state 2464 if (data.regionActiveState && im.bool(data.regionActiveState.enabled)) { 2465 active = regionTemplate.states.create('active'); 2466 2467 if (data.regionActiveState.source === 'custom') { 2468 active.properties.fill = data.regionActiveState.fill; 2469 } else { 2470 active.propertyFields.fill = 'hover'; 2471 } 2472 } 2473 // highlight - for group hover 2474 highlight = regionTemplate.states.create('highlight'); 2475 highlight.propertyFields.fill = 'hover'; 2476 2477 if (groupHover) { 2478 regionTemplate.events.on('out', function (ev) { 2479 im.groupHoverOut(id, ev); 2480 }); 2481 regionTemplate.events.on('over', function (ev) { 2482 im.groupHover(id, ev); 2483 // bring this series (and label series if it exists) to front when group is hovered 2484 regionSeries.toFront(); 2485 if (typeof regionSeries.autoLabelSeries !== 'undefined') { 2486 regionSeries.autoLabelSeries.toFront(); 2487 } 2488 }); 2489 regionTemplate.events.on('hit', function (ev) { 2490 im.groupHit(id, ev); 2491 }); 2492 } else { 2493 regionTemplate.events.on('hit', function (ev) { 2494 im.singleHit(id, ev); 2495 }); 2496 regionTemplate.events.on('over', function (ev) { 2497 im.setupHoverEvents(id, ev); 2498 }); 2499 } // Events 2500 2501 // iOS bug fix, remove focus 2502 regionTemplate.focusable = false; 2503 2504 regionTemplate.events.on('hit', function (ev) { 2505 im.setupHitEvents(id, ev); 2506 }); 2507 2508 // enable small map 2509 if (im.bool(data.smallMap)) { 2510 map.smallMap.series.push(regionSeries); 2511 } 2512 2513 // auto Labels 2514 if (data.regionLabels && im.bool(data.regionLabels.source)) { 2515 regionSeries.calculateVisualCenter = true; 2516 2517 // Configure label series 2518 var labelSeries = map.series.push(new am4maps.MapImageSeries()); 2519 var labelTemplate = labelSeries.mapImages.template.createChild(am4core.Label); 2520 2521 // Label Background - currently only possible with global 2522 var background = typeof igmLabelsBackground !== 'undefined' ? igmLabelsBackground : false; 2523 if (typeof background === 'object') { 2524 labelTemplate.background = new am4core.RoundedRectangle(); 2525 labelTemplate.background.cornerRadius(...background.cornerRadius); 2526 labelTemplate.background.fill = am4core.color(background.color); 2527 labelTemplate.padding(...background.padding); 2528 labelTemplate.background.stroke = am4core.color(background.stroke); 2529 } 2530 2531 im.maps[id].labelSeries.push(labelSeries); 2532 2533 // add reference to parent region series 2534 regionSeries.autoLabelSeries = labelSeries; 2535 2536 labelTemplate.horizontalCenter = data.regionLabels.horizontalCenter; 2537 labelTemplate.verticalCenter = data.regionLabels.verticalCenter; 2538 labelTemplate.fontSize = data.regionLabels.fontSize; 2539 labelTemplate.fill = data.regionLabels.fill; 2540 // automatic region label hover state 2541 const hoverState = labelTemplate.states.create('hover'); 2542 hoverState.properties.fill = am4core.color(data.regionLabels.hover); 2543 2544 labelTemplate.fontFamily = data.regionLabels.fontFamily 2545 ? data.regionLabels.fontFamily 2546 : 'inherit'; 2547 labelTemplate.fontWeight = data.regionLabels.fontWeight 2548 ? data.regionLabels.fontWeight 2549 : 'normal'; 2550 2551 // let's set a listener to the hide event of main series to hide this one also 2552 if (data.regionLabels.mobileFontSize && parseInt(data.regionLabels.mobileFontSize) !== 100) { 2553 if (window.innerWidth <= 780) { 2554 labelTemplate.fontSize = 2555 (parseInt(labelTemplate.fontSize) * parseInt(data.regionLabels.mobileFontSize)) / 100; 2556 labelTemplate.size = labelTemplate.fontSize; 2557 } 2558 } 2559 2560 regionSeries.events.on('hidden', function () { 2561 labelSeries.hide(); 2562 }); 2563 regionSeries.events.on('shown', function () { 2564 labelSeries.show(); 2565 }); 2566 // label events 2567 labelTemplate.events.on('hit', function (ev) { 2568 clkLabel = regionSeries.getPolygonById(ev.target.parent.LabelForRegion); 2569 clkLabel.dispatchImmediately('hit'); 2570 }); 2571 labelTemplate.events.on('over', function (ev) { 2572 iMapsManager.hover(id, ev.target.parent.LabelForRegion, false); 2573 }); 2574 labelTemplate.events.on('out', function (ev) { 2575 iMapsManager.clearHovered(id, ev.target.parent.LabelForRegion); 2576 }); 2577 2578 im.setupTooltip(id, labelSeries, data, labelTemplate); 2579 labelTemplate.interactionsEnabled = true; 2580 labelTemplate.nonScaling = im.bool(data.regionLabels.nonScaling); 2581 labelSeries.hiddenInLegend = true; // fix initially hidden series - for example drilldown overlay 2582 2583 regionSeries.events.on('inited', function () { 2584 if (regionSeries.hidden) { 2585 labelSeries.hide(); 2586 labelSeries.hidden = true; 2587 } 2588 }); 2589 2590 // set labels drag listener 2591 // allow labels to be dragged if in admin 2592 2593 if (im.bool(data.admin)) { 2594 labelTemplate.draggable = true; 2595 labelTemplate.cursorOverStyle = am4core.MouseCursorStyle.grab; 2596 labelTemplate.events.on('dragstop', function (ev) { 2597 var svgPoint = am4core.utils.spritePointToSvg( 2598 { 2599 x: 0, 2600 y: 0, 2601 }, 2602 ev.target 2603 ); 2604 svgPoint = am4core.utils.spritePointToSvg( 2605 { 2606 x: 0 - ev.target.maxLeft, 2607 y: 0 - ev.target.maxTop, 2608 }, 2609 ev.target 2610 ); 2611 var geo = map.svgPointToGeo(svgPoint); // check if field to add json object with adjustments exists 2612 2613 var adjField = document.querySelector( 2614 '[data-depend-id=' + data.regionLabelCustomCoordinates + ']' 2615 ); 2616 2617 if (adjField) { 2618 var jsonAdjustments; 2619 2620 if (iMapsManager.isJSON(adjField.value)) { 2621 jsonAdjustments = JSON.parse(adjField.value); 2622 } else { 2623 jsonAdjustments = {}; 2624 } 2625 2626 jsonAdjustments[ev.target.parent.LabelForRegion] = { 2627 latitude: geo.latitude, 2628 longitude: geo.longitude, 2629 }; 2630 adjField.value = JSON.stringify(jsonAdjustments); 2631 } 2632 2633 map.seriesContainer.draggable = im.bool(data.zoom.draggable); 2634 ev.target.cursorOverStyle = am4core.MouseCursorStyle.grab; 2635 }); 2636 labelTemplate.events.on('down', function (ev) { 2637 map.seriesContainer.draggable = false;
2638 ev.target.cursorOverStyle = am4core.MouseCursorStyle.grabbing; 2639 }); 2640 } // end drag event 2641 2642 // convert custom json position string to object 2643 var regionLabelCustomCoordinates = im.isJSON(data.regionLabels.regionLabelCustomCoordinates) 2644 ? JSON.parse(data.regionLabels.regionLabelCustomCoordinates) 2645 : false; 2646 2647 let event = 'inited'; 2648 if (data.map === 'custom') { 2649 event = 'datavalidated'; 2650 } 2651 2652 regionSeries.events.on(event, function () { 2653 regionSeries.mapPolygons.each(function (polygon) { 2654 // if they are not displaying with lat/long, skip, unless we're using a custom map 2655 if (data.map !== 'custom' && typeof polygon.visualLatitude === 'undefined') { 2656 return; 2657 } 2658 2659 var label = labelSeries.mapImages.create(), 2660 text; // if we're only adding labels to active regions 2661 2662 if ( 2663 im.bool(data.regionLabels.activeOnly) && 2664 polygon.dataItem.dataContext && 2665 typeof polygon.dataItem.dataContext.tooltipContent === 'undefined' 2666 ) { 2667 return; 2668 } // if it's a group entry, ignore 2669 2670 if (polygon.dataItem.dataContext.id.includes(',')) { 2671 return; 2672 } 2673 2674 if (data.regionLabels.source === 'code') { 2675 text = polygon.dataItem.dataContext.id.split('-').pop(); 2676 } 2677 2678 if (data.regionLabels.source === '{name}') { 2679 text = polygon.dataItem.dataContext.name; 2680 } 2681 2682 if (data.regionLabels.source === '{id}') { 2683 text = polygon.dataItem.dataContext.id; 2684 } 2685 2686 if ( 2687 data.regionLabels.source === 'custom' && 2688 typeof data.regionLabels.customSource !== 'undefined' 2689 ) { 2690 text = polygon.dataItem.dataContext.autoLabel; 2691 } 2692 2693 label.LabelForRegion = polygon.dataItem.dataContext.id; // if it was a group 2694
2695 if (typeof polygon.dataItem.dataContext.originalID !== 'undefined') { 2696 label.groupRegion = polygon.dataItem.dataContext.originalID; 2697 } 2698 2699 // tooltip content 2700 label.tooltipDataItem = polygon.tooltipDataItem; 2701 label.tooltip = polygon.tooltip; 2702 label.tooltipHTML = polygon.tooltipHTML; 2703 label.tooltipPosition = im.bool(data.tooltip.fixed) ? 'fixed' : 'pointer'; // cursor style 2704 2705 if (polygon.dataItem.dataContext.action && polygon.dataItem.dataContext.action !== 'none') { 2706 label.cursorOverStyle = am4core.MouseCursorStyle.pointer; 2707 } 2708 2709 // use custom coordinates adjustments or use auto position 2710 if ( 2711 regionLabelCustomCoordinates && 2712 regionLabelCustomCoordinates.hasOwnProperty(polygon.dataItem.dataContext.id) 2713 ) { 2714 label.latitude = regionLabelCustomCoordinates[polygon.dataItem.dataContext.id].latitude; 2715 label.longitude = regionLabelCustomCoordinates[polygon.dataItem.dataContext.id].longitude; 2716 } else { 2717 if (polygon.visualLatitude) { 2718 label.latitude = polygon.visualLatitude; 2719 label.longitude = polygon.visualLongitude; 2720 } 2721 } 2722 2723 if (label.children.getIndex(0)) { 2724 label.children.getIndex(0).text = text; 2725 } 2726 }); 2727 }); 2728 } 2729 2730 // if the external dropdown is enabled, calculate visual center 2731 2732 if (typeof data.externalDropdown !== 'undefined' && im.bool(data.externalDropdown.enabled)) { 2733 regionSeries.calculateVisualCenter = true; 2734 } // add this series to map series to reference it later if needed 2735 2736 im.maps[id].series.push(regionSeries); 2737 return regionSeries; 2738}; 2739 2740iMapsManager.pushRoundMarkerSeries = function (id, data) { 2741 var im = this, 2742 map = im.maps[id].map, 2743 // shorter reference for the map 2744 markerSeries, 2745 markerSeriesTemplate, 2746 circle, 2747 label, 2748 activeState, 2749 highlightState, 2750 hoverState; 2751 2752 if (Array.isArray(data.roundMarkers) && data.roundMarkers.length) { 2753 // Create image series 2754 markerSeries = map.series.push(new am4maps.MapImageSeries()); 2755 markerSeries.name = 2756 data.roundMarkersLegend && data.roundMarkersLegend.title !== '' 2757 ? data.roundMarkersLegend.title 2758 : data.title; 2759 markerSeries.hiddenInLegend = data.roundMarkersLegend 2760 ? !im.bool(data.roundMarkersLegend.enabled) 2761 : false; // Create a circle image in image series template so it gets replicated to all new images 2762 2763 markerSeriesTemplate = markerSeries.mapImages.template; 2764 2765 circle = markerSeriesTemplate.createChild(am4core.Circle); 2766 im.setupTooltip(id, markerSeries, data, circle); 2767 2768 //iOS focus scroll bug fix 2769 markerSeriesTemplate.focusable = false; 2770 2771 circle.radius = data.markerDefaults.radius; 2772 circle.fill = data.markerDefaults.fill; 2773 circle.stroke = am4core.color('#FFFFFF'); 2774 circle.strokeWidth = 1; 2775 circle.nonScaling = 2776 typeof igmRoundMarkersNonScaling !== 'undefined' ? igmRoundMarkersNonScaling : true; 2777 2778 // label 2779 label = markerSeriesTemplate.createChild(am4core.Label); 2780 label.text = '{label}'; 2781 label.fill = am4core.color('#fff'); 2782 label.verticalCenter = 'middle'; 2783 label.horizontalCenter = 'middle'; 2784 label.nonScaling = 2785 typeof igmRoundMarkersNonScaling !== 'undefined' ? igmRoundMarkersNonScaling : true; 2786 label.fontSize = 2787 typeof igmClusterMarkerFontSize !== 'undefined' 2788 ? igmClusterMarkerFontSize 2789 : data.markerDefaults.radius; 2790 label.clickable = false; 2791 label.focusable = false; 2792 label.hoverable = false; 2793 2794 // check for custom tooltip template 2795 if ( 2796 typeof data.roundMarkersTooltipTemplate !== 'undefined' && 2797 data.roundMarkersTooltipTemplate.trim() !== '' 2798 ) { 2799 markerSeriesTemplate.tooltipText = data.roundMarkersTooltipTemplate; 2800 markerSeriesTemplate.tooltipHTML = data.roundMarkersTooltipTemplate; 2801 } else { 2802 markerSeriesTemplate.tooltipText = 2803 data.tooltip && data.tooltip.template ? data.tooltip.template : '{tooltipContent}'; 2804 markerSeriesTemplate.tooltipHTML = 2805 data.tooltip && data.tooltip.template ? data.tooltip.template : '{tooltipContent}'; 2806 } 2807 2808 markerSeriesTemplate.propertyFields.tooltipText = 'tooltipTemplate'; 2809 markerSeriesTemplate.propertyFields.tooltipHTML = 'tooltipTemplate'; // fill can only be set if heatmap is not enabled and not a range 2810 2811 if (data.heatMapMarkers && im.bool(data.heatMapMarkers.enabled)) { 2812 im.setupHeatMap(markerSeries, id, data); // setup the fill and radius if type is range 2813 2814 if (typeof data.heatMapMarkers.type !== 'undefined' && data.heatMapMarkers.type === 'range') { 2815 circle.propertyFields.radius = 'radius'; 2816 circle.propertyFields.fill = 'fill'; 2817 } 2818 } else { 2819 circle.propertyFields.radius = 'radius'; 2820 circle.propertyFields.fill = 'fill'; 2821 } 2822 2823 circle.propertyFields.userClassName = 'customClass'; // Set property fields 2824 2825 markerSeriesTemplate.propertyFields.radius = 'radius'; 2826 markerSeriesTemplate.propertyFields.latitude = 'latitude'; 2827 markerSeriesTemplate.propertyFields.longitude = 'longitude'; 2828 markerSeriesTemplate.setStateOnChildren = true; // hover & active 2829 2830 hoverState = circle.states.create('hover'); 2831 hoverState.properties.fill = data.hover; 2832 hoverState.propertyFields.fill = 'hover'; // active 2833 2834 activeState = circle.states.create('active'); 2835 activeState.properties.fill = data.hover; 2836 activeState.propertyFields.fill = 'hover'; // highlight - for legend hover 2837 2838 highlightState = circle.states.create('highlight'); 2839 highlightState.properties.fill = data.hover; 2840 highlightState.propertyFields.fill = 'hover'; // text label below 2841 2842 if (data.roundMarkerLabels && im.bool(data.roundMarkerLabels.enabled)) { 2843 // create dummy state to force all object to get this state 2844 markerSeriesTemplate.states.create('hover'); 2845 2846 var markerLabel = markerSeriesTemplate.createChild(am4core.Label); 2847 var markerLabelPosition = 2848 typeof data.roundMarkerLabels.position !== 'undefined' && 2849 data.roundMarkerLabels.position !== '' 2850 ? data.roundMarkerLabels.position 2851 : 'bottom'; 2852 markerLabel.text = 2853 typeof data.roundMarkerLabels.source !== 'undefined' && data.roundMarkerLabels.source !== '' 2854 ? data.roundMarkerLabels.source 2855 : '{name}'; 2856 markerLabel.fontSize = data.roundMarkerLabels.fontSize; 2857 2858 // set state on parent 2859 markerLabel.setStateOnChildren = true; 2860 2861 //for mobile devices 2862 if ( 2863 data.roundMarkerLabels.mobileSize && 2864 parseInt(data.roundMarkerLabels.mobileSize) !== 100 2865 ) { 2866 if (window.innerWidth <= 780) { 2867 markerLabel.fontSize = 2868 (parseInt(data.roundMarkerLabels.fontSize) * 2869 parseInt(data.roundMarkerLabels.mobileSize)) / 2870 100; 2871 } 2872 } 2873 2874 markerLabel.nonScaling = 2875 typeof igmRoundMarkersNonScaling !== 'undefined' ? igmRoundMarkersNonScaling : true; 2876 //im.bool(data.roundMarkerLabels.nonScaling); 2877 2878 markerLabel.fill = data.roundMarkerLabels.fill; 2879 markerLabel.clickable = false;
2880 markerLabel.focusable = false; 2881 markerLabel.hoverable = false; 2882 2883 // control position 2884 markerLabel.padding(0, 0, 0, 0); 2885 2886 // this is a first iteration of this feature 2887 // in the future we can have the position individually for each marker and use the propertyFields approach 2888 if (markerLabelPosition === 'bottom') { 2889 markerLabel.horizontalCenter = 'middle'; 2890 markerLabel.verticalCenter = 'top'; 2891 markerLabel.propertyFields.paddingTop = 'radius'; 2892 } 2893 2894 if (markerLabelPosition === 'top') { 2895 markerLabel.horizontalCenter = 'middle'; 2896 markerLabel.verticalCenter = 'bottom'; 2897 markerLabel.propertyFields.paddingBottom = 'radius'; 2898 } 2899 2900 if (markerLabelPosition === 'right') { 2901 markerLabel.horizontalCenter = 'left'; 2902 markerLabel.verticalCenter = 'middle'; 2903 markerLabel.propertyFields.paddingLeft = 'radius'; 2904 } 2905 2906 if (markerLabelPosition === 'left') { 2907 markerLabel.horizontalCenter = 'right'; 2908 markerLabel.verticalCenter = 'middle'; 2909 markerLabel.propertyFields.paddingRight = 'radius'; 2910 } 2911 } 2912 2913 // send to front (so on overlay they are always on top of regions) 2914 markerSeries.zIndex = Number.MAX_VALUE; 2915 markerSeries.toFront(); 2916 2917 // Add data 2918 markerSeries.data = data.roundMarkers; // For legend color 2919 2920 markerSeries.fill = data.markerDefaults.fill; // Events 2921 2922 markerSeriesTemplate.events.on('hit', function (ev) { 2923 im.singleHit(id, ev); 2924 im.setupHitEvents(id, ev); 2925 }); 2926 markerSeriesTemplate.events.on('over', function (ev) { 2927 im.setupHoverEvents(id, ev); 2928 }); 2929 } // enable small map 2930 2931 if (data.zoom && data.zoom.smallMap && im.bool(data.zoom.smallMap)) { 2932 map.smallMap.series.push(markerSeries); 2933 } // add this series to map series to reference it later if needed 2934 2935 im.maps[id].series.push(markerSeries); // if part of the parent map 2936 2937 if (id === data.id) { 2938 // only add as base if not a cluster 2939 if (data.clusterMarkers && !im.bool(data.clusterMarkers.enabled)) { 2940 im.maps[id].allBaseSeries.push(markerSeries); 2941 } else if (data.clusterMarkers && im.bool(data.clusterMarkers.enabled)) { 2942 // it's a cluster, so the main series with all markers 2943 // markerSeries.hidden = true; 2944 } 2945 } 2946 2947 return markerSeries; 2948}; 2949 2950iMapsManager.pushImageMarkerSeries = function (id, data) { 2951 var im = this, 2952 map = im.maps[id].map, 2953 // shorter reference for the map 2954 markerSeries, 2955 markerSeriesTemplate, 2956 imageMarker; 2957 2958 if (Array.isArray(data.imageMarkers) && data.imageMarkers.length) { 2959 // Create image series 2960 markerSeries = map.series.push(new am4maps.MapImageSeries()); 2961 markerSeries.name = 2962 data.imageMarkersLegend && data.imageMarkersLegend.title !== '' 2963 ? data.imageMarkersLegend.title 2964 : data.title; 2965 markerSeries.hiddenInLegend = data.imageMarkersLegend 2966 ? !im.bool(data.imageMarkersLegend.enabled) 2967 : false; // Create a circle image in image series template so it gets replicated to all new images 2968 2969 markerSeriesTemplate = markerSeries.mapImages.template; 2970 2971 //iOS focus scroll bug fix 2972 markerSeriesTemplate.focusable = false; 2973 2974 imageMarker = markerSeriesTemplate.createChild(am4core.Image); 2975 imageMarker.propertyFields.href = 'href'; 2976 imageMarker.propertyFields.width = 'size'; 2977 imageMarker.propertyFields.height = 'size'; 2978 imageMarker.propertyFields.userClassName = 'customClass'; //imageMarker.propertyFields.height = "height"; 2979 2980 imageMarker.propertyFields.horizontalCenter = 'horizontalCenter'; 2981 imageMarker.propertyFields.verticalCenter = 'verticalCenter'; 2982 imageMarker.nonScaling = true; 2983 imageMarker.propertyFields.nonScaling = 'nonScaling'; 2984 im.setupTooltip(id, markerSeries, data, imageMarker); // to have tooltip display above the image 2985 //imageMarker.tooltipX = am4core.percent(50); 2986 //imageMarker.tooltipY = am4core.percent(0); 2987 // check for custom tooltip template 2988 2989 if ( 2990 typeof data.imageMarkersTooltipTemplate !== 'undefined' && 2991 data.imageMarkersTooltipTemplate.trim() !== '' 2992 ) { 2993 imageMarker.tooltipText = data.imageMarkersTooltipTemplate; 2994 imageMarker.tooltipHTML = data.imageMarkersTooltipTemplate; 2995 } else { 2996 imageMarker.tooltipText = data.tooltip.template ? data.tooltip.template : '{tooltipContent}'; 2997 imageMarker.tooltipHTML = data.tooltip.template ? data.tooltip.template : '{tooltipContent}'; 2998 } // Set property fields 2999 3000 markerSeriesTemplate.propertyFields.latitude = 'latitude'; 3001 markerSeriesTemplate.propertyFields.longitude = 'longitude'; // Add data for the three cities 3002 3003 // send to front (so on overlay they are always on top of regions) 3004 markerSeries.zIndex = Number.MAX_VALUE; 3005 markerSeries.toFront(); 3006 3007 markerSeries.data = data.imageMarkers; // Events 3008 3009 markerSeriesTemplate.events.on('hit', function (ev) { 3010 im.singleHit(id, ev); 3011 im.setupHitEvents(id, ev); 3012 }); 3013 markerSeriesTemplate.events.on('over', function (ev) { 3014 im.setupHoverEvents(id, ev); 3015 }); 3016 } // enable small map 3017 3018 if (data.zoom && data.zoom.smallMap && im.bool(data.zoom.smallMap)) { 3019 map.smallMap.series.push(markerSeries); 3020 }
3020 // add this series to map series to reference it later if needed 3021 3022 im.maps[id].series.push(markerSeries); 3023 return markerSeries; 3024}; 3025 3026iMapsManager.pushIconMarkerSeries = function (id, data) { 3027 var im = this, 3028 map = im.maps[id].map, 3029 // shorter reference for the map 3030 markerSeries, 3031 markerSeriesTemplate, 3032 icon, 3033 hover, 3034 active, 3035 highlightState, 3036 clickableOverlay; 3037 3038 if (Array.isArray(data.iconMarkers) && data.iconMarkers.length) { 3039 // Create image series 3040 markerSeries = map.series.push(new am4maps.MapImageSeries()); 3041 markerSeries.hiddenInLegend = data.iconMarkersLegend 3042 ? !im.bool(data.iconMarkersLegend.enabled) 3043 : false; 3044 markerSeries.name = 3045 data.iconMarkersLegend && data.iconMarkersLegend.title !== '' 3046 ? data.iconMarkersLegend.title 3047 : data.title; 3048 markerSeriesTemplate = markerSeries.mapImages.template; 3049 markerSeriesTemplate.nonScaling = true; 3050 markerSeriesTemplate.setStateOnChildren = true; //apply parent's current state to children 3051 3052 //iOS focus scroll bug fix 3053 markerSeriesTemplate.focusable = false; 3054 3055 markerSeriesTemplate.states.create('hover'); //create dummy state for hover 3056 // Create a circle image in image series template so it gets replicated to all new images 3057 3058 icon = markerSeriesTemplate.createChild(am4core.Sprite); 3059 icon.propertyFields.scale = 'scale'; 3060 icon.propertyFields.path = 'path'; 3061 icon.propertyFields.rotation = 'rotation'; 3062 3063 /* 3064 if (typeof data.iconMarkersTooltipTemplate !== 'undefined' && data.iconMarkersTooltipTemplate.trim() !== '') { 3065 icon.tooltipText = data.iconMarkersTooltipTemplate; 3066 icon.tooltipHTML = data.iconMarkersTooltipTemplate; 3067 } else { 3068 icon.tooltipText = data.tooltip.template ? data.tooltip.template : "{tooltipContent}"; 3069 icon.tooltipHTML = data.tooltip.template ? data.tooltip.template : "{tooltipContent}"; 3070 }*/ 3071 3072 icon.propertyFields.horizontalCenter = 'horizontalCenter'; 3073 icon.propertyFields.verticalCenter = 'verticalCenter'; 3074 icon.propertyFields.fill = 'fill'; // For legend color 3075 3076 markerSeries.fill = data.iconMarkerDefaults.fill; // clickable overlay 3077 3078 clickableOverlay = markerSeriesTemplate.createChild(am4core.Sprite); 3079 clickableOverlay.propertyFields.scale = 'scale'; 3080 clickableOverlay.path = 'M-10,0a10,10 0 1,0 20,0a10,10 0 1,0 -20,0'; 3081 clickableOverlay.opacity = 0; 3082 clickableOverlay.propertyFields.horizontalCenter = 'horizontalCenter'; 3083 clickableOverlay.propertyFields.verticalCenter = 'verticalCenter'; 3084 3085 markerSeriesTemplate.tooltipText = data.tooltip.template 3086 ? data.tooltip.template 3087 : '{tooltipContent}'; 3088 markerSeriesTemplate.tooltipHTML = data.tooltip.template 3089 ? data.tooltip.template 3090 : '{tooltipContent}'; 3091 3092 im.setupTooltip(id, markerSeries, data, clickableOverlay); 3093 3094 if (data.iconMarkerLabels && im.bool(data.iconMarkerLabels.enabled)) { 3095 var markerLabel = markerSeriesTemplate.createChild(am4core.Label); 3096 markerLabel.text = 3097 typeof data.iconMarkerLabels.source !== 'undefined' && data.iconMarkerLabels.source !== '' 3098 ? data.iconMarkerLabels.source 3099 : '{name}'; 3100 markerLabel.horizontalCenter = 'middle'; 3101 markerLabel.verticalCenter = 'top'; 3102 markerLabel.fontSize = data.iconMarkerLabels.fontSize; 3103 markerLabel.nonScaling = false; 3104 markerLabel.fill = data.iconMarkerLabels.fill; 3105 markerLabel.clickable = false; 3106 markerLabel.focusable = false; 3107 markerLabel.hoverable = false; 3108 markerLabel.padding(0, 0, 0, 0); 3109 markerLabel.adapter.add('dy', function (dy, target) { 3110 var icon = target.parent.children.getIndex(0); 3111 var scale = icon.scale; 3112 var space; 3113 3114 if (icon.verticalCenter === 'middle') { 3115 space = 10 * scale; 3116 } 3117 3118 if (icon.verticalCenter === 'bottom') { 3119 space = 0; 3120 } 3121 3122 if (icon.verticalCenter === 'top') { 3123 space = 20 * scale + 5; 3124 } // formula to get the label to distance at an accepted level 3125 3126 return space; 3127 }); 3128 } // hover & active 3129 3130 hover = icon.states.create('hover'); 3131 hover.propertyFields.fill = 'hover'; 3132 active = icon.states.create('active'); 3133 active.propertyFields.fill = 'hover'; // highlight - for legend hover 3134 3135 highlightState = icon.states.create('highlight'); 3136 highlightState.properties.fill = data.hover; 3137 highlightState.propertyFields.fill = 'hover'; // Set property fields 3138 3139 markerSeriesTemplate.propertyFields.latitude = 'latitude'; 3140 markerSeriesTemplate.propertyFields.longitude = 'longitude'; // Add data 3141 3142 // send to front (so on overlay they are always on top of regions) 3143 markerSeries.zIndex = Number.MAX_VALUE; 3144 markerSeries.toFront(); 3145 3146 markerSeries.data = data.iconMarkers; // Events 3147 3148 markerSeriesTemplate.events.on('hit', function (ev) { 3149 im.singleHit(id, ev); 3150 im.setupHitEvents(id, ev); 3151 }); 3152 markerSeriesTemplate.events.on('over', function (ev) { 3153 im.setupHoverEvents(id, ev); 3154 }); 3155 } // enable small map 3156 3157 if (data.zoom && data.zoom.smallMap && im.bool(data.zoom.smallMap)) { 3158 map.smallMap.series.push(markerSeries); 3159 }
3159 // add this series to map series to reference it later if needed 3160 3161 im.maps[id].series.push(markerSeries); 3162 return markerSeries; 3163}; 3164 3165iMapsManager.pushLineSeries = function (id, data) { 3166 var im = this, 3167 map = im.maps[id].map, 3168 // shorter reference for the map 3169 lineSeries = {}, 3170 lineData = []; // Lines 3171 3172 if (Array.isArray(data.lines) && data.lines.length) { 3173 // Add line series 3174 if (data.projection === 'Orthographic') { 3175 lineSeries = map.series.push(new am4maps.MapLineSeries()); 3176 lineSeries.mapLines.template.propertyFields.shortestDistance = true; 3177 } else { 3178 lineSeries = map.series.push(new am4maps.MapArcSeries()); 3179 lineSeries.mapLines.template.line.propertyFields.controlPointDistance = 'curvature'; 3180 lineSeries.mapLines.template.line.controlPointPosition = 0.5; 3181 } 3182 3183 lineSeries.name = 3184 data.linesLegend && data.linesLegend.title !== '' ? data.linesLegend.title : data.title; 3185 lineSeries.hiddenInLegend = data.linesLegend ? !im.bool(data.linesLegend.enabled) : false; 3186 lineSeries.mapLines.template.nonScalingStroke = true; 3187 lineSeries.mapLines.template.propertyFields.strokeWidth = 'strokeWidth'; 3188 lineSeries.mapLines.template.propertyFields.strokeDasharray = 'strokeDash'; 3189 lineSeries.mapLines.template.propertyFields.stroke = 'stroke'; 3190 3191 // arrow 3192 lineSeries.mapLines.template.arrow.position = 1; // 1 is the end 3193 lineSeries.mapLines.template.arrow.nonScaling = true; 3194 lineSeries.mapLines.template.arrow.propertyFields.fill = 'stroke'; 3195 lineSeries.mapLines.template.arrow.horizontalCenter = 'middle'; 3196 //lineSeries.mapLines.template.arrow.tooltipHTML = "{title}"; 3197 3198 //lineSeries.mapLines.template.arrow.disabled = true; 3199 lineSeries.mapLines.template.arrow.propertyFields.disabled = 'arrowDisabled'; 3200 3201 data.lines.forEach(function (lineObj) { 3202 // make sure multiGeoLine is array of arrays: 3203 lineObj.multiGeoLine = [lineObj.multiGeoLine]; 3204 lineData.push(lineObj); 3205 }); 3206 3207 // events - to do 3208 lineSeries.mapLines.template.events.on('hit', function (ev) { 3209 im.singleHit(id, ev); 3210 im.setupHitEvents(id, ev); 3211 }); 3212 lineSeries.mapLines.template.events.on('over', function (ev) { 3213 im.setupHoverEvents(id, ev); 3214 }); 3215 3216 lineSeries.data = lineData; 3217 3218 // bring to front 3219 lineSeries.zIndex = Number.MAX_VALUE - 1; 3220 lineSeries.toFront(); 3221 3222 // enable small map 3223 if (data.zoom && data.zoom.smallMap && im.bool(data.zoom.smallMap)) { 3224 map.smallMap.series.push(lineSeries); 3225 } //let's hide this from legend, since they don't group in the same Series 3226 //lineSeries.hiddenInLegend = true; 3227 // add this series to map series to reference it later if needed 3228 3229 im.maps[id].series.push(lineSeries); // For legend color 3230 3231 lineSeries.fill = data.lineDefaults.stroke; // if it's part of the parent map 3232 3233 if (id === data.id) { 3234 im.maps[id].allBaseSeries.push(lineSeries); 3235 } 3236 } 3237 3238 return lineSeries; 3239}; 3240 3241iMapsManager.pushLabelSeries = function (id, data) { 3242 var im = this, 3243 map = im.maps[id].map, 3244 // shorter reference for the map 3245 labelSeries, 3246 labelSeriesTemplate, 3247 label, 3248 activeState, 3249 highlightState, 3250 hoverState, 3251 background = false; 3252 3253 if (Array.isArray(data.labels) && data.labels.length) { 3254 // Create image series 3255 labelSeries = map.series.push(new am4maps.MapImageSeries()); 3256 labelSeries.name = 3257 data.labelsLegend && data.labelsLegend.title !== '' ? data.labelsLegend.title : data.title; 3258 labelSeries.hiddenInLegend = data.labelsLegend ? !im.bool(data.labelsLegend.enabled) : false; 3259 3260 labelSeriesTemplate = labelSeries.mapImages.template; 3261 labelSeriesTemplate.setStateOnChildren = true; 3262 3263 // label 3264 label = labelSeriesTemplate.createChild(am4core.Label); 3265 label.text = '{id}'; 3266 3267 //label.nonScaling = true; 3268 label.nonScaling = typeof igmLabelsNonScaling !== 'undefined' ? igmLabelsNonScaling : true; 3269 3270 if (data.labelStyle) { 3271 label.fontFamily = data.labelStyle.fontFamily; 3272 label.fontWeight = data.labelStyle.fontWeight; 3273 } 3274 3275 label.horizontalCenter = data.labelPosition.horizontalCenter; 3276 label.verticalCenter = data.labelPosition.verticalCenter; 3277 label.propertyFields.fill = 'fill'; 3278 label.propertyFields.fontSize = 'fontSize'; 3279 im.setupTooltip(id, labelSeries, data, label); // custom fields 3280 3281 if ( 3282 typeof data.labelsTooltipTemplate !== 'undefined' && 3283 data.labelsTooltipTemplate.trim() !== '' 3284 ) { 3285 label.tooltipText = data.labelsTooltipTemplate; 3286 label.tooltipHTML = data.labelsTooltipTemplate; 3287 } else { 3288 label.tooltipText = 3289 data.tooltip && data.tooltip.template ? data.tooltip.template : '{tooltipContent}'; 3290 label.tooltipHTML = 3291 data.tooltip && data.tooltip.template ? data.tooltip.template : '{tooltipContent}'; 3292 } 3293 3294 // Set property fields 3295 labelSeriesTemplate.propertyFields.latitude = 'latitude'; 3296 labelSeriesTemplate.propertyFields.longitude = 'longitude'; 3297 labelSeriesTemplate.propertyFields.fill = 'fill'; 3298 labelSeriesTemplate.propertyFields.fontSize = 'fontSize'; 3299 label.propertyFields.verticalCenter = 'verticalCenter'; 3300 label.propertyFields.horizontalCenter = 'horizontalCenter'; 3301 3302 // labels background - currently only possible through global
3303 background = typeof igmLabelsBackground !== 'undefined' ? igmLabelsBackground : false; 3304 if (typeof background === 'object') { 3305 label.background = new am4core.RoundedRectangle(); 3306 label.background.cornerRadius(...background.cornerRadius); 3307 label.background.fill = am4core.color(background.color); 3308 label.padding(...background.padding); 3309 label.background.stroke = am4core.color(background.stroke); 3310 } 3311 3312 // hover & active 3313 hoverState = label.states.create('hover'); 3314 hoverState.properties.fill = data.hover; 3315 hoverState.propertyFields.fill = 'hover'; // active 3316 3317 activeState = label.states.create('active'); 3318 activeState.properties.fill = data.hover; 3319 activeState.propertyFields.fill = 'hover'; // highlight - for legend hover 3320 3321 highlightState = label.states.create('highlight'); 3322 highlightState.properties.fill = data.hover; 3323 highlightState.propertyFields.fill = 'hover'; 3324 3325 // send to front (so on overlay they are always on top of regions) 3326 labelSeries.zIndex = Number.MAX_VALUE; 3327 labelSeries.toFront(); 3328 3329 // Add data 3330 labelSeries.data = data.labels; // For legend color 3331 3332 labelSeries.fill = data.labelDefaults.fill; // Events 3333 3334 labelSeriesTemplate.events.on('hit', function (ev) { 3335 im.singleHit(id, ev); 3336 im.setupHitEvents(id, ev); 3337 }); 3338 labelSeriesTemplate.events.on('over', function (ev) { 3339 im.setupHoverEvents(id, ev); 3340 }); 3341 } // enable small map 3342 3343 if (data.zoom && data.zoom.smallMap && im.bool(data.zoom.smallMap)) { 3344 map.smallMap.series.push(labelSeries); 3345 } // add this series to map series to reference it later if needed 3346 3347 im.maps[id].labelSeries.push(labelSeries); 3348 im.maps[id].series.push(labelSeries); // if part of the parent map 3349 3350 if (id === data.id) { 3351 im.maps[id].allBaseSeries.push(labelSeries); 3352 } 3353 3354 return labelSeries; 3355}; 3356 3357iMapsManager.setupTooltip = function (id, series, data, marker) { 3358 var im = this, 3359 tooltip = data.tooltip, 3360 map = im.maps[id].map, 3361 shadow; 3362 marker = marker || false; // don't include it in export 3363 // regionSeries.tooltip.exportable = false; 3364 // default behaviour 3365 3366 if (typeof data.tooltip === 'undefined') { 3367 series.tooltip.disabled = false; 3368 series.tooltip.getFillFromObject = false; 3369 series.tooltip.getStrokeFromObject = false; 3370 series.tooltip.label.fill = am4core.color('#000000'); 3371 series.tooltip.background.fill = am4core.color('#FFFFFF'); 3372 return; 3373 } 3374 3375 if (!im.bool(data.tooltip.enabled)) { 3376 series.tooltip.disabled = true; 3377 return series; 3378 } 3379 3380 // if it's disabled on mobile/smaller screens 3381 if ( 3382 _typeof(data.tooltip.disableMobile) !== undefined && 3383 im.bool(data.tooltip.disableMobile) && 3384 window.innerWidth <= 780 3385 ) { 3386 series.tooltip.disabled = true; 3387 return series; 3388 } 3389 3390 //if it's overlay, it might have a custom config 3391 3392 // tooltip settings from map config 3393 series.tooltip.label.interactionsEnabled = im.bool(tooltip.fixed); 3394 series.tooltip.background.cornerRadius = tooltip.cornerRadius; 3395 if (tooltip.pointerLength) { 3396 series.tooltip.background.pointerLength = parseInt(tooltip.pointerLength); 3397 } 3398 series.tooltip.getFillFromObject = false; 3399 series.tooltip.getStrokeFromObject = false; 3400 series.tooltip.label.fill = tooltip.color; 3401 series.tooltip.background.fill = tooltip.backgroundColor; 3402 series.tooltip.fontFamily = tooltip.fontFamily; 3403 series.tooltip.fontSize = tooltip.fontSize; 3404 series.tooltip.fontWeight = tooltip.fontWeight; 3405 3406 // animation - disable the fly out effect on markers 3407 series.tooltip.animationDuration = 0; 3408 3409 // border 3410 if (tooltip.borderColor !== 'undefined') { 3411 series.tooltip.background.stroke = tooltip.borderColor; 3412 series.tooltip.background.strokeWidth = tooltip.borderWidth; 3413 } 3414 3415 if (typeof tooltip.maxWidth !== 'undefined' && tooltip.maxWidth !== '') { 3416 series.tooltip.maxWidth = parseInt(tooltip.maxWidth); 3417 series.tooltip.contentWidth = parseInt(tooltip.maxWidth); 3418 } 3419 series.tooltip.label.wrap = true; 3420 3421 // box-shadow 3422 if (typeof tooltip.customShadow !== 'undefined' && im.bool(tooltip.customShadow)) { 3423 shadow = series.tooltip.background.filters.getIndex(0); 3424 shadow.dx = tooltip.customShadowOpts.dx; 3425 shadow.dy = tooltip.customShadowOpts.dy; 3426 shadow.blur = tooltip.customShadowOpts.blur; 3427 shadow.opacity = tooltip.customShadowOpts.opacity; 3428 shadow.color = tooltip.customShadowOpts.color; 3429 } 3430 3431 // Set up fixed tooltips 3432 if (im.bool(tooltip.fixed)) { 3433 if (tooltip.showTooltipOn === 'always') { 3434 //allow tooltip to be hidden outside viewport 3435 series.tooltip.ignoreBounds = true; 3436 3437 series.tooltip.pointerOrientation = (function (toolTipPosition) { 3438 switch (toolTipPosition) { 3439 case 'horizontal': 3440 return 'horizontal'; 3441 case 'below': 3442 return 'up'; 3443 case 'above': 3444 return 'down'; 3445 case 'right': 3446 return 'left'; 3447 case 'left': 3448 return 'right'; 3449 default: 3450 return 'vertical'; 3451 } 3452 })(tooltip.toolTipPosition); 3453 } 3454 3455 if (series.mapPolygons) { 3456 series.calculateVisualCenter = true; 3457 series.mapPolygons.template.tooltipPosition = 'fixed'; 3458 3459 // in case it's a group and the tooltip is set to fixed, 3460 // we need to set the tooltip hover to have the regions keep the hover state 3461 if (series.groupHover) { 3462 // set to false so that the tooltip does not 3463 // inherit the highlight state color on hover 3464 series.tooltip.getFillFromObject = false;
3465 series.tooltip.events.on('over', function (ev) { 3466 ev.target.dataItem.component.mapPolygons.each(function (polygon) { 3467 polygon.setState('highlight'); 3468 }); 3469 }); 3470 series.tooltip.events.on('out', function (ev) { 3471 ev.target.dataItem.component.mapPolygons.each(function (polygon) { 3472 polygon.setState('default'); 3473 }); 3474 }); 3475 } 3476 3477 series.tooltip.keepTargetHover = true; 3478 3479 if (tooltip.showTooltipOn) { 3480 series.mapPolygons.template.showTooltipOn = tooltip.showTooltipOn; 3481 3482 // to have the tooltip in the marker fixed, even after over out 3483 if (tooltip.showTooltipOn === 'hit') { 3484 series.tooltip.keepTargetHover = false; 3485 } 3486 } 3487 } else { 3488 // for markers 3489 series.mapImages.template.tooltipPosition = 'fixed'; 3490 series.tooltip.keepTargetHover = true; 3491 3492 if (tooltip.showTooltipOn && marker) { 3493 series.mapImages.template.showTooltipOn = tooltip.showTooltipOn; 3494 marker.showTooltipOn = tooltip.showTooltipOn; 3495 3496 // to have the tooltip in the marker fixed, even after over out 3497 if (tooltip.showTooltipOn === 'hit') { 3498 series.tooltip.keepTargetHover = false; 3499 } 3500 3501 // to have the tooltip display after the map loads 3502 if (tooltip.showTooltipOn === 'always') { 3503 map.events.on('appeared', function () { 3504 marker.clones.each(function (clone) { 3505 clone.showTooltip(); 3506 }); 3507 }); 3508 3509 map.events.on('mappositionchanged', function () { 3510 marker.clones.each(function (clone) { 3511 clone.showTooltip(); 3512 }); 3513 }); 3514 } 3515 } 3516 } 3517 } 3518 return series; 3519}; 3520 3521iMapsManager.prepareURL = function (str) { 3522 if (typeof str !== 'string') { 3523 return str; 3524 } 3525 3526 // parse html entities 3527 str = str.replace(/&/gi, '&'); 3528 str.replace(/&#(\d+);/g, function (match, dec) { 3529 return String.fromCharCode(dec); 3530 }); 3531 3532 // check if allowed url 3533 var url, protocols; 3534 try { 3535 url = new URL(str); 3536 } catch { 3537 url = false; 3538 } 3539 3540 // check if valid url. If string it might be a anchor or relative path, so keep going 3541 if (url) { 3542 // accepted protocols 3543 protocols = [null, 'http:', 'https:', 'mailto:', 'tel:']; 3544 if (!protocols.includes(url.protocol)) { 3545 console.log('URL protocol not allowed'); 3546 return ''; 3547 } 3548 } 3549 3550 return str; 3551}; 3552 3553iMapsManager.setupHitEvents = function (id, ev) { 3554 var im = this, 3555 data = im.maps[id].data, 3556 dataContext, 3557 map = im.maps[id].map, 3558 customActionName, 3559 targetType = im.getTargetSeriesType(ev.target), 3560 clicked = im.maps[id].clicked || false, 3561 zoomCluster = data.clusterMarkers ? parseFloat(data.clusterMarkers.zoomLevel) : 1, 3562 currentRegion, 3563 mapFunction, 3564 container = document.getElementById(data.container), 3565 event = new Event('mapEntryClicked'); 3566 3567 if (ev.target.isLabels) { 3568 dataContext = ev.target.dataItems.first.dataContext; 3569 } else { 3570 dataContext = ev.target.dataItem.dataContext; 3571 } 3572 3573 // on certain devices, the click gets triggered twice, so the 'hold click actions' won't work properly 3574 // but we minize the issue by allowing it to run anyway - so on devices where the tap runs twice, the hold won't work at the moment 3575 if (map.lastClickedEntry === ev.target && !im.maps[id].clicked) { 3576 // the clicked is used to control the "hold click actions" feature 3577 im.maps[id].clicked = dataContext; 3578 3579 // we reset after 1 second, to allow real second clicks to run 3580 // this also has the side effect that when the 'hold click actions' is enabled, only after 1 second, the second tap will actually work 3581 setTimeout(function () { 3582 map.lastClickedEntry = null; 3583 im.maps[id].clicked = null; 3584 }, 1000); 3585 3586 return; 3587 } 3588 3589 // we reset it to null, in case it was clicked before, double tap 3590 im.maps[id].clicked = null; 3591 map.lastClickedEntry = ev.target; 3592 container.dispatchEvent(event); 3593 3594 // if it's a cluster, zoom in a bit 3595 if (targetType === 'MapImage') { 3596 if (dataContext.cluster) { 3597 // if we're far from the max, let's just zoom half 3598 if (zoomCluster - parseInt(map.zoomLevel) > 5) { 3599 zoomCluster = parseInt(map.zoomLevel) + zoomCluster / 2; 3600 } 3601 ev.target.series.chart.zoomToMapObject(ev.target, zoomCluster); 3602 } 3603 } // for admin log 3604 3605 console.log(dataContext); // Zoom on click 3606 3607 if (data.zoom && im.bool(data.zoom.enabled) && im.bool(data.zoom.zoomOnClick)) { 3608 ev.zooming = true; 3609 im.zoomToRegion(ev, id); 3610 } // drill down 3611 3612 if (targetType === 'MapPolygon' && im.bool(data.drillDownOnClick)) { 3613 im.drillDown(id, ev); 3614 } 3615 3616 if (dataContext.madeFromGeoData) { 3617 // check if we should clear selected or not? 3618 // iMapsManager.clearSelected(id); 3619 3620 mapFunction = 'igm_inactive_' + data.id; 3621 3622 if (typeof window[mapFunction] === 'function') { 3623 data = window[mapFunction](data); 3624 } 3625 3626 return; 3627 } 3628 3629 // if it's a marker with action to open specific map 3630 if ( 3631 targetType === 'MapImage' && 3632 _typeof(dataContext.action) !== undefined &&
3633 dataContext.action === 'igm_display_map' 3634 ) { 3635 if (Array.isArray(iMapsManager.maps[id].seriesById[parseInt(dataContext.content)])) { 3636 currentRegion = iMapsManager.maps[id].seriesById[parseInt(dataContext.content)]; 3637 im.drillTo(id, ev, currentRegion, true); 3638 } 3639 } // if admin, we don't trigger the actions 3640 3641 if (im.bool(data.admin)) { 3642 return; 3643 } // if we need to hold action on mobile/smaller screens to show tooltip 3644 3645 if ( 3646 data.tooltip && 3647 _typeof(data.tooltip.enabled) !== undefined && 3648 im.bool(data.tooltip.enabled) && 3649 _typeof(data.tooltip.disableMobile) !== undefined && 3650 !im.bool(data.tooltip.disableMobile) && 3651 _typeof(data.tooltip.holdAction) !== undefined && 3652 im.bool(data.tooltip.holdAction) && 3653 window.innerWidth <= 780 3654 ) { 3655 if (!clicked || clicked !== dataContext) { 3656 console.log('Holding action for second tap.'); 3657 im.maps[id].clicked = dataContext; 3658 return; 3659 } 3660 3661 // in case the previously clicked will now perform action, we reset it 3662 if (clicked === dataContext) { 3663 im.maps[id].clicked = false; 3664 } // if it's a different one, set it normally 3665 else { 3666 im.maps[id].clicked = dataContext; 3667 } 3668 } 3669 3670 if (dataContext.action === 'none') { 3671 // do nothing 3672 return; 3673 } 3674 3675 // check urls 3676 if (dataContext.action === 'open_url' || dataContext.action === 'open_url_new') { 3677 dataContext.content = iMapsManager.prepareURL(dataContext.content); 3678 } 3679 // open new url 3680 if (dataContext.action === 'open_url' && dataContext.content !== '') { 3681 document.location = dataContext.content; 3682 } else if (dataContext.action === 'open_url_new' && dataContext.content !== '') { 3683 window.open(dataContext.content); 3684 } // custom 3685 else if (dataContext.action && dataContext.action.includes('custom')) { 3686 customActionName = dataContext.action + '_' + dataContext.mapID; 3687 3688 if (typeof window[customActionName] !== 'undefined') { 3689 window[customActionName](dataContext); 3690 } 3691 } else { 3692 if (typeof window[dataContext.action] !== 'undefined') { 3693 window[dataContext.action](id, dataContext); 3694 } 3695 } 3696}; 3697 3698iMapsManager.zoomToMap = function (ev, target) { 3699 var im = this; 3700 var baseMap = false; 3701 3702 target.forEach(function (series) { 3703 if ('MapPolygonSeries' == im.getTargetSeriesType(series)) { 3704 baseMap = series; 3705 return; 3706 } 3707 }); 3708 3709 if (baseMap) { 3710 ev.target.series.chart.zoomToRectangle( 3711 baseMap.north, 3712 baseMap.east, 3713 baseMap.south, 3714 baseMap.west, 3715 1, 3716 true 3717 ); 3718 console.log('zoomed to specific map'); 3719 return; 3720 } 3721 console.log('failed to zoom to specific map'); 3722}; 3723 3724iMapsManager.zoomToRegion = function (ev, id) { 3725 var im = this, 3726 seriesType = im.getTargetSeriesType(ev.target), 3727 data = im.maps[id].data, 3728 markerZoomLevel, 3729 dataContext; // do nothing if we clicked a label 3730 3731 if (ev.target.isLabels) { 3732 return; 3733 } 3734 3735 dataContext = ev.target.dataItem.dataContext; // if it's a marker, handle it differently 3736 3737 if (seriesType == 'MapImage') { 3738 // if it's a cluster marker 3739 if (dataContext.cluster) { 3740 //do nothing, we already zoomed 3741 } else { 3742 markerZoomLevel = 3743 typeof igmMarkerZoomLevelOnClick !== 'undefined' 3744 ? igmMarkerZoomLevelOnClick 3745 : ev.target.parent.chart.zoomLevel * 2; 3746 ev.target.series.chart.zoomToMapObject(ev.target, markerZoomLevel, true); 3747 } 3748 } else { 3749 if (dataContext.id === 'asia' && !data.map.startsWith('continents')) { 3750 ev.target.series.chart.deltaLongitudeOriginal = ev.target.series.chart.deltaLongitude; 3751 ev.target.series.chart.deltaLongitude = -10; 3752 ev.target.series.chart.zoomToGeoPoint( 3753 { 3754 latitude: 34.076842, 3755 longitude: 100.693068, 3756 }, 3757 1.7, 3758 true 3759 ); 3760 } else if (dataContext.id === 'asia' && data.map.startsWith('continents')) { 3761 ev.target.series.chart.zoomToGeoPoint( 3762 { 3763 latitude: 34.076842, 3764 longitude: 100.693068, 3765 }, 3766 2.2, 3767 true 3768 ); 3769 } else if ( 3770 dataContext.id === 'northAmerica' && 3771 data.map.startsWith('region/world/worldRegion') 3772 ) { 3773 ev.target.series.chart.zoomToGeoPoint( 3774 { 3775 latitude: 55.5, 3776 longitude: -105.5, 3777 }, 3778 3, 3779 true 3780 ); 3781 } else if (dataContext.id === 'northAmerica' && data.map.startsWith('continents')) { 3782 ev.target.series.chart.zoomToGeoPoint( 3783 { 3784 latitude: 55.5, 3785 longitude: -105.5, 3786 }, 3787 2.3, 3788 true 3789 ); 3790 } else if (dataContext.id === 'ZA' && data.map.startsWith('world')) { 3791 ev.target.series.chart.zoomToGeoPoint( 3792 { 3793 latitude: -28.6, 3794 longitude: 24.7, 3795 }, 3796 12.2, 3797 true 3798 ); 3799 } else if (dataContext.id === 'US' && data.map.startsWith('world')) { 3800 ev.target.series.chart.zoomToGeoPoint( 3801 { 3802 latitude: 49, 3803 longitude: -119, 3804 }, 3805 2.6, 3806 true 3807 ); 3808 } else if (dataContext.id === 'RU' && data.map.startsWith('world')) { 3809 ev.target.series.chart.zoomToGeoPoint( 3810 { 3811 latitude: 64.5, 3812 longitude: 105, 3813 }, 3814 2.1, 3815 true 3816 ); 3817 } else { 3818 if (typeof ev.target.series.chart.deltaLongitudeOriginal !== 'undefined') { 3819 ev.target.series.chart.deltaLongitude = ev.target.series.chart.deltaLongitude; 3820 } 3821 3822 ev.target.series.chart.zoomToMapObject(ev.target, ev.target.zoomLevel * 2); 3823 } 3824 } 3825}; 3826 3827iMapsManager.setupHoverEvents = function (id, ev) { 3828 var im = this, 3829 selected = im.maps[id].selected || false, 3830 dataContext; 3831 3832 if (ev.target.isLabels) { 3833 dataContext = ev.target.dataItems.first.dataContext; 3834 } else { 3835 dataContext = ev.target.dataItem.dataContext; 3836 } 3837 3838 // when tooltip position is fixed, hovering regions might leave hovered state behind, when the overout goes through the tooltip 3839 if (ev.target.className !== 'MapImage' && ev.target.tooltipPosition === 'fixed') { 3840 if (Array.isArray(im.tempHover) && im.tempHover.length >= 0) { 3841 im.tempHover[0].setState('default'); 3842 im.tempHover = []; 3843 } 3844 im.tempHover = [ev.target]; 3845 } 3846 3847 if (dataContext.action && dataContext.action !== 'none') { 3848 ev.target.cursorOverStyle = am4core.MouseCursorStyle.pointer; 3849 } 3850 3851 if ( 3852 Array.isArray(selected) && 3853 !selected.includes(ev.target) && 3854 ev.target.dataItem && 3855 typeof ev.target.dataItem.dataContext.madeFromGeoData === 'undefined' 3856 ) { 3857 selected.forEach(function (sel) { 3858 if (typeof sel === 'object' && typeof sel.isHover !== 'undefined') { 3859 sel.isHover = false;
3860 } 3861 }); 3862 } 3863 3864 // we exclude touch devices, since the hover event is also triggered on tap, otherwise we have 2 select events triggered 3865 if ( 3866 im.bool(dataContext.triggerClickOnHover) && 3867 (!iMapsManager.isTouchScreenDevice() || ev.type === 'over') && 3868 (typeof iMaps.maps[id].mapClicked === 'undefined' || iMaps.maps[id].mapClicked === false) 3869 ) { 3870 iMapsManager.select(id, dataContext.id, false, true, dataContext.mapID, false); 3871 } 3872 3873 // if it's a marker and we want to trigger hover event also on associated regions in marker value 3874 if (im.bool(dataContext.triggerRegionHover) && dataContext.val && dataContext.val !== '') { 3875 iMapsManager.hover(id, dataContext.val); 3876 ev.target.events.on('out', function () { 3877 iMapsManager.clearHovered(id); 3878 }); 3879 } 3880}; 3881 3882iMapsManager.singleHit = function (id, ev) { 3883 var im = this, 3884 dataContext, 3885 data = im.maps[id].data; 3886 3887 if (ev.target.isLabels) { 3888 dataContext = ev.target.dataItems.first.dataContext; 3889 } else { 3890 dataContext = ev.target.dataItem.dataContext; 3891 } 3892 3893 if (dataContext.madeFromGeoData) { 3894 return; 3895 } 3896 3897 if (iMaps.maps[id].activeStateControl === true && dataContext.activeState) { 3898 iMaps.maps[id].mapClicked = true; 3899 } 3900
3901 // causes issues on tap on mobile, we need to click twice? 3902 // seems the clear selected is affecting 3903 3904 // update: 3905 // let's try passing second argument as false if tooltip is set to display on click? 3906 let keepThis = true; 3907 if (data.tooltip && data.tooltip.showTooltipOn === 'hit') { 3908 keepThis = false; 3909 } 3910 iMapsManager.clearSelected(id, keepThis, true); 3911 3912 ev.target.isActive = true; 3913 ev.target.isHover = true; 3914 ev.target.setState('active'); 3915 im.maps[id].selected = [ev.target]; 3916}; 3917 3918iMapsManager.groupHit = function (id, ev) { 3919 var im = this, 3920 selected = im.maps[id].selected || false; 3921 3922 if (ev.target.dataItem.dataContext.madeFromGeoData) { 3923 return; 3924 } 3925 3926 if (iMaps.maps[id].activeStateControl === true && ev.target.dataItem.dataContext.activeState) { 3927 iMaps.maps[id].mapClicked = true; 3928 } 3929 3930 //removed to improve click on group ? 3931 iMapsManager.clearSelected(id); 3932 3933 selected = []; 3934 3935 ev.target.parent.mapPolygons.each(function (polygon) { 3936 // added the typeof control to only run code on original clicked/hit entry and not the individual shape 3937 // removed, because the code wasn't running otherwise -> && typeof polygon.dataItem.dataContext.originalID === 'undefined' 3938 if (!polygon.dataItem.dataContext.madeFromGeoData) { 3939 // toggle active state 3940 polygon.setState('active'); 3941 3942 if (ev.target === polygon) { 3943 polygon.isHover = true; 3944 } 3945 3946 //removed to fix bug when hovering groups after clicked ? 3947 polygon.isActive = true; 3948 polygon.isGroupActive = true; 3949 selected.push(polygon); 3950 } 3951 }); 3952 3953 im.maps[id].selected = selected; 3954}; 3955 3956iMapsManager.groupHover = function (id, ev) { 3957 var im = this, 3958 dataContext; 3959 3960 if (ev.target.isLabels) { 3961 dataContext = ev.target.dataItems.first.dataContext; 3962 } else { 3963 dataContext = ev.target.dataItem.dataContext; 3964 } 3965 3966 if (ev.target.dataItem.dataContext.madeFromGeoData) { 3967 return; 3968 } 3969 3970 if ( 3971 im.bool(dataContext.triggerClickOnHover) && 3972 (typeof iMaps.maps[id].mapClicked === 'undefined' || iMaps.maps[id].mapClicked === false) 3973 ) { 3974 iMapsManager.select(id, dataContext.id, false, true, dataContext.mapID, false); 3975 } // set mouse hover pointer cursor 3976 3977 if (ev.target.dataItem.dataContext.action && ev.target.dataItem.dataContext.action != 'none') { 3978 ev.target.cursorOverStyle = am4core.MouseCursorStyle.pointer; 3979 } // highlight all polygons from this group 3980 3981 ev.target.parent.mapPolygons.each(function (polygon) { 3982 if (!polygon.dataItem.dataContext.madeFromGeoData) { 3983 if (!polygon.isActive) { 3984 polygon.setState('highlight'); 3985 } 3986 } 3987 }); 3988}; 3989 3990iMapsManager.groupHoverOut = function (id, ev) { 3991 if (ev.target.dataItem.dataContext.madeFromGeoData) { 3992 return; 3993 } 3994 3995 ev.target.parent.mapPolygons.each(function (polygon) { 3996 if (!polygon.isGroupActive) { 3997 polygon.setState('default'); 3998 polygon.isActive = false; 3999 polygon.isHover = false; 4000 } 4001 }); 4002}; 4003 4004/** 4005 * Get regions object collection based on value of a specific parameter 4006 * id - map id 4007 * value - value you want to filter by 4008 * parameter - parameter to search 4009 */ 4010iMapsManager.getRegionsByValue = function (id, value, parameter) { 4011 var im = this, 4012 map = im.maps[id], 4013 series = map.series, 4014 seriesType = false, 4015 regions = [], 4016 tempArray; 4017 4018 value = value || '*'; 4019 parameter = parameter || 'val'; 4020 4021 series.forEach(function (serie) { 4022 seriesType = im.getTargetSeriesType(serie); 4023 if (seriesType === 'MapPolygonSeries') { 4024 tempArray = serie.mapPolygons.values.filter(function (entry) { 4025 if (entry.dataItem.dataContext[parameter] === value || value === '*') { 4026 return true; 4027 } 4028 }); 4029 regions = regions.concat(tempArray); 4030 } 4031 }); 4032 4033 return regions; 4034}; 4035 4036/** Get markers object collection based on value of a specific parameter 4037 * It will search for all kinds of markers (icons, images, round markers) 4038 * id - map id 4039 * value - value you want to filter by 4040 * parameter - parameter to search 4041 */ 4042iMapsManager.getMarkersByValue = function (id, value, parameter) { 4043 var im = this, 4044 map = im.maps[id], 4045 series = map.series, 4046 seriesType = false, 4047 markers = [], 4048 tempArray; 4049 4050 value = value || '*'; 4051 parameter = parameter || 'val'; 4052
4053 series.forEach(function (serie) { 4054 seriesType = im.getTargetSeriesType(serie); 4055 if (seriesType === 'MapImageSeries') { 4056 tempArray = serie.mapImages.values.filter(function (entry) { 4057 if (entry.dataItem.dataContext[parameter] === value || value === '*') { 4058 return true; 4059 } 4060 }); 4061 markers = markers.concat(tempArray); 4062 } 4063 }); 4064 4065 return markers; 4066}; 4067 4068/** 4069 * Selects a element in the map 4070 * id - id of the map 4071 * elID - id of the element to select 4072 * forceFixedTooltip - if we should force the tooltip to be fixed or not 4073 * showTooltip 4074 * seriesMapID - map id of the series, which could be ab overlay 4075 * click - boolean - trigger true click event 4076 */ 4077 4078iMapsManager.select = function (id, elID, forceFixedTooltip, showTooltip, seriesMapID, click) { 4079 var im = this, 4080 map = im.maps[id], 4081 data = im.maps[id].data, 4082 series = map.series.slice().reverse(), // we clone and reverse so that the grouped region series are at the end, which solves a particular bug with the select() function and the tooltip 4083 selected = [], 4084 select, 4085 group, 4086 defaultTooltipPosition, 4087 defaultTooltipShowOn, 4088 seriesByID = iMaps.maps[id].seriesById, 4089 thisSeries = false, 4090 customRegionGroup = true, 4091 triggered = false, // temp solution to prevent map from triggering multiple click actions if there are entries with same ID in different layers 4092 keepThis = true; 4093 4094 // map sure it's string 4095 if (Number.isInteger(elID)) { 4096 elID = elID.toString(); 4097 } 4098 4099 // Force fixed position? 4100 if (typeof forceFixedTooltip === 'undefined') { 4101 forceFixedTooltip = true; 4102 } 4103 4104 if (typeof showTooltip === 'undefined') { 4105 showTooltip = true; 4106 } 4107 4108 if (typeof seriesMapID === 'undefined') { 4109 seriesMapID = id; 4110 } 4111 4112 if (seriesByID.hasOwnProperty(seriesMapID)) { 4113 thisSeries = seriesByID[seriesMapID]; 4114 } 4115 4116 if (typeof click === 'undefined') { 4117 click = true; 4118 } else { 4119 click = false; 4120 } 4121 4122 // we pass the click as the 'skipReset' - if not a real click, its the hover and we skip the reset to prevent flickering 4123 // second argument, the keepThis set to true, to avoid removing hover status of selected/hovered entry 4124 // update - second argument might be set to false, if tooltip only displays on hit to fix issue where the tooltip wouldn't close 4125 if (data.tooltip && data.tooltip.showTooltipOn === 'hit') { 4126 keepThis = false; 4127 } 4128 4129 iMapsManager.clearSelected(id, keepThis, !click); 4130 4131 if (click) { 4132 iMaps.maps[id].activeStateControl = true; 4133 } else { 4134 iMaps.maps[id].activeStateControl = false; 4135 } 4136 4137 // if we have to search in specific series and this is not that one, skip 4138 if (thisSeries) { 4139 series = thisSeries; 4140 } 4141 4142 if (Array.isArray(series)) { 4143 for (var i = 0, len = series.length; i < len; i++) { 4144 if (triggered) { 4145 break; 4146 } 4147 4148 // if it's one of the cluster series, ignore 4149 if (typeof series[i].isCluster !== 'undefined' && series[i].isCluster) { 4150 continue; 4151 } 4152 // regionSeries 4153 if (series[i].mapPolygons) { 4154 //first trigger click 4155 // this might return false if there is no entry created for this group and we are selecting programmatically 4156 select = series[i].getPolygonById(elID); 4157 4158 if ( 4159 select && 4160 typeof select.dataItem.dataContext.originalID !== 'undefined' && 4161 select.dataItem.dataContext.originalID.includes(',') 4162 ) { 4163 elID = select.dataItem.dataContext.originalID; 4164 } 4165 4166 // show series if it's hidden 4167 if (select) { 4168 series[i].show(); 4169 } 4170 4171 // check if group 4172 if (elID.includes(',')) { 4173 if (typeof select !== 'undefined' && select) { 4174 select.tooltip = false; 4175 select.dispatchImmediately('hit'); 4176 select.hideTooltip(); 4177 4178 customRegionGroup = false; 4179 4180 // reset true click events controller 4181 iMaps.maps[id].activeStateControl = true; 4182 } 4183 4184 //then highlight the first one 4185 group = elID.split(','); 4186 group.forEach(function (rxid, indx) { 4187 select = series[i].getPolygonById(rxid.trim()); 4188 4189 if (typeof select !== 'undefined' && select) { 4190 if (select.dataItem.dataContext.madeFromGeoData) { 4191 return; 4192 } 4193 4194 // if originalID is not the same as the current originalID from the group, let's ignore it, it could belong to another group 4195 if (select.dataItem.dataContext.originalID !== elID && !customRegionGroup) { 4196 return; 4197 } 4198 4199 //the first one, let's trigger the tooltip and the hit 4200 if (indx === 0 && showTooltip) { 4201 triggered = true; 4202 if (forceFixedTooltip) { 4203 defaultTooltipPosition = 4204 typeof select !== 'undefined' && typeof select.tooltipPosition !== 'undefined' 4205 ? select.tooltipPosition 4206 : 'hover'; 4207 select.tooltipPosition = 'fixed'; 4208 4209 // experimental code to check if on hit tooltip remains 4210 defaultTooltipShowOn = select.showTooltipOn; 4211 select.showTooltipOn = 'always'; 4212
4213 iMaps.maps[id].activeStateControl = true; 4214 4215 select.tooltipPosition = defaultTooltipPosition; 4216 select.showTooltipOn = defaultTooltipShowOn; 4217 4218 select.selectedFromGroup = true; 4219 } else { 4220 select.isHover = true; 4221 } 4222 } 4223 4224 // if we have the active state, use it instead 4225 if (data.regionActiveState && im.bool(data.regionActiveState.enabled)) { 4226 select.setState('active'); 4227 } else { 4228 select.setState('highlight'); 4229 } 4230 4231 selected.push(select); 4232 } 4233 }); 4234 } else { 4235 // individual region 4236 select = series[i].getPolygonById(elID); 4237 4238 if (typeof select !== 'undefined' && select) { 4239 let timeout = 0; 4240 //check if globe to rotate 4241 if (data.projection === 'Orthographic') { 4242 let map = iMaps.maps[id].map; 4243 map.animate( 4244 { 4245 property: 'deltaLongitude', 4246 to: -select.longitude, 4247 }, 4248 500, 4249 am4core.ease.linear 4250 ); 4251 map.animate( 4252 { 4253 property: 'deltaLatitude', 4254 to: -select.latitude, 4255 }, 4256 550, 4257 am4core.ease.linear 4258 ); 4259 timeout = 550; 4260 } 4261 4262 setTimeout( 4263 function (select) { 4264 console.log(select.dataItem.dataContext); 4265 4266 if ( 4267 forceFixedTooltip && 4268 select.dataItem.dataContext && 4269 select.dataItem.dataContext.action !== 'igm_display_map' 4270 ) { 4271 defaultTooltipPosition = 4272 typeof select !== 'undefined' && typeof select.tooltipPosition !== 'undefined' 4273 ? select.tooltipPosition 4274 : 'hover'; 4275 select.tooltipPosition = 'fixed'; 4276 // experimental code to check if on hit tooltip remains 4277 defaultTooltipShowOn = select.showTooltipOn; 4278 select.showTooltipOn = 'always'; 4279 select.dispatchImmediately('hit'); 4280 triggered = true; 4281 select.tooltipPosition = defaultTooltipPosition; 4282 select.showTooltipOn = defaultTooltipShowOn; 4283 selected.push(select); 4284 } 4285 // if action is set to display map it will zoom and we don't need to show tooltip 4286 else if ( 4287 select.dataItem.dataContext && 4288 select.dataItem.dataContext.action === 'igm_display_map' 4289 ) { 4290 select.dispatchImmediately('hit'); 4291 select.hideTooltip(); 4292 triggered = true; 4293 selected.push(select); 4294 } else { 4295 select.dispatchImmediately('hit'); 4296 triggered = true; 4297 selected.push(select); 4298 } 4299 }, 4300 timeout, 4301 select 4302 ); 4303 } 4304 } 4305 } 4306 // imageSeries 4307 if (series[i].mapImages) { 4308 // multiple markers 4309 if (elID.includes(',')) { 4310 // hilight 4311 group = elID.split(','); 4312 group.forEach(function (rxid) { 4313 select = series[i].getImageById(rxid); 4314 4315 if (typeof select !== 'undefined' && select) { 4316 // show series if it's hidden 4317 series[i].show(); 4318 4319 if (forceFixedTooltip) { 4320 defaultTooltipShowOn = select.showTooltipOn; 4321 select.showTooltipOn = 'always'; 4322 4323 defaultTooltipPosition = 4324 typeof select && typeof select.tooltipPosition !== 'undefined' 4325 ? select.tooltipPosition 4326 : 'hover'; 4327 select.tooltipPosition = 'fixed'; 4328 select.dispatchImmediately('hit'); 4329 triggered = true; 4330 select.tooltipPosition = defaultTooltipPosition; 4331 select.showTooltipOn = defaultTooltipShowOn; 4332 selected.push(select); 4333 } else { 4334 select.dispatchImmediately('hit'); 4335 triggered = true; 4336 selected.push(select); 4337 } 4338 } 4339 }); 4340 } 4341 // single marker 4342 else { 4343 let selectMarker = series[i].getImageById(elID); 4344 if (selectMarker) { 4345 // show series if it's hidden 4346 series[i].show(); 4347 4348 let timeoutM = 0; 4349 //check if globe to rotate
4350 if (data.projection === 'Orthographic') { 4351 let map = iMaps.maps[id].map; 4352 map.animate( 4353 { 4354 property: 'deltaLongitude', 4355 to: -selectMarker.longitude, 4356 }, 4357 500, 4358 am4core.ease.linear 4359 ); 4360 map.animate( 4361 { 4362 property: 'deltaLatitude', 4363 to: -selectMarker.latitude, 4364 }, 4365 550, 4366 am4core.ease.linear 4367 ); 4368 timeoutM = 550; 4369 } 4370 4371 setTimeout(function () { 4372 if (forceFixedTooltip) { 4373 defaultTooltipPosition = selectMarker.tooltipPosition; 4374 defaultTooltipShowOn = selectMarker.showTooltipOn; 4375 selectMarker.tooltipPosition = 'fixed'; 4376 selectMarker.showTooltipOn = 'always'; 4377 selectMarker.isHover = true; 4378 selectMarker.isActive = true; 4379 // to also show tooltip when using the select method 4380 selectMarker.dispatchImmediately('hit'); 4381 selectMarker.setState('active'); 4382 selectMarker.children.each(function (child) { 4383 //if(child.className === 'Circle'){ 4384 child.showTooltip(0); 4385 //} 4386 }); 4387 triggered = true; 4388 selectMarker.tooltipPosition = defaultTooltipPosition; 4389 selectMarker.showTooltipOn = defaultTooltipShowOn; 4390 selected.push(selectMarker); 4391 } else { 4392 selectMarker.dispatchImmediately('hit'); 4393 triggered = true; 4394 selected.push(selectMarker); 4395 } 4396 }, timeoutM); 4397 } 4398 } 4399 } 4400 } 4401 } 4402 4403 im.maps[id].selected = selected; 4404 return select; 4405}; 4406 4407iMapsManager.setupRangeHeatMap = function (series, id, data) { 4408 var im = this, 4409 regions = data.regions, 4410 markers = data.roundMarkers, 4411 reordered, 4412 seriesType = im.getTargetSeriesType(series); 4413 4414 if (seriesType === 'MapImageSeries') { 4415 if (!Array.isArray(data.heatMapMarkers.range) || data.heatMapMarkers.range.length === 0) { 4416 return; 4417 } 4418 4419 // reorder ranges by value 4420 reordered = data.heatMapMarkers.range.slice(0); 4421 reordered.sort(function (a, b) { 4422 if (isNaN(a.rule)) { 4423 var x = a.rule.toLowerCase(); 4424 var y = b.rule.toLowerCase(); 4425 return x < y ? -1 : x > y ? 1 : 0; 4426 } else { 4427 return parseFloat(a.rule) - parseFloat(b.rule); 4428 } 4429 }); 4430 4431 if (Array.isArray(markers) && markers.length > 0) { 4432 markers.forEach(function (entry) { 4433 if (typeof entry[data.heatMapMarkers.source] === 'undefined') { 4434 return; 4435 } 4436 4437 // default to correct value reference, since value will be only numeric 4438 if (data.heatMapMarkers.source === 'value') { 4439 data.heatMapMarkers.source = 'val'; 4440 } 4441 4442 var val = entry[data.heatMapMarkers.source]; 4443 var start; 4444 4445 if (!isNaN(val)) { 4446 val = parseFloat(val); 4447 } 4448 4449 reordered.forEach(function (ruleData) { 4450 if (isNaN(ruleData.rule)) { 4451 start = ruleData.rule.trim(); // if it's not a number 4452 4453 if (val == start) { 4454 entry.fill = ruleData.fill; 4455 entry.radius = parseFloat(ruleData.radius); 4456 } 4457 } else { 4458 start = parseFloat(ruleData.rule); // if it's a number 4459 4460 if (val >= start) { 4461 entry.fill = ruleData.fill; 4462 entry.radius = parseFloat(ruleData.radius); 4463 } 4464 } 4465 }); 4466 }); 4467 } 4468 } else if (seriesType === 'MapPolygonSeries') { 4469 if (!Array.isArray(data.heatMapRegions.range) || data.heatMapRegions.range.length === 0) { 4470 return; 4471 } // reorder ranges by value 4472 4473 reordered = data.heatMapRegions.range.slice(0); 4474 reordered.sort(function (a, b) { 4475 if (isNaN(a.rule)) { 4476 var x = a.rule.toLowerCase(); 4477 var y = b.rule.toLowerCase(); 4478 return x < y ? -1 : x > y ? 1 : 0; 4479 } else { 4480 return parseFloat(a.rule) - parseFloat(b.rule); 4481 } 4482 }); 4483 4484 if (Array.isArray(regions) && regions.length > 0) { 4485 if (!isNaN(data.heatMapRegions.source)) { 4486 data.heatMapRegions.source = parseInt(data.heatMapRegions.source); 4487 } 4488 4489 regions.forEach(function (entry) { 4490 if (typeof entry[data.heatMapRegions.source] === 'undefined') { 4491 return; 4492 } 4493 4494 if (data.heatMapRegions.source === 'value') { 4495 data.heatMapRegions.source = 'val'; 4496 } 4497 4498 var val = entry[data.heatMapRegions.source]; 4499 var start; 4500 4501 if (!isNaN(val)) { 4502 val = parseFloat(val); 4503 } 4504 4505 reordered.forEach(function (ruleData) { 4506 if (isNaN(ruleData.rule)) { 4507 start = ruleData.rule.trim(); // if it's a number 4508 4509 if (val == start) { 4510 entry.fill = ruleData.fill; 4511 } 4512 } else { 4513 start = parseFloat(ruleData.rule); // if it's a number 4514 4515 if (val >= start) { 4516 entry.fill = ruleData.fill; 4517 } 4518 } 4519 }); 4520 }); 4521 } 4522 } 4523}; 4524/** 4525 * 4526 * @param {object} series 4527 * @param {int} id - parent map id 4528 * @param {object} data - current map data 4529 */ 4530 4531iMapsManager.setupHeatMap = function (series, id, data) { 4532 var im = this, 4533 map = im.maps[id].map, 4534 heatLegend, 4535 legendLabel, 4536 legendContainer, 4537 minRange, 4538 maxRange, 4539 target, 4540 minProp, 4541 maxProp, 4542 propTargets, 4543 dataSource, 4544 seriesType = im.getTargetSeriesType(series); // setup target 4545 4546 if (seriesType === 'MapImageSeries') { 4547 if (typeof data.heatMapMarkers.type !== 'undefined' && data.heatMapMarkers.type === 'range') { 4548 im.setupRangeHeatMap(series, data.id, data); 4549 return; 4550 } 4551 4552 target = series.mapImages.template.children.values[0]; 4553 propTargets = ['fill', 'radius']; 4554 dataSource = data.heatMapMarkers; 4555 } else if (seriesType === 'MapPolygonSeries') { 4556 if (typeof data.heatMapRegions.type !== 'undefined' && data.heatMapRegions.type === 'range') { 4557 im.setupRangeHeatMap(series, data.id, data); 4558 return; 4559 } 4560 4561 target = series.mapPolygons.template; 4562 propTargets = ['fill']; 4563 dataSource = data.heatMapRegions; 4564 } else { 4565 return; 4566 } 4567 4568 // make sure we read data form the correct property 4569 series.dataFields.value = dataSource.source; 4570 4571 if (!Array.isArray(propTargets)) { 4572 propTargets = [propTargets]; 4573 } 4574 4575 propTargets.map(function (prop) { 4576 // setup min/max sources 4577 if (prop === 'fill') { 4578 minProp = dataSource.minColor; 4579 maxProp = dataSource.maxColor; 4580 } else if (prop === 'radius') { 4581 minProp = dataSource.minRadius; 4582 maxProp = dataSource.maxRadius; 4583 } 4584 4585 series.heatRules.push({ 4586 property: prop, 4587 target: target, 4588 min: minProp, 4589 max: maxProp, 4590 }); 4591 }); 4592 4593 if (im.bool(dataSource.legend)) { 4594 legendContainer = map.createChild(am4core.Container); 4595 legendContainer.align = 4596 typeof dataSource.legendAlign !== 'undefined' ? dataSource.legendAlign : 'right'; 4597 legendContainer.valign = 4598 typeof dataSource.legendValign !== 'undefined' ? dataSource.legendValign : 'bottom'; 4599 legendContainer.userClassName = 'mapLegendContainer'; 4600 legendContainer.marginRight = am4core.percent(4); 4601 //legendContainer.parent = map; 4602 4603 if (window.innerWidth <= 780) { 4604 legendContainer.width = am4core.percent(40); 4605 } else { 4606 legendContainer.width = am4core.percent(25); 4607 } 4608 4609 // legend title 4610 if (typeof dataSource.label !== 'undefined' && dataSource.label !== '') { 4611 legendLabel = legendContainer.createChild(am4core.Label); 4612 legendLabel.text = dataSource.label; 4613 legendLabel.horizontalCenter = 'left'; 4614 legendLabel.verticalCenter = 'top'; 4615 4616 legendLabel.fontSize = 12; 4617 legendLabel.paddingBottom = 40; 4618 4619 if (window.innerWidth <= 780) { 4620 legendLabel.fontSize = 10; 4621 legendLabel.paddingBottom = 48; 4622 } else { 4623 legendLabel.fontSize = 12; 4624 legendLabel.paddingBottom = 48; 4625 } 4626 4627 legendLabel.nonScaling = false;
4628 legendLabel.clickable = false; 4629 legendLabel.focusable = false; 4630 legendLabel.hoverable = false; 4631 } 4632 4633 //legendLabel.parent = heatLegend; 4634 //label.insertAfter(heatLegend.valueAxis); 4635 //heatLegend.valueAxis.title.text = 'test title'; 4636 4637 heatLegend = legendContainer.createChild(am4maps.HeatLegend); 4638 heatLegend.series = series; 4639 heatLegend.align = 'right'; 4640 heatLegend.valign = 'bottom'; 4641 heatLegend.width = am4core.percent(100); 4642 //heatLegend.marginRight = am4core.percent(4); 4643 heatLegend.minValue = 0; 4644 heatLegend.maxValue = 99999999999999; // Set up custom heat map legend labels using axis ranges 4645 4646 minRange = heatLegend.valueAxis.axisRanges.create(); 4647 minRange.value = heatLegend.minValue; 4648 minRange.label.text = dataSource.minLabel; 4649 maxRange = heatLegend.valueAxis.axisRanges.create(); 4650 maxRange.value = heatLegend.maxValue; 4651 maxRange.label.text = dataSource.maxLabel; 4652 4653 minRange.label.fontSize = 12; 4654 maxRange.label.fontSize = 12; 4655 4656 if (window.innerWidth <= 780) { 4657 minRange.label.fontSize = 10; 4658 maxRange.label.fontSize = 10; 4659 } else { 4660 minRange.label.fontSize = 12; 4661 maxRange.label.fontSize = 12; 4662 } 4663 4664 // Blank out internal heat legend value axis labels 4665 heatLegend.valueAxis.renderer.labels.template.adapter.add('text', function () { 4666 return ''; 4667 }); 4668 } 4669}; 4670 4671iMapsManager.drillTo = function (id, ev, currentRegion, customMap) { 4672 var im = iMapsManager, 4673 data = im.maps[id].data, 4674 allCurrentSeries = iMapsManager.maps[id].series, 4675 baseSeries = iMapsManager.maps[id].baseSeries, 4676 allBaseSeries = iMapsManager.maps[id].allBaseSeries, 4677 bgSeries = im.maps[id].backgroundSeries, 4678 opacity, 4679 i, 4680 len; 4681 4682 (opacity = typeof igmDrilldownBaseMapOpacity !== 'undefined' ? igmDrilldownBaseMapOpacity : 0.3), 4683 // hide all others except this one and baseSeries 4684 // if were opening a custom map 4685 (customMap = customMap || false); 4686 4687 // hide or fade series 4688 for (i = 0, len = allCurrentSeries.length; i < len; i++) { 4689 if (baseSeries.includes(allCurrentSeries[i])) { 4690 // let's check if new option to keep base map is enabled 4691 if (typeof data.alwaysKeepBase === 'undefined' || !im.bool(data.alwaysKeepBase)) { 4692 allCurrentSeries[i].opacity = opacity; 4693 4694 // hide image background 4695 bgSeries.opacity = opacity; 4696 } 4697 } else if (allBaseSeries.includes(allCurrentSeries[i])) { 4698 // let's check if new option to keep base map is enabled 4699 if (typeof data.alwaysKeepBase === 'undefined' || !im.bool(data.alwaysKeepBase)) { 4700 allCurrentSeries[i].hide(); 4701 } 4702 } else { 4703 allCurrentSeries[i].hide(); 4704 } 4705 } 4706 4707 for (i = 0, len = currentRegion.length; i < len; i++) { 4708 currentRegion[i].show(); 4709 } 4710 // is drilling 4711 iMapsManager.maps[id].isDrilling = true; 4712 4713 // zoom to region - it will only work when zoom is enabled so that controls exist 4714 if (!ev.zooming) { 4715 if (customMap) { 4716 console.log('drill to specific map'); 4717 im.zoomToMap(ev, currentRegion); 4718 return; 4719 } 4720 4721 im.zoomToRegion(ev, id); 4722 } 4723}; 4724 4725iMapsManager.drillDown = function (id, ev) { 4726 var mapName = iMapsRouter.iso2cleanName(ev.target.dataItem.dataContext.id, id), 4727 targetID = ev.target.dataItem.dataContext.id, 4728 allCurrentSeries = iMapsManager.maps[id].series, 4729 clicked = ev.target.dataItem.dataContext, 4730 currentRegion, 4731 customMap = false, 4732 baseSeries = iMapsManager.maps[id].baseSeries, 4733 allBaseSeries = iMapsManager.maps[id].allBaseSeries, 4734 i, 4735 len, 4736 checkSeries = [], 4737 seriesExists = false; 4738 console.log('Map Name:', mapName); 4739 console.log('Available Series:', iMapsManager.maps[id].seriesIndex); 4740 console.log('Available Series by ID: ', iMapsManager.maps[id].seriesById); // check if geofile info exists or return if the id is numeric 4741 4742 if (!mapName || !isNaN(targetID)) { 4743 // well, let's only return if it's not showing another map 4744 // code needs better logic... 4745 if (_typeof(clicked) === undefined || clicked.action !== 'igm_display_map') { 4746 return false;
4747 } 4748 } 4749 4750 if (ev.target.polygon) { 4751 // what we need to check 4752 checkSeries.push(mapName); // check if series exists for this map 4753 4754 checkSeries.forEach(function (ser) { 4755 if (_typeof(clicked) !== undefined && clicked.action == 'igm_display_map') { 4756 console.log('Display custom map ' + clicked.content); 4757 4758 if (Array.isArray(iMapsManager.maps[id].seriesById[parseInt(clicked.content)])) { 4759 seriesExists = true; 4760 currentRegion = iMapsManager.maps[id].seriesById[parseInt(clicked.content)]; 4761 customMap = true; 4762 } 4763 } else { 4764 if (Array.isArray(iMapsManager.maps[id].seriesIndex[ser])) { 4765 seriesExists = true; 4766 currentRegion = iMapsManager.maps[id].seriesIndex[ser]; 4767 } 4768 } 4769 }); 4770 4771 if (seriesExists) { 4772 iMapsManager.drillTo(id, ev, currentRegion, customMap); 4773 iMapsManager.maps[id].drilledTo = currentRegion[0].mapID; 4774 } else { 4775 // if the target is part of current series, do nothing 4776 if (currentRegion === ev.target.series) { 4777 iMapsManager.maps[id].isDrilling = false; 4778 return; 4779 } 4780 // if target is base series, show it 4781 if (baseSeries.includes(ev.target.series)) { 4782 iMapsManager.maps[id].isDrilling = false; 4783 iMapsManager.maps[id].drilledTo = false; 4784 4785 // hide all except baseSeries 4786 for (i = 0, len = allCurrentSeries.length; i < len; i++) { 4787 if (allBaseSeries.includes(allCurrentSeries[i])) { 4788 allCurrentSeries[i].show(); 4789 } else { 4790 allCurrentSeries[i].hide(); 4791 } 4792 } 4793 } 4794 } 4795 } 4796}; 4797/*HELPERS*/ 4798 4799iMapsManager.getSelected = function (id) { 4800 var im = this, 4801 map = im.maps[id], 4802 selected = map.selected || false, 4803 multiple = []; 4804 4805 if (selected) { 4806 if (Array.isArray(selected)) { 4807 selected.forEach(function (sel) { 4808 multiple.push(sel.dataItem.dataContext); 4809 }); 4810 return multiple; 4811 } 4812 4813 return selected.dataItem.dataContext; 4814 } else { 4815 return false; 4816 } 4817}; 4818 4819iMapsManager.getHovered = function (id) { 4820 var im = this, 4821 map = im.maps[id], 4822 hovered = map.hovered || false, 4823 multiple = []; 4824 4825 if (hovered) { 4826 if (Array.isArray(hovered)) { 4827 hovered.forEach(function (sel) { 4828 multiple.push(sel.dataItem.dataContext); 4829 }); 4830 return multiple; 4831 } 4832 } else { 4833 return false; 4834 } 4835}; 4836 4837iMapsManager.getHighlighted = function (id) { 4838 var im = this, 4839 map = im.maps[id], 4840 highlighted = map.highlighted || false, 4841 multiple = []; 4842 4843 if (highlighted) { 4844 if (Array.isArray(highlighted)) { 4845 highlighted.forEach(function (sel) { 4846 multiple.push(sel.dataItem.dataContext); 4847 }); 4848 return multiple; 4849 } 4850 4851 return highlighted.dataItem.dataContext; 4852 } else { 4853 return false; 4854 } 4855}; 4856 4857iMapsManager.clearSelected = function (id, keepThis, skipReset) { 4858 var im = this, 4859 map = im.maps[id], 4860 selected = map.selected || []; 4861 4862 // to keep the state of this element 4863 keepThis = keepThis || false; 4864 skipReset = skipReset || false; 4865 4866 if (Array.isArray(selected) && selected.length > 0) { 4867 selected.forEach(function (polygon) { 4868 if ( 4869 polygon !== keepThis && 4870 typeof polygon === 'object' && 4871 typeof polygon.isHover !== 'undefined' 4872 ) { 4873 polygon.isHover = false; 4874 polygon.isActive = false; 4875 polygon.isGroupActive = false; 4876 4877 // there were some issues on mobile tap (singleHit) where the tooltip would disappear, 4878 // so we added this check before hiding the tooltip 4879 if (!keepThis) { 4880 polygon.hideTooltip(0); // needed to hide tooltip 4881 } 4882 4883 if (polygon.selectedFromGroup) { 4884 polygon.hideTooltip(0); // needed to hide tooltip when group was selected 4885 polygon.selectedFromGroup = false; 4886 } 4887 4888 polygon.setState('default'); 4889 } 4890 }); 4891 selected = []; 4892 } 4893 4894 if (!keepThis && typeof iMapsActions !== 'undefined') { 4895 if (!skipReset) { 4896 //iMapsActions.resetActions(id); 4897 } 4898 map.selected = []; 4899 } else { 4900 map.selected = [keepThis]; 4901 } 4902 4903 return map.selected; 4904}; 4905 4906iMapsManager.clearHighlighted = function (id) { 4907 var im = this, 4908 map = im.maps[id], 4909 highlighted = map.highlighted || []; 4910 4911 if (Array.isArray(highlighted) && highlighted.length > 0) { 4912 highlighted.forEach(function (polygon) { 4913 polygon.isHover = false;
4914 polygon.isActive = false; 4915 polygon.setState('default'); 4916 }); 4917 highlighted = []; 4918 } 4919 4920 return highlighted; 4921}; 4922/* 4923 * setup hover events 4924 * id - id of the map 4925 * eID - hovered element ID 4926 * forcedFixedTooltip - if we should force the tooltip to be fixed or not 4927 */ 4928 4929iMapsManager.hover = function (id, eID, forceFixedTooltip) { 4930 var im = this, 4931 map = im.maps[id], 4932 series = map.series, 4933 hovered = map.hovered || [], 4934 hover, 4935 group, 4936 defaultShowTooltipOn, 4937 defaultTooltipPosition; // map sure it's string 4938 4939 if (Number.isInteger(eID)) { 4940 eID = eID.toString(); 4941 } // Force fixed position? 4942 4943 if (typeof forceFixedTooltip === 'undefined') { 4944 forceFixedTooltip = true; 4945 } 4946 4947 iMapsManager.clearHovered(id); 4948 hovered = []; 4949 4950 if (Array.isArray(series)) { 4951 for (var i = 0, len = series.length; i < len; i++) { 4952 // regionSeries 4953 if (series[i].mapPolygons) { 4954 // multiple 4955 // check if group 4956 if (eID.includes(',')) { 4957 // foreach code 4958 group = eID.split(','); 4959 group.forEach(function (rxid) { 4960 // single 4961 hover = series[i].getPolygonById(rxid.trim()); 4962 4963 if (hover) { 4964 if (forceFixedTooltip) { 4965 defaultTooltipPosition = 4966 typeof hover.tooltipPosition !== 'undefined' ? hover.tooltipPosition : 'fixed'; 4967 defaultShowTooltipOn = 4968 typeof hover.showTooltipOn !== 'undefined' ? hover.showTooltipOn : 'hover'; 4969 hover.tooltipPosition = 'fixed'; 4970 hover.showTooltipOn = 'always'; 4971 hovered.push(hover); 4972 hover.dispatchImmediately('over'); 4973 hover.isHover = true; 4974 hover.tooltipPosition = defaultTooltipPosition; 4975 hover.showTooltipOn = defaultShowTooltipOn; 4976 } else { 4977 hovered.push(hover); 4978 hover.dispatchImmediately('over'); 4979 hover.isHover = true; 4980 } 4981 } 4982 }); 4983 } else { 4984 // single region 4985 hover = series[i].getPolygonById(eID); 4986 4987 if (hover) { 4988 if (forceFixedTooltip) { 4989 defaultTooltipPosition = hover.tooltipPosition; 4990 hover.tooltipPosition = 'fixed'; 4991 hovered = [hover]; 4992 hover.dispatchImmediately('over'); 4993 hover.isHover = true; 4994 hover.tooltipPosition = defaultTooltipPosition; 4995 } else { 4996 hovered = [hover]; 4997 hover.dispatchImmediately('over'); 4998 hover.isHover = true; 4999 } 5000 } 5001 } 5002 } 5003 // imageSeries 5004 if (series[i].mapImages) { 5005 // multiple markers 5006 if (eID.includes(',')) { 5007 // foreach code 5008 group = eID.split(','); 5009 group.forEach(function (rxid) { 5010 hover = series[i].getImageById(rxid); 5011 5012 if (hover) { 5013 if (forceFixedTooltip) { 5014 defaultTooltipPosition = hover.tooltipPosition; 5015 defaultShowTooltipOn = hover.showTooltipOn; 5016 hover.tooltipPosition = 'fixed'; 5017 hover.showTooltipOn = 'always'; 5018 hovered = [hover]; 5019 hover.dispatchImmediately('over'); 5020 hover.isHover = true; 5021 hover.setState('hover'); 5022 hover.children.each(function (child) { 5023 if (child.className === 'Circle') { 5024 child.showTooltip(0); 5025 } 5026 }); 5027 hover.tooltipPosition = defaultTooltipPosition; 5028 hover.showTooltipOn = defaultShowTooltipOn; 5029 } else { 5030 hovered = [hover]; 5031 hover.dispatchImmediately('over'); 5032 hover.isHover = true; 5033 hover.setState('hover'); 5034 } 5035 } 5036 }); 5037 } 5038 // single marker 5039 else { 5040 hover = series[i].getImageById(eID); 5041 5042 if (hover) { 5043 if (forceFixedTooltip) { 5044 defaultTooltipPosition = hover.tooltipPosition; 5045 hover.tooltipPosition = 'fixed'; 5046 hovered = [hover]; 5047 hover.dispatchImmediately('over'); 5048 hover.isHover = true; 5049 hover.setState('hover'); 5050 hover.children.each(function (child) { 5051 if (child.className === 'Circle') { 5052 child.showTooltip(0); 5053 } 5054 }); 5055 hover.tooltipPosition = defaultTooltipPosition; 5056 } else { 5057 hovered = [hover]; 5058 hover.dispatchImmediately('over'); 5059 hover.isHover = true; 5060 hover.setState('hover'); 5061 } 5062 } 5063 } 5064 } 5065 } 5066 } 5067 5068 map.hovered = hovered; 5069 return hover; 5070}; 5071 5072iMapsManager.clearHovered = function (id, eID) { 5073 var im = this, 5074 map = im.maps[id], 5075 hovered = map.hovered || false, 5076 series = map.series, 5077 hover; 5078 eID = eID || false; 5079 5080 if (eID) { 5081 if (Array.isArray(series)) { 5082 for (var i = 0, len = series.length; i < len; i++) { 5083 // regionSeries - specific region 5084 if (series[i].mapPolygons) { 5085 hover = series[i].getPolygonById(eID); 5086 5087 if (hover) { 5088 hover.dispatchImmediately('out'); 5089 hover.isHover = false;
5090 } 5091 } 5092 5093 // imageSeries - specific marker 5094 if (series[i].mapImages) { 5095 hover = series[i].getImageById(eID); 5096 5097 if (hover) { 5098 hover.isHover = false; 5099 hover.setState('default'); 5100 hover.dispatchImmediately('out'); 5101 } 5102 } 5103 } 5104 } 5105 } 5106 // all of the regions or markers 5107 else { 5108 if (hovered) { 5109 hovered.forEach(function (hov) { 5110 hov.dispatchImmediately('out'); 5111 if (typeof hov.isGroupActive === 'undefined' || !hov.isGroupActive) { 5112 hov.setState('default'); 5113 hov.isHover = false; 5114 } 5115 if (typeof hov.children !== 'undefined') { 5116 hov.children.each(function (child) { 5117 if (child.className === 'Circle') { 5118 child.hideTooltip(0); 5119 } 5120 }); 5121 } 5122 }); 5123 map.hovered = []; 5124 return true; 5125 } 5126 } 5127 5128 return false; 5129}; 5130/** 5131 * id - map ID 5132 * elID - element to highlight 5133 */ 5134 5135iMapsManager.highlight = function (id, elID) { 5136 var im = this, 5137 map = im.maps[id], 5138 series = map.series, 5139 select, 5140 highlighted = map.highlighted || [], 5141 group; // map sure it's string 5142 5143 if (Number.isInteger(elID)) { 5144 elID = elID.toString(); 5145 } //iMapsManager.clearSelected(id); 5146 5147 if (Array.isArray(series)) { 5148 for (var i = 0, len = series.length; i < len; i++) { 5149 // regionSeries 5150 if (series[i].mapPolygons) { 5151 // check if group 5152 if (elID.includes(',')) { 5153 group = elID.split(','); 5154 group.forEach(function (rxid) { 5155 select = series[i].getPolygonById(rxid.trim()); 5156 5157 if (typeof select !== 'undefined' && select) { 5158 if (select.dataItem.dataContext.madeFromGeoData) { 5159 return; 5160 } 5161 5162 select.setState('highlight'); 5163 highlighted.push(select); 5164 } 5165 }); 5166 } else { 5167 select = series[i].getPolygonById(elID); 5168 5169 if (typeof select !== 'undefined' && select) { 5170 select.setState('highlight'); 5171 highlighted.push(select); 5172 } 5173 } 5174 } // imageSeries 5175 5176 if (series[i].mapImages) { 5177 if (elID.includes(',')) { 5178 group = elID.split(','); 5179 group.forEach(function (rxid) { 5180 select = series[i].getImageById(rxid); 5181 5182 if (typeof select !== 'undefined' && select) { 5183 select.setStateOnChildren = true; 5184 select.setState('highlight'); 5185 highlighted.push(select); 5186 } 5187 }); 5188 } else { 5189 select = series[i].getImageById(elID); 5190 5191 if (typeof select !== 'undefined' && select) { 5192 select.setStateOnChildren = true; 5193 select.setState('highlight'); 5194 highlighted.push(select); 5195 } 5196 } 5197 } 5198 } 5199 } 5200 5201 map.highlighted = highlighted; 5202 return select; 5203}; 5204 5205iMapsManager.getTargetSeriesType = function (el) { 5206 var className = el.className; 5207 return className; 5208}; 5209/** 5210 * Setups clustered series based on coordinate values from data 5211 */ 5212 5213iMapsManager.setupClusters = function (data, id, overlay) { 5214 var im = this, 5215 map = im.maps[id], 5216 series = [], 5217 markerSeries, 5218 tempData = {}, 5219 biasLevels = [], 5220 zoomLevels = [], 5221 biasSteps = 4, 5222 i = 0, 5223 prevBias = parseFloat(data.clusterMarkers.maxBias), 5224 maxZoomLevel = parseFloat(data.clusterMarkers.zoomLevel) || 20, 5225 tooltipTemplate = 5226 typeof data.clusterMarkers.tooltipTemplate !== 'undefined' 5227 ? data.clusterMarkers.tooltipTemplate 5228 : false; 5229 overlay = overlay || false; 5230 var currentMap = overlay ? overlay : id; 5231 5232 while (i <= biasSteps) { 5233 biasLevels.push(prevBias); 5234 prevBias = prevBias / 2; 5235 zoomLevels.push(maxZoomLevel); 5236 5237 // make sure the last one is set to 1, otherwise it will be hidden 5238 maxZoomLevel = i == 3 ? 1 : Math.ceil(maxZoomLevel / 2); 5239 i++; 5240 } 5241 5242 // reverse array to match detail level 5243 zoomLevels.reverse().pop(); 5244 biasLevels.pop(); 5245 5246 if (typeof map.clusterSeries[currentMap] === 'undefined') { 5247 map.clusterSeries[currentMap] = { 5248 zoomLevels: {}, 5249 overlay: overlay, 5250 }; 5251 } 5252 5253 if (Array.isArray(data.roundMarkers)) {
5254 biasLevels.forEach(function (item, index) { 5255 series = geocluster(data.roundMarkers, item, data.markerDefaults, tooltipTemplate); 5256 tempData = Object.assign({}, data); 5257 tempData.roundMarkers = series; 5258 markerSeries = im.pushRoundMarkerSeries(id, tempData); 5259 markerSeries.name = tempData.title || 'Map'; 5260 markerSeries.hiddenInLegend = true; // set as cluster to be identified later in select method 5261 5262 markerSeries.isCluster = true; 5263 map.clusterSeries[currentMap].zoomLevels[zoomLevels[index]] = markerSeries; 5264 5265 if (index === 0 && !overlay) { 5266 // this somehow interferes with the clusters after home button is clicked 5267 // im.maps[id].allBaseSeries.push(markerSeries); 5268 } 5269 5270 // hide all series except the first 5271 //if (index > 0 ) { 5272 markerSeries.hidden = true; 5273 //} 5274 }); 5275 } 5276 5277 return true; 5278}; 5279 5280/** 5281 * triggers when map is ready 5282 * @param {int} id of the map 5283 */ 5284iMapsManager.triggerOnReady = function (id, data) { 5285 let isCustom = data.map == 'custom' ? true : false; 5286 let urlParams = new URLSearchParams(window.location.search); 5287 let myParam = urlParams.get('mregion'); 5288 if (myParam) { 5289 //if it's a custom map, do nothing, we will trigger it on the map appeared event 5290 if (!isCustom) { 5291 iMapsManager.select(id, myParam, true, true); 5292 } 5293 } 5294}; 5295 5296/** 5297 * triggers when map is ready 5298 * @param {int} id of the map 5299 */ 5300iMapsManager.triggerOnAppeared = function (id, data) { 5301 let isCustom = data.map == 'custom' ? true : false; 5302 let urlParams = new URLSearchParams(window.location.search); 5303 let myParam = urlParams.get('mregion'); 5304 if (myParam) { 5305 //if it's a custom map, do nothing, we will trigger it on the map appeared event 5306 if (isCustom) { 5307 setTimeout(function () { 5308 iMapsManager.select(id, myParam, true, true); 5309 }, 500); 5310 } 5311 } 5312}; 5313 5314/** 5315 * Adds a new region Series currently not loaded, adding the script to the body of the page and creating a new series after 5316 * id - map id to attach series 5317 * dataContent - object with data that would typically be a polygon dataContent, like name and id 5318 * config - config object for the new series being added 5319 * 5320 * @return newSeries - the new created series object 5321 */ 5322 5323iMapsManager.addGeoFileSeries = function (id, dataContext) { 5324 var newSeries, 5325 geoFiles = iMapsRouter.getGeoFiles(dataContext); 5326 var scriptPromise = new Promise(function (resolve, reject) { 5327 var script = document.createElement('script'); 5328 document.body.appendChild(script); 5329 script.onload = resolve; 5330 script.onerror = reject; 5331 script.async = true; 5332 script.src = geoFiles.src; 5333 }); 5334 scriptPromise.then(function () { 5335 var data = { 5336 title: geoFiles.title, 5337 map: geoFiles.map, 5338 regions: [], 5339 config: data, // not working, we changed the config to be at parent level with data 5340 }; 5341 iMapsManager.maps[id].seriesIndex[geoFiles.map] = []; 5342 newSeries = iMapsManager.pushRegionSeries(id, data); 5343 iMapsManager.maps[id].seriesIndex[geoFiles.map].push(newSeries); 5344 return newSeries; 5345 }); 5346 return false; 5347}; 5348 5349iMapsManager.handleInfoBox = function (id) { 5350 var im = this, 5351 map = im.maps[id].map, 5352 events = ['ready', 'mappositionchanged', 'zoomlevelchanged'], 5353 container = document.getElementById('map_visual_info'), 5354 coordinatesc = document.getElementById('map_click_events_coordinates'); 5355 5356 if (container) { 5357 iMapsManager.populateInfo(id, container); // zoom, etc 5358 5359 events.forEach(function (event) { 5360 map.events.on( 5361 event, 5362 function () { 5363 iMapsManager.populateInfo(id, container); 5364 }, 5365 this 5366 ); 5367 }); 5368 } 5369 5370 if (coordinatesc) { 5371 map.events.on( 5372 'hit', 5373 function (ev) { 5374 var coordinates = map.svgPointToGeo(ev.svgPoint); 5375 var lat = Number(coordinates.latitude).toFixed(6); 5376 5377 var _long = Number(coordinates.longitude).toFixed(6); // latitude 5378 5379 var latEl = document.createElement('div'); 5380 var latLabelEl = document.createElement('span'); 5381 var latValueEl = document.createElement('span'); 5382 latLabelEl.classList.add('info--unselectable'); 5383 latValueEl.classList.add('map_clicked_lat'); 5384 latLabelEl.innerHTML = 'LAT: '; 5385 latValueEl.innerHTML = lat; 5386 latEl.appendChild(latLabelEl); 5387 latEl.appendChild(latValueEl); // longitude 5388 5389 var longEl = document.createElement('div'); 5390 var longLabelEl = document.createElement('span'); 5391 var longValueEl = document.createElement('span'); 5392 longLabelEl.classList.add('info--unselectable'); 5393 longValueEl.classList.add('map_clicked_long'); 5394 longLabelEl.innerHTML = 'LON: '; 5395 longValueEl.innerHTML = _long; 5396 longEl.appendChild(longLabelEl); 5397 longEl.appendChild(longValueEl); 5398 coordinatesc.innerHTML = ''; 5399 coordinatesc.appendChild(latEl); 5400 coordinatesc.appendChild(longEl); 5401 coordinatesc.parentElement.style.display = 'block'; 5402 var event = new CustomEvent('mapPointClicked', { 5403 detail: { 5404 latitude: lat, 5405 longitude: _long, 5406 }, 5407 }); 5408 document.dispatchEvent(event); 5409 }, 5410 this 5411 ); 5412 } 5413}; 5414 5415iMapsManager.populateInfo = function (id, container) { 5416 var im = this, 5417 map = im.maps[id].map, 5418 info = ''; 5419 info += 'Zoom Level: ' + parseFloat(Number(map.zoomLevel).toFixed(2)) + '<br>'; 5420 info += 5421 'Center Coordinates: <br>' + 5422 "<span class='info--unselectable'>LAT </span><span>" + 5423 Number(map.zoomGeoPoint.latitude).toFixed(6) + 5424 '</span>'; 5425 info += 5426 "<br><span class='info--unselectable'>LONG </span><span>" + 5427 Number(map.zoomGeoPoint.longitude).toFixed(6) + 5428 '</span><br>'; 5429 container.innerHTML = info; 5430 5431 let centerData = { 5432 zoom: parseFloat(Number(map.zoomLevel).toFixed(2)), 5433 lat: Number(map.zoomGeoPoint.latitude).toFixed(6), 5434 long: Number(map.zoomGeoPoint.longitude).toFixed(6), 5435 }; 5436 5437 container.setAttribute('data-visual', JSON.stringify(centerData)); 5438}; 5439 5440iMapsManager.hideAllSeries = function (id, keepBase) { 5441 id = parseInt(id); 5442 5443 if (!id) { 5444 return; 5445 } 5446 5447 keepBase = keepBase || false; 5448 var map = iMaps.maps[id]; 5449 var groupedSeries = map.groupedBaseRegionSeries; 5450 var allbaseSeries = map.allBaseSeries; 5451 5452 for (var index = 0; index < map.series.length; index++) { 5453 var serie = map.series[index]; 5454 5455 //if (baseRegionSeries !== serie && !groupedSeries.includes(serie)) { 5456 // we don't need to check if it's not the base series at this point 5457 5458 if (!groupedSeries.includes(serie)) { 5459 // in case we need to check also if we keep base series 5460 if (!keepBase || (keepBase && !allbaseSeries.includes(serie))) { 5461 serie.hide(); 5462 } 5463 } 5464 } 5465}; 5466 5467iMapsManager.showAllSeries = function (id) { 5468 id = parseInt(id); 5469 5470 if (!id) { 5471 return; 5472 } 5473 5474 var map = iMaps.maps[id]; 5475 5476 for (var index = 0; index < map.series.length; index++) { 5477 var serie = map.series[index]; 5478 5479 if (typeof serie.isCluster === 'undefined' || serie.isCluster === false) { 5480 serie.show(); 5481 } 5482 } 5483}; 5484/** Util function to return boolean value of string */ 5485 5486iMapsManager.bool = function (string) { 5487 var bool = 5488 Number(string) === 0 || string === 'false' || typeof string === 'undefined' ? false : true; 5489 return bool; 5490}; 5491 5492iMapsManager.isJSON = function (str) { 5493 try { 5494 JSON.parse(str); 5495 } catch { 5496 return false;
5497 } 5498 5499 return true; 5500}; 5501/* Closest Polyfill */ 5502 5503if (!Element.prototype.matches) { 5504 Element.prototype.matches = 5505 Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 5506} 5507 5508if (!Element.prototype.closest) { 5509 Element.prototype.closest = function (s) { 5510 var el = this; 5511 5512 do { 5513 if (el.matches(s)) { 5514 return el; 5515 } 5516 el = el.parentElement || el.parentNode; 5517 } while (el !== null && el.nodeType === 1); 5518 5519 return null; 5520 }; 5521} 5522/** Library for elements 5523 */ 5524 5525iMapsManager.library = { 5526 icons: { 5527 goFullIconPath: 5528 'm15.78742,5.93715l-3.95414,3.95414l3.95414,3.95414l1.60393,-1.60393q0.32301,-0.34529 0.77969,-0.15594q0.4344,0.18935 0.4344,0.65717l0,4.99002q0,0.2896 -0.21163,0.50123t-0.50123,0.21163l-4.99002,0q-0.46781,0 -0.65717,-0.44554q-0.18935,-0.4344 0.15594,-0.76855l1.60393,-1.60393l-3.95414,-3.95414l-3.95414,3.95414l1.60393,1.60393q0.34529,0.33415 0.15594,0.76855q-0.18935,0.44554 -0.65717,0.44554l-4.99002,0q-0.2896,0 -0.50123,-0.21163t-0.21163,-0.50123l0,-4.99002q0,-0.46781 0.44554,-0.65717q0.4344,-0.18935 0.76855,0.15594l1.60393,1.60393l3.95414,-3.95414l-3.95414,-3.95414l-1.60393,1.60393q-0.21163,0.21163 -0.50123,0.21163q-0.13366,0 -0.26732,-0.05569q-0.44554,-0.18935 -0.44554,-0.65717l0,-4.99002q0,-0.2896 0.21163,-0.50123t0.50123,-0.21163l4.99002,0q0.46781,0 0.65717,0.44554q0.18935,0.4344 -0.15594,0.76855l-1.60393,1.60393l3.95414,3.95414l3.95414,-3.95414l-1.60393,-1.60393q-0.34529,-0.33415 -0.15594,-0.76855q0.18935,-0.44554 0.65717,-0.44554l4.99002,0q0.2896,0 0.50123,0.21163t0.21163,0.50123l0,4.99002q0,0.46781 -0.4344,0.65717q-0.1448,0.05569 -0.27846,0.05569q-0.2896,0 -0.50123,-0.21163l-1.60393,-1.60393z', 5529 exitFullIconPath: 5530 'm10.04411,10.81638l0,5.40556q0,0.31372 -0.22925,0.54297t-0.54297,0.22925t-0.54297,-0.22925l-1.7375,-1.7375l-4.00591,4.00591q-0.12066,0.12066 -0.27752,0.12066t-0.27752,-0.12066l-1.37552,-1.37552q-0.12066,-0.12066 -0.12066,-0.27752t0.12066,-0.27752l4.00591,-4.00591l-1.7375,-1.7375q-0.22925,-0.22925 -0.22925,-0.54297t0.22925,-0.54297t0.54297,-0.22925l5.40556,0q0.31372,0 0.54297,0.22925t0.22925,0.54297zm9.10982,-8.10834q0,0.15686 -0.12066,0.27752l-4.00591,4.00591l1.7375,1.7375q0.22925,0.22925 0.22925,0.54297t-0.22925,0.54297t-0.54297,0.22925l-5.40556,0q-0.31372,0 -0.54297,-0.22925t-0.22925,-0.54297l0,-5.40556q0,-0.31372 0.22925,-0.54297t0.54297,-0.22925t0.54297,0.22925l1.7375,1.7375l4.00591,-4.00591q0.12066,-0.12066 0.27752,-0.12066t0.27752,0.12066l1.37552,1.37552q0.12066,0.12066 0.12066,0.27752z', 5531 }, 5532}; 5533 5534iMapsManager.handleExternalZoom = function (id) { 5535 var mapContainer, mapBox, controls, homeBtn, zoomInBtn, zoomOutBtn; 5536 mapContainer = document.getElementById('map_wrapper_' + id); 5537 var im = this, 5538 data = im.maps[id].data, 5539 allCurrentSeries = im.maps[id].series, 5540 allBaseSeries = im.maps[id].allBaseSeries; 5541 5542 if (!mapContainer) { 5543 return; 5544 } 5545 5546 mapBox = mapContainer.querySelector('.map_box'); 5547 mapContainer.classList.add('map_has_external_controls'); // home button 5548 5549 homeBtn = document.createElement('div'); 5550 homeBtn.setAttribute('id', 'map_home_buttom_' + id); 5551 homeBtn.setAttribute('data-map-id', id); 5552 homeBtn.classList.add('map_home_button'); 5553 homeBtn.innerHTML = 5554 '<svg height="20" width="20"><path d="M16,8 L14,8 L14,16 L10,16 L10,10 L6,10 L6,16 L2,16 L2,8 L0,8 L8,0 L16,8 Z M16,8" /></svg>'; 5555 homeBtn.addEventListener('click', function () { 5556 var id = this.getAttribute('data-map-id'); 5557 iMaps.maps[id].map.goHome(); 5558 5559 // in case drillDown is enabled, we hide everything else 5560 if (im.bool(data.drillDownOnClick)) { 5561 for (var i = 0, len = allCurrentSeries.length; i < len; i++) { 5562 allCurrentSeries[i].hide(); //map.deltaLongitude = 0; 5563 } 5564 5565 for (var ib = 0, lenb = allBaseSeries.length; ib < lenb; ib++) { 5566 // this is messing the cluster markers on base map 5567 allBaseSeries[ib].show(); 5568 } 5569 5570 iMapsManager.maps[id].drilledTo = false; 5571 iMapsManager.maps[id].isDrilling = false; 5572 } 5573 5574 // reset actions 5575 if (typeof iMapsActions !== 'undefined' && typeof iMapsActions.resetActions !== 'undefined') { 5576 iMapsActions.resetActions(id); 5577 } 5578 }); // zoom in 5579 5580 zoomInBtn = document.createElement('div'); 5581 zoomInBtn.setAttribute('id', 'map_zoomin_buttom_' + id); 5582 zoomInBtn.setAttribute('data-map-id', id); 5583 zoomInBtn.classList.add('map_zoomin_button'); 5584 zoomInBtn.innerHTML = '+'; 5585 zoomInBtn.addEventListener('click', function () { 5586 var id = this.getAttribute('data-map-id'); 5587 iMaps.maps[id].map.zoomIn(); 5588 }); // zoom out 5589 5590 zoomOutBtn = document.createElement('div'); 5591 zoomOutBtn.setAttribute('id', 'map_zoomout_buttom_' + id); 5592 zoomOutBtn.setAttribute('data-map-id', id); 5593 zoomOutBtn.classList.add('map_zoomout_button'); 5594 zoomOutBtn.innerHTML = '-'; 5595 zoomOutBtn.addEventListener('click', function () { 5596 var id = this.getAttribute('data-map-id'); 5597 iMaps.maps[id].map.zoomOut(); 5598 }); // controls container 5599 5600 controls = document.createElement('div'); 5601 controls.setAttribute('id', 'map_controls_' + id); 5602 controls.classList.add('map_controls'); 5603 controls.appendChild(homeBtn); 5604 controls.appendChild(zoomInBtn); 5605 controls.appendChild(zoomOutBtn); // add buttons 5606
5607 mapBox.parentNode.insertBefore(controls, mapBox.nextSibling); 5608}; 5609 5610iMapsManager.toggleFullscreen = function (element) { 5611 // se não está em tela cheia 5612 if (!document.fullscreen && !document.webkitIsFullScreen) { 5613 // solicitar tela cheia 5614 if (element.requestFullscreen) { 5615 // default 5616 element.requestFullscreen(); 5617 } else if (element.mozRequestFullScreen) { 5618 // Mozilla 5619 element.mozRequestFullScreen(); 5620 } else if (element.webkitRequestFullscreen) { 5621 // Chrome e Safari 5622 element.webkitRequestFullscreen(); 5623 } else if (element.msRequestFullscreen) { 5624 // Internet Explorer 5625 element.msRequestFullscreen(); 5626 } 5627 } else { 5628 // exit fullscreen 5629 if (document.exitFullscreen) { 5630 // default 5631 document.exitFullscreen(); 5632 } else if (document.mozCancelFullScreen) { 5633 // Mozilla 5634 document.mozCancelFullScreen(); 5635 } else if (document.webkitExitFullscreen) { 5636 // Chrome e Safari 5637 document.webkitExitFullscreen(); 5638 } else if (document.msExitFullscreen) { 5639 // Internet Explorer 5640 document.msExitFullscreen(); 5641 } 5642 iMapsManager.isFullScreen = false; 5643 } 5644}; 5645 5646iMapsManager.isTouchScreenDevice = function () { 5647 return 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0; 5648}; 5649 5650/** 5651 * This function is same as PHP's nl2br() with default parameters. 5652 * 5653 * @param {string} str Input text 5654 * @param {boolean} replaceMode Use replace instead of insert 5655 * @param {boolean} isXhtml Use XHTML 5656 * @return {string} Filtered text 5657 */ 5658 5659iMapsManager.nl2br = function (str) { 5660 var replaceStr = 'HI<br>HI'; 5661 return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, replaceStr); 5662}; 5663 5664iMapsManager.isFullScreen = false; 5665/** 5666 * Main app file. Initializes app components. 5667 */ 5668 5669/** 5670 * The main app object. 5671 * 5672 */ 5673 5674var iMaps = { 5675 originalData: JSON.parse(JSON.stringify(iMapsData)), 5676}; 5677 5678iMaps.reset = function () { 5679 if (iMaps.maps) { 5680 Object.keys(iMaps.maps).forEach(function (id) { 5681 iMaps.maps[id].map.dispose(); 5682 }); 5683 } 5684 5685 iMapsData = iMaps.originalData; 5686 iMaps.init(); 5687}; 5688/** 5689 * Initializes the interactiveMaps app 5690 * 5691 */ 5692 5693iMaps.init = function (hold) { 5694 // if map should not render 5695 if ( 5696 typeof hold === 'undefined' && 5697 typeof iMapsData.options !== 'undefined' && 5698 typeof iMapsData.options.hold !== 'undefined' && 5699 iMapsData.options.hold === '1' 5700 ) { 5701 hold = true; 5702 } 5703 5704 if (hold) { 5705 return; 5706 } 5707 5708 if (typeof am4core === 'undefined') { 5709 console.log('Map files not loaded properly.'); 5710 5711 let oxygen = document.querySelector('.oxygen-body .map_wrapper .map_render'); 5712 if (oxygen) { 5713 oxygen.innerHTML = 5714 'Map Container. <br> Map will not render in Oxygen preview, but will render in live page.<br>Consider enabling the "Async Loading" option in the Settings > Performance page.'; 5715 } 5716 return; 5717 } 5718 5719 am4core.ready(function () { 5720 var data; 5721 am4core.options.autoSetClassName = true; 5722 am4core.options.classNamePrefix = 'imaps'; 5723 am4core.options.commercialLicense = true; 5724 am4core.options.queue = true; 5725 5726 if ( 5727 typeof iMapsData.options !== 'undefined' && 5728 typeof iMapsData.options.lazyLoad !== 'undefined' && 5729 iMapsData.options.lazyLoad === '1' 5730 ) { 5731 am4core.options.onlyShowOnViewport = true; 5732 } // animated 5733 5734 if ( 5735 typeof iMapsData.options !== 'undefined' && 5736 typeof iMapsData.options.animations !== 'undefined' && 5737 (iMapsData.options.animations === '1' || iMapsData.options.animations === true) 5738 ) { 5739 am4core.useTheme(am4themes_animated); 5740 } 5741 5742 data = iMapsModel.prepareData(iMapsData.data); 5743 data.forEach(function (data, index) { 5744 if (index.disabled) { 5745 return; 5746 } 5747 5748 iMapsManager.init(index); 5749 }); 5750 iMaps.maps = iMapsManager.maps; 5751 }); 5752}; 5753 5754iMaps.loadScript = function (url, callback) { 5755 var script = document.createElement('script'); 5756 script.type = 'text/javascript'; 5757 script.src = url; 5758 script.onreadystatechange = callback; 5759 script.onload = callback; 5760 document.head.appendChild(script); 5761}; 5762 5763iMaps.loadScripts = function (urls, callback) { 5764 var loadedCount = 0; 5765 5766 var multiCallback = function multiCallback() { 5767 loadedCount++; 5768 5769 if (loadedCount >= urls.length) { 5770 callback.call(this, arguments); 5771 } 5772 }; 5773
5774 urls.forEach(function (url) { 5775 iMaps.loadScript(url, multiCallback); 5776 }); 5777}; 5778 5779if ( 5780 typeof iMapsData.async !== 'undefined' && 5781 Array.isArray(iMapsData.async) && 5782 iMapsData.async.length > 0 5783) { 5784 // we need to load the core file first 5785 iMaps.loadScript(iMapsData.async[0], function () { 5786 // then we load the rest - shift() removes the first entry 5787 iMapsData.async.shift(); 5788 iMaps.loadScripts(iMapsData.async, function () { 5789 iMaps.init(); 5790 }); 5791 }); 5792} else { 5793 iMaps.init(); 5794}
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.