{"version":3,"file":"markerclusterer.js","sources":["markerclusterer.js"],"sourcesContent":["// ==ClosureCompiler==\n// @compilation_level ADVANCED_OPTIMIZATIONS\n// @externs_url http://closure-compiler.googlecode.com/svn/trunk/contrib/externs/maps/google_maps_api_v3_3.js\n// ==/ClosureCompiler==\n\n/**\n * @name MarkerClusterer for Google Maps v3\n * @version version 1.0.1\n * @author Luke Mahe\n * @fileoverview\n * The library creates and manages per-zoom-level clusters for large amounts of\n * markers.\n * <br/>\n * This is a v3 implementation of the\n * <a href=\"http://gmaps-utility-library-dev.googlecode.com/svn/tags/markerclusterer/\"\n * >v2 MarkerClusterer</a>.\n */\n\n/**\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n/**\n * A Marker Clusterer that clusters markers.\n *\n * @param {google.maps.Map} map The Google map to attach to.\n * @param {Array.<google.maps.Marker>=} opt_markers Optional markers to add to\n *   the cluster.\n * @param {Object=} opt_options support the following options:\n *     'gridSize': (number) The grid size of a cluster in pixels.\n *     'maxZoom': (number) The maximum zoom level that a marker can be part of a\n *                cluster.\n *     'zoomOnClick': (boolean) Whether the default behaviour of clicking on a\n *                    cluster is to zoom into it.\n *     'averageCenter': (boolean) Wether the center of each cluster should be\n *                      the average of all markers in the cluster.\n *     'minimumClusterSize': (number) The minimum number of markers to be in a\n *                           cluster before the markers are hidden and a count\n *                           is shown.\n *     'styles': (object) An object that has style properties:\n *       'url': (string) The image url.\n *       'height': (number) The image height.\n *       'width': (number) The image width.\n *       'anchor': (Array) The anchor position of the label text.\n *       'textColor': (string) The text color.\n *       'textSize': (number) The text size.\n *       'backgroundPosition': (string) The position of the backgound x, y.\n * @constructor\n * @extends google.maps.OverlayView\n */\nfunction MarkerClusterer(map, opt_markers, opt_options) {\n  // MarkerClusterer implements google.maps.OverlayView interface. We use the\n  // extend function to extend MarkerClusterer with google.maps.OverlayView\n  // because it might not always be available when the code is defined so we\n  // look for it at the last possible moment. If it doesn't exist now then\n  // there is no point going ahead :)\n  this.extend(MarkerClusterer, google.maps.OverlayView);\n  this.map_ = map;\n\n  /**\n   * @type {Array.<google.maps.Marker>}\n   * @private\n   */\n  this.markers_ = [];\n\n  /**\n   *  @type {Array.<Cluster>}\n   */\n  this.clusters_ = [];\n\n  this.sizes = [53, 56, 66, 78, 90];\n\n  /**\n   * @private\n   */\n  this.styles_ = [];\n\n  /**\n   * @type {boolean}\n   * @private\n   */\n  this.ready_ = false;\n\n  var options = opt_options || {};\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.gridSize_ = options['gridSize'] || 60;\n\n  /**\n   * @private\n   */\n  this.minClusterSize_ = options['minimumClusterSize'] || 2;\n\n\n  /**\n   * @type {?number}\n   * @private\n   */\n  this.maxZoom_ = options['maxZoom'] || null;\n\n  this.styles_ = options['styles'] || [];\n\n  /**\n   * @type {string}\n   * @private\n   */\n  this.imagePath_ = options['imagePath'] ||\n      this.MARKER_CLUSTER_IMAGE_PATH_;\n\n  /**\n   * @type {string}\n   * @private\n   */\n  this.imageExtension_ = options['imageExtension'] ||\n      this.MARKER_CLUSTER_IMAGE_EXTENSION_;\n\n  /**\n   * @type {boolean}\n   * @private\n   */\n  this.zoomOnClick_ = true;\n\n  if (options['zoomOnClick'] != undefined) {\n    this.zoomOnClick_ = options['zoomOnClick'];\n  }\n\n  /**\n   * @type {boolean}\n   * @private\n   */\n  this.averageCenter_ = false;\n\n  if (options['averageCenter'] != undefined) {\n    this.averageCenter_ = options['averageCenter'];\n  }\n\n  this.setupStyles_();\n\n  this.setMap(map);\n\n  /**\n   * @type {number}\n   * @private\n   */\n  this.prevZoom_ = this.map_.getZoom();\n\n  // Add the map event listeners\n  var that = this;\n  google.maps.event.addListener(this.map_, 'zoom_changed', function() {\n    // Determines map type and prevent illegal zoom levels\n    var zoom = that.map_.getZoom();\n    var minZoom = that.map_.minZoom || 0;\n    var maxZoom = Math.min(that.map_.maxZoom || 100,\n                         that.map_.mapTypes[that.map_.getMapTypeId()].maxZoom);\n    zoom = Math.min(Math.max(zoom,minZoom),maxZoom);\n\n    if (that.prevZoom_ != zoom) {\n      that.prevZoom_ = zoom;\n      that.resetViewport();\n    }\n  });\n\n  google.maps.event.addListener(this.map_, 'idle', function() {\n    that.redraw();\n  });\n\n  // Finally, add the markers\n  if (opt_markers && (opt_markers.length || Object.keys(opt_markers).length)) {\n    this.addMarkers(opt_markers, false);\n  }\n}\n\n\n/**\n * The marker cluster image path.\n *\n * @type {string}\n * @private\n */\nMarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_PATH_ =\n    'http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclusterer/' +\n    'images/m';\n\n\n/**\n * The marker cluster image path.\n *\n * @type {string}\n * @private\n */\nMarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_EXTENSION_ = 'png';\n\n\n/**\n * Extends a objects prototype by anothers.\n *\n * @param {Object} obj1 The object to be extended.\n * @param {Object} obj2 The object to extend with.\n * @return {Object} The new extended object.\n * @ignore\n */\nMarkerClusterer.prototype.extend = function(obj1, obj2) {\n  return (function(object) {\n    for (var property in object.prototype) {\n      this.prototype[property] = object.prototype[property];\n    }\n    return this;\n  }).apply(obj1, [obj2]);\n};\n\n\n/**\n * Implementaion of the interface method.\n * @ignore\n */\nMarkerClusterer.prototype.onAdd = function() {\n  this.setReady_(true);\n};\n\n/**\n * Implementaion of the interface method.\n * @ignore\n */\nMarkerClusterer.prototype.draw = function() {};\n\n/**\n * Sets up the styles object.\n *\n * @private\n */\nMarkerClusterer.prototype.setupStyles_ = function() {\n  if (this.styles_.length) {\n    return;\n  }\n\n  for (var i = 0, size; size = this.sizes[i]; i++) {\n    this.styles_.push({\n      url: this.imagePath_ + (i + 1) + '.' + this.imageExtension_,\n      height: size,\n      width: size\n    });\n  }\n};\n\n/**\n *  Fit the map to the bounds of the markers in the clusterer.\n */\nMarkerClusterer.prototype.fitMapToMarkers = function() {\n  var markers = this.getMarkers();\n  var bounds = new google.maps.LatLngBounds();\n  for (var i = 0, marker; marker = markers[i]; i++) {\n    bounds.extend(marker.getPosition());\n  }\n\n  this.map_.fitBounds(bounds);\n};\n\n\n/**\n *  Sets the styles.\n *\n *  @param {Object} styles The style to set.\n */\nMarkerClusterer.prototype.setStyles = function(styles) {\n  this.styles_ = styles;\n};\n\n\n/**\n *  Gets the styles.\n *\n *  @return {Object} The styles object.\n */\nMarkerClusterer.prototype.getStyles = function() {\n  return this.styles_;\n};\n\n\n/**\n * Whether zoom on click is set.\n *\n * @return {boolean} True if zoomOnClick_ is set.\n */\nMarkerClusterer.prototype.isZoomOnClick = function() {\n  return this.zoomOnClick_;\n};\n\n/**\n * Whether average center is set.\n *\n * @return {boolean} True if averageCenter_ is set.\n */\nMarkerClusterer.prototype.isAverageCenter = function() {\n  return this.averageCenter_;\n};\n\n\n/**\n *  Returns the array of markers in the clusterer.\n *\n *  @return {Array.<google.maps.Marker>} The markers.\n */\nMarkerClusterer.prototype.getMarkers = function() {\n  return this.markers_;\n};\n\n\n/**\n *  Returns the number of markers in the clusterer\n *\n *  @return {Number} The number of markers.\n */\nMarkerClusterer.prototype.getTotalMarkers = function() {\n  return this.markers_.length;\n};\n\n\n/**\n *  Sets the max zoom for the clusterer.\n *\n *  @param {number} maxZoom The max zoom level.\n */\nMarkerClusterer.prototype.setMaxZoom = function(maxZoom) {\n  this.maxZoom_ = maxZoom;\n};\n\n\n/**\n *  Gets the max zoom for the clusterer.\n *\n *  @return {number} The max zoom level.\n */\nMarkerClusterer.prototype.getMaxZoom = function() {\n  return this.maxZoom_;\n};\n\n\n/**\n *  The function for calculating the cluster icon image.\n *\n *  @param {Array.<google.maps.Marker>} markers The markers in the clusterer.\n *  @param {number} numStyles The number of styles available.\n *  @return {Object} A object properties: 'text' (string) and 'index' (number).\n *  @private\n */\nMarkerClusterer.prototype.calculator_ = function(markers, numStyles) {\n  var index = 0;\n  var count = markers.length;\n  var dv = count;\n  while (dv !== 0) {\n    dv = parseInt(dv / 10, 10);\n    index++;\n  }\n\n  index = Math.min(index, numStyles);\n  return {\n    text: count,\n    index: index\n  };\n};\n\n\n/**\n * Set the calculator function.\n *\n * @param {function(Array, number)} calculator The function to set as the\n *     calculator. The function should return a object properties:\n *     'text' (string) and 'index' (number).\n *\n */\nMarkerClusterer.prototype.setCalculator = function(calculator) {\n  this.calculator_ = calculator;\n};\n\n\n/**\n * Get the calculator function.\n *\n * @return {function(Array, number)} the calculator function.\n */\nMarkerClusterer.prototype.getCalculator = function() {\n  return this.calculator_;\n};\n\n\n/**\n * Add an array of markers to the clusterer.\n *\n * @param {Array.<google.maps.Marker>} markers The markers to add.\n * @param {boolean=} opt_nodraw Whether to redraw the clusters.\n */\nMarkerClusterer.prototype.addMarkers = function(markers, opt_nodraw) {\n  if (markers.length) {\n    for (var i = 0, marker; marker = markers[i]; i++) {\n      this.pushMarkerTo_(marker);\n    }\n  } else if (Object.keys(markers).length) {\n    for (var marker in markers) {\n      this.pushMarkerTo_(markers[marker]);\n    }\n  }\n  if (!opt_nodraw) {\n    this.redraw();\n  }\n};\n\n\n/**\n * Pushes a marker to the clusterer.\n *\n * @param {google.maps.Marker} marker The marker to add.\n * @private\n */\nMarkerClusterer.prototype.pushMarkerTo_ = function(marker) {\n  marker.isAdded = false;\n  if (marker['draggable']) {\n    // If the marker is draggable add a listener so we update the clusters on\n    // the drag end.\n    var that = this;\n    google.maps.event.addListener(marker, 'dragend', function() {\n      marker.isAdded = false;\n      that.repaint();\n    });\n  }\n  this.markers_.push(marker);\n};\n\n\n/**\n * Adds a marker to the clusterer and redraws if needed.\n *\n * @param {google.maps.Marker} marker The marker to add.\n * @param {boolean=} opt_nodraw Whether to redraw the clusters.\n */\nMarkerClusterer.prototype.addMarker = function(marker, opt_nodraw) {\n  this.pushMarkerTo_(marker);\n  if (!opt_nodraw) {\n    this.redraw();\n  }\n};\n\n\n/**\n * Removes a marker and returns true if removed, false if not\n *\n * @param {google.maps.Marker} marker The marker to remove\n * @return {boolean} Whether the marker was removed or not\n * @private\n */\nMarkerClusterer.prototype.removeMarker_ = function(marker) {\n  var index = -1;\n  if (this.markers_.indexOf) {\n    index = this.markers_.indexOf(marker);\n  } else {\n    for (var i = 0, m; m = this.markers_[i]; i++) {\n      if (m == marker) {\n        index = i;\n        break;\n      }\n    }\n  }\n\n  if (index == -1) {\n    // Marker is not in our list of markers.\n    return false;\n  }\n\n  marker.setMap(null);\n\n  this.markers_.splice(index, 1);\n\n  return true;\n};\n\n\n/**\n * Remove a marker from the cluster.\n *\n * @param {google.maps.Marker} marker The marker to remove.\n * @param {boolean=} opt_nodraw Optional boolean to force no redraw.\n * @return {boolean} True if the marker was removed.\n */\nMarkerClusterer.prototype.removeMarker = function(marker, opt_nodraw) {\n  var removed = this.removeMarker_(marker);\n\n  if (!opt_nodraw && removed) {\n    this.resetViewport();\n    this.redraw();\n    return true;\n  } else {\n   return false;\n  }\n};\n\n\n/**\n * Removes an array of markers from the cluster.\n *\n * @param {Array.<google.maps.Marker>} markers The markers to remove.\n * @param {boolean=} opt_nodraw Optional boolean to force no redraw.\n */\nMarkerClusterer.prototype.removeMarkers = function(markers, opt_nodraw) {\n  var removed = false;\n\n  for (var i = 0, marker; marker = markers[i]; i++) {\n    var r = this.removeMarker_(marker);\n    removed = removed || r;\n  }\n\n  if (!opt_nodraw && removed) {\n    this.resetViewport();\n    this.redraw();\n    return true;\n  }\n};\n\n\n/**\n * Sets the clusterer's ready state.\n *\n * @param {boolean} ready The state.\n * @private\n */\nMarkerClusterer.prototype.setReady_ = function(ready) {\n  if (!this.ready_) {\n    this.ready_ = ready;\n    this.createClusters_();\n  }\n};\n\n\n/**\n * Returns the number of clusters in the clusterer.\n *\n * @return {number} The number of clusters.\n */\nMarkerClusterer.prototype.getTotalClusters = function() {\n  return this.clusters_.length;\n};\n\n\n/**\n * Returns the google map that the clusterer is associated with.\n *\n * @return {google.maps.Map} The map.\n */\nMarkerClusterer.prototype.getMap = function() {\n  return this.map_;\n};\n\n\n/**\n * Sets the google map that the clusterer is associated with.\n *\n * @param {google.maps.Map} map The map.\n */\nMarkerClusterer.prototype.setMap = function(map) {\n  this.map_ = map;\n};\n\n\n/**\n * Returns the size of the grid.\n *\n * @return {number} The grid size.\n */\nMarkerClusterer.prototype.getGridSize = function() {\n  return this.gridSize_;\n};\n\n\n/**\n * Sets the size of the grid.\n *\n * @param {number} size The grid size.\n */\nMarkerClusterer.prototype.setGridSize = function(size) {\n  this.gridSize_ = size;\n};\n\n\n/**\n * Returns the min cluster size.\n *\n * @return {number} The grid size.\n */\nMarkerClusterer.prototype.getMinClusterSize = function() {\n  return this.minClusterSize_;\n};\n\n/**\n * Sets the min cluster size.\n *\n * @param {number} size The grid size.\n */\nMarkerClusterer.prototype.setMinClusterSize = function(size) {\n  this.minClusterSize_ = size;\n};\n\n\n/**\n * Extends a bounds object by the grid size.\n *\n * @param {google.maps.LatLngBounds} bounds The bounds to extend.\n * @return {google.maps.LatLngBounds} The extended bounds.\n */\nMarkerClusterer.prototype.getExtendedBounds = function(bounds) {\n  var projection = this.getProjection();\n\n  // Turn the bounds into latlng.\n  var tr = new google.maps.LatLng(bounds.getNorthEast().lat(),\n      bounds.getNorthEast().lng());\n  var bl = new google.maps.LatLng(bounds.getSouthWest().lat(),\n      bounds.getSouthWest().lng());\n\n  // Convert the points to pixels and the extend out by the grid size.\n  var trPix = projection.fromLatLngToDivPixel(tr);\n  trPix.x += this.gridSize_;\n  trPix.y -= this.gridSize_;\n\n  var blPix = projection.fromLatLngToDivPixel(bl);\n  blPix.x -= this.gridSize_;\n  blPix.y += this.gridSize_;\n\n  // Convert the pixel points back to LatLng\n  var ne = projection.fromDivPixelToLatLng(trPix);\n  var sw = projection.fromDivPixelToLatLng(blPix);\n\n  // Extend the bounds to contain the new bounds.\n  bounds.extend(ne);\n  bounds.extend(sw);\n\n  return bounds;\n};\n\n\n/**\n * Determins if a marker is contained in a bounds.\n *\n * @param {google.maps.Marker} marker The marker to check.\n * @param {google.maps.LatLngBounds} bounds The bounds to check against.\n * @return {boolean} True if the marker is in the bounds.\n * @private\n */\nMarkerClusterer.prototype.isMarkerInBounds_ = function(marker, bounds) {\n  return bounds.contains(marker.getPosition());\n};\n\n\n/**\n * Clears all clusters and markers from the clusterer.\n */\nMarkerClusterer.prototype.clearMarkers = function() {\n  this.resetViewport(true);\n\n  // Set the markers a empty array.\n  this.markers_ = [];\n};\n\n\n/**\n * Clears all existing clusters and recreates them.\n * @param {boolean} opt_hide To also hide the marker.\n */\nMarkerClusterer.prototype.resetViewport = function(opt_hide) {\n  // Remove all the clusters\n  for (var i = 0, cluster; cluster = this.clusters_[i]; i++) {\n    cluster.remove();\n  }\n\n  // Reset the markers to not be added and to be invisible.\n  for (var i = 0, marker; marker = this.markers_[i]; i++) {\n    marker.isAdded = false;\n    if (opt_hide) {\n      marker.setMap(null);\n    }\n  }\n\n  this.clusters_ = [];\n};\n\n/**\n *\n */\nMarkerClusterer.prototype.repaint = function() {\n  var oldClusters = this.clusters_.slice();\n  this.clusters_.length = 0;\n  this.resetViewport();\n  this.redraw();\n\n  // Remove the old clusters.\n  // Do it in a timeout so the other clusters have been drawn first.\n  window.setTimeout(function() {\n    for (var i = 0, cluster; cluster = oldClusters[i]; i++) {\n      cluster.remove();\n    }\n  }, 0);\n};\n\n\n/**\n * Redraws the clusters.\n */\nMarkerClusterer.prototype.redraw = function() {\n  this.createClusters_();\n};\n\n\n/**\n * Calculates the distance between two latlng locations in km.\n * @see http://www.movable-type.co.uk/scripts/latlong.html\n *\n * @param {google.maps.LatLng} p1 The first lat lng point.\n * @param {google.maps.LatLng} p2 The second lat lng point.\n * @return {number} The distance between the two points in km.\n * @private\n*/\nMarkerClusterer.prototype.distanceBetweenPoints_ = function(p1, p2) {\n  if (!p1 || !p2) {\n    return 0;\n  }\n\n  var R = 6371; // Radius of the Earth in km\n  var dLat = (p2.lat() - p1.lat()) * Math.PI / 180;\n  var dLon = (p2.lng() - p1.lng()) * Math.PI / 180;\n  var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +\n    Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) *\n    Math.sin(dLon / 2) * Math.sin(dLon / 2);\n  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n  var d = R * c;\n  return d;\n};\n\n\n/**\n * Add a marker to a cluster, or creates a new cluster.\n *\n * @param {google.maps.Marker} marker The marker to add.\n * @private\n */\nMarkerClusterer.prototype.addToClosestCluster_ = function(marker) {\n  var distance = 40000; // Some large number\n  var clusterToAddTo = null;\n  var pos = marker.getPosition();\n  for (var i = 0, cluster; cluster = this.clusters_[i]; i++) {\n    var center = cluster.getCenter();\n    if (center) {\n      var d = this.distanceBetweenPoints_(center, marker.getPosition());\n      if (d < distance) {\n        distance = d;\n        clusterToAddTo = cluster;\n      }\n    }\n  }\n\n  if (clusterToAddTo && clusterToAddTo.isMarkerInClusterBounds(marker)) {\n    clusterToAddTo.addMarker(marker);\n  } else {\n    var cluster = new Cluster(this);\n    cluster.addMarker(marker);\n    this.clusters_.push(cluster);\n  }\n};\n\n\n/**\n * Creates the clusters.\n *\n * @private\n */\nMarkerClusterer.prototype.createClusters_ = function() {\n  if (!this.ready_) {\n    return;\n  }\n\n  // Get our current map view bounds.\n  // Create a new bounds object so we don't affect the map.\n  var mapBounds = new google.maps.LatLngBounds(this.map_.getBounds().getSouthWest(),\n      this.map_.getBounds().getNorthEast());\n  var bounds = this.getExtendedBounds(mapBounds);\n\n  for (var i = 0, marker; marker = this.markers_[i]; i++) {\n    if (!marker.isAdded && this.isMarkerInBounds_(marker, bounds)) {\n      this.addToClosestCluster_(marker);\n    }\n  }\n};\n\n\n/**\n * A cluster that contains markers.\n *\n * @param {MarkerClusterer} markerClusterer The markerclusterer that this\n *     cluster is associated with.\n * @constructor\n * @ignore\n */\nfunction Cluster(markerClusterer) {\n  this.markerClusterer_ = markerClusterer;\n  this.map_ = markerClusterer.getMap();\n  this.gridSize_ = markerClusterer.getGridSize();\n  this.minClusterSize_ = markerClusterer.getMinClusterSize();\n  this.averageCenter_ = markerClusterer.isAverageCenter();\n  this.center_ = null;\n  this.markers_ = [];\n  this.bounds_ = null;\n  this.clusterIcon_ = new ClusterIcon(this, markerClusterer.getStyles(),\n      markerClusterer.getGridSize());\n}\n\n/**\n * Determins if a marker is already added to the cluster.\n *\n * @param {google.maps.Marker} marker The marker to check.\n * @return {boolean} True if the marker is already added.\n */\nCluster.prototype.isMarkerAlreadyAdded = function(marker) {\n  if (this.markers_.indexOf) {\n    return this.markers_.indexOf(marker) != -1;\n  } else {\n    for (var i = 0, m; m = this.markers_[i]; i++) {\n      if (m == marker) {\n        return true;\n      }\n    }\n  }\n  return false;\n};\n\n\n/**\n * Add a marker the cluster.\n *\n * @param {google.maps.Marker} marker The marker to add.\n * @return {boolean} True if the marker was added.\n */\nCluster.prototype.addMarker = function(marker) {\n  if (this.isMarkerAlreadyAdded(marker)) {\n    return false;\n  }\n\n  if (!this.center_) {\n    this.center_ = marker.getPosition();\n    this.calculateBounds_();\n  } else {\n    if (this.averageCenter_) {\n      var l = this.markers_.length + 1;\n      var lat = (this.center_.lat() * (l-1) + marker.getPosition().lat()) / l;\n      var lng = (this.center_.lng() * (l-1) + marker.getPosition().lng()) / l;\n      this.center_ = new google.maps.LatLng(lat, lng);\n      this.calculateBounds_();\n    }\n  }\n\n  marker.isAdded = true;\n  this.markers_.push(marker);\n\n  var len = this.markers_.length;\n  if (len < this.minClusterSize_ && marker.getMap() != this.map_) {\n    // Min cluster size not reached so show the marker.\n    marker.setMap(this.map_);\n  }\n\n  if (len == this.minClusterSize_) {\n    // Hide the markers that were showing.\n    for (var i = 0; i < len; i++) {\n      this.markers_[i].setMap(null);\n    }\n  }\n\n  if (len >= this.minClusterSize_) {\n    marker.setMap(null);\n  }\n\n  this.updateIcon();\n  return true;\n};\n\n\n/**\n * Returns the marker clusterer that the cluster is associated with.\n *\n * @return {MarkerClusterer} The associated marker clusterer.\n */\nCluster.prototype.getMarkerClusterer = function() {\n  return this.markerClusterer_;\n};\n\n\n/**\n * Returns the bounds of the cluster.\n *\n * @return {google.maps.LatLngBounds} the cluster bounds.\n */\nCluster.prototype.getBounds = function() {\n  var bounds = new google.maps.LatLngBounds(this.center_, this.center_);\n  var markers = this.getMarkers();\n  for (var i = 0, marker; marker = markers[i]; i++) {\n    bounds.extend(marker.getPosition());\n  }\n  return bounds;\n};\n\n\n/**\n * Removes the cluster\n */\nCluster.prototype.remove = function() {\n  this.clusterIcon_.remove();\n  this.markers_.length = 0;\n  delete this.markers_;\n};\n\n\n/**\n * Returns the center of the cluster.\n *\n * @return {number} The cluster center.\n */\nCluster.prototype.getSize = function() {\n  return this.markers_.length;\n};\n\n\n/**\n * Returns the center of the cluster.\n *\n * @return {Array.<google.maps.Marker>} The cluster center.\n */\nCluster.prototype.getMarkers = function() {\n  return this.markers_;\n};\n\n\n/**\n * Returns the center of the cluster.\n *\n * @return {google.maps.LatLng} The cluster center.\n */\nCluster.prototype.getCenter = function() {\n  return this.center_;\n};\n\n\n/**\n * Calculated the extended bounds of the cluster with the grid.\n *\n * @private\n */\nCluster.prototype.calculateBounds_ = function() {\n  var bounds = new google.maps.LatLngBounds(this.center_, this.center_);\n  this.bounds_ = this.markerClusterer_.getExtendedBounds(bounds);\n};\n\n\n/**\n * Determines if a marker lies in the clusters bounds.\n *\n * @param {google.maps.Marker} marker The marker to check.\n * @return {boolean} True if the marker lies in the bounds.\n */\nCluster.prototype.isMarkerInClusterBounds = function(marker) {\n  return this.bounds_.contains(marker.getPosition());\n};\n\n\n/**\n * Returns the map that the cluster is associated with.\n *\n * @return {google.maps.Map} The map.\n */\nCluster.prototype.getMap = function() {\n  return this.map_;\n};\n\n\n/**\n * Updates the cluster icon\n */\nCluster.prototype.updateIcon = function() {\n  var zoom = this.map_.getZoom();\n  var mz = this.markerClusterer_.getMaxZoom();\n\n  if (mz && zoom > mz) {\n    // The zoom is greater than our max zoom so show all the markers in cluster.\n    for (var i = 0, marker; marker = this.markers_[i]; i++) {\n      marker.setMap(this.map_);\n    }\n    return;\n  }\n\n  if (this.markers_.length < this.minClusterSize_) {\n    // Min cluster size not yet reached.\n    this.clusterIcon_.hide();\n    return;\n  }\n\n  var numStyles = this.markerClusterer_.getStyles().length;\n  var sums = this.markerClusterer_.getCalculator()(this.markers_, numStyles);\n  this.clusterIcon_.setCenter(this.center_);\n  this.clusterIcon_.setSums(sums);\n  this.clusterIcon_.show();\n};\n\n\n/**\n * A cluster icon\n *\n * @param {Cluster} cluster The cluster to be associated with.\n * @param {Object} styles An object that has style properties:\n *     'url': (string) The image url.\n *     'height': (number) The image height.\n *     'width': (number) The image width.\n *     'anchor': (Array) The anchor position of the label text.\n *     'textColor': (string) The text color.\n *     'textSize': (number) The text size.\n *     'backgroundPosition: (string) The background postition x, y.\n * @param {number=} opt_padding Optional padding to apply to the cluster icon.\n * @constructor\n * @extends google.maps.OverlayView\n * @ignore\n */\nfunction ClusterIcon(cluster, styles, opt_padding) {\n  cluster.getMarkerClusterer().extend(ClusterIcon, google.maps.OverlayView);\n\n  this.styles_ = styles;\n  this.padding_ = opt_padding || 0;\n  this.cluster_ = cluster;\n  this.center_ = null;\n  this.map_ = cluster.getMap();\n  this.div_ = null;\n  this.sums_ = null;\n  this.visible_ = false;\n\n  this.setMap(this.map_);\n}\n\n\n/**\n * Triggers the clusterclick event and zoom's if the option is set.\n */\nClusterIcon.prototype.triggerClusterClick = function() {\n  var markerClusterer = this.cluster_.getMarkerClusterer();\n\n  // Trigger the clusterclick event.\n  google.maps.event.trigger(markerClusterer, 'clusterclick', this.cluster_);\n\n  if (markerClusterer.isZoomOnClick()) {\n    // Zoom into the cluster.\n    this.map_.fitBounds(this.cluster_.getBounds());\n  }\n};\n\n\n/**\n * Adding the cluster icon to the dom.\n * @ignore\n */\nClusterIcon.prototype.onAdd = function() {\n  this.div_ = document.createElement('DIV');\n  if (this.visible_) {\n    var pos = this.getPosFromLatLng_(this.center_);\n    this.div_.style.cssText = this.createCss(pos);\n    this.div_.innerHTML = this.sums_.text;\n  }\n\n  var panes = this.getPanes();\n  panes.overlayMouseTarget.appendChild(this.div_);\n\n  var that = this;\n  google.maps.event.addDomListener(this.div_, 'click', function() {\n    that.triggerClusterClick();\n  });\n};\n\n\n/**\n * Returns the position to place the div dending on the latlng.\n *\n * @param {google.maps.LatLng} latlng The position in latlng.\n * @return {google.maps.Point} The position in pixels.\n * @private\n */\nClusterIcon.prototype.getPosFromLatLng_ = function(latlng) {\n  var pos = this.getProjection().fromLatLngToDivPixel(latlng);\n  pos.x -= parseInt(this.width_ / 2, 10);\n  pos.y -= parseInt(this.height_ / 2, 10);\n  return pos;\n};\n\n\n/**\n * Draw the icon.\n * @ignore\n */\nClusterIcon.prototype.draw = function() {\n  if (this.visible_) {\n    var pos = this.getPosFromLatLng_(this.center_);\n    this.div_.style.top = pos.y + 'px';\n    this.div_.style.left = pos.x + 'px';\n  }\n};\n\n\n/**\n * Hide the icon.\n */\nClusterIcon.prototype.hide = function() {\n  if (this.div_) {\n    this.div_.style.display = 'none';\n  }\n  this.visible_ = false;\n};\n\n\n/**\n * Position and show the icon.\n */\nClusterIcon.prototype.show = function() {\n  if (this.div_) {\n    var pos = this.getPosFromLatLng_(this.center_);\n    this.div_.style.cssText = this.createCss(pos);\n    this.div_.style.display = '';\n  }\n  this.visible_ = true;\n};\n\n\n/**\n * Remove the icon from the map\n */\nClusterIcon.prototype.remove = function() {\n  this.setMap(null);\n};\n\n\n/**\n * Implementation of the onRemove interface.\n * @ignore\n */\nClusterIcon.prototype.onRemove = function() {\n  if (this.div_ && this.div_.parentNode) {\n    this.hide();\n    this.div_.parentNode.removeChild(this.div_);\n    this.div_ = null;\n  }\n};\n\n\n/**\n * Set the sums of the icon.\n *\n * @param {Object} sums The sums containing:\n *   'text': (string) The text to display in the icon.\n *   'index': (number) The style index of the icon.\n */\nClusterIcon.prototype.setSums = function(sums) {\n  this.sums_ = sums;\n  this.text_ = sums.text;\n  this.index_ = sums.index;\n  if (this.div_) {\n    this.div_.innerHTML = sums.text;\n  }\n\n  this.useStyle();\n};\n\n\n/**\n * Sets the icon to the the styles.\n */\nClusterIcon.prototype.useStyle = function() {\n  var index = Math.max(0, this.sums_.index - 1);\n  index = Math.min(this.styles_.length - 1, index);\n  var style = this.styles_[index];\n  this.url_ = style['url'];\n  this.height_ = style['height'];\n  this.width_ = style['width'];\n  this.textColor_ = style['textColor'];\n  this.anchor_ = style['anchor'];\n  this.textSize_ = style['textSize'];\n  this.backgroundPosition_ = style['backgroundPosition'];\n};\n\n\n/**\n * Sets the center of the icon.\n *\n * @param {google.maps.LatLng} center The latlng to set as the center.\n */\nClusterIcon.prototype.setCenter = function(center) {\n  this.center_ = center;\n};\n\n\n/**\n * Create the css text based on the position of the icon.\n *\n * @param {google.maps.Point} pos The position.\n * @return {string} The css style text.\n */\nClusterIcon.prototype.createCss = function(pos) {\n  var style = [];\n  style.push('background-image:url(' + this.url_ + ');');\n  var backgroundPosition = this.backgroundPosition_ ? this.backgroundPosition_ : '0 0';\n  style.push('background-position:' + backgroundPosition + ';');\n\n  if (typeof this.anchor_ === 'object') {\n    if (typeof this.anchor_[0] === 'number' && this.anchor_[0] > 0 &&\n        this.anchor_[0] < this.height_) {\n      style.push('height:' + (this.height_ - this.anchor_[0]) +\n          'px; padding-top:' + this.anchor_[0] + 'px;');\n    } else {\n      style.push('height:' + this.height_ + 'px; line-height:' + this.height_ +\n          'px;');\n    }\n    if (typeof this.anchor_[1] === 'number' && this.anchor_[1] > 0 &&\n        this.anchor_[1] < this.width_) {\n      style.push('width:' + (this.width_ - this.anchor_[1]) +\n          'px; padding-left:' + this.anchor_[1] + 'px;');\n    } else {\n      style.push('width:' + this.width_ + 'px; text-align:center;');\n    }\n  } else {\n    style.push('height:' + this.height_ + 'px; line-height:' +\n        this.height_ + 'px; width:' + this.width_ + 'px; text-align:center;');\n  }\n\n  var txtColor = this.textColor_ ? this.textColor_ : 'black';\n  var txtSize = this.textSize_ ? this.textSize_ : 11;\n\n  style.push('cursor:pointer; top:' + pos.y + 'px; left:' +\n      pos.x + 'px; color:' + txtColor + '; position:absolute; font-size:' +\n      txtSize + 'px; text-align:center; font-family:Arial,helvetica,sans-serif; font-weight:normal');\n  return style.join('');\n};\n\n\n// Export Symbols for Closure\n// If you are not going to compile with closure then you can remove the\n// code below.\nwindow['MarkerClusterer'] = MarkerClusterer;\nMarkerClusterer.prototype['addMarker'] = MarkerClusterer.prototype.addMarker;\nMarkerClusterer.prototype['addMarkers'] = MarkerClusterer.prototype.addMarkers;\nMarkerClusterer.prototype['clearMarkers'] =\n    MarkerClusterer.prototype.clearMarkers;\nMarkerClusterer.prototype['fitMapToMarkers'] =\n    MarkerClusterer.prototype.fitMapToMarkers;\nMarkerClusterer.prototype['getCalculator'] =\n    MarkerClusterer.prototype.getCalculator;\nMarkerClusterer.prototype['getGridSize'] =\n    MarkerClusterer.prototype.getGridSize;\nMarkerClusterer.prototype['getExtendedBounds'] =\n    MarkerClusterer.prototype.getExtendedBounds;\nMarkerClusterer.prototype['getMap'] = MarkerClusterer.prototype.getMap;\nMarkerClusterer.prototype['getMarkers'] = MarkerClusterer.prototype.getMarkers;\nMarkerClusterer.prototype['getMaxZoom'] = MarkerClusterer.prototype.getMaxZoom;\nMarkerClusterer.prototype['getStyles'] = MarkerClusterer.prototype.getStyles;\nMarkerClusterer.prototype['getTotalClusters'] =\n    MarkerClusterer.prototype.getTotalClusters;\nMarkerClusterer.prototype['getTotalMarkers'] =\n    MarkerClusterer.prototype.getTotalMarkers;\nMarkerClusterer.prototype['redraw'] = MarkerClusterer.prototype.redraw;\nMarkerClusterer.prototype['removeMarker'] =\n    MarkerClusterer.prototype.removeMarker;\nMarkerClusterer.prototype['removeMarkers'] =\n    MarkerClusterer.prototype.removeMarkers;\nMarkerClusterer.prototype['resetViewport'] =\n    MarkerClusterer.prototype.resetViewport;\nMarkerClusterer.prototype['repaint'] =\n    MarkerClusterer.prototype.repaint;\nMarkerClusterer.prototype['setCalculator'] =\n    MarkerClusterer.prototype.setCalculator;\nMarkerClusterer.prototype['setGridSize'] =\n    MarkerClusterer.prototype.setGridSize;\nMarkerClusterer.prototype['setMaxZoom'] =\n    MarkerClusterer.prototype.setMaxZoom;\nMarkerClusterer.prototype['onAdd'] = MarkerClusterer.prototype.onAdd;\nMarkerClusterer.prototype['draw'] = MarkerClusterer.prototype.draw;\n\nCluster.prototype['getCenter'] = Cluster.prototype.getCenter;\nCluster.prototype['getSize'] = Cluster.prototype.getSize;\nCluster.prototype['getMarkers'] = Cluster.prototype.getMarkers;\n\nClusterIcon.prototype['onAdd'] = ClusterIcon.prototype.onAdd;\nClusterIcon.prototype['draw'] = ClusterIcon.prototype.draw;\nClusterIcon.prototype['onRemove'] = ClusterIcon.prototype.onRemove;\n\nObject.keys = Object.keys || function(o) {  \n    var result = [];  \n    for(var name in o) {  \n        if (o.hasOwnProperty(name))  \n          result.push(name);  \n    }  \n    return result;  \n};\n"],"names":["MarkerClusterer","map","opt_markers","opt_options","this","extend","google","maps","OverlayView","map_","markers_","clusters_","sizes","styles_","ready_","options","that","gridSize_","minClusterSize_","maxZoom_","imagePath_","MARKER_CLUSTER_IMAGE_PATH_","imageExtension_","MARKER_CLUSTER_IMAGE_EXTENSION_","zoomOnClick_","undefined","averageCenter_","setupStyles_","setMap","prevZoom_","getZoom","event","addListener","zoom","minZoom","maxZoom","Math","min","mapTypes","getMapTypeId","max","resetViewport","redraw","length","Object","keys","addMarkers","Cluster","markerClusterer","markerClusterer_","getMap","getGridSize","getMinClusterSize","isAverageCenter","center_","bounds_","clusterIcon_","ClusterIcon","getStyles","cluster","styles","opt_padding","getMarkerClusterer","padding_","cluster_","div_","sums_","visible_","prototype","obj1","obj2","object","property","apply","onAdd","setReady_","draw","size","i","push","url","height","width","fitMapToMarkers","marker","markers","getMarkers","bounds","LatLngBounds","getPosition","fitBounds","setStyles","isZoomOnClick","getTotalMarkers","setMaxZoom","getMaxZoom","calculator_","numStyles","index","count","dv","parseInt","text","setCalculator","calculator","getCalculator","opt_nodraw","pushMarkerTo_","isAdded","repaint","addMarker","removeMarker_","indexOf","m","splice","removeMarker","removed","removeMarkers","r","ready","createClusters_","getTotalClusters","setGridSize","setMinClusterSize","getExtendedBounds","projection","getProjection","tr","LatLng","getNorthEast","lat","lng","bl","getSouthWest","trPix","fromLatLngToDivPixel","blPix","x","y","ne","fromDivPixelToLatLng","sw","isMarkerInBounds_","contains","clearMarkers","opt_hide","remove","oldClusters","slice","window","setTimeout","distanceBetweenPoints_","p1","p2","dLon","a","dLat","PI","sin","cos","atan2","sqrt","addToClosestCluster_","distance","clusterToAddTo","center","getCenter","d","isMarkerInClusterBounds","mapBounds","getBounds","isMarkerAlreadyAdded","l","calculateBounds_","len","updateIcon","getSize","mz","hide","sums","setCenter","setSums","show","triggerClusterClick","trigger","pos","document","createElement","getPosFromLatLng_","style","cssText","createCss","innerHTML","getPanes","overlayMouseTarget","appendChild","addDomListener","latlng","width_","height_","top","left","display","onRemove","parentNode","removeChild","text_","index_","useStyle","url_","textColor_","anchor_","textSize_","backgroundPosition_","backgroundPosition","txtColor","txtSize","join","o","name","result","hasOwnProperty"],"mappings":"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"}