Commits

Anonymous committed 2bf32b2

some refactor in naming variables and code style
add support for different styles of cluster icons depending on cluster size
fix bug with incorrect position of cluster icon - adding offset depending on icon size
update distance method
pack clasterer

Comments (0)

Files changed (3)

  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 /**
  * Clusterer main class.
  * Init only once for each map.
   this.zoom = null;
   this.map.YandexClusterer = this;
 
-  this.om = new YMaps.ObjectManager(); // cluster's object manager
-  this.map.addOverlay(this.om);
+  this.yandexObjectManager = new YMaps.ObjectManager(); // cluster's object manager
+  this.map.addOverlay(this.yandexObjectManager);
 
   // options
   opts = opts || {};
   this.min_size = opts.min_size || 2;
   this.centered = opts.centered || false;
   this.batch = opts.batch || 400;
-  this.style = opts.style || {
-    icon: 'http://gmaps-utility-library.googlecode.com/svn/trunk/markerclusterer/images/m1.png',
-    height: 52,
-    width: 53,
-    offset: [0, 0],
-    textColor: '#000000',
-    textSize: 11,
-    printable: false
-  };
+  
+  this.imagePath_ = opts.imagePath || YandexClusterer.IMAGE_PATH;
+  this.imageExtension_ = opts.imageExtension || YandexClusterer.IMAGE_EXTENSION;
+  this.imageSizes_ = opts.imageSizes || YandexClusterer.IMAGE_SIZES;
 
+  this.styles = opts.styles || this.generateClasterStyles();
+  this.printable = opts.printable || false;
   // check if there are previous events - remove them
   if (this.map._yandexClustererEvents) {
     for (event in this.map._yandexClustererEvents) {
   var l = this.markers.length;
   while (l--) {
     var marker = this.markers[l];
+    this.map.removeOverlay(marker);
     marker.isAdded = false;
     if (marker.isOnMap) {
       marker.isOnMap = false;
     }
   }
-  this.om.removeAll();
+  this.yandexObjectManager.removeAll();
 
   l = this.clusters.length;
   while (l--) {
  * Create clusters for markers. Working in several iterations.
  */
 YandexClusterer.prototype.createClusters = function(iter) {
-  var self = this,
-      i = iter,
-      length = this.markers.length,
-      iter_last = Math.min(iter + this.batch, length);
+  var self = this;
+  var i = iter;
+  var length = this.markers.length;
+  var iter_last = Math.min(iter + this.batch, length);
 
   // if first iteration
   if (iter === 0) {
     }
   }
 
