1 /* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
2 * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
3 * full text of the license. */
6 * @requires OpenLayers/Strategy.js
7 * @requires OpenLayers/Filter/Spatial.js
11 * Class: OpenLayers.Strategy.BBOX
12 * A simple strategy that reads new features when the viewport invalidates
16 * - <OpenLayers.Strategy>
18 OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {
22 * {<OpenLayers.Bounds>} The current data bounds (in the same projection
23 * as the layer - not always the same projection as the map).
28 * Property: resolution
29 * {Float} The current data resolution.
35 * {Float} The ratio of the data bounds to the viewport bounds (in each
36 * dimension). Default is 2.
42 * {Float} Optional factor used to determine when previously requested
43 * features are invalid. If set, the resFactor will be compared to the
44 * resolution of the previous request to the current map resolution.
45 * If resFactor > (old / new) and 1/resFactor < (old / new). If you
46 * set a resFactor of 1, data will be requested every time the
47 * resolution changes. If you set a resFactor of 3, data will be
48 * requested if the old resolution is 3 times the new, or if the new is
49 * 3 times the old. If the old bounds do not contain the new bounds
50 * new data will always be requested (with or without considering
57 * {<OpenLayers.Protocol.Response>} The protocol response object returned
58 * by the layer protocol.
63 * Constructor: OpenLayers.Strategy.BBOX
64 * Create a new BBOX strategy.
67 * options - {Object} Optional object whose properties will be set on the
70 initialize: function(options) {
71 OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
76 * Set up strategy with regard to reading new batches of remote data.
79 * {Boolean} The strategy was successfully activated.
81 activate: function() {
82 var activated = OpenLayers.Strategy.prototype.activate.call(this);
84 this.layer.events.on({
85 "moveend": this.update,
88 this.layer.events.on({
89 "refresh": this.update,
98 * Tear down strategy with regard to reading new batches of remote data.
101 * {Boolean} The strategy was successfully deactivated.
103 deactivate: function() {
104 var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
106 this.layer.events.un({
107 "moveend": this.update,
110 this.layer.events.un({
111 "refresh": this.update,
120 * Callback function called on "moveend" or "refresh" layer events.
123 * options - {Object} An object with a property named "force", this
124 * property references a boolean value indicating if new data
125 * must be incondtionally read.
127 update: function(options) {
128 var mapBounds = this.getMapBounds();
129 if ((options && options.force) || this.invalidBounds(mapBounds)) {
130 this.calculateBounds(mapBounds);
131 this.resolution = this.layer.map.getResolution();
137 * Method: getMapBounds
138 * Get the map bounds expressed in the same projection as this layer.
141 * {<OpenLayers.Bounds>} Map bounds in the projection of the layer.
143 getMapBounds: function() {
144 var bounds = this.layer.map.getExtent();
145 if(!this.layer.projection.equals(this.layer.map.getProjectionObject())) {
146 bounds = bounds.clone().transform(
147 this.layer.map.getProjectionObject(), this.layer.projection
154 * Method: invalidBounds
155 * Determine whether the previously requested set of features is invalid.
156 * This occurs when the new map bounds do not contain the previously
157 * requested bounds. In addition, if <resFactor> is set, it will be
161 * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be
162 * retrieved from the map object if not provided
167 invalidBounds: function(mapBounds) {
169 mapBounds = this.getMapBounds();
171 var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds);
172 if(!invalid && this.resFactor) {
173 var ratio = this.resolution / this.layer.map.getResolution();
174 invalid = (ratio >= this.resFactor || ratio <= (1 / this.resFactor));
180 * Method: calculateBounds
183 * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be
184 * retrieved from the map object if not provided
186 calculateBounds: function(mapBounds) {
188 mapBounds = this.getMapBounds();
190 var center = mapBounds.getCenterLonLat();
191 var dataWidth = mapBounds.getWidth() * this.ratio;
192 var dataHeight = mapBounds.getHeight() * this.ratio;
193 this.bounds = new OpenLayers.Bounds(
194 center.lon - (dataWidth / 2),
195 center.lat - (dataHeight / 2),
196 center.lon + (dataWidth / 2),
197 center.lat + (dataHeight / 2)
202 * Method: triggerRead
205 * {<OpenLayers.Protocol.Response>} The protocol response object
206 * returned by the layer protocol.
208 triggerRead: function() {
209 this.layer.protocol.abort(this.response);
210 this.layer.events.triggerEvent("loadstart");
211 this.response = this.layer.protocol.read({
212 filter: this.createFilter(),
213 callback: this.merge,
219 * Method: createFilter
222 * {<OpenLayers.Filter>} The filter object.
224 createFilter: function() {
225 var filter = new OpenLayers.Filter.Spatial({
226 type: OpenLayers.Filter.Spatial.BBOX,
228 projection: this.layer.projection
230 if (this.layer.filter) {
231 filter = new OpenLayers.Filter.Logical({
232 type: OpenLayers.Filter.Logical.AND,
233 filters: [this.layer.filter, filter]
241 * Given a list of features, determine which ones to add to the layer.
242 * If the layer projection differs from the map projection, features
243 * will be transformed from the layer projection to the map projection.
246 * resp - {<OpenLayers.Protocol.Response>} The response object passed
249 merge: function(resp) {
250 this.layer.destroyFeatures();
251 var features = resp.features;
252 if(features && features.length > 0) {
253 var remote = this.layer.projection;
254 var local = this.layer.map.getProjectionObject();
255 if(!local.equals(remote)) {
257 for(var i=0, len=features.length; i<len; ++i) {
258 geom = features[i].geometry;
260 geom.transform(remote, local);
264 this.layer.addFeatures(features);
266 this.layer.events.triggerEvent("loadend");
269 CLASS_NAME: "OpenLayers.Strategy.BBOX"