vendor: 4,764 bytes, lines 1-168
1 2// ==ClosureCompiler== 3// @compilation_level ADVANCED_OPTIMIZATIONS 4// @externs_url http://closure-compiler.googlecode.com/svn/trunk/contrib/externs/maps/google_maps_api_v3_3.js 5// ==/ClosureCompiler== 6 7/** 8 * @name MarkerClusterer for Google Maps v3 9 * @version version 1.0 10 * @author Luke Mahe 11 * @fileoverview 12 * The library creates and manages per-zoom-level clusters for large amounts of 13 * markers. 14 * <br/> 15 * This is a v3 implementation of the 16 * <a href="http://gmaps-utility-library-dev.googlecode.com/svn/tags/markerclusterer/" 17 * >v2 MarkerClusterer</a>. 18 */ 19 20/** 21 * Licensed under the Apache License, Version 2.0 (the "License"); 22 * you may not use this file except in compliance with the License. 23 * You may obtain a copy of the License at 24 * 25 * http://www.apache.org/licenses/LICENSE-2.0 26 * 27 * Unless required by applicable law or agreed to in writing, software 28 * distributed under the License is distributed on an "AS IS" BASIS, 29 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 30 * See the License for the specific language governing permissions and 31 * limitations under the License. 32 */ 33 34 35/** 36 * A Marker Clusterer that clusters markers. 37 * 38 * @param {google.maps.Map} map The Google map to attach to. 39 * @param {Array.<google.maps.Marker>=} opt_markers Optional markers to add to 40 * the cluster. 41 * @param {Object=} opt_options support the following options: 42 * 'gridSize': (number) The grid size of a cluster in pixels. 43 * 'maxZoom': (number) The maximum zoom level that a marker can be part of a 44 * cluster. 45 * 'zoomOnClick': (boolean) Whether the default behaviour of clicking on a 46 * cluster is to zoom into it. 47 * 'averageCenter': (boolean) Wether the center of each cluster should be 48 * the average of all markers in the cluster. 49 * 'minimumClusterSize': (number) The minimum number of markers to be in a 50 * cluster before the markers are hidden and a count 51 * is shown. 52 * 'styles': (object) An object that has style properties: 53 * 'url': (string) The image url. 54 * 'height': (number) The image height. 55 * 'width': (number) The image width. 56 * 'anchor': (Array) The anchor position of the label text. 57 * 'textColor': (string) The text color. 58 * 'textSize': (number) The text size. 59 * 'backgroundPosition': (string) The position of the backgound x, y. 60 * @constructor 61 * @extends google.maps.OverlayView 62 * 63 * 64 * 65 * Modified by @lluisruscalleda 66 * 67 * personal icons , marker labels (need smart_info.js by Gary Little) 68 * 69 * 70 * 71 * 'styles': 72 * 'iconColor': (string) Icon color 73 * 74 * 75 * 76 */ 77function MarkerClusterer(map, opt_markers, opt_options) { 78 // MarkerClusterer implements google.maps.OverlayView interface. We use the 79 // extend function to extend MarkerClusterer with google.maps.OverlayView 80 // because it might not always be available when the code is defined so we 81 // look for it at the last possible moment. If it doesn't exist now then 82 // there is no point going ahead :) 83 this.extend(MarkerClusterer, google.maps.OverlayView); 84 this.map_ = map; 85 86 /** 87 * @type {Array.<google.maps.Marker>} 88 * @private 89 */ 90 this.markers_ = []; 91 92 /** 93 * @type {Array.<Cluster>} 94 */ 95 this.clusters_ = []; 96 97 this.sizes = [30, 33, 35, 45, 65]; 98 99 /** 100 * @private 101 */ 102 this.styles_ = []; 103 104 /** 105 * @type {boolean} 106 * @private 107 */ 108 this.ready_ = false; 109 110 var options = opt_options || {}; 111 112 /** 113 * @type {number} 114 * @private 115 */ 116 this.gridSize_ = options['gridSize'] || 60; 117 118 /** 119 * @private 120 */ 121 this.minClusterSize_ = options['minimumClusterSize'] || 2; 122 123 124 /** 125 * @type {?number} 126 * @private 127 */ 128 this.maxZoom_ = options['maxZoom'] || null; 129 130 this.iconStyle_ = options['iconStyle'][0] || null; 131 132 this.labels_ = options['labels'] || null; 133 /** 134 * @type {string} 135 * @private 136 */ 137 this.imagePath_ = options['imagePath'] || 138 this.MARKER_CLUSTER_IMAGE_PATH_; 139 140 /** 141 * @type {string} 142 * @private 143 */ 144 this.imageExtension_ = options['imageExtension'] || 145 this.MARKER_CLUSTER_IMAGE_EXTENSION_; 146 147 /** 148 * @type {boolean} 149 * @private 150 */ 151 this.zoomOnClick_ = true; 152 153 if (options['zoomOnClick'] != undefined) { 154 this.zoomOnClick_ = options['zoomOnClick']; 155 } 156 157 /** 158 * @type {boolean} 159 * @private 160 */ 161 this.averageCenter_ = false; 162 163 if (options['averageCenter'] != undefined) { 164 this.averageCenter_ = options['averageCenter']; 165 } 166 167 // this.setupStyles_(); 168
169 this.setMap(map); 170 171 /** 172 * @type {number} 173 * @private 174 */ 175 this.prevZoom_ = this.map_.getZoom(); 176 177 // Add the map event listeners 178 var that = this; 179 google.maps.event.addListener(this.map_, 'zoom_changed', function() { 180 var zoom = that.map_.getZoom(); 181 182 if (that.prevZoom_ != zoom) { 183 that.prevZoom_ = zoom; 184 that.resetViewport(); 185 } 186 }); 187 188 google.maps.event.addListener(this.map_, 'idle', function() { 189 that.redraw(); 190 }); 191 192 // Finally, add the markers 193 if (opt_markers && opt_markers.length) { 194 this.addMarkers(opt_markers, false); 195 } 196} 197 198 199/** 200 * The marker cluster image path. 201 * 202 * @type {string} 203 * @private 204 */ 205MarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_PATH_ = 206 '/js/mapas/img/map-icons-collection/numeric/white'; 207 208 209/** 210 * The marker cluster image path. 211 * 212 * @type {string} 213 * @private 214 */ 215MarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_EXTENSION_ = 'png'; 216 217 218/** 219 * Extends a objects prototype by anothers. 220 * 221 * @param {Object} obj1 The object to be extended. 222 * @param {Object} obj2 The object to extend with. 223 * @return {Object} The new extended object. 224 * @ignore 225 */ 226MarkerClusterer.prototype.extend = function(obj1, obj2) { 227 return (function(object) { 228 for (var property in object.prototype) { 229 this.prototype[property] = object.prototype[property]; 230 } 231 return this; 232 }).apply(obj1, [obj2]); 233}; 234 235 236/** 237 * Implementaion of the interface method. 238 * @ignore 239 */ 240MarkerClusterer.prototype.onAdd = function() { 241 this.setReady_(true); 242}; 243 244/** 245 * Implementaion of the interface method. 246 * @ignore 247 */ 248MarkerClusterer.prototype.draw = function() {}; 249 250/** 251 * Sets up the styles object. 252 * 253 * @private 254 */ 255/*MarkerClusterer.prototype.setupStyles_ = function() { 256 257 if (this.iconStyle) { 258 259 260 for (var i = 0, size; size = this.sizes[i]; i++) { 261 262 index = (i<=9)?"0"+i:i; 263 264 this.iconStyle['url'] = iconUrl + (index ) + '.' + this.imageExtension_; 265 alert(this.iconStyle['url']); 266 this.styles_.push(this.iconStyle); 267 268 } 269 270 271 return; 272 } 273 274 for (var i = 0, size; size = this.sizes[i]; i++) { 275 276 index = (i<=9)?"0"+i:i; 277 this.styles_.push({ 278 url: this.imagePath_ + (index ) + '.' + this.imageExtension_, 279 height: size, 280 width: size 281 }); 282 283 } 284};*/ 285 286/** 287 * Fit the map to the bounds of the markers in the clusterer. 288 */ 289MarkerClusterer.prototype.fitMapToMarkers = function() { 290 var markers = this.getMarkers(); 291 var bounds = new google.maps.LatLngBounds(); 292 for (var i = 0, marker; marker = markers[i]; i++) { 293 bounds.extend(marker.getPosition()); 294 } 295 296 this.map_.fitBounds(bounds); 297}; 298 299 300/** 301 * Gets the icon image extension . 302 * 303 * @return {String} The imageExtension string. 304 */ 305MarkerClusterer.prototype.getImageExtension = function() { 306 307 return this.imageExtension_; 308}; 309/** 310 * Sets the iconStyle. 311 * 312 * @param {Object} style The iconStyle to set. 313 */ 314MarkerClusterer.prototype.setIconStyle = function(iconStyle) { 315 this.iconStyle_ = iconStyle; 316}; 317 318 319/** 320 * Gets the iconStyle. 321 * 322 * @return {Object} The iconStyle object. 323 */ 324MarkerClusterer.prototype.getIconStyle = function() { 325 326 return this.iconStyle_; 327}; 328 329/** 330 * Sets the styles. 331 * 332 * @param {Object} styles The style to set. 333 */ 334MarkerClusterer.prototype.setStyles = function(styles) { 335 this.styles_ = styles; 336}; 337 338 339/** 340 * Gets the styles. 341 * 342 * @return {Object} The styles object. 343 */ 344MarkerClusterer.prototype.getStyles = function() { 345 346 return this.styles_; 347}; 348 349 350/** 351 * Whether zoom on click is set. 352 * 353 * @return {boolean} True if zoomOnClick_ is set. 354 */ 355MarkerClusterer.prototype.isZoomOnClick = function() { 356 return this.zoomOnClick_; 357}; 358 359/** 360 * Whether average center is set. 361 * 362 * @return {boolean} True if averageCenter_ is set. 363 */ 364MarkerClusterer.prototype.isAverageCenter = function() { 365 return this.averageCenter_; 366}; 367 368 369/** 370 * Returns the array of markers in the clusterer. 371 * 372 * @return {Array.<google.maps.Marker>} The markers. 373 */ 374MarkerClusterer.prototype.getMarkers = function() { 375 return this.markers_; 376}; 377 378 379/** 380 * Returns the number of markers in the clusterer 381 * 382 * @return {Number} The number of markers. 383 */ 384MarkerClusterer.prototype.getTotalMarkers = function() { 385 return this.markers_.length; 386}; 387 388 389/** 390 * Sets the max zoom for the clusterer. 391 * 392 * @param {number} maxZoom The max zoom level. 393 */ 394MarkerClusterer.prototype.setMaxZoom = function(maxZoom) { 395 this.maxZoom_ = maxZoom; 396}; 397 398 399/** 400 * Gets the max zoom for the clusterer. 401 * 402 * @return {number} The max zoom level. 403 */ 404MarkerClusterer.prototype.getMaxZoom = function() { 405 return this.maxZoom_; 406}; 407 408 409/** 410 * The function for calculating the cluster icon image. 411 * 412 * @param {Array.<google.maps.Marker>} markers The markers in the clusterer. 413 * @param {number} numStyles The number of styles available. 414 * @return {Object} A object properties: 'text' (string) and 'index' (number). 415 * @private 416 */ 417/*MarkerClusterer.prototype.calculator_ = function(markers, numStyles) { 418 419 var index = 0; 420 var count = markers.length; 421 var dv = count; 422 423 while (dv !== 0) { 424 dv = parseInt(dv / 10, 10); 425 index++; 426 427 } 428 429 index = Math.min(index, numStyles); 430 431 return { 432 text: count, 433 index: index 434 }; 435};*/ 436 437 438/** 439 * Set the calculator function. 440 * 441 * @param {function(Array, number)} calculator The function to set as the 442 * calculator. The function should return a object properties: 443 * 'text' (string) and 'index' (number). 444 * 445 */ 446/*MarkerClusterer.prototype.setCalculator = function(calculator) { 447 this.calculator_ = calculator; 448};*/ 449 450 451/** 452 * Get the calculator function. 453 * 454 * @return {function(Array, number)} the calculator function. 455 */ 456/*MarkerClusterer.prototype.getCalculator = function() { 457 return this.calculator_; 458};*/ 459 460 461/** 462 * Add an array of markers to the clusterer. 463 * 464 * @param {Array.<google.maps.Marker>} markers The markers to add. 465 * @param {boolean=}
465 opt_nodraw Whether to redraw the clusters. 466 */ 467MarkerClusterer.prototype.addMarkers = function(markers, opt_nodraw) { 468 for (var i = 0, marker; marker = markers[i]; i++) { 469 this.pushMarkerTo_(marker); 470 } 471 if (!opt_nodraw) { 472 this.redraw(); 473 } 474}; 475 476 477/** 478 * Pushes a marker to the clusterer. 479 * 480 * @param {google.maps.Marker} marker The marker to add. 481 * @private 482 */ 483MarkerClusterer.prototype.pushMarkerTo_ = function(marker) { 484 marker.isAdded = false; 485 if (marker['draggable']) { 486 // If the marker is draggable add a listener so we update the clusters on 487 // the drag end. 488 var that = this; 489 google.maps.event.addListener(marker, 'dragend', function() { 490 marker.isAdded = false; 491 that.repaint(); 492 }); 493 } 494 this.markers_.push(marker); 495}; 496 497 498/** 499 * Adds a marker to the clusterer and redraws if needed. 500 * 501 * @param {google.maps.Marker} marker The marker to add. 502 * @param {boolean=} opt_nodraw Whether to redraw the clusters. 503 */ 504MarkerClusterer.prototype.addMarker = function(marker, opt_nodraw) { 505 this.pushMarkerTo_(marker); 506 507 if (!opt_nodraw) { 508 this.redraw(); 509 } 510}; 511 512 513/** 514 * Removes a marker and returns true if removed, false if not 515 * 516 * @param {google.maps.Marker} marker The marker to remove 517 * @return {boolean} Whether the marker was removed or not 518 * @private 519 */ 520MarkerClusterer.prototype.removeMarker_ = function(marker) { 521 var index = -1; 522 if (this.markers_.indexOf) { 523 index = this.markers_.indexOf(marker); 524 } else { 525 for (var i = 0, m; m = this.markers_[i]; i++) { 526 if (m == marker) { 527 index = i; 528 break; 529 } 530 } 531 } 532 533 if (index == -1) { 534 // Marker is not in our list of markers. 535 return false; 536 } 537 538 marker.setMap(null); 539 540 this.markers_.splice(index, 1); 541 542 return true; 543}; 544 545 546/** 547 * Remove a marker from the cluster. 548 * 549 * @param {google.maps.Marker} marker The marker to remove. 550 * @param {boolean=} opt_nodraw Optional boolean to force no redraw. 551 * @return {boolean} True if the marker was removed. 552 */ 553MarkerClusterer.prototype.removeMarker = function(marker, opt_nodraw) { 554 var removed = this.removeMarker_(marker); 555 556 if (!opt_nodraw && removed) { 557 558 this.resetViewport(); 559 this.redraw(); 560 return true; 561 } else { 562 return false; 563 } 564}; 565 566 567/** 568 * Removes an array of markers from the cluster. 569 * 570 * @param {Array.<google.maps.Marker>} markers The markers to remove. 571 * @param {boolean=} opt_nodraw Optional boolean to force no redraw. 572 */ 573MarkerClusterer.prototype.removeMarkers = function(markers, opt_nodraw) { 574 var removed = false; 575 576 for (var i = 0, marker; marker = markers[i]; i++) { 577 var r = this.removeMarker_(marker); 578 removed = removed || r; 579 } 580 581 if (!opt_nodraw && removed) { 582 this.resetViewport(); 583 this.redraw(); 584 return true; 585 } 586}; 587 588 589/** 590 * Sets the clusterer's ready state. 591 * 592 * @param {boolean} ready The state. 593 * @private 594 */ 595MarkerClusterer.prototype.setReady_ = function(ready) { 596 if (!this.ready_) { 597 this.ready_ = ready; 598 this.createClusters_(); 599 } 600}; 601 602 603/** 604 * Returns the number of clusters in the clusterer. 605 * 606 * @return {number} The number of clusters. 607 */ 608MarkerClusterer.prototype.getTotalClusters = function() { 609 return this.clusters_.length; 610}; 611 612 613/** 614 * Returns the google map that the clusterer is associated with. 615 * 616 * @return {google.maps.Map} The map. 617 */ 618MarkerClusterer.prototype.getMap = function() { 619 return this.map_; 620}; 621 622 623/** 624 * Sets the google map that the clusterer is associated with. 625 * 626 * @param {google.maps.Map} map The map. 627 */ 628MarkerClusterer.prototype.setMap = function(map) { 629 this.map_ = map; 630}; 631 632 633/** 634 * Returns the size of the grid. 635 * 636 * @return {number} The grid size. 637 */ 638MarkerClusterer.prototype.getGridSize = function() { 639 return this.gridSize_; 640}; 641 642 643/** 644 * Sets the size of the grid. 645 * 646 * @param {number} size The grid size. 647 */ 648MarkerClusterer.prototype.setGridSize = function(size) { 649 this.gridSize_ = size; 650}; 651 652 653/** 654 * Returns the min cluster size. 655 * 656 * @return {number} The grid size. 657 */ 658MarkerClusterer.prototype.getMinClusterSize = function() { 659 return this.minClusterSize_; 660}; 661 662/** 663 * Sets the min cluster size. 664 * 665 * @param {number} size The grid size. 666 */ 667MarkerClusterer.prototype.setMinClusterSize = function(size) { 668 this.minClusterSize_ = size; 669}; 670 671 672/** 673 * Extends a bounds object by the grid size. 674 * 675 * @param {google.maps.LatLngBounds} bounds The bounds to extend. 676 * @return {google.maps.LatLngBounds}
676 The extended bounds. 677 */ 678MarkerClusterer.prototype.getExtendedBounds = function(bounds) { 679 var projection = this.getProjection(); 680 681 // Turn the bounds into latlng. 682 var tr = new google.maps.LatLng(bounds.getNorthEast().lat(), 683 bounds.getNorthEast().lng()); 684 var bl = new google.maps.LatLng(bounds.getSouthWest().lat(), 685 bounds.getSouthWest().lng()); 686 687 // Convert the points to pixels and the extend out by the grid size. 688 var trPix = projection.fromLatLngToDivPixel(tr); 689 trPix.x += this.gridSize_; 690 trPix.y -= this.gridSize_; 691 692 var blPix = projection.fromLatLngToDivPixel(bl); 693 blPix.x -= this.gridSize_; 694 blPix.y += this.gridSize_; 695 696 // Convert the pixel points back to LatLng 697 var ne = projection.fromDivPixelToLatLng(trPix); 698 var sw = projection.fromDivPixelToLatLng(blPix); 699 700 // Extend the bounds to contain the new bounds. 701 bounds.extend(ne); 702 bounds.extend(sw); 703 704 return bounds; 705}; 706 707 708/** 709 * Determins if a marker is contained in a bounds. 710 * 711 * @param {google.maps.Marker} marker The marker to check. 712 * @param {google.maps.LatLngBounds} bounds The bounds to check against. 713 * @return {boolean} True if the marker is in the bounds. 714 * @private 715 */ 716MarkerClusterer.prototype.isMarkerInBounds_ = function(marker, bounds) { 717 return bounds.contains(marker.getPosition()); 718}; 719 720 721/** 722 * Clears all clusters and markers from the clusterer. 723 */ 724MarkerClusterer.prototype.clearMarkers = function() { 725 this.resetViewport(true); 726 727 // Set the markers a empty array. 728 this.markers_ = []; 729}; 730 731 732/** 733 * Clears all existing clusters and recreates them. 734 * @param {boolean} opt_hide To also hide the marker. 735 */ 736MarkerClusterer.prototype.resetViewport = function(opt_hide) { 737 // Remove all the clusters 738 for (var i = 0, cluster; cluster = this.clusters_[i]; i++) { 739 cluster.remove(); 740 } 741 742 // Reset the markers to not be added and to be invisible. 743 for (var i = 0, marker; marker = this.markers_[i]; i++) { 744 marker.isAdded = false; 745 if (opt_hide) { 746 747 marker.setMap(null); 748 749 } 750 } 751 752 this.clusters_ = []; 753}; 754 755/** 756 * 757 */ 758MarkerClusterer.prototype.repaint = function() { 759 var oldClusters = this.clusters_.slice(); 760 this.clusters_.length = 0; 761 this.resetViewport(); 762 this.redraw(); 763 764 // Remove the old clusters. 765 // Do it in a timeout so the other clusters have been drawn first. 766 window.setTimeout(function() { 767 for (var i = 0, cluster; cluster = oldClusters[i]; i++) { 768 cluster.remove(); 769 } 770 }, 0); 771 772}; 773 774 775/** 776 * Redraws the clusters. 777 */ 778MarkerClusterer.prototype.redraw = function() { 779 780 this.createClusters_(); 781}; 782 783 784/** 785 * Calculates the distance between two latlng locations in km. 786 * @see http://www.movable-type.co.uk/scripts/latlong.html 787 * 788 * @param {google.maps.LatLng} p1 The first lat lng point. 789 * @param {google.maps.LatLng} p2 The second lat lng point. 790 * @return {number} The distance between the two points in km. 791 * @private 792*/ 793MarkerClusterer.prototype.distanceBetweenPoints_ = function(p1, p2) { 794 if (!p1 || !p2) { 795 return 0; 796 } 797 798 var R = 6371; // Radius of the Earth in km 799 var dLat = (p2.lat() - p1.lat()) * Math.PI / 180; 800 var dLon = (p2.lng() - p1.lng()) * Math.PI / 180; 801 var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + 802 Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) * 803 Math.sin(dLon / 2) * Math.sin(dLon / 2); 804 var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); 805 var d = R * c; 806 return d; 807}; 808 809 810/** 811 * Add a marker to a cluster, or creates a new cluster. 812 * 813 * @param {google.maps.Marker} marker The marker to add. 814 * @private 815 */ 816MarkerClusterer.prototype.addToClosestCluster_ = function(marker) { 817 818 var distance = 40000; // Some large number 819 var clusterToAddTo = null; 820 var pos = marker.getPosition(); 821 for (var i = 0, cluster; cluster = this.clusters_[i]; i++) { 822 var center = cluster.getCenter(); 823 if (center) { 824 var d = this.distanceBetweenPoints_(center, marker.getPosition()); 825 if (d < distance) { 826 distance = d; 827 clusterToAddTo = cluster; 828 } 829 } 830 } 831 832 if (clusterToAddTo && clusterToAddTo.isMarkerInClusterBounds(marker)) { 833 834 clusterToAddTo.addMarker(marker); 835 836 } else { 837 838 var cluster = new Cluster(this); 839 cluster.addMarker(marker);
840 this.clusters_.push(cluster); 841 842 } 843}; 844 845 846/** 847 * Creates the clusters. 848 * 849 * @private 850 */ 851MarkerClusterer.prototype.createClusters_ = function() { 852 if (!this.ready_) { 853 return; 854 } 855 856 // Get our current map view bounds. 857 // Create a new bounds object so we don't affect the map. 858 var mapBounds = new google.maps.LatLngBounds(this.map_.getBounds().getSouthWest(), 859 this.map_.getBounds().getNorthEast()); 860 var bounds = this.getExtendedBounds(mapBounds); 861 862 for (var i = 0, marker; marker = this.markers_[i]; i++) { 863 864 if (!marker.isAdded && this.isMarkerInBounds_(marker, bounds)) { 865 this.addToClosestCluster_(marker); 866 } 867 } 868}; 869 870 871/** 872 * A cluster that contains markers. 873 * 874 * @param {MarkerClusterer} markerClusterer The markerclusterer that this 875 * cluster is associated with. 876 * @constructor 877 * @ignore 878 */ 879function Cluster(markerClusterer) { 880 this.markerClusterer_ = markerClusterer; 881 this.map_ = markerClusterer.getMap(); 882 this.gridSize_ = markerClusterer.getGridSize(); 883 this.minClusterSize_ = markerClusterer.getMinClusterSize(); 884 this.averageCenter_ = markerClusterer.isAverageCenter(); 885 this.center_ = null; 886 this.markers_ = []; 887 this.bounds_ = null; 888 889 890 this.clusterIcon_ = new ClusterIcon(this, markerClusterer.getIconStyle(), 891 markerClusterer.getGridSize()); 892} 893 894/** 895 * Determins if a marker is already added to the cluster. 896 * 897 * @param {google.maps.Marker} marker The marker to check. 898 * @return {boolean} True if the marker is already added. 899 */ 900Cluster.prototype.isMarkerAlreadyAdded = function(marker) { 901 if (this.markers_.indexOf) { 902 return this.markers_.indexOf(marker) != -1; 903 } else { 904 for (var i = 0, m; m = this.markers_[i]; i++) { 905 if (m == marker) { 906 return true; 907 } 908 } 909 } 910 return false; 911}; 912 913 914/** 915 * Add a marker the cluster. 916 * 917 * @param {google.maps.Marker} marker The marker to add. 918 * @return {boolean} True if the marker was added. 919 */ 920Cluster.prototype.addMarker = function(marker) { 921 922 if (this.isMarkerAlreadyAdded(marker)) { 923 924 return false; 925 } 926 927 if (!this.center_) { 928 this.center_ = marker.getPosition(); 929 this.calculateBounds_(); 930 } else { 931 if (this.averageCenter_) { 932 var l = this.markers_.length + 1; 933 var lat = (this.center_.lat() * (l-1) + marker.getPosition().lat()) / l; 934 var lng = (this.center_.lng() * (l-1) + marker.getPosition().lng()) / l; 935 this.center_ = new google.maps.LatLng(lat, lng); 936 this.calculateBounds_(); 937 } 938 } 939 940 marker.isAdded = true; 941 this.markers_.push(marker); 942 943 var len = this.markers_.length; 944 if (len < this.minClusterSize_ && marker.getMap() != this.map_) { 945 // Min cluster size not reached so show the marker. 946 marker.setMap(this.map_); 947 948 //marker_labels 949 //marker['label'].open(this.map_); 950 } 951 952 if (len == this.minClusterSize_) { 953 // Hide the markers that were showing. 954 for (var i = 0; i < len; i++) { 955 this.markers_[i].setMap(null); 956 //this.toggleLabel(this.markers_[i]); 957 } 958 } 959 960 if (len >= this.minClusterSize_) { 961 marker.setMap(null); 962 } 963 964 965 this.updateIcon(); 966 967 968 return true; 969}; 970 971 972Cluster.prototype.toggleLabel = function(marker) { 973 if(marker.isHidden_){ 974 marker['label'].open(this.map_); 975 }else{ 976 marker['label'].close(); 977 } 978}; 979 980/** 981 * Returns the marker clusterer that the cluster is associated with. 982 * 983 * @return {MarkerClusterer} The associated marker clusterer. 984 */ 985Cluster.prototype.getMarkerClusterer = function() { 986 return this.markerClusterer_; 987}; 988 989 990/** 991 * Returns the bounds of the cluster. 992 * 993 * @return {google.maps.LatLngBounds} the cluster bounds. 994 */ 995Cluster.prototype.getBounds = function() { 996 var bounds = new google.maps.LatLngBounds(this.center_, this.center_); 997 var markers = this.getMarkers(); 998 for (var i = 0, marker; marker = markers[i]; i++) { 999 bounds.extend(marker.getPosition()); 1000 } 1001 return bounds; 1002}; 1003 1004 1005/** 1006 * Removes the cluster 1007 */ 1008Cluster.prototype.remove = function() { 1009 this.clusterIcon_.remove(); 1010 this.markers_.length = 0; 1011 delete this.markers_; 1012}; 1013 1014 1015/** 1016 * Returns the center of the cluster. 1017 * 1018 * @return {number} The cluster center.
1019 */ 1020Cluster.prototype.getSize = function() { 1021 return this.markers_.length; 1022}; 1023 1024 1025/** 1026 * Returns the center of the cluster. 1027 * 1028 * @return {Array.<google.maps.Marker>} The cluster center. 1029 */ 1030Cluster.prototype.getMarkers = function() { 1031 return this.markers_; 1032}; 1033 1034 1035/** 1036 * Returns the center of the cluster. 1037 * 1038 * @return {google.maps.LatLng} The cluster center. 1039 */ 1040Cluster.prototype.getCenter = function() { 1041 return this.center_; 1042}; 1043 1044 1045/** 1046 * Calculated the extended bounds of the cluster with the grid. 1047 * 1048 * @private 1049 */ 1050Cluster.prototype.calculateBounds_ = function() { 1051 var bounds = new google.maps.LatLngBounds(this.center_, this.center_); 1052 this.bounds_ = this.markerClusterer_.getExtendedBounds(bounds); 1053}; 1054 1055 1056/** 1057 * Determines if a marker lies in the clusters bounds. 1058 * 1059 * @param {google.maps.Marker} marker The marker to check. 1060 * @return {boolean} True if the marker lies in the bounds. 1061 */ 1062Cluster.prototype.isMarkerInClusterBounds = function(marker) { 1063 return this.bounds_.contains(marker.getPosition()); 1064}; 1065 1066 1067/** 1068 * Returns the map that the cluster is associated with. 1069 * 1070 * @return {google.maps.Map} The map. 1071 */ 1072Cluster.prototype.getMap = function() { 1073 return this.map_; 1074}; 1075 1076 1077/** 1078 * Updates the cluster icon 1079 */ 1080Cluster.prototype.updateIcon = function() { 1081 1082 for (var i = 0, marker; marker = this.markers_[i]; i++) { 1083 //marker_labels 1084 marker['label'].open(this.map_); 1085 } 1086 1087 1088 1089 var zoom = this.map_.getZoom(); 1090 var mz = this.markerClusterer_.getMaxZoom(); 1091 1092 if (mz && zoom > mz) { 1093 // The zoom is greater than our max zoom so show all the markers in cluster. 1094 for (var i = 0, marker; marker = this.markers_[i]; i++) { 1095 marker.setMap(this.map_); 1096 //marker_labels 1097 marker['label'].open(this.map_); 1098 } 1099 return; 1100 } 1101 1102 if (this.markers_.length < this.minClusterSize_) { 1103 // Min cluster size not yet reached. 1104 this.clusterIcon_.hide(); 1105 1106 return; 1107 } 1108 1109 //var numStyles = this.markerClusterer_.getStyles().length; 1110 //var sums = this.markerClusterer_.getCalculator()(this.markers_); 1111 this.clusterIcon_.setCenter(this.center_); 1112 this.clusterIcon_.setSums(this.markers_.length); 1113 this.clusterIcon_.show(); 1114 1115}; 1116 1117 1118/** 1119 * A cluster icon 1120 * 1121 * @param {Cluster} cluster The cluster to be associated with. 1122 * @param {Object} styles An object that has style properties: 1123 * 'url': (string) The image url. 1124 * 'height': (number) The image height. 1125 * 'width': (number) The image width. 1126 * 'anchor': (Array) The anchor position of the label text. 1127 * 'textColor': (string) The text color. 1128 * 'textSize': (number) The text size. 1129 * 'backgroundPosition: (string) The background postition x, y. 1130 * @param {number=} opt_padding Optional padding to apply to the cluster icon. 1131 * @constructor 1132 * @extends google.maps.OverlayView 1133 * @ignore 1134 */ 1135function ClusterIcon(cluster, style, opt_padding) { 1136 cluster.getMarkerClusterer().extend(ClusterIcon, google.maps.OverlayView); 1137 1138 this.style_ = style; 1139 this.padding_ = opt_padding || 0; 1140 this.cluster_ = cluster; 1141 this.center_ = null; 1142 this.map_ = cluster.getMap(); 1143 this.div_ = null; 1144 this.sums_ = null; 1145 this.visible_ = false; 1146 this.ibLabel_ = null; 1147 this.setMap(this.map_); 1148} 1149 1150 1151/** 1152 * Triggers the clusterclick event and zoom's if the option is set. 1153 */ 1154ClusterIcon.prototype.triggerClusterClick = function() { 1155 var markerClusterer = this.cluster_.getMarkerClusterer(); 1156 1157 // Trigger the clusterclick event. 1158 google.maps.event.trigger(markerClusterer, 'clusterclick', this.cluster_); 1159 1160 if (markerClusterer.isZoomOnClick()) { 1161 // Zoom into the cluster. 1162 this.map_.fitBounds(this.cluster_.getBounds()); 1163 } 1164}; 1165 1166 1167/* 1168* Creates a cluster label from DB 1169*/ 1170ClusterIcon.prototype.clusterLabel = function(){ 1171 // cluster label 1172 var that = this; 1173 var label_text = ""; 1174 var cluster_center = { 1175 'lat' : that.center_.lat() 1176 ,'lon' : that.center_.lng() 1177 }; 1178 1179 $.ajax({ 1180 url: "/Scripts/labelCluster", 1181 async:true, 1182 complete: function(objeto, exito){ 1183 if(exito=="success" && label_text != ""){ 1184 1185 var myOptions = { 1186 content: label_text 1187 ,classname: "info_marker_small" 1188 ,disableAutoPan: true 1189 ,pixelOffset: new google.maps.Size(-20, -50) 1190 ,position: that.center_ 1191 ,closeBoxURL: "" 1192 ,isHidden: false 1193 ,pane: "mapPane" 1194 ,enableEventPropagation: true 1195 ,boxStyle: { 1196 fontSize: "6pt" 1197 ,whiteSpace:"nowrap" 1198 ,textAlign: "center" 1199 } 1200 }; 1201 1202 that.ibLabel_ = new InfoBox(myOptions); 1203 that.ibLabel_.open(that.map_); 1204 1205 } 1206 }, 1207 contentType: "application/x-www-form-urlencoded", 1208 dataType: "text", 1209 error: function(objeto, quepaso, otroobj){ 1210 alert("Error: "+quepaso); 1211 }, 1212 global: true, 1213 ifModified: false, 1214 processData:true, 1215 success: function(label){ 1216 label_text = label; 1217 }, 1218 type: "POST", 1219 data: {cluster_center : cluster_center } 1220 }); 1221 1222}; 1223 1224/** 1225 * Adding the cluster icon to the dom. 1226 * @ignore 1227 */ 1228ClusterIcon.prototype.onAdd = function() { 1229 this.div_ = document.createElement('DIV'); 1230 if (this.visible_) { 1231 var pos = this.getPosFromLatLng_(this.center_); 1232 this.div_.style.cssText = this.createCss(pos); 1233 this.div_.innerHTML = this.sums_; 1234 1235 if(this.ibLabel_ == null){ 1236 //this.ibLabel_.close(); 1237 this.clusterLabel(); 1238 } 1239 1240 } 1241 1242 var panes = this.getPanes(); 1243 panes.overlayMouseTarget.appendChild(this.div_); 1244 1245 var that = this; 1246 google.maps.event.addDomListener(this.div_, 'click', function() { 1247 that.triggerClusterClick(); 1248 }); 1249}; 1250 1251 1252/** 1253 * Returns the position to place the div dending on the latlng. 1254 * 1255 * @param {google.maps.LatLng} latlng The position in latlng. 1256 * @return {google.maps.Point} The position in pixels. 1257 * @private 1258 */ 1259ClusterIcon.prototype.getPosFromLatLng_ = function(latlng) { 1260 var pos = this.getProjection().fromLatLngToDivPixel(latlng); 1261 pos.x -= parseInt(this.width_ / 2, 10); 1262 pos.y -= parseInt(this.height_ / 2, 10); 1263 return pos; 1264}; 1265 1266 1267/** 1268 * Draw the icon. 1269 * @ignore 1270 */ 1271ClusterIcon.prototype.draw = function() { 1272 if (this.visible_) { 1273 var pos = this.getPosFromLatLng_(this.center_); 1274 this.div_.style.top = ( pos.y - 20 ) + 'px'; 1275 this.div_.style.left = pos.x + 'px'; 1276 } 1277}; 1278 1279 1280/** 1281 * Hide the icon. 1282 */ 1283ClusterIcon.prototype.hide = function() { 1284 if (this.div_) { 1285 this.div_.style.display = 'none'; 1286 } 1287 this.visible_ = false; 1288}; 1289 1290 1291/** 1292 * Position and show the icon. 1293 */ 1294ClusterIcon.prototype.show = function() { 1295 if (this.div_) { 1296 var pos = this.getPosFromLatLng_(this.center_); 1297 this.div_.style.cssText = this.createCss(pos); 1298 this.div_.style.display = ''; 1299 } 1300 this.visible_ = true; 1301 1302 //marker_labels 1303 1304 for (var i = 0, marker; marker = this.cluster_.getMarkerClusterer().markers_[i]; i++) { 1305 if(!marker.getMap()){ 1306 1307 marker['label'].close(); 1308 } 1309 } 1310 1311}; 1312 1313 1314/** 1315 * Remove the icon from the map 1316 */ 1317ClusterIcon.prototype.remove = function() { 1318 //this.ibLabel_ = null; 1319 this.setMap(null); 1320}; 1321 1322 1323/** 1324 * Implementation of the onRemove interface. 1325 * @ignore 1326 */ 1327ClusterIcon.prototype.onRemove = function() { 1328 if (this.div_ && this.div_.parentNode) { 1329 this.hide(); 1330 this.div_.parentNode.removeChild(this.div_); 1331 this.div_ = null; 1332 } 1333}; 1334 1335 1336/** 1337 * Set the number of markers for the icon. 1338 * 1339 * @param {Number} sums 1340 */ 1341ClusterIcon.prototype.setSums = function(sums) { 1342 this.sums_ = sums; 1343 this.text_ = sums; 1344 1345 if (this.div_) { 1346 1347 this.div_.innerHTML = this.text_; 1348 } 1349 this.useStyle(); 1350}; 1351 1352 1353/** 1354 * Sets the icon to the the styles. 1355 */ 1356ClusterIcon.prototype.useStyle = function() { 1357 1358 var style = this.style_; 1359 1360 //numMarkers = (this.sums_<=9)?"0"+this.sums_:this.sums_; 1361 1362 iconUrl = style['url'] + '.' + this.cluster_.getMarkerClusterer().getImageExtension(); 1363 1364 this.url_ = iconUrl; 1365 this.height_ = style['height']; 1366 this.width_ = style['width']; 1367 this.textColor_ = style['textColor']; 1368 this.anchor_ = style['anchor'] || [0 , 0]; 1369 this.textSize_ = style['textSize']; 1370 this.backgroundPosition_ = style['backgroundPosition']; 1371 1372}; 1373 1374 1375/** 1376 * Sets the center of the icon. 1377 * 1378 * @param {google.maps.LatLng} center The latlng to set as the center.
1379 */ 1380ClusterIcon.prototype.setCenter = function(center) { 1381 this.center_ = center; 1382}; 1383 1384 1385/** 1386 * Create the css text based on the position of the icon. 1387 * 1388 * @param {google.maps.Point} pos The position. 1389 * @return {string} The css style text. 1390 */ 1391ClusterIcon.prototype.createCss = function(pos) { 1392 1393 1394 1395 var style = []; 1396 style.push('background-image:url(' + this.url_ + ');'); 1397 var backgroundPosition = this.backgroundPosition_ ? this.backgroundPosition_ : '0 0'; 1398 style.push('background-position:' + backgroundPosition + ';'); 1399 style.push('background-repeat:no-repeat;'); 1400 1401 1402 var lineheight = eval(this.height_+16); 1403 var posy = eval(pos.y-20); 1404 1405 // we don't use anchors 1406 if (typeof this.anchor_ === 'object') { 1407 if (typeof this.anchor_[0] === 'number' && this.anchor_[0] > 0 && 1408 this.anchor_[0] < this.height_) { 1409 style.push('height:' + (this.height_ - this.anchor_[0]) + 1410 'px; padding-top:' + this.anchor_[0] + 'px;'); 1411 } else { 1412 1413 style.push('height:' + this.height_ + 'px; line-height:' + lineheight + 1414 'px;'); 1415 } 1416 if (typeof this.anchor_[1] === 'number' && this.anchor_[1] > 0 && 1417 this.anchor_[1] < this.width_) { 1418 style.push('width:' + (this.width_ - this.anchor_[1]) + 1419 'px; padding-left:' + this.anchor_[1] + 'px;'); 1420 } else { 1421 style.push('width:' + this.width_ + 'px; text-align:center;'); 1422 } 1423 } else { 1424 1425 style.push('height:' + this.height_ + 'px; line-height:' + 1426 lineheight + 'px; width:' + this.width_ + 'px; text-align:center;'); 1427 } 1428 1429 var txtColor = this.textColor_ ? this.textColor_ : 'white'; 1430 var txtSize = this.textSize_ ? this.textSize_ : 11; 1431 1432 style.push('cursor:pointer; top:' + posy + 'px; left:' + 1433 pos.x + 'px; color:' + txtColor + '; position:absolute; font-size:' + 1434 txtSize + 'px; font-family:Arial,sans-serif; font-weight:bold'); 1435 return style.join(''); 1436 1437 1438}; 1439 1440 1441// Export Symbols for Closure 1442// If you are not going to compile with closure then you can remove the 1443// code below. 1444window['MarkerClusterer'] = MarkerClusterer; 1445MarkerClusterer.prototype['addMarker'] = MarkerClusterer.prototype.addMarker; 1446MarkerClusterer.prototype['addMarkers'] = MarkerClusterer.prototype.addMarkers; 1447MarkerClusterer.prototype['clearMarkers'] = 1448 MarkerClusterer.prototype.clearMarkers; 1449MarkerClusterer.prototype['fitMapToMarkers'] = 1450 MarkerClusterer.prototype.fitMapToMarkers; 1451MarkerClusterer.prototype['getCalculator'] = 1452 MarkerClusterer.prototype.getCalculator; 1453MarkerClusterer.prototype['getGridSize'] = 1454 MarkerClusterer.prototype.getGridSize; 1455MarkerClusterer.prototype['getExtendedBounds'] = 1456 MarkerClusterer.prototype.getExtendedBounds; 1457MarkerClusterer.prototype['getMap'] = MarkerClusterer.prototype.getMap; 1458MarkerClusterer.prototype['getMarkers'] = MarkerClusterer.prototype.getMarkers; 1459MarkerClusterer.prototype['getMaxZoom'] = MarkerClusterer.prototype.getMaxZoom; 1460MarkerClusterer.prototype['getStyles'] = MarkerClusterer.prototype.getStyles; 1461MarkerClusterer.prototype['getTotalClusters'] = 1462 MarkerClusterer.prototype.getTotalClusters; 1463MarkerClusterer.prototype['getTotalMarkers'] = 1464 MarkerClusterer.prototype.getTotalMarkers; 1465MarkerClusterer.prototype['redraw'] = MarkerClusterer.prototype.redraw; 1466MarkerClusterer.prototype['removeMarker'] = 1467 MarkerClusterer.prototype.removeMarker; 1468MarkerClusterer.prototype['removeMarkers'] = 1469 MarkerClusterer.prototype.removeMarkers; 1470MarkerClusterer.prototype['resetViewport'] = 1471 MarkerClusterer.prototype.resetViewport; 1472MarkerClusterer.prototype['repaint'] = 1473 MarkerClusterer.prototype.repaint; 1474MarkerClusterer.prototype['setCalculator'] = 1475 MarkerClusterer.prototype.setCalculator; 1476MarkerClusterer.prototype['setGridSize'] = 1477 MarkerClusterer.prototype.setGridSize; 1478MarkerClusterer.prototype['setMaxZoom'] = 1479 MarkerClusterer.prototype.setMaxZoom; 1480MarkerClusterer.prototype['onAdd'] = MarkerClusterer.prototype.onAdd; 1481MarkerClusterer.prototype['draw'] = MarkerClusterer.prototype.draw; 1482 1483Cluster.prototype['getCenter'] = Cluster.prototype.getCenter; 1484Cluster.prototype['getSize'] = Cluster.prototype.getSize; 1485Cluster.prototype['getMarkers'] = Cluster.prototype.getMarkers; 1486 1487ClusterIcon.prototype['onAdd'] = ClusterIcon.prototype.onAdd; 1488ClusterIcon.prototype['draw'] = ClusterIcon.prototype.draw; 1489ClusterIcon.prototype['onRemove'] = ClusterIcon.prototype.onRemove;
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.