/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the * full text of the license. */ /** * @requires OpenLayers/Strategy.js */ /** * Class: OpenLayers.Strategy.Cluster * Strategy for vector feature clustering. * * Inherits from: * - */ OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, { /** * Property: layer * {} The layer that this strategy is assigned to. */ layer: null, /** * APIProperty: distance * {Integer} Pixel distance between features that should be considered a * single cluster. Default is 20 pixels. */ distance: 20, /** * Property: features * {Array()} Cached features. */ features: null, /** * Property: clusters * {Array()} Calculated clusters. */ clusters: null, /** * Property: clustering * {Boolean} The strategy is currently clustering features. */ clustering: false, /** * Property: resolution * {Float} The resolution (map units per pixel) of the current cluster set. */ resolution: null, /** * Constructor: OpenLayers.Strategy.Cluster * Create a new clustering strategy. * * Parameters: * options - {Object} Optional object whose properties will be set on the * instance. */ initialize: function(options) { OpenLayers.Strategy.prototype.initialize.apply(this, [options]); }, /** * APIMethod: activate * Activate the strategy. Register any listeners, do appropriate setup. * * Returns: * {Boolean} The strategy was successfully activated. */ activate: function() { var activated = OpenLayers.Strategy.prototype.activate.call(this); if(activated) { this.layer.events.on({ "beforefeaturesadded": this.cacheFeatures, scope: this }); this.layer.map.events.on({"zoomend": this.cluster, scope: this}); } return activated; }, /** * APIMethod: deactivate * Deactivate the strategy. Unregister any listeners, do appropriate * tear-down. * * Returns: * {Boolean} The strategy was successfully deactivated. */ deactivate: function() { var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); if(deactivated) { this.clearCache(); this.layer.events.un({ "beforefeaturesadded": this.cacheFeatures, scope: this }); this.layer.map.events.un({"zoomend": this.cluster, scope: this}); } return deactivated; }, /** * Method: cacheFeatures * Cache features before they are added to the layer. * * Parameters: * event - {Object} The event that this was listening for. This will come * with a batch of features to be clustered. * * Returns: * {Boolean} False to stop layer from being added to the layer. */ cacheFeatures: function(event) { var propagate = true; if(!this.clustering) { this.clearCache(); this.features = event.features; this.cluster(); propagate = false; } return propagate; }, /** * Method: clearCache * Clear out the cached features. This destroys features, assuming * nothing else has a reference. */ clearCache: function() { if(this.features) { for(var i=0; i 0) { this.clustering = true; // A legitimate feature addition could occur during this // addFeatures call. For clustering to behave well, features // should be removed from a layer before requesting a new batch. this.layer.addFeatures(clusters); this.clustering = false; } this.clusters = clusters; } } }, /** * Method: clustersExist * Determine whether calculated clusters are already on the layer. * * Returns: * {Boolean} The calculated clusters are already on the layer. */ clustersExist: function() { var exist = false; if(this.clusters && this.clusters.length > 0 && this.clusters.length == this.layer.features.length) { exist = true; for(var i=0; i} A cluster. * feature - {} A feature. * * Returns: * {Boolean} The feature should be included in the cluster. */ shouldCluster: function(cluster, feature) { var cc = cluster.geometry.getBounds().getCenterLonLat(); var fc = feature.geometry.getBounds().getCenterLonLat(); var distance = ( Math.sqrt( Math.pow((cc.lon - fc.lon), 2) + Math.pow((cc.lat - fc.lat), 2) ) / this.resolution ); return (distance <= this.distance); }, /** * Method: addToCluster * Add a feature to a cluster. * * Parameters: * cluster - {} A cluster. * feature - {} A feature. */ addToCluster: function(cluster, feature) { cluster.cluster.push(feature); cluster.attributes.count += 1; }, /** * Method: createCluster * Given a feature, create a cluster. * * Parameters: * feature - {} * * Returns: * {} A cluster. */ createCluster: function(feature) { var center = feature.geometry.getBounds().getCenterLonLat(); var cluster = new OpenLayers.Feature.Vector( new OpenLayers.Geometry.Point(center.lon, center.lat), {count: 1} ); cluster.cluster = [feature]; return cluster; }, CLASS_NAME: "OpenLayers.Strategy.Cluster" });