Batch merge for rc2 of 2.7. 'svn merge -r7967:HEAD from trunk (Closes #1733) (Closes #1489) (Closes #1639) (Closes #1718) (Closes #1723) (Closes #1732) (Closes #1616) (Closes #1722)

git-svn-id: http://svn.openlayers.org/branches/openlayers/2.7@8012 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
euzuro
2008-09-12 17:24:20 +00:00
parent a43e98762c
commit f7f338e265
51 changed files with 7219 additions and 90 deletions
+210
View File
@@ -0,0 +1,210 @@
/* 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
* @requires OpenLayers/Filter/Spatial.js
*/
/**
* Class: OpenLayers.Strategy.BBOX
* A simple strategy that reads new features when the viewport invalidates
* some bounds.
*
* Inherits from:
* - <OpenLayers.Strategy>
*/
OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {
/**
* Property: bounds
* {<OpenLayers.Bounds>} The current data bounds.
*/
bounds: null,
/**
* Property: ratio
* {Float} The ratio of the data bounds to the viewport bounds (in each
* dimension).
*/
ratio: 2,
/**
* Property: response
* {<OpenLayers.Protocol.Response>} The protocol response object returned
* by the layer protocol.
*/
response: null,
/**
* Constructor: OpenLayers.Strategy.BBOX
* Create a new BBOX strategy.
*
* Parameters:
* options - {Object} Optional object whose properties will be set on the
* instance.
*/
initialize: function(options) {
OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
},
/**
* Method: activate
* Set up strategy with regard to reading new batches of remote data.
*
* Returns:
* {Boolean} The strategy was successfully activated.
*/
activate: function() {
var activated = OpenLayers.Strategy.prototype.activate.call(this);
if(activated) {
this.layer.events.on({
"moveend": this.update,
scope: this
});
this.layer.events.on({
"refresh": this.update,
scope: this
});
}
return activated;
},
/**
* Method: deactivate
* Tear down strategy with regard to reading new batches of remote data.
*
* Returns:
* {Boolean} The strategy was successfully deactivated.
*/
deactivate: function() {
var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
if(deactivated) {
this.layer.events.un({
"moveend": this.update,
scope: this
});
this.layer.events.un({
"refresh": this.update,
scope: this
});
}
return deactivated;
},
/**
* Method: update
* Callback function called on "moveend" or "refresh" layer events.
*
* Parameters:
* options - {Object} An object with a property named "force", this
* property references a boolean value indicating if new data
* must be incondtionally read.
*/
update: function(options) {
var mapBounds = this.layer.map.getExtent();
if ((options && options.force) || this.invalidBounds(mapBounds)) {
this.calculateBounds(mapBounds);
this.triggerRead();
}
},
/**
* Method: invalidBounds
*
* Parameters:
* mapBounds - {<OpenLayers.Bounds>} the current map extent, will be
* retrieved from the map object if not provided
*
* Returns:
* {Boolean}
*/
invalidBounds: function(mapBounds) {
if(!mapBounds) {
mapBounds = this.layer.map.getExtent();
}
return !this.bounds || !this.bounds.containsBounds(mapBounds);
},
/**
* Method: calculateBounds
*
* Parameters:
* mapBounds - {<OpenLayers.Bounds>} the current map extent, will be
* retrieved from the map object if not provided
*/
calculateBounds: function(mapBounds) {
if(!mapBounds) {
mapBounds = this.layer.map.getExtent();
}
var center = mapBounds.getCenterLonLat();
var dataWidth = mapBounds.getWidth() * this.ratio;
var dataHeight = mapBounds.getHeight() * this.ratio;
this.bounds = new OpenLayers.Bounds(
center.lon - (dataWidth / 2),
center.lat - (dataHeight / 2),
center.lon + (dataWidth / 2),
center.lat + (dataHeight / 2)
);
},
/**
* Method: triggerRead
*
* Returns:
* {<OpenLayers.Protocol.Response>} The protocol response object
* returned by the layer protocol.
*/
triggerRead: function() {
var filter = this.createFilter();
if (this.response && this.response.priv &&
typeof this.response.priv.abort == "function") {
this.response.priv.abort();
}
this.response = this.layer.protocol.read({
filter: filter,
callback: this.merge,
scope: this
});
},
/**
* Method: createFilter
*
* Returns
* {<OpenLayers.Filter>} The filter object.
*/
createFilter: function() {
var filter = new OpenLayers.Filter.Spatial({
type: OpenLayers.Filter.Spatial.BBOX,
value: this.bounds,
projection: this.layer.projection
});
if (this.layer.filter) {
filter = new OpenLayers.Filter.Logical({
type: OpenLayers.Filter.Logical.AND,
filters: [this.layer.filter, filter]
});
}
return filter;
},
/**
* Method: merge
* Given a list of features, determine which ones to add to the layer.
*
* Parameters:
* resp - {<OpenLayers.Protocol.Response>} The response object passed
* by the protocol.
*/
merge: function(resp) {
this.layer.destroyFeatures();
var features = resp.features;
if(features && features.length > 0) {
this.layer.addFeatures(features);
}
},
CLASS_NAME: "OpenLayers.Strategy.BBOX"
});
+261
View File
@@ -0,0 +1,261 @@
/* 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>
*/
OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, {
/**
* Property: layer
* {<OpenLayers.Layer.Vector>} 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(<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.
*/
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<this.features.length; ++i) {
this.features[i].destroy();
}
}
this.features = null;
},
/**
* Method: cluster
* Cluster features based on some threshold distance.
*/
cluster: function() {
if(this.features) {
var resolution = this.layer.getResolution();
if(resolution != this.resolution || !this.clustersExist()) {
this.resolution = resolution;
var clusters = [];
var feature, clustered, cluster;
for(var i=0; i<this.features.length; ++i) {
feature = this.features[i];
clustered = false;
for(var j=0; j<clusters.length; ++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.destroyFeatures();
if(clusters.length > 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<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"
});
+241
View File
@@ -0,0 +1,241 @@
/* 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.Paging
* Strategy for vector feature paging
*
* Inherits from:
* - <OpenLayers.Strategy>
*/
OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, {
/**
* Property: layer
* {<OpenLayers.Layer.Vector>} The layer that this strategy is assigned to.
*/
layer: null,
/**
* Property: features
* {Array(<OpenLayers.Feature.Vector>)} Cached features.
*/
features: null,
/**
* Property: length
* {Integer} Number of features per page. Default is 10.
*/
length: 10,
/**
* Property: num
* {Integer} The currently displayed page number.
*/
num: null,
/**
* Property: paging
* {Boolean} The strategy is currently changing pages.
*/
paging: false,
/**
* Constructor: OpenLayers.Strategy.Paging
* Create a new paging 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
});
}
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
});
}
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 paged.
*/
cacheFeatures: function(event) {
if(!this.paging) {
this.clearCache();
this.features = event.features;
this.pageNext(event);
}
},
/**
* 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<this.features.length; ++i) {
this.features[i].destroy();
}
}
this.features = null;
this.num = null;
},
/**
* APIMethod: pageCount
* Get the total count of pages given the current cache of features.
*
* Returns:
* {Integer} The page count.
*/
pageCount: function() {
var numFeatures = this.features ? this.features.length : 0;
return Math.ceil(numFeatures / this.length);
},
/**
* APIMethod: pageNum
* Get the zero based page number.
*
* Returns:
* {Integer} The current page number being displayed.
*/
pageNum: function() {
return this.num;
},
/**
* APIMethod: pageLength
* Gets or sets page length.
*
* Parameters:
* newLength: {Integer} Optional length to be set.
*
* Returns:
* {Integer} The length of a page (number of features per page).
*/
pageLength: function(newLength) {
if(newLength && newLength > 0) {
this.length = newLength;
}
return this.length;
},
/**
* APIMethod: pageNext
* Display the next page of features.
*
* Returns:
* {Boolean} A new page was displayed.
*/
pageNext: function(event) {
var changed = false;
if(this.features) {
if(this.num === null) {
this.num = -1;
}
var start = (this.num + 1) * this.length;
changed = this.page(start, event);
}
return changed;
},
/**
* APIMethod: pagePrevious
* Display the previous page of features.
*
* Returns:
* {Boolean} A new page was displayed.
*/
pagePrevious: function() {
var changed = false;
if(this.features) {
if(this.num === null) {
this.num = this.pageCount();
}
var start = (this.num - 1) * this.length;
changed = this.page(start);
}
return changed;
},
/**
* Method: page
* Display the page starting at the given index from the cache.
*
* Returns:
* {Boolean} A new page was displayed.
*/
page: function(start, event) {
var changed = false;
if(this.features) {
if(start >= 0 && start < this.features.length) {
var num = Math.floor(start / this.length);
if(num != this.num) {
this.paging = true;
var features = this.features.slice(start, start + this.length);
this.layer.removeFeatures(this.layer.features);
this.num = num;
// modify the event if any
if(event && event.features) {
// this.was called by an event listener
event.features = features;
} else {
// this was called directly on the strategy
this.layer.addFeatures(features);
}
this.paging = false;
changed = true;
}
}
}
return changed;
},
CLASS_NAME: "OpenLayers.Strategy.Paging"
});