1/* google-maps-connector */ 2XA.connector.mapsConnector = (function ($, document) { 3 4 "use strict"; 5 6 var api = {}, 7 maps = [], 8 markers = [], 9 map, 10 getMapType, 11 createMarker, 12 infoWindows = [], 13 activeInfoWindows = [], 14 popupGenerations = [], 15 addMarker, 16 callbacks = [], 17 animationTimeout, 18 loading = false, 19 maxMapZoom = 18, 20 customPoiIconSize = 26; 21 22 var notifyPoiClicked = function (mapId, data) { 23 var event; 24 25 if (!data || typeof data.id === "undefined" || data.id === null) { 26 return; 27 } 28 29 event = new CustomEvent("thr:map-poi-clicked", { 30 detail: { 31 mapId: mapId, 32 id: data.id, 33 type: data.type 34 } 35 }); 36 37 document.dispatchEvent(event); 38 }; 39 40 var closeInfoWindowsForMap = function (mapId) { 41 var key, 42 mapKeyPrefix = mapId + "#"; 43 44 popupGenerations[mapId] = (popupGenerations[mapId] || 0) + 1; 45 46 if (activeInfoWindows[mapId]) { 47 activeInfoWindows[mapId].close(); 48 activeInfoWindows[mapId] = null; 49 } 50 51 for (key in infoWindows) { 52 if (infoWindows.hasOwnProperty(key) && 53 (key === String(mapId) || key.indexOf(mapKeyPrefix) === 0)) { 54 infoWindows[key].close(); 55 // Dynamic popups are replaced after their content is fetched. 56 // Keep static popup instances available for future pin clicks. 57 if (key === String(mapId)) { 58 delete infoWindows[key]; 59 } 60 } 61 } 62 }; 63 64 var clusterers = []; 65 var clustererReady = false; 66 var clustererReadyPromise = null; 67 68 var getMarkerClustererCtor = function () { 69 if (window.markerClusterer && window.markerClusterer.MarkerClusterer) { 70 return window.markerClusterer.MarkerClusterer; 71 } 72 if (window.MarkerClusterer) { 73 return window.MarkerClusterer; 74 } 75 return null; 76 }; 77 78 var syncClustererMarkers = function (mapId) { 79 var clusterer = clusterers[mapId], 80 mapMarkers, 81 i; 82 83 if (!clusterer || !markers.hasOwnProperty(mapId)) { 84 return; 85 } 86 87 mapMarkers = markers[mapId]; 88 clusterer.clearMarkers(); 89 90 for (i = 0; i < mapMarkers.length; i++) { 91 clusterer.addMarker(mapMarkers[i].marker); 92 } 93 }; 94 95 var clusterStyles = [ 96 { maxCount: 9, diameter: 34, fontSize: 13 }, 97 { maxCount: 24, diameter: 42, fontSize: 14 }, 98 { maxCount: 49, diameter: 50, fontSize: 15 }, 99 { maxCount: 99, diameter: 60, fontSize: 17 }, 100 { maxCount: Infinity, diameter: 72, fontSize: 18 } 101 ]; 102 103 var getClusterStyle = function (count) { 104 var i; 105 106 for (i = 0; i < clusterStyles.length; i++) { 107 if (count <= clusterStyles[i].maxCount) { 108 return clusterStyles[i]; 109 } 110 } 111 112 return clusterStyles[clusterStyles.length - 1]; 113 }; 114 115 var buildClusterRenderer = function () { 116 return { 117 render: function (cluster, stats) { 118 var count = cluster.count, 119 position = cluster.position, 120 style = getClusterStyle(count), 121 radius, 122 textY, 123 svg, 124 title; 125 126 radius = (style.diameter / 2) - 2.5; 127 textY = (style.diameter / 2) + 2; 128 129 svg = [ 130 '<svg xmlns="http://www.w3.org/2000/svg" width="' + style.diameter + '" height="' + style.diameter + '" viewBox="0 0 ' + style.diameter + ' ' + style.diameter + '">', 131 '<defs>', 132 '<filter id="clusterShadow" x="-20%" y="-20%" width="140%" height="140%">', 133 '<feDropShadow dx="0" dy="1" stdDeviation="1.5" flood-color="#000000" flood-opacity="0.18" />', 134 '</filter>', 135 '</defs>', 136 '<circle cx="' + (style.diameter / 2) + '" cy="' + (style.diameter / 2) + '" r="' + radiu
136s + '" fill="#475569" stroke="#ffffff" stroke-width="3" filter="url(#clusterShadow)" />', 137 '<text x="50%" y="' + textY + '" text-anchor="middle" dominant-baseline="middle" font-family="Arial, sans-serif" font-size="' + style.fontSize + '" font-weight="700" fill="#ffffff">', 138 String(count), 139 '</text>', 140 '</svg>' 141 ].join(""); 142 143 title = "Cluster of " + count + " markers"; 144 145 return new google.maps.Marker({ 146 position: position, 147 title: title, 148 zIndex: Number(google.maps.Marker.MAX_ZINDEX) + count, 149 icon: { 150 url: "data:image/svg+xml;charset=UTF-8," + encodeURIComponent(svg), 151 scaledSize: new google.maps.Size(style.diameter, style.diameter) 152 } 153 }); 154 } 155 }; 156 }; 157 158 getMapType = function (options) { 159 switch (options.mode) { 160 case 'Roadmap': { 161 return google.maps.MapTypeId.ROADMAP; 162 } 163 case 'Satellite': { 164 return google.maps.MapTypeId.SATELLITE; 165 } 166 case 'Hybrid':{ 167 return google.maps.MapTypeId.HYBRID; 168 } 169 default: { 170 return google.maps.MapTypeId.ROADMAP; 171 } 172 } 173 }; 174 175 createMarker = function(mapId, data) { 176 var marker; 177 //Added by Vijay - 10/09/2020 - Determine the Zoom based on the distance 178 var zoom = 12; 179 if (data.distance < 12) { 180 zoom = 15; 181 } 182 var map = maps[mapId]; 183 map.setZoom(zoom); 184 185 if (data.icon === null) { 186 marker = new google.maps.Marker({ 187 position: new google.maps.LatLng(data.latitude, data.longitude), 188 title: data.title 189 }); 190 } else { 191 marker = new google.maps.Marker({ 192 position: new google.maps.LatLng(data.latitude, data.longitude), 193 title: data.title, 194 icon: { 195 url: data.icon, 196 scaledSize: new google.maps.Size(customPoiIconSize, customPoiIconSize), 197 anchor: new google.maps.Point(customPoiIconSize / 2, customPoiIconSize / 2) 198 } 199 }); 200 } 201 //Added by Vijay - 10/09/2020 - Determine the Zoom based on the distance 202 // marker.addListener("click", () => { 203 // map.setZoom(zoom); 204 // map.setCenter(marker.getPosition()); 205 //}); 206 if (data.latitude === '' && data.longitude === '') { 207 //if marker doesn't have coordinated then create it but doesn't show it on the map 208 marker.setVisible(false); 209 } 210 211/******** Add By Donaldo Function AddCustomAnimation *****/ 212 /********* Start ***********/ 213 const Divmap = document.getElementById("search-map-urgent-care"); 214 if (Divmap) { 215 marker.setAnimation(google.maps.Animation.BOUNCE); 216 } 217 /********* End ***********/ 218 return marker; 219 }; 220 221 addMarker = function(mapId, marker, data) { 222 //save POI id - this will be used while removing dynamic POIs from the map 223 marker.id = data.id; 224 //Added by Vijay - 10/09/2020 - Determine the Zoom based on the distance 225 if (markers[mapId]) { 226 markers[mapId].push({ marker: marker, type: data.type, zoom: data.zoom }); 227 } else { 228 markers[mapId] = []; 229 markers[mapId].push({ marker: marker, type: data.type, zoom: data.zoom }); 230 } 231 232 if (clusterers[mapId]) { 233 clusterers[mapId].addMarker(marker); 234 } 235 }; 236 237 api.loadScript = function(key, callback) { 238 //save each callback and call them all when script will be loaded - protection for loading maps twice 239 callbacks.push(callback); 240 241 if (!loading) { 242 loading = true; 243 var script = document.createElement("script"),
244 src = "https://maps.googleapis.com/maps/api/js?v=3.exp"; 245 script.type = "text/javascript"; 246 if (typeof key !== "undefined" && key !== "") { 247 src += "&key=" + key + "&v=3.exp&signed_in=false"; 248 } else { 249 src += "&signed_in=false"; 250 } 251 src += "&libraries=places&callback=XA.connector.mapsConnector.scriptsLoaded"; 252 script.src = src; 253 script.onload = function () { 254 console.log("Google loader has been loaded, waiting for maps api"); 255 }; 256 document.body.appendChild(script); 257 258 // Clusterer script 259 clustererReadyPromise = new Promise(function(resolve, reject) { 260 var clustererScript = document.createElement("script"); 261 clustererScript.type = "text/javascript"; 262 clustererScript.src = "https://unpkg.com/@googlemaps/markerclusterer/dist/index.min.js"; 263 clustererScript.onload = function () { 264 clustererReady = true; 265 resolve(); 266 }; 267 clustererScript.onerror = reject; 268 document.body.appendChild(clustererScript); 269 }); 270 } 271 }; 272 273 api.scriptsLoaded = function () { 274 var i, length = callbacks.length; 275 for (i = 0; i < length; i++) { 276 callbacks[i].call(); 277 } 278 loading = false; 279 }; 280 281 api.showMap = function(mapId, options, viewBounds) { 282 var mapOptions, 283 listener, 284 idleListener, 285 scrollwheel = options.disableMapZoomOnScroll !== "1", 286 mapDragging = options.disableMapScrolling !== "1"; 287 288 if (viewBounds instanceof Array) { 289 mapOptions = { 290 zoom: options.zoom, 291 scrollwheel: scrollwheel, 292 draggable: mapDragging, 293 center: new google.maps.LatLng(viewBounds[0], viewBounds[1]), 294 mapTypeId: getMapType(options), 295 styles: [{ 296 featureType: 'poi.business', 297 stylers: [{ visibility: 'off' }], 298 },] 299 }; 300 map = new google.maps.Map(document.getElementById(options.canvasId), mapOptions); 301 } else { 302 mapOptions = { 303 scrollwheel: scrollwheel, 304 draggable: mapDragging, 305 mapTypeId: getMapType(options), 306 maxZoom: maxMapZoom, 307 styles: [{ 308 featureType: 'poi.business', 309 stylers: [{ visibility: 'off' }], 310 },] 311 }; 312 map = new google.maps.Map(document.getElementById(options.canvasId), mapOptions); 313 map.fitBounds(viewBounds); 314 if (options.poiCount < 2) { 315 idleListener = google.maps.event.addListener(map, "idle", function() { 316 if (Object.keys(markers).length > 0 && markers[mapId].length < 2) { 317 map.setZoom(options.zoom); 318 google.maps.event.removeListener(idleListener); 319 } 320 }); 321 } 322 } 323 324 listener = google.maps.event.addListener(map, "zoom_changed", function(a, b, c, d) { 325 var zoom = map.getZoom(); 326 327 // A hidden InfoWindow remains active while zooming. Close it so 328 // Google Maps cannot auto-pan back to it later. 329 closeInfoWindowsForMap(mapId); 330 331 if (zoom < 1) { 332 map.setZoom(1); 333 } 334 if (zoom > maxMapZoom) { 335 map.setZoom(maxMapZoom); 336 } 337 }); 338 339 maps[mapId] = map; 340 341 if (XA.connector.mapOverlapSpiderfy) { 342 XA.connector.mapOverlapSpiderfy.init(mapId, map); 343 } 344 345 var createClusterer = function () { 346 var MarkerClustererCtor = getMarkerClustererCtor(); 347 348 if (!MarkerClustererCtor) { 349 return; 350 } 351 352 clusterers[mapId] = new MarkerClustererCtor({ 353 map: maps[mapId], 354 markers: [], 355 renderer: buildClusterRenderer(), 356 onClusterClick: function (event, cluster, clusterMap) { 357 closeInfoWindowsForMap(mapId); 358 359 // Preserve the clusterer's normal behavior of zooming 360 // into the clicked cluster after closing the popup. 361 if (cluster.bounds) { 362 clusterMap.fitBounds(cluster.bounds); 363 } 364 } 365 }); 366 syncClustererMarkers(mapId); 367 }; 368 369 if (clustererReady) { 370 createClusterer(); 371 } else if (clustererReadyPromise) { 372 clustererReadyPromise.then(createClusterer); 373 } else { 374 createClusterer(); 375 } 376 }; 377 378 api.renderPoi = function(mapId, data) { 379 var marker = createMarker(mapId, data), 380 key = mapId + "#" + data.id; 381 382 addMarker(mapId, marker, data); 383 384 if (data.html !== "" && data.html !== null) { 385 infoWindows[key] = new google.maps.InfoWindow({ 386 content: data.html 387 }); 388 } 389 390 (function(currentKey, marker, poiData) { 391 var clickHandler = function() { 392 for (var key in infoWindows) { 393 if (infoWindows.hasOwnProperty(key)) { 394 infoWindows[key].close(); 395 } 396 } 397 398 notifyPoiClicked(mapId, poiData); 399 400 if (typeof infoWindows[currentKey] !== "undefined") { 401 activeInfoWindows[mapId] = infoWindows[currentKey]; 402 activeInfoWindows[mapId].open(maps[mapId], marker); 403 } 404 }; 405 406 if (XA.connector.mapOverlapSpiderfy && XA.connector.mapOverlapSpiderfy.registerMarker(mapId, marker, clickHandler)) { 407 return; 408 } 409 410 google.maps.event.addListener(marker, "click", clickHandler); 411 })(key, marker, data); 412 }; 413 414 api.renderDynamicPoi = function(mapId, data, getPoiContent) { 415 var marker = createMarker(mapId, data); 416 417 addMarker(mapId, marker, data); 418 419 var clickHandler = function () { 420 notifyPoiClicked(mapId, data); 421 422 if (typeof (getPoiContent) === "function") { 423 var poiId = data.id, 424 poiTypeId = data.poiTypeId, 425 poiVariantId = data.poiVariantId; 426 427 if (poiVariantId == null) { 428 return; 429 } 430 431 getPoiContent(poiId, poiTypeId, poiVariantId, function (result) { 432 if (popupGeneration !== popupGenerations[mapId]) { 433 return; 434 } 435 436 infoWindows[mapId] = new google.maps.InfoWindow({ 437 content: result.Html 438 }); 439 activeInfoWindows[mapId] = infoWindows[mapId]; 440 activeInfoWindows[mapId].open(maps[mapId], marker); 441 }); 442 } 443 }; 444 445 if (XA.connector.mapOverlapSpiderfy && XA.connector.mapOverlapSpiderfy.registerMarker(mapId, marker, clickHandler)) { 446 return; 447 } 448 449 google.maps.event.addListener(marker, "click", clickHandler); 450 }; 451 452 api.clearMarkers = function(mapId) { 453 var mapMarkers; 454 if (markers.hasOwnProperty(mapId)) { 455 mapMarkers = markers[mapId]; 456 for (var i = 0; i < mapMarkers.length; i++) { 457 if (mapMarkers[i].type === "Dynamic") { 458 if (XA.connector.mapOverlapSpiderfy) { 459 XA.connector.mapOverlapSpiderfy.unregisterMarker(mapId, mapMarkers[i].marker); 460 } 461 mapMarkers[i].marker.setMap(null); 462 } 463 } 464 markers[mapId] = mapMarkers.filter(function (markerData) { 465 if (markerData.type === "Static" || markerData.type === "MyLocation") { 466 return true; 467 } else { 468 return false;
469 } 470 }); 471 472 if (clusterers[mapId]) { 473 syncClustererMarkers(mapId); 474 } 475 } 476 }; 477 478 api.updateMapPosition = function (mapId) { 479 var map = maps[mapId], 480 marker, 481 mapMarkers = [], 482 bounds = new google.maps.LatLngBounds(), 483 i; 484 485 if (markers.hasOwnProperty(mapId)) { 486 mapMarkers = markers[mapId]; 487 } 488 489 // Keep the last map position when there are no markers to fit. 490 if (mapMarkers.length === 0) { 491 return; 492 } 493 494 for (i =0; i < mapMarkers.length; i++) { 495 marker = mapMarkers[i].marker; 496 bounds.extend(new google.maps.LatLng(marker.position.lat(), marker.position.lng())); 497 } 498 499 map.fitBounds(bounds); 500 }; 501 502 api.centerMap = function(mapId, data, centerMap, animate) { 503 var map = maps[mapId], 504 mapMarkers = [], 505 animatedMarker, 506 zoom, 507 targetZoom; 508 509 if (centerMap) { 510 map.setCenter(new google.maps.LatLng(data.coordinates[0], data.coordinates[1])); 511 } 512 513 if (animate) { 514 if (markers.hasOwnProperty(mapId)) { 515 mapMarkers = markers[mapId]; 516 } 517 for (var i = 0; i < mapMarkers.length; i++) { 518 mapMarkers[i].marker.setAnimation(null); 519 if (mapMarkers[i].marker.id === data.id) { 520 animatedMarker = mapMarkers[i].marker; 521 //Added by Vijay - 10/09/2020 - Determine the Zoom based on the distance 522 zoom = mapMarkers[i].zoom; 523 if (!clusterers[mapId]) { 524 mapMarkers[i].marker.setMap(null); 525 } 526 } 527 } 528 if (typeof animatedMarker !== "undefined") { 529 targetZoom = clusterers[mapId] ? maxMapZoom : zoom; 530 map.setCenter(animatedMarker.getPosition()); 531 map.setZoom(targetZoom); 532 animatedMarker.setAnimation(google.maps.Animation.BOUNCE); 533 animationTimeout = setTimeout(function () { 534 if (!clusterers[mapId]) { 535 animatedMarker.setMap(map); 536 } 537 }, 2000); 538 } 539 } 540 }; 541 542 api.getCentralPoint = function(poisCoords) { 543 var i, 544 poiCoords, 545 count = poisCoords.length, 546 bounds = new google.maps.LatLngBounds(); 547 548 for (i = 0; i < count; i++) { 549 poiCoords = poisCoords[i]; 550 if (poiCoords.latitude !== "" && poiCoords.longitude !== "") { 551 bounds.extend(new google.maps.LatLng(poiCoords.latitude, poiCoords.longitude)); 552 } 553 } 554 return bounds; 555 }; 556 557 // api.locationAutocomplete has been updated to be able to search location only in us. 558 // function updated at 11/12/2020 559 api.locationAutocomplete = function(queryParams, successCallback, failCallback){ 560 var autocomplete = new google.maps.places.AutocompleteService(), 561 maxResults = queryParams.maxResults <= 0 ? 1 : queryParams.maxResults; 562 autocomplete.getPlacePredictions({ 563 input: queryParams.text, 564 'componentRestrictions': { 565 'country': 'us' 566 }, 567 'types': ['geocode'] 568 }, function(results) { 569 var predictions = [], 570 length; 571 if (results != null && results.length) { 572 length = results.length >= maxResults ? maxResults : results.length; 573 574 for (var i = 0; i < length; i++) { 575 predictions.push(_.extend(results[i], { 576 text: results[i].description 577 })); 578 } 579 successCallback(predictions); 580 } else { 581 failCallback(); 582 } 583 }); 584 }; 585 586/* 587 api.locationAutocomplete = function(queryParams, successCallback, failCallback) { 588 var autocomplete = new google.maps.places.AutocompleteService(), 589 maxResults = queryParams.maxResults <= 0 ? 1 : queryParams.maxResults; 590 var bounds = new google.maps.LatLngBounds( 591 new google.maps.LatLng("32.204460", "-97.910215"), 592 new google.maps.LatLng("33.292131", "-96.428846")); 593 autocomplete.getQueryPredictions({ input: queryParams.text, bounds: boun
593ds }, function(results) { 594 var predictions = [], 595 length; 596 if (results != null && results.length) { 597 length = results.length >= maxResults ? maxResults : results.length; 598 599 for (var i = 0; i < length; i++) { 600 predictions.push(_.extend(results[i], { text: results[i].description })); 601 } 602 603 successCallback(predictions); 604 } else { 605 failCallback(); 606 } 607 }); 608 }; 609 610 */ 611 612 api.addressLookup = function (queryParams, successCallback, failCallback) { 613 var search, 614 query; 615 616 if(queryParams.hasOwnProperty("place_id")){ //places lookup 617 search = new google.maps.places.PlacesService(typeof map !== "undefined" ? map : new google.maps.Map(document.createElement("div"))); 618 search.getDetails({ 619 placeId : queryParams["place_id"] 620 }, function(results,status){ 621 if (status == google.maps.places.PlacesServiceStatus.OK) { 622 if(typeof(results) !== "undefined" && typeof(results.geometry.location) !== "undefined"){ 623 successCallback([results.geometry.location.lat(),results.geometry.location.lng()]); 624 return; 625 } 626 } 627 failCallback(); 628 }); 629 } 630 else { //standard lookup 631 var bounds = new google.maps.LatLngBounds( 632 new google.maps.LatLng("32.204460", "-97.910215"), 633 new google.maps.LatLng("33.292131", "-96.428846")); 634 query = { 635 address: queryParams.text, 636 bounds: bounds 637 }; 638 search = new google.maps.Geocoder(); 639 search.geocode(query, function(results,status){ 640 if (status == google.maps.GeocoderStatus.OK) { 641 if(typeof(results[0]) !== "undefined" && typeof(results[0].geometry.location) !== "undefined"){ 642 successCallback([results[0].geometry.location.lat(),results[0].geometry.location.lng()]); 643 return; 644 } 645 } 646 failCallback(); 647 }); 648 } 649 }; 650 651 api.updateMyPoiLocation = function(mapId, coordinates, zoom) { 652 var map = maps[mapId], 653 mapMarkers = [], 654 myLocationMarker; 655 656 if (markers.hasOwnProperty(mapId)) { 657 mapMarkers = markers[mapId]; 658 myLocationMarker = mapMarkers.filter(function (marker) { 659 if (marker.type === "MyLocation") { 660 return true; 661 } 662 return false; 663 }); 664 if (myLocationMarker.length > 0) { 665 myLocationMarker[0].marker.setPosition(new google.maps.LatLng(coordinates[0], coordinates[1])); 666 myLocationMarker[0].marker.setVisible(true); 667 this.updateMapPosition(mapId); 668 if (clusterers[mapId]) { 669 syncClustererMarkers(mapId); 670 } 671 if (typeof zoom !== "undefined") { 672 map.setZoom(zoom); 673 } 674 } 675 } 676 }; 677 678 return api; 679 680})(jQuery, document); 681 682 683/* map-overlap-spiderfy */ 684XA.connector.mapOverlapSpiderfy = (function (window, document) { 685 "use strict"; 686 687 var api = {}, 688 instances = {}, 689 mapListeners = {}, 690 libraryName = "OverlappingMarkerSpiderfier"; 691 692 function getInstance(mapId) { 693 return instances[mapId]; 694 } 695 696 function detachMapListeners(mapId) { 697 var listeners = mapListeners[mapId] || [], 698 i; 699 700 for (i = 0; i < listeners.length; i++) { 701 google.maps.event.removeListener(listeners[i]); 702 } 703 704 delete mapListeners[mapId]; 705 } 706 707 api.init = function (mapId, map) { 708 var instance, 709 listeners; 710 711 if (!map || typeof window[libraryName] !== "function") { 712 return null; 713 } 714 715 if (instances[mapId]) { 716 return instances[mapId]; 717 } 718 719 instance = new window[libraryName](map, { 720 nearbyDistance: 20, 721 keepSpiderfied: true, 722 ignoreMapClick: false, 723 markersWontMove: false, 724 markersWontHide: false 725 }); 726 727 listeners = [ 728 google.maps.event.addListener(map, "zoom_changed", function () { 729 instance.unspiderfy(); 730 }), 731 google.maps.event.addListener(map, "dragstart", function () { 732 instance.unspiderfy(); 733 }) 734 ]; 735 736 instances[mapId] = instance; 737 mapListeners[mapId] = listeners; 738 739 return instance; 740 }; 741 742 api.registerMarker = function (mapId, marker, clickHandler) { 743 var instance = getInstance(mapId); 744 745 if (!instance || !marker) { 746 return false;
747 } 748 749 // trackMarker deliberately does not call marker.setMap(). The existing 750 // MarkerClusterer must remain responsible for marker visibility. 751 // spider_click behaves normally for isolated markers and expands an 752 // overlapping group when necessary. 753 instance.trackMarker(marker, clickHandler); 754 return true; 755 }; 756 757 api.unregisterMarker = function (mapId, marker) { 758 var instance = getInstance(mapId); 759 760 if (instance && marker) { 761 instance.removeMarker(marker); 762 } 763 }; 764 765 api.collapse = function (mapId) { 766 var instance = getInstance(mapId); 767 768 if (instance) { 769 instance.unspiderfy(); 770 } 771 }; 772 773 api.destroy = function (mapId) { 774 var instance = getInstance(mapId); 775 776 if (instance) { 777 instance.removeAllMarkers(); 778 detachMapListeners(mapId); 779 delete instances[mapId]; 780 } 781 }; 782 783 return api; 784}(window, document)); 785 786 787/* overlapping-marker-spiderfier */ 788/* 789 OverlappingMarkerSpiderfier 790https://github.com/jawj/OverlappingMarkerSpiderfier 791Copyright (c) 2011 - 2017 George MacKerron 792Released under the MIT licence: http://opensource.org/licenses/mit-license 793Note: The Google Maps API v3 must be included *before* this code 794*/ 795(function(){var m,t,w,y,u,z={}.hasOwnProperty,A=[].slice;this.OverlappingMarkerSpiderfier=function(){function r(a,d){var b,f,e;this.map=a;null==d&&(d={});null==this.constructor.N&&(this.constructor.N=!0,h=google.maps,l=h.event,p=h.MapTypeId,c.keepSpiderfied=!1,c.ignoreMapClick=!1,c.markersWontHide=!1,c.markersWontMove=!1,c.basicFormatEvents=!1,c.nearbyDistance=20,c.circleSpiralSwitchover=9,c.circleFootSeparation=23,c.circleStartAngle=x/12,c.spiralFootSeparation=26,c.spiralLengthStart=11,c.spiralLengthFactor= 7964,c.spiderfiedZIndex=h.Marker.MAX_ZINDEX+2E4,c.highlightedLegZIndex=h.Marker.MAX_ZINDEX+1E4,c.usualLegZIndex=h.Marker.MAX_ZINDEX+1,c.legWeight=1.5,c.legColors={usual:{},highlighted:{}},e=c.legColors.usual,f=c.legColors.highlighted,e[p.HYBRID]=e[p.SATELLITE]="#fff",f[p.HYBRID]=f[p.SATELLITE]="#f00",e[p.TERRAIN]=e[p.ROADMAP]="#444",f[p.TERRAIN]=f[p.ROADMAP]="#f00",this.constructor.j=function(a){return this.setMap(a)},this.constructor.j.prototype=new h.OverlayView,this.constructor.j.prototype.draw=function(){}); 797for(b in d)z.call(d,b)&&(f=d[b],this[b]=f);this.g=new this.constructor.j(this.map);this.C();this.c={};this.B=this.l=null;this.addListener("click",function(a,b){return l.trigger(a,"spider_click",b)});this.addListener("format",function(a,b){return l.trigger(a,"spider_format",b)});this.ignoreMapClick||l.addListener(this.map,"click",function(a){return function(){return a.unspiderfy()}}(this));l.addListener(this.map,"maptypeid_changed",function(a){return function(){return a.unspiderfy()}}(this));l.addListener(this.map, 798"zoom_changed",function(a){return function(){a.unspiderfy();if(!a.basicFormatEvents)return a.h()}}(this))}var l,h,m,v,p,c,t,x,u;c=r.prototype;t=[r,c];m=0;for(v=t.length;m<v;m++)u=t[m],u.VERSION="1.0.3";x=2*Math.PI;h=l=p=null;r.markerStatus={SPIDERFIED:"SPIDERFIED",SPIDERFIABLE:"SPIDERFIABLE",UNSPIDERFIABLE:"UNSPIDERFIABLE",UNSPIDERFIED:"UNSPIDERFIED"};c.C=function(){this.a=[];this.s=[]};c.addMarker=function(a,d){a.setMap(this.map);return this.trackMarker(a,d)};c.trackMarker=function(a,d){var b;if(null!= 799a._oms)return this;a._oms=!0;b=[l.addListener(a,"click",function(b){return function(d){return b.V(a,d)}}(this))];this.markersWontHide||b.push(l.addListener(a,"visible_changed",function(b){return function(){return b.D(a,!1)}}(this)));this.markersWontMove||b.push(l.addListener(a,"position_changed",function(b){return function(){return b.D(a,!0)}}(this)));null!=d&&b.push(l.addListener(a,"spider_click",d));this.s.push(b);this.a.push(a);this.basicFormatEvents?this.trigger("format",a,this.constructor.markerStatus.UNSPIDERFIED): 800(this.trigger("format",a,this.constructor.markerStatus.UNSPIDERFIABLE),this.h());return this};c.D=function(a,d){if(!this.J&&!this.K)return null==a._omsData||!d&&a.getVisible()||this.unspiderfy(d?a:null),this.h()};c.getMarkers=function(){return this.a.slice(0)};c.removeMarker=function(a){this.forgetMarker(a);return a.setMap(null)};c.forgetMarker=function(a){var d,b,f,e,g;null!=a._omsData&&this.unspiderfy();d=this.A(this.a,a);if(0>d)return this;g=this.s.splice(d,1)[0];b=0;for(f=g.length;b<f;b++)e=g[b], 801l.removeListener(e);delete a._oms;this.a.splice(d,1);this.h();return this};c.removeAllMarkers=c.clearMarkers=function(){var a,d,b,f;f=this.getMarkers();this.forgetAllMarkers();a=0;for(d=f.length;a<d;a++)b=f[a],b.setMap(null);return this};c.forgetAllMarkers=function(){var a,d,b,f,e,g,c,q;this.unspiderfy();q=this.a;a=d=0;for(b=q.length;d<b;a=++d){g=q[a];e=this.s[a];c=0;for(a=e.length;c<a;c++)f=e[c],l.removeListener(f);delete g._oms}this.C();return this};c.addListener=function(a,d){var b;(null!=(b=this.c)[a]?
802b[a]:b[a]=[]).push(d);return this};c.removeListener=function(a,d){var b;b=this.A(this.c[a],d);0>b||this.c[a].splice(b,1);return this};c.clearListeners=function(a){this.c[a]=[];return this};c.trigger=function(){var a,d,b,f,e,g;d=arguments[0];a=2<=arguments.length?A.call(arguments,1):[];d=null!=(b=this.c[d])?b:[];g=[];f=0;for(e=d.length;f<e;f++)b=d[f],g.push(b.apply(null,a));return g};c.L=function(a,d){var b,f,e,g,c;g=this.circleFootSeparation*(2+a)/x;f=x/a;c=[];for(b=e=0;0<=a?e<a:e>a;b=0<=a?++e:--e)b= 803this.circleStartAngle+b*f,c.push(new h.Point(d.x+g*Math.cos(b),d.y+g*Math.sin(b)));return c};c.M=function(a,d){var b,f,e,c,k;c=this.spiralLengthStart;b=0;k=[];for(f=e=0;0<=a?e<a:e>a;f=0<=a?++e:--e)b+=this.spiralFootSeparation/c+5E-4*f,f=new h.Point(d.x+c*Math.cos(b),d.y+c*Math.sin(b)),c+=x*this.spiralLengthFactor/b,k.push(f);return k};c.V=function(a,d){var b,f,e,c,k,q,n,l,h;(q=null!=a._omsData)&&this.keepSpiderfied||this.unspiderfy();if(q||this.map.getStreetView().getVisible()||"GoogleEarthAPI"=== 804this.map.getMapTypeId())return this.trigger("click",a,d);q=[];n=[];b=this.nearbyDistance;l=b*b;k=this.f(a.position);h=this.a;b=0;for(f=h.length;b<f;b++)e=h[b],null!=e.map&&e.getVisible()&&(c=this.f(e.position),this.i(c,k)<l?q.push({R:e,G:c}):n.push(e));return 1===q.length?this.trigger("click",a,d):this.W(q,n)};c.markersNearMarker=function(a,d){var b,f,e,c,k,q,n,l,h,m;null==d&&(d=!1);if(null==this.g.getProjection())throw"Must wait for 'idle' event on map before calling markersNearMarker";b=this.nearbyDistance; 805n=b*b;k=this.f(a.position);q=[];l=this.a;b=0;for(f=l.length;b<f&&!(e=l[b],e!==a&&null!=e.map&&e.getVisible()&&(c=this.f(null!=(h=null!=(m=e._omsData)?m.v:void 0)?h:e.position),this.i(c,k)<n&&(q.push(e),d)));b++);return q};c.F=function(){var a,d,b,f,e,c,k,l,n,h,m;if(null==this.g.getProjection())throw"Must wait for 'idle' event on map before calling markersNearAnyOtherMarker";n=this.nearbyDistance;n*=n;var p;e=this.a;p=[];h=0;for(d=e.length;h<d;h++)f=e[h],p.push({H:this.f(null!=(a=null!=(b=f._omsData)? 806b.v:void 0)?a:f.position),b:!1});h=this.a;a=b=0;for(f=h.length;b<f;a=++b)if(d=h[a],null!=d.getMap()&&d.getVisible()&&(c=p[a],!c.b))for(m=this.a,d=l=0,e=m.length;l<e;d=++l)if(k=m[d],d!==a&&null!=k.getMap()&&k.getVisible()&&(k=p[d],(!(d<a)||k.b)&&this.i(c.H,k.H)<n)){c.b=k.b=!0;break}return p};c.markersNearAnyOtherMarker=function(){var a,d,b,c,e,g,k;e=this.F();g=this.a;k=[];a=d=0;for(b=g.length;d<b;a=++d)c=g[a],e[a].b&&k.push(c);return k};c.setImmediate=function(a){return window.setTimeout(a,0)};c.h= 807function(){if(!this.basicFormatEvents&&null==this.l)return this.l=this.setImmediate(function(a){return function(){a.l=null;return null!=a.g.getProjection()?a.w():null!=a.B?void 0:a.B=l.addListenerOnce(a.map,"idle",function(){return a.w()})}}(this))};c.w=function(){var a,d,b,c,e,g,k;if(this.basicFormatEvents){e=[];d=0;for(b=markers.length;d<b;d++)c=markers[d],a=null!=c._omsData?"SPIDERFIED":"UNSPIDERFIED",e.push(this.trigger("format",c,this.constructor.markerStatus[a]));return e}e=this.F();g=this.a; 808k=[];a=b=0;for(d=g.length;b<d;a=++b)c=g[a],a=null!=c._omsData?"SPIDERFIED":e[a].b?"SPIDERFIABLE":"UNSPIDERFIABLE",k.push(this.trigger("format",c,this.constructor.markerStatus[a]));return k};c.P=function(a){return{m:function(d){return function(){return a._omsData.o.setOptions({strokeColor:d.legColors.highlighted[d.map.mapTypeId],zIndex:d.highlightedLegZIndex})}}(this),u:function(d){return function(){return a._omsData.o.setOptions({strokeColor:d.legColors.usual[d.map.mapTypeId],zIndex:d.usualLegZIndex})}}(this)}}; 809c.W=function(a,d){var b,c,e,g,k,q,n,m,p,r;this.J=!0;r=a.length;b=this.T(function(){var b,d,c;c=[];b=0;for(d=a.length;b<d;b++)m=a[b],c.push(m.G);return c}());g=r>=this.circleSpiralSwitchover?this.M(r,b).reverse():this.L(r,b);b=function(){var b,d,f;f=[];
809b=0;for(d=g.length;b<d;b++)e=g[b],c=this.U(e),p=this.S(a,function(a){return function(b){return a.i(b.G,e)}}(this)),n=p.R,q=new h.Polyline({map:this.map,path:[n.position,c],strokeColor:this.legColors.usual[this.map.mapTypeId],strokeWeight:this.legWeight, 810zIndex:this.usualLegZIndex}),n._omsData={v:n.getPosition(),X:n.getZIndex(),o:q},this.legColors.highlighted[this.map.mapTypeId]!==this.legColors.usual[this.map.mapTypeId]&&(k=this.P(n),n._omsData.O={m:l.addListener(n,"mouseover",k.m),u:l.addListener(n,"mouseout",k.u)}),this.trigger("format",n,this.constructor.markerStatus.SPIDERFIED),n.setPosition(c),n.setZIndex(Math.round(this.spiderfiedZIndex+e.y)),f.push(n);return f}.call(this);delete this.J;this.I=!0;return this.trigger("spiderfy",b,d)};c.unspiderfy= 811function(a){var d,b,c,e,g,k,h;null==a&&(a=null);if(null==this.I)return this;this.K=!0;h=[];g=[];k=this.a;d=0;for(b=k.length;d<b;d++)e=k[d],null!=e._omsData?(e._omsData.o.setMap(null),e!==a&&e.setPosition(e._omsData.v),e.setZIndex(e._omsData.X),c=e._omsData.O,null!=c&&(l.removeListener(c.m),l.removeListener(c.u)),delete e._omsData,e!==a&&(c=this.basicFormatEvents?"UNSPIDERFIED":"SPIDERFIABLE",this.trigger("format",e,this.constructor.markerStatus[c])),h.push(e)):g.push(e);delete this.K;delete this.I; 812this.trigger("unspiderfy",h,g);return this};c.i=function(a,d){var b,c;b=a.x-d.x;c=a.y-d.y;return b*b+c*c};c.T=function(a){var c,b,f,e,g;c=e=g=0;for(b=a.length;c<b;c++)f=a[c],e+=f.x,g+=f.y;a=a.length;return new h.Point(e/a,g/a)};c.f=function(a){return this.g.getProjection().fromLatLngToDivPixel(a)};c.U=function(a){return this.g.getProjection().fromDivPixelToLatLng(a)};c.S=function(a,c){var b,d,e,g,k,h;e=k=0;for(h=a.length;k<h;e=++k)if(g=a[e],g=c(g),"undefined"===typeof b||null===b||g<d)d=g,b=e;return a.splice(b, 8131)[0]};c.A=function(a,c){var b,d,e,g;if(null!=a.indexOf)return a.indexOf(c);b=d=0;for(e=a.length;d<e;b=++d)if(g=a[b],g===c)return b;return-1};return r}();t=/(\?.*(&|&)|\?)spiderfier_callback=(\w+)/;m=document.currentScript;null==m&&(m=function(){var m,l,h,w,v;h=document.getElementsByTagName("script");v=[];m=0;for(l=h.length;m<l;m++)u=h[m],null!=(w=u.getAttribute("src"))&&w.match(t)&&v.push(u);return v}()[0]);if(null!=m&&(m=null!=(w=m.getAttribute("src"))?null!=(y=w.match(t))?y[3]:void 0:void 0)&& 814"function"===typeof window[m])window[m]();"function"===typeof window.spiderfier_callback&&window.spiderfier_callback()}).call(this); 815/* Thu 11 May 2017 09:00:27 BST */ 816 817
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.