-  for (i; i < iter_last; i++) {
+  for (; i < iter_last; i++) {
     var marker = this.markers[i];
     if (!marker.isAdded && this.bounds.contains(marker.getCoordPoint())) {
       this.addToCluster(marker);
  * Calculates distance between points.
  */
 YandexClusterer.prototype.distanceBetween = function (p1, p2) {
-  var R = 6371; // Radius of the Earth in km
-  var dLat = (p2.getLat() - p1.getLat()) * Math.PI / 180;
-  var dLon = (p2.getLng() - p1.getLng()) * Math.PI / 180;
-  var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
-    Math.cos(p1.getLat() * Math.PI / 180) * Math.cos(p2.getLat() * Math.PI / 180) *
-    Math.sin(dLon / 2) * Math.sin(dLon / 2);
-  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
-  var d = R * c;
-  return d;
+  return p1.distance(p2)/1000;
 };
 
 /**
       while (i--) {
         var marker = cluster.markers[i];
         if (!marker.isOnMap) {
-          this.om.add(marker, this.zoom, this.zoom);
+          this.yandexObjectManager.add(marker, this.zoom, this.zoom);
           marker.isOnMap = true;
         }
       }
       while (i--) {
         var marker = cluster.markers[i];
         if (!marker.isOnMap) {
-          this.om.add(marker, this.zoom, this.zoom);
+          this.yandexObjectManager.add(marker, this.zoom, this.zoom);
           marker.isOnMap = true;
         }
       }
 };
 
 /**
+ * Return style for claster depending on it's count of markers.
+ * @param {YandexCluster} cluster object
+ * @return {Object} style for claster
+ */
+YandexClusterer.prototype.getClasterStyle = function (cluster) {
+  return this.styles[cluster.getIconStyleIndex(this.getStylesCount())];
+};
+
+/**
+ * Generate styles for different claster size.
+ * @return {Array<Object>} generated set of styles
+ */
+YandexClusterer.prototype.generateClasterStyles = function () {
+  var styles = [];
+  for (var i = 0; i < this.getStylesCount(); i++) {
+    styles.push(this.genStyleForIndex(i));
+  }
+  return styles;
+};
+
+/**
+ * Generate style for specified style index.
+ * used by YandexClusterer.generateClasterStyles()
+ * @param {number} index - index of style
+ * @return {Object} generated style 
+ */
+YandexClusterer.prototype.genStyleForIndex = function (index) {
+  var size = this.imageSizes_[index];
+  var iconPath = this.imagePath_ + (index + 1) + this.imageExtension_; 
+  var style = {
+    icon: iconPath,
+    height: size,
+    width: size,
+    offset: [-parseInt(size / 2, 10), -parseInt(size / 2, 10)],
+    textColor: '#000000',
+    textSize: 11
+  };
+  return style; 
+};
+
+/**
+ * Return styles count of clasterer.
+ */
+YandexClusterer.prototype.getStylesCount = function() {
+  return this.imageSizes_.length;
+}
+
+/**
+ * The default root name for the marker cluster images.
+ *
+ * @type {string}
+ * @constant
+ */
+YandexClusterer.IMAGE_PATH = "http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclustererplus/images/m";
+
+
+/**
+ * The default extension name for the marker cluster images.
+ *
+ * @type {string}
+ * @constant
+ */
+YandexClusterer.IMAGE_EXTENSION = ".png";
+
+
+/**
+ * The default array of sizes for the marker cluster images.
+ *
+ * @type {Array.<number>}
+ * @constant
+ */
+YandexClusterer.IMAGE_SIZES = [53, 56, 66, 78, 90];
+
+
+/**
  * Cluster class.
  * Used internally from main class.
  *
  * @param {YandexClusterer} Associated Yandex clusterer class.
  */
-function YandexCluster(mc) {
-  this.mc = mc;
-  this.om = mc.om;
-  this.map = mc.map;
+function YandexCluster(clasterOwner) {
+  this.clustererObject = clasterOwner;
+  this.yandexObjectManager = clasterOwner.yandexObjectManager;
+  this.map = clasterOwner.map;
   this.center = null;
   this.markers = [];
+  this.markers_bounds = new YMaps.GeoCollectionBounds();
   this.bounds = null;
-  this.min_size = mc.min_size;
-  this.style = mc.style;
+  this.min_size = clasterOwner.min_size;
   this.point = null;
 }
 
   if (!this.center) {
     this.center = marker.getCoordPoint();
     this.bounds = this.calculateBounds();
-  } else if (this.mc.centered) {
+  } else if (this.clustererObject.centered) {
     var l = this.markers.length + 1,
         m_coord = marker.getCoordPoint();
     var lat = (this.center.getLat() * (l - 1) + m_coord.getLat()) / l;
     this.center = new YMaps.GeoPoint(lng, lat);
     this.bounds = this.calculateBounds();
   }
-
   marker.isAdded = true;
   this.markers.push(marker);
+  this.markers_bounds.add(marker.getGeoPoint());
 
   return true;
 }
 
+YandexCluster.prototype.getClasterBounds = function() {
+  return this.markers_bounds;
+};
+
 /**
  * Returns bounds for this cluster.
  */
 YandexCluster.prototype.calculateBounds = function() {
   var bounds = new YMaps.GeoCollectionBounds(this.center);
-  return this.mc.extendBounds(bounds);
+  return this.clustererObject.extendBounds(bounds);
 };
 
 /**
 
   // remove icon if it's already on map
   if (this.point) {
-    this.om.remove(this.point);
+    this.yandexObjectManager.remove(this.point);
   }
 
   // for printable version add <img> tag
-  if (this.style.printable) {
+  if (this.clustererObject.printable) {
     var template = new YMaps.Template('<div style="cursor:pointer;position:relative;line-height:$[style.iconStyle.size.y]px;height:$[style.iconStyle.size.y]px;width:$[style.iconStyle.size.x]px;text-align:center"><img src="$[style.iconStyle.href]" alt="" style="position:absolute;left:0;top:0"><span style="position:relative;font-weight:bold;font-size:$[textSize|12]px;color:$[textColor|#000]">$[markersCount|0]</span></div>');
   } else {
     var template = new YMaps.Template('<div style="cursor:pointer;position:relative;line-height:$[style.iconStyle.size.y]px;height:$[style.iconStyle.size.y]px;width:$[style.iconStyle.size.x]px;text-align:center;background:url($[style.iconStyle.href]) no-repeat;font-weight:bold;font-size:$[textSize|12]px;color:$[textColor|#000]">$[markersCount|0]</div>');
   }
+
+  var clasterStyle = this.clustererObject.getClasterStyle(this);
   var style = new YMaps.Style();
   style.iconStyle = new YMaps.IconStyle(template);
-  style.iconStyle.href = this.style.icon;
-  style.iconStyle.size = new YMaps.Point(this.style.width, this.style.height);
-  style.iconStyle.offset = new YMaps.Point(this.style.offset);
+  style.iconStyle.href = clasterStyle.icon;
+  style.iconStyle.size = new YMaps.Point(clasterStyle.width, clasterStyle.height);
+  style.iconStyle.offset = new YMaps.Point(clasterStyle.offset[0], clasterStyle.offset[1]);
   this.point = new YMaps.Placemark(position, {
     style: style,
     hasBalloon: false
   });
   this.point.markersCount = this.markers.length;
-  this.point.textSize = this.style.textSize;
-  this.point.textColor = this.style.textColor;
+  this.point.textSize = clasterStyle.textSize;
+  this.point.textColor = clasterStyle.textColor;
 
   // click event - zoom to cluster bounds
   YMaps.Events.observe(this.point, this.point.Events.Click, function () {
-    this.map.setBounds(this.bounds);
+    this.map.setBounds(this.getClasterBounds());
     // Don't zoom beyond the max zoom level
-    if (this.mc.getMaxZoom() < this.map.getZoom()) {
-      this.map.setZoom(this.mc.getMaxZoom() + 1);
+    if (this.clustererObject.getMaxZoom() < this.map.getZoom()) {
+      this.map.setZoom(this.clustererObject.getMaxZoom() + 1);
     }
   }, this);
 
   var zoom = this.map.getZoom();
-  this.om.add(this.point, zoom, zoom);
+  this.yandexObjectManager.add(this.point, zoom, zoom);
 }
 
 /**
  */
 YandexCluster.prototype.remove = function () {
   this.markers = [];
+  this.markers_bounds.clear();
   if (this.point) {
     this.point = null;
   }
 };
+
+/**
+ * The function that calculates style index for claster.
+ * @param {number} styles_num styles count
+ * @return {number} style index
+ */
+YandexCluster.prototype.getIconStyleIndex = function (styles_num) {
+  var index = -1;
+  var count = this.markers.length.toString();
+
+  var dv = count;
+  while (dv !== 0) {
+    dv = parseInt(dv / 10, 10);
+    index++;
+  }
+
+  index = Math.min(index, styles_num);
+  return index;
+};

yandex.clusterer.min.js

  *
  * Based on MarkerClustererPlus for Google Maps V3 by Gary Little
  */
-function YandexCluster(a){this.mc=a;this.om=a.om;this.map=a.map;this.center=null;this.markers=[];this.bounds=null;this.min_size=a.min_size;this.style=a.style;this.point=null}function YandexClusterer(a,b,c){this.map=a;this.bounds=null;this.clusters=[];this.markers=b||[];this.zoom=null;this.map.YandexClusterer=this;this.om=new YMaps.ObjectManager;this.map.addOverlay(this.om);c=c||{};this.max_zoom=c.max_zoom||0;this.grid=c.grid||60;this.min_size=c.min_size||2;this.centered=c.centered||false;this.batch=c.batch||400;this.style=c.style||{icon:"http://gmaps-utility-library.googlecode.com/svn/trunk/markerclusterer/images/m1.png",height:52,width:53,offset:[0,0],textColor:"#000000",textSize:11,printable:false};if(this.map._yandexClustererEvents){for(event in this.map._yandexClustererEvents){this.map._yandexClustererEvents[event].cleanup()}}this.map._yandexClustererEvents={};this.map._yandexClustererEvents["update"]=YMaps.Events.observe(this.map,this.map.Events.Update,function(){this.repaint()},this);this.map._yandexClustererEvents["move"]=YMaps.Events.observe(this.map,this.map.Events.MoveEnd,function(){this.redraw()},this);this.repaint()}YandexClusterer.prototype.setMarkers=function(a){this.markers=a};YandexClusterer.prototype.clearMarkers=function(){var a=this.markers.length;while(a--){var b=this.markers[a];b.isAdded=false;if(b.isOnMap){b.isOnMap=false}}this.om.removeAll();a=this.clusters.length;while(a--){this.clusters[a].remove()}this.clusters=[]};YandexClusterer.prototype.repaint=function(){this.clearMarkers();this.redraw()};YandexClusterer.prototype.redraw=function(){this.createClusters(0)};YandexClusterer.prototype.createClusters=function(a){var b=this,c=a,d=this.markers.length,e=Math.min(a+this.batch,d);if(a===0){this.bounds=this.extendBounds(this.map.getBounds());this.zoom=this.map.getZoom();if(typeof this.timerRefStatic!=="undefined"){clearTimeout(this.timerRefStatic);delete this.timerRefStatic}}for(c;c<e;c++){var f=this.markers[c];if(!f.isAdded&&this.bounds.contains(f.getCoordPoint())){this.addToCluster(f)}}if(e<d){this.timerRefStatic=setTimeout(function(){b.createClusters(e)},0)}else{delete this.timerRefStatic;setTimeout(function(){b.updateClusterIcons()},0)}};YandexClusterer.prototype.extendBounds=function(a){var b=this.map.converter,c,d,e,f;c=b.coordinatesToMapPixels(a.getRightTop());c.x+=this.grid;c.y-=this.grid;d=b.coordinatesToMapPixels(a.getLeftBottom());d.x-=this.grid;d.y+=this.grid;e=b.mapPixelsToCoordinates(c);f=b.mapPixelsToCoordinates(d);return new YMaps.GeoBounds(f,e)};YandexClusterer.prototype.addToCluster=function(a){var b,c,d,e=this.clusters.length;var f=4e4;var g=null;while(e--){c=this.clusters[e];if(c.center){b=this.distanceBetween(c.center,a.getCoordPoint());if(b<f){f=b;g=c}}}if(g&&g.isMarkerInBounds(a)){g.addMarker(a)}else{c=new YandexCluster(this);c.addMarker(a);this.clusters.push(c)}};YandexClusterer.prototype.distanceBetween=function(a,b){var c=6371;var d=(b.getLat()-a.getLat())*Math.PI/180;var e=(b.getLng()-a.getLng())*Math.PI/180;var f=Math.sin(d/2)*Math.sin(d/2)+Math.cos(a.getLat()*Math.PI/180)*Math.cos(b.getLat()*Math.PI/180)*Math.sin(e/2)*Math.sin(e/2);var g=2*Math.atan2(Math.sqrt(f),Math.sqrt(1-f));var h=c*g;return h};YandexClusterer.prototype.updateClusterIcons=function(){var a=this,b=this.clusters.length,c=this.getMaxZoom(),d=this.map.getZoom();while(b--){var e=this.clusters[b];count=e.markers.length;if(d>=c){var f=e.markers.length;while(f--){var g=e.markers[f];if(!g.isOnMap){this.om.add(g,this.zoom,this.zoom);g.isOnMap=true}}continue}else if(count<this.min_size){var f=e.markers.length;while(f--){var g=e.markers[f];if(!g.isOnMap){this.om.add(g,this.zoom,this.zoom);g.isOnMap=true}}continue}else{var f=e.markers.length;while(f--){var g=e.markers[f];this.map.removeOverlay(g);g.isOnMap=false}}e.showIcon()}};YandexClusterer.prototype.getMaxZoom=function(){return this.max_zoom||this.map.getMaxZoom()};YandexCluster.prototype.addMarker=function(a){var b,c,d=this.map.getZoom();if(a.isAdded)return false;if(!this.center){this.center=a.getCoordPoint();this.bounds=this.calculateBounds()}else if(this.mc.centered){var e=this.markers.length+1,f=a.getCoordPoint();var g=(this.center.getLat()*(e-1)+f.getLat())/e;var h=(this.center.getLng()*(e-1)+f.getLng())/e;this.center=new YMaps.GeoPoint(h,g);this.bounds=this.calculateBounds()}a.isAdded=true;this.markers.push(a);return true};YandexCluster.prototype.calculateBounds=function(){var a=new YMaps.GeoCollectionBounds(this.center);return this.mc.extendBounds(a)};YandexCluster.prototype.isMarkerInBounds=function(a){return this.bounds.contains(a.getCoordPoint())};YandexCluster.prototype.showIcon=function(){var a=this,b=new YMaps.GeoPoint(this.center.getLng(),this.center.getLat());if(this.point){this.om.remove(this.point)}if(this.style.printable){var c=new YMaps.Template('<div style="cursor:pointer;position:relative;line-height:$[style.iconStyle.size.y]px;height:$[style.iconStyle.size.y]px;width:$[style.iconStyle.size.x]px;text-align:center"><img src="$[style.iconStyle.href]" alt="" style="position:absolute;left:0;top:0"><span style="position:relative;font-weight:bold;font-size:$[textSize|12]px;color:$[textColor|#000]">$[markersCount|0]</span></div>')}else{var c=new YMaps.Template('<div style="cursor:pointer;position:relative;line-height:$[style.iconStyle.size.y]px;height:$[style.iconStyle.size.y]px;width:$[style.iconStyle.size.x]px;text-align:center;background:url($[style.iconStyle.href]) no-repeat;font-weight:bold;font-size:$[textSize|12]px;color:$[textColor|#000]">$[markersCount|0]</div>')}var d=new YMaps.Style;d.iconStyle=new YMaps.IconStyle(c);d.iconStyle.href=this.style.icon;d.iconStyle.size=new YMaps.Point(this.style.width,this.style.height);d.iconStyle.offset=new YMaps.Point(this.style.offset);this.point=new YMaps.Placemark(b,{style:d,hasBalloon:false});this.point.markersCount=this.markers.length;this.point.textSize=this.style.textSize;this.point.textColor=this.style.textColor;YMaps.Events.observe(this.point,this.point.Events.Click,function(){this.map.setBounds(this.bounds);if(this.mc.getMaxZoom()<this.map.getZoom()){this.map.setZoom(this.mc.getMaxZoom()+1)}},this);var e=this.map.getZoom();this.om.add(this.point,e,e)};YandexCluster.prototype.remove=function(){this.markers=[];if(this.point){this.point=null}}
+function YandexClusterer(map,markers,opts){this.map=map;this.bounds=null;this.clusters=[];this.markers=markers||[];this.zoom=null;this.map.YandexClusterer=this;this.yandexObjectManager=new YMaps.ObjectManager();this.map.addOverlay(this.yandexObjectManager);opts=opts||{};this.max_zoom=opts.max_zoom||0;this.grid=opts.grid||60;this.min_size=opts.min_size||2;this.centered=opts.centered||false;this.batch=opts.batch||400;this.imagePath_=opts.imagePath||YandexClusterer.IMAGE_PATH;this.imageExtension_=opts.imageExtension||YandexClusterer.IMAGE_EXTENSION;this.imageSizes_=opts.imageSizes||YandexClusterer.IMAGE_SIZES;this.styles=opts.styles||this.generateClasterStyles();this.printable=opts.printable||false;if(this.map._yandexClustererEvents){for(event in this.map._yandexClustererEvents){this.map._yandexClustererEvents[event].cleanup()}}this.map._yandexClustererEvents={};this.map._yandexClustererEvents['update']=YMaps.Events.observe(this.map,this.map.Events.Update,function(){this.repaint()},this);this.map._yandexClustererEvents['move']=YMaps.Events.observe(this.map,this.map.Events.MoveEnd,function(){this.redraw()},this);this.repaint()}YandexClusterer.prototype.setMarkers=function(markers){this.markers=markers};YandexClusterer.prototype.clearMarkers=function(){var l=this.markers.length;while(l--){var marker=this.markers[l];this.map.removeOverlay(marker);marker.isAdded=false;if(marker.isOnMap){marker.isOnMap=false}}this.yandexObjectManager.removeAll();l=this.clusters.length;while(l--){this.clusters[l].remove()}this.clusters=[]};YandexClusterer.prototype.repaint=function(){this.clearMarkers();this.redraw()};YandexClusterer.prototype.redraw=function(){this.createClusters(0)};YandexClusterer.prototype.createClusters=function(iter){var self=this;var i=iter;var length=this.markers.length;var iter_last=Math.min(iter+this.batch,length);if(iter===0){this.bounds=this.extendBounds(this.map.getBounds());this.zoom=this.map.getZoom();if(typeof this.timerRefStatic!=="undefined"){clearTimeout(this.timerRefStatic);delete this.timerRefStatic}}for(;i<iter_last;i++){var marker=this.markers[i];if(!marker.isAdded&&this.bounds.contains(marker.getCoordPoint())){this.addToCluster(marker)}}if(iter_last<length){this.timerRefStatic=setTimeout(function(){self.createClusters(iter_last)},0)}else{delete this.timerRefStatic;setTimeout(function(){self.updateClusterIcons()},0)}};YandexClusterer.prototype.extendBounds=function(bounds){var converter=this.map.converter,rtPix,lbPix,ne,sw;rtPix=converter.coordinatesToMapPixels(bounds.getRightTop());rtPix.x+=this.grid;rtPix.y-=this.grid;lbPix=converter.coordinatesToMapPixels(bounds.getLeftBottom());lbPix.x-=this.grid;lbPix.y+=this.grid;ne=converter.mapPixelsToCoordinates(rtPix);sw=converter.mapPixelsToCoordinates(lbPix);return new YMaps.GeoBounds(sw,ne)};YandexClusterer.prototype.addToCluster=function(marker){var d,cluster,center,l=this.clusters.length;var distance=40000;var clusterToAddTo=null;while(l--){cluster=this.clusters[l];if(cluster.center){d=this.distanceBetween(cluster.center,marker.getCoordPoint());if(d<distance){distance=d;clusterToAddTo=cluster}}}if(clusterToAddTo&&clusterToAddTo.isMarkerInBounds(marker)){clusterToAddTo.addMarker(marker)}else{cluster=new YandexCluster(this);cluster.addMarker(marker);this.clusters.push(cluster)}};YandexClusterer.prototype.distanceBetween=function(p1,p2){return p1.distance(p2)/1000};YandexClusterer.prototype.updateClusterIcons=function(){var self=this;var l=this.clusters.length;var max_zoom=this.getMaxZoom();var max_map_zoom=this.map.getZoom();while(l--){var cluster=this.clusters[l];count=cluster.markers.length;if(max_map_zoom>=max_zoom){var i=cluster.markers.length;while(i--){var marker=cluster.markers[i];if(!marker.isOnMap){this.yandexObjectManager.add(marker,this.zoom,this.zoom);marker.isOnMap=true}}continue}else if(count<this.min_size){var i=cluster.markers.length;while(i--){var marker=cluster.markers[i];if(!marker.isOnMap){this.yandexObjectManager.add(marker,this.zoom,this.zoom);marker.isOnMap=true}}continue}else{var i=cluster.markers.length;while(i--){var marker=cluster.markers[i];this.map.removeOverlay(marker);marker.isOnMap=false}}cluster.showIcon()}};YandexClusterer.prototype.getMaxZoom=function(){return this.max_zoom||this.map.getMaxZoom()};YandexClusterer.prototype.getClasterStyle=function(cluster){return this.styles[cluster.getIconStyleIndex(this.getStylesCount())]};YandexClusterer.prototype.generateClasterStyles=function(){var styles=[];for(var i=0;i<this.getStylesCount();i++){styles.push(this.genStyleForIndex(i))}return styles};YandexClusterer.prototype.genStyleForIndex=function(index){var size=this.imageSizes_[index];var iconPath=this.imagePath_+(index+1)+this.imageExtension_;var style={icon:iconPath,height:size,width:size,offset:[-parseInt(size/2,10),-parseInt(size/2,10)],textColor:'#000000',textSize:11};return style};YandexClusterer.prototype.getStylesCount=function(){return this.imageSizes_.length};YandexClusterer.IMAGE_PATH="http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclustererplus/images/m";YandexClusterer.IMAGE_EXTENSION=".png";YandexClusterer.IMAGE_SIZES=[53,56,66,78,90];function YandexCluster(clasterOwner){this.clustererObject=clasterOwner;this.yandexObjectManager=clasterOwner.yandexObjectManager;this.map=clasterOwner.map;this.center=null;this.markers=[];this.markers_bounds=new YMaps.GeoCollectionBounds();this.bounds=null;this.min_size=clasterOwner.min_size;this.point=null}YandexCluster.prototype.addMarker=function(marker){var count,i,zoom=this.map.getZoom();if(marker.isAdded)return false;if(!this.center){this.center=marker.getCoordPoint();this.bounds=this.calculateBounds()}else if(this.clustererObject.centered){var l=this.markers.length+1,m_coord=marker.getCoordPoint();var lat=(this.center.getLat()*(l-1)+m_coord.getLat())/l;var lng=(this.center.getLng()*(l-1)+m_coord.getLng())/l;this.center=new YMaps.GeoPoint(lng,lat);this.bounds=this.calculateBounds()}marker.isAdded=true;this.markers.push(marker);this.markers_bounds.add(marker.getGeoPoint());return true};YandexCluster.prototype.getClasterBounds=function(){return this.markers_bounds};YandexCluster.prototype.calculateBounds=function(){var bounds=new YMaps.GeoCollectionBounds(this.center);return this.clustererObject.extendBounds(bounds)};YandexCluster.prototype.isMarkerInBounds=function(marker){return this.bounds.contains(marker.getCoordPoint())};YandexCluster.prototype.showIcon=function(){var self=this,position=new YMaps.GeoPoint(this.center.getLng(),this.center.getLat());if(this.point){this.yandexObjectManager.remove(this.point)}if(this.clustererObject.printable){var template=new YMaps.Template('<div style="cursor:pointer;position:relative;line-height:$[style.iconStyle.size.y]px;height:$[style.iconStyle.size.y]px;width:$[style.iconStyle.size.x]px;text-align:center"><img src="$[style.iconStyle.href]" alt="" style="position:absolute;left:0;top:0"><span style="position:relative;font-weight:bold;font-size:$[textSize|12]px;color:$[textColor|#000]">$[markersCount|0]</span></div>')}else{var template=new YMaps.Template('<div style="cursor:pointer;position:relative;line-height:$[style.iconStyle.size.y]px;height:$[style.iconStyle.size.y]px;width:$[style.iconStyle.size.x]px;text-align:center;background:url($[style.iconStyle.href]) no-repeat;font-weight:bold;font-size:$[textSize|12]px;color:$[textColor|#000]">$[markersCount|0]</div>')}var clasterStyle=this.clustererObject.getClasterStyle(this);var style=new YMaps.Style();style.iconStyle=new YMaps.IconStyle(template);style.iconStyle.href=clasterStyle.icon;style.iconStyle.size=new YMaps.Point(clasterStyle.width,clasterStyle.height);style.iconStyle.offset=new YMaps.Point(clasterStyle.offset[0],clasterStyle.offset[1]);this.point=new YMaps.Placemark(position,{style:style,hasBalloon:false});this.point.markersCount=this.markers.length;this.point.textSize=clasterStyle.textSize;this.point.textColor=clasterStyle.textColor;YMaps.Events.observe(this.point,this.point.Events.Click,function(){this.map.setBounds(this.getClasterBounds());if(this.clustererObject.getMaxZoom()<this.map.getZoom()){this.map.setZoom(this.clustererObject.getMaxZoom()+1)}},this);var zoom=this.map.getZoom();this.yandexObjectManager.add(this.point,zoom,zoom)};YandexCluster.prototype.remove=function(){this.markers=[];this.markers_bounds.clear();if(this.point){this.point=null}};YandexCluster.prototype.getIconStyleIndex=function(styles_num){var index=-1;var count=this.markers.length.toString();var dv=count;while(dv!==0){dv=parseInt(dv/10,10);index++}index=Math.min(index,styles_num);return index};

yandex.clusterer.packed.js

+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('5 7(a,b,c){3.6=a;3.B=D;3.t=[];3.f=b||[];3.C=D;3.6.7=3;3.s=j g.2t();3.6.2B(3.s);c=c||{};3.18=c.18||0;3.K=c.K||2E;3.U=c.U||2;3.16=c.16||A;3.1b=c.1b||2P;3.2a=c.2w||7.25;3.23=c.2F||7.20;3.1u=c.2p||7.1Z;3.17=c.17||3.1Y();3.19=c.19||A;9(3.6.L){1f(1W 2q 3.6.L){3.6.L[1W].2r()}}3.6.L={};3.6.L[\'2s\']=g.G.1k(3.6,3.6.G.2z,5(){3.1m()},3);3.6.L[\'2C\']=g.G.1k(3.6,3.6.G.2D,5(){3.1q()},3);3.1m()}7.8.2H=5(a){3.f=a};7.8.1T=5(){4 l=3.f.o;v(l--){4 a=3.f[l];3.6.1S(a);a.15=A;9(a.F){a.F=A}}3.s.2x();l=3.t.o;v(l--){3.t[l].1d()}3.t=[]};7.8.1m=5(){3.1T();3.1q()};7.8.1q=5(){3.1e(0)};7.8.1e=5(a){4 b=3;4 i=a;4 c=3.f.o;4 d=1Q.1N(a+3.1b,c);9(a===0){3.B=3.1j(3.6.2I());3.C=3.6.R();9(2L 3.N!=="2U"){2W(3.N);1M 3.N}}1f(;i<d;i++){4 e=3.f[i];9(!e.15&&3.B.1L(e.O())){3.1K(e)}}9(d<c){3.N=1J(5(){b.1e(d)},0)}J{1M 3.N;1J(5(){b.1H()},0)}};7.8.1j=5(a){4 b=3.6.2A,S,P,1h,1a;S=b.1G(a.2G());S.x+=3.K;S.y-=3.K;P=b.1G(a.2J());P.x-=3.K;P.y+=3.K;1h=b.1F(S);1a=b.1F(P);k j g.2M(1a,1h)};7.8.1K=5(a){4 d,z,h,l=3.t.o;4 b=3e;4 c=D;v(l--){z=3.t[l];9(z.h){d=3.1E(z.h,a.O());9(d<b){b=d;c=z}}}9(c&&c.1D(a)){c.1l(a)}J{z=j r(3);z.1l(a);3.t.1n(z)}};7.8.1E=5(a,b){k a.2u(b)/2v};7.8.1H=5(){4 a=3;4 l=3.t.o;4 b=3.T();4 c=3.6.R();v(l--){4 d=3.t[l];1C=d.f.o;9(c>=b){4 i=d.f.o;v(i--){4 e=d.f[i];9(!e.F){3.s.Y(e,3.C,3.C);e.F=Z}}1B}J 9(1C<3.U){4 i=d.f.o;v(i--){4 e=d.f[i];9(!e.F){3.s.Y(e,3.C,3.C);e.F=Z}}1B}J{4 i=d.f.o;v(i--){4 e=d.f[i];3.6.1S(e);e.F=A}}d.1A()}};7.8.T=5(){k 3.18||3.6.T()};7.8.1z=5(a){k 3.17[a.1R(3.1v())]};7.8.1Y=5(){4 a=[];1f(4 i=0;i<3.1v();i++){a.1n(3.1x(i))}k a};7.8.1x=5(a){4 b=3.1u[a];4 c=3.2a+(a+1)+3.23;4 d={1y:c,H:b,14:b,13:[-1p(b/2,10),-1p(b/2,10)],M:\'#2V\',Q:11};k d};7.8.1v=5(){k 3.1u.o};7.25="2X://2Y-2Z-30-37-2c.2d.2e/2f/2g/2h/2i/m";7.20=".2j";7.1Z=[2k,2l,2m,2n,2o];5 r(a){3.E=a;3.s=a.s;3.6=a.6;3.h=D;3.f=[];3.W=j g.1I();3.B=D;3.U=a.U;3.p=D}r.8.1l=5(a){4 b,i,C=3.6.R();9(a.15)k A;9(!3.h){3.h=a.O();3.B=3.1t()}J 9(3.E.16){4 l=3.f.o+1,1r=a.O();4 c=(3.h.1o()*(l-1)+1r.1o())/l;4 d=(3.h.1i()*(l-1)+1r.1i())/l;3.h=j g.1O(d,c);3.B=3.1t()}a.15=Z;3.f.1n(a);3.W.Y(a.2y());k Z};r.8.1P=5(){k 3.W};r.8.1t=5(){4 a=j g.1I(3.h);k 3.E.1j(a)};r.8.1D=5(a){k 3.B.1L(a.O())};r.8.1A=5(){4 a=3,I=j g.1O(3.h.1i(),3.h.1o());9(3.p){3.s.1d(3.p)}9(3.E.19){4 b=j g.1w(\'<V n="1U:1V;I:1g;1X-H:$[n.q.u.y]w;H:$[n.q.u.y]w;14:$[n.q.u.x]w;21-22:h"><2N 2O="$[n.q.1s]" 2Q="" n="I:2R;2S:0;2T:0"><24 n="I:1g;X-26:27;X-u:$[Q|12]w;28:$[M|#29]">$[1c|0]</24></V>\')}J{4 b=j g.1w(\'<V n="1U:1V;I:1g;1X-H:$[n.q.u.y]w;H:$[n.q.u.y]w;14:$[n.q.u.x]w;21-22:h;31:32($[n.q.1s]) 33-34;X-26:27;X-u:$[Q|12]w;28:$[M|#29]">$[1c|0]</V>\')}4 c=3.E.1z(3);4 d=j g.35();d.q=j g.36(b);d.q.1s=c.1y;d.q.u=j g.2b(c.14,c.H);d.q.13=j g.2b(c.13[0],c.13[1]);3.p=j g.38(I,{n:d,39:A});3.p.1c=3.f.o;3.p.Q=c.Q;3.p.M=c.M;g.G.1k(3.p,3.p.G.3a,5(){3.6.3b(3.1P());9(3.E.T()<3.6.R()){3.6.3c(3.E.T()+1)}},3);4 e=3.6.R();3.s.Y(3.p,e,e)};r.8.1d=5(){3.f=[];3.W.3d();9(3.p){3.p=D}};r.8.1R=5(a){4 b=-1;4 c=3.f.o.2K();4 d=c;v(d!==0){d=1p(d/10,10);b++}b=1Q.1N(b,a);k b};',62,201,'|||this|var|function|map|YandexClusterer|prototype|if||||||markers|YMaps|center||new|return|||style|length|point|iconStyle|YandexCluster|yandexObjectManager|clusters|size|while|px|||cluster|false|bounds|zoom|null|clustererObject|isOnMap|Events|height|position|else|grid|_yandexClustererEvents|textColor|timerRefStatic|getCoordPoint|lbPix|textSize|getZoom|rtPix|getMaxZoom|min_size|div|markers_bounds|font|add|true||||offset|width|isAdded|centered|styles|max_zoom|printable|sw|batch|markersCount|remove|createClusters|for|relative|ne|getLng|extendBounds|observe|addMarker|repaint|push|getLat|parseInt|redraw|m_coord|href|calculateBounds|imageSizes_|getStylesCount|Template|genStyleForIndex|icon|getClasterStyle|showIcon|continue|count|isMarkerInBounds|distanceBetween|mapPixelsToCoordinates|coordinatesToMapPixels|updateClusterIcons|GeoCollectionBounds|setTimeout|addToCluster|contains|delete|min|GeoPoint|getClasterBounds|Math|getIconStyleIndex|removeOverlay|clearMarkers|cursor|pointer|event|line|generateClasterStyles|IMAGE_SIZES|IMAGE_EXTENSION|text|align|imageExtension_|span|IMAGE_PATH|weight|bold|color|000|imagePath_|Point|v3|googlecode|com|svn|trunk|markerclustererplus|images|png|53|56|66|78|90|imageSizes|in|cleanup|update|ObjectManager|distance|1000|imagePath|removeAll|getGeoPoint|Update|converter|addOverlay|move|MoveEnd|60|imageExtension|getRightTop|setMarkers|getBounds|getLeftBottom|toString|typeof|GeoBounds|img|src|400|alt|absolute|left|top|undefined|000000|clearTimeout|http|google|maps|utility|background|url|no|repeat|Style|IconStyle|library|Placemark|hasBalloon|Click|setBounds|setZoom|clear|40000'.split('|'),0,{}))