所以,我在OpenLayers中聚集了许多项目。
我正在使用一种策略,根据其属性对项目进行聚类。
我更改了项目的属性。
如何让群集策略重新计算群集?
答案 0 :(得分:13)
好的,事实证明,从2.11RC1开始,此功能在OpenLayers中不可用。因此,我自己将它实现为Cluster类的影子。该代码也可作为OpenLayers Trac中的补丁提供。
此答案末尾的代码可以直接删除到javascript文件中,并覆盖现有的OpenLayers OpenLayers.Strategy.Cluster
类。它添加了一个方法recluster
,当被调用时,将导致策略重新计算其聚类。由于我们正在更改Cluster
基类,因此任何派生类都应该适当地继承recluster
方法。
如何使用它的一个例子是:
var clustering=new OpenLayers.Strategy.Cluster()
var vectorlayer = new OpenLayers.Layer.Vector('Vectorlayer', {
strategies: [clustering]
});
//ADD_LOTS_OF_FEATURES_TO_VECTOR_LAYER
clustering.distance=value;
clustering.recluster();
替换类的代码是:
OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, {
/**
* APIProperty: distance
* {Integer} Pixel distance between features that should be considered a
* single cluster. Default is 20 pixels.
*/
distance: 20,
/**
* APIProperty: threshold
* {Integer} Optional threshold below which original features will be
* added to the layer instead of clusters. For example, a threshold
* of 3 would mean that any time there are 2 or fewer features in
* a cluster, those features will be added directly to the layer instead
* of a cluster representing those features. Default is null (which is
* equivalent to 1 - meaning that clusters may contain just one feature).
*/
threshold: null,
/**
* Property: features
* {Array(<OpenLayers.Feature.Vector>)} Cached features.
*/
features: null,
/**
* Property: clusters
* {Array(<OpenLayers.Feature.Vector>)} 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.
*/
/**
* 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,
"moveend": 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,
"moveend": 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 features 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.
*/
clearCache: function() {
this.features = null;
},
/**
* Method: cluster
* Cluster features based on some threshold distance.
*
* Parameters:
* event - {Object} The event received when cluster is called as a
* result of a moveend event.
*/
cluster: function(event) {
if((!event || event.zoomChanged || (event && event.recluster)) && this.features) {
var resolution = this.layer.map.getResolution();
if(resolution != this.resolution || !this.clustersExist() || (event && event.recluster)) {
this.resolution = resolution;
var clusters = [];
var feature, clustered, cluster;
for(var i=0; i<this.features.length; ++i) {
feature = this.features[i];
if(feature.geometry) {
clustered = false;
for(var j=clusters.length-1; j>=0; --j) {
cluster = clusters[j];
if(this.shouldCluster(cluster, feature)) {
this.addToCluster(cluster, feature);
clustered = true;
break;
}
}
if(!clustered) {
clusters.push(this.createCluster(this.features[i]));
}
}
}
this.layer.removeAllFeatures();
if(clusters.length > 0) {
if(this.threshold > 1) {
var clone = clusters.slice();
clusters = [];
var candidate;
for(var i=0, len=clone.length; i<len; ++i) {
candidate = clone[i];
if(candidate.attributes.count < this.threshold) {
Array.prototype.push.apply(clusters, candidate.cluster);
} else {
clusters.push(candidate);
}
}
}
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: recluster
* User-callable function to recluster features
* Useful for instances where a clustering attribute (distance, threshold, ...)
* has changed
*/
recluster: function(){
var event={"recluster":true};
this.cluster(event);
},
/**
* 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<this.clusters.length; ++i) {
if(this.clusters[i] != this.layer.features[i]) {
exist = false;
break;
}
}
}
return exist;
},
/**
* Method: shouldCluster
* Determine whether to include a feature in a given cluster.
*
* Parameters:
* cluster - {<OpenLayers.Feature.Vector>} A cluster.
* feature - {<OpenLayers.Feature.Vector>} 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 - {<OpenLayers.Feature.Vector>} A cluster.
* feature - {<OpenLayers.Feature.Vector>} A feature.
*/
addToCluster: function(cluster, feature) {
cluster.cluster.push(feature);
cluster.attributes.count += 1;
},
/**
* Method: createCluster
* Given a feature, create a cluster.
*
* Parameters:
* feature - {<OpenLayers.Feature.Vector>}
*
* Returns:
* {<OpenLayers.Feature.Vector>} 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"
});
答案 1 :(得分:1)
OpenLayers.Strategy.Cluster.cluster方法仅在它是zoomechanged事件或者cluster对象不存在时才重新计算。删除集群对象并在集群对象上调用集群。
var clustering=new OpenLayers.Strategy.Cluster()
var vectorlayer = new OpenLayers.Layer.Vector('Vectorlayer', {
strategies: [clustering]
});
//ADD_LOTS_OF_FEATURES_TO_VECTOR_LAYER
clustering.distance=value;
//cluster() recalculate only if it is a zoomechanged event or clusters object does not exist.
clustering.clusters = null; //remove cluster object so that it calculates again.
clustering.cluster();