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