Strategies that request data (fixed and bbox currently) should transform geometries when the layer projection is different than the map projection. This adds reprojection support to the Fixed and BBOX strategies. Given more strategies that request data, we will likely want to extract out the common parts. r=elemoine (closes #1841)
git-svn-id: http://svn.openlayers.org/trunk/openlayers@8804 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
@@ -19,7 +19,8 @@ OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {
|
||||
|
||||
/**
|
||||
* Property: bounds
|
||||
* {<OpenLayers.Bounds>} The current data bounds.
|
||||
* {<OpenLayers.Bounds>} The current data bounds (in the same projection
|
||||
* as the layer - not always the same projection as the map).
|
||||
*/
|
||||
bounds: null,
|
||||
|
||||
@@ -103,12 +104,29 @@ OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {
|
||||
* must be incondtionally read.
|
||||
*/
|
||||
update: function(options) {
|
||||
var mapBounds = this.layer.map.getExtent();
|
||||
var mapBounds = this.getMapBounds();
|
||||
if ((options && options.force) || this.invalidBounds(mapBounds)) {
|
||||
this.calculateBounds(mapBounds);
|
||||
this.triggerRead();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: getMapBounds
|
||||
* Get the map bounds expressed in the same projection as this layer.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Bounds>} Map bounds in the projection of the layer.
|
||||
*/
|
||||
getMapBounds: function() {
|
||||
var bounds = this.layer.map.getExtent();
|
||||
if(!this.layer.projection.equals(this.layer.map.getProjectionObject())) {
|
||||
bounds = bounds.clone().transform(
|
||||
this.layer.map.getProjectionObject(), this.layer.projection
|
||||
);
|
||||
}
|
||||
return bounds;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: invalidBounds
|
||||
@@ -122,7 +140,7 @@ OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {
|
||||
*/
|
||||
invalidBounds: function(mapBounds) {
|
||||
if(!mapBounds) {
|
||||
mapBounds = this.layer.map.getExtent();
|
||||
mapBounds = this.getMapBounds();
|
||||
}
|
||||
return !this.bounds || !this.bounds.containsBounds(mapBounds);
|
||||
},
|
||||
@@ -136,7 +154,7 @@ OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {
|
||||
*/
|
||||
calculateBounds: function(mapBounds) {
|
||||
if(!mapBounds) {
|
||||
mapBounds = this.layer.map.getExtent();
|
||||
mapBounds = this.getMapBounds();
|
||||
}
|
||||
var center = mapBounds.getCenterLonLat();
|
||||
var dataWidth = mapBounds.getWidth() * this.ratio;
|
||||
@@ -189,6 +207,8 @@ OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {
|
||||
/**
|
||||
* Method: merge
|
||||
* Given a list of features, determine which ones to add to the layer.
|
||||
* If the layer projection differs from the map projection, features
|
||||
* will be transformed from the layer projection to the map projection.
|
||||
*
|
||||
* Parameters:
|
||||
* resp - {<OpenLayers.Protocol.Response>} The response object passed
|
||||
@@ -198,6 +218,17 @@ OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {
|
||||
this.layer.destroyFeatures();
|
||||
var features = resp.features;
|
||||
if(features && features.length > 0) {
|
||||
var remote = this.layer.projection;
|
||||
var local = this.layer.map.getProjectionObject();
|
||||
if(!local.equals(remote)) {
|
||||
var geom;
|
||||
for(var i=0, len=features.length; i<len; ++i) {
|
||||
geom = features[i].geometry;
|
||||
if(geom) {
|
||||
geom.transform(remote, local);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.layer.addFeatures(features);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -88,6 +88,17 @@ OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, {
|
||||
merge: function(resp) {
|
||||
var features = resp.features;
|
||||
if (features && features.length > 0) {
|
||||
var remote = this.layer.projection;
|
||||
var local = this.layer.map.getProjectionObject();
|
||||
if(!local.equals(remote)) {
|
||||
var geom;
|
||||
for(var i=0, len=features.length; i<len; ++i) {
|
||||
geom = features[i].geometry;
|
||||
if(geom) {
|
||||
geom.transform(remote, local);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.layer.addFeatures(features);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -33,46 +33,56 @@
|
||||
}
|
||||
|
||||
function test_update(t) {
|
||||
t.plan(6);
|
||||
t.plan(5);
|
||||
|
||||
var s = new OpenLayers.Strategy.BBOX();
|
||||
// Create a dummy layer that can act as the map base layer.
|
||||
// This will be unnecessary if #1921 is addressed (allowing
|
||||
// map to have different projection than base layer).
|
||||
var dummy = new OpenLayers.Layer(null, {isBaseLayer: true});
|
||||
|
||||
var invalidBoundsReturnValue;
|
||||
var bounds = new OpenLayers.Bounds(-100, -40, 100, 40);
|
||||
|
||||
s.invalidBounds = function(b) {
|
||||
t.ok(b == bounds,
|
||||
"update calls invalidBounds with correct arg");
|
||||
return invalidBoundsReturnValue;
|
||||
};
|
||||
s.calculateBounds = function(b) {
|
||||
t.ok(b == bounds,
|
||||
"update calls calculateBounds with correct arg");
|
||||
};
|
||||
s.triggerRead = function() {
|
||||
t.ok(true,
|
||||
"update calls triggerRead");
|
||||
};
|
||||
|
||||
s.setLayer({
|
||||
map: {
|
||||
getExtent: function() {
|
||||
return bounds;
|
||||
}
|
||||
}
|
||||
var strategy = new OpenLayers.Strategy.BBOX({
|
||||
ratio: 1 // makes for easier comparison to map bounds
|
||||
});
|
||||
var layer = new OpenLayers.Layer.Vector(null, {
|
||||
isBaseLayer: true,
|
||||
protocol: new OpenLayers.Protocol(),
|
||||
strategies: [strategy]
|
||||
});
|
||||
|
||||
// 2 tests
|
||||
invalidBoundsReturnValue = true;
|
||||
s.update({force: true});
|
||||
// create a map with the layers and a center
|
||||
var map = new OpenLayers.Map("map");
|
||||
map.addLayers([dummy, layer]);
|
||||
map.zoomToMaxExtent();
|
||||
|
||||
/**
|
||||
* The setCenter call above should set strategy bounds. I *think* this
|
||||
* issue is captured in http://trac.openlayers.org/ticket/1835.
|
||||
* For now, I'm going to force an update on the strategy. This line
|
||||
* should be removed when the issue(s) described in #1835 are addressed.
|
||||
*/
|
||||
strategy.update({force: true});
|
||||
|
||||
// test that the strategy bounds were set
|
||||
t.ok(map.getExtent().equals(strategy.bounds), "[set center] bounds set to map extent");
|
||||
|
||||
// zoom and test that bounds are not reset
|
||||
var old = strategy.bounds.clone();
|
||||
map.zoomIn();
|
||||
t.ok(strategy.bounds.equals(old), "[zoom in] bounds not reset");
|
||||
|
||||
// force update and check that bounds change
|
||||
strategy.update({force: true});
|
||||
t.ok(!strategy.bounds.equals(old), "[force update] bounds changed");
|
||||
t.ok(strategy.bounds.equals(map.getExtent()), "[force update] bounds set to map extent");
|
||||
|
||||
// change the layer projection to confirm strategy uses same
|
||||
layer.projection = new OpenLayers.Projection("EPSG:900913");
|
||||
strategy.update({force: true});
|
||||
var from = map.getProjectionObject();
|
||||
var to = layer.projection;
|
||||
t.ok(strategy.bounds.equals(map.getExtent().transform(from, to)), "[force update different proj] bounds transformed");
|
||||
|
||||
|
||||
// 3 tests
|
||||
invalidBoundsReturnValue = true;
|
||||
s.update();
|
||||
|
||||
// 1 tests
|
||||
invalidBoundsReturnValue = false;
|
||||
s.update();
|
||||
}
|
||||
|
||||
function test_triggerRead(t) {
|
||||
@@ -131,25 +141,58 @@
|
||||
}
|
||||
|
||||
function test_merge(t) {
|
||||
t.plan(2);
|
||||
|
||||
var s = new OpenLayers.Strategy.BBOX();
|
||||
|
||||
var features = ["fake", "feature", "array"];
|
||||
|
||||
s.setLayer({
|
||||
destroyFeatures: function() {
|
||||
t.ok(true,
|
||||
"merge calls destroyFeatures");
|
||||
},
|
||||
addFeatures: function(f) {
|
||||
t.ok(f == features,
|
||||
"merge calls addFeatures with the correct features");
|
||||
}
|
||||
t.plan(4);
|
||||
|
||||
var strategy = new OpenLayers.Strategy.BBOX();
|
||||
|
||||
// create map with default projection
|
||||
var map = new OpenLayers.Map("map");
|
||||
|
||||
// create layer with custom projection
|
||||
var layer = new OpenLayers.Layer.Vector(null, {
|
||||
isBaseLayer: true,
|
||||
strategies: [strategy],
|
||||
protocol: new OpenLayers.Protocol(),
|
||||
projection: new OpenLayers.Projection("EPSG:900913")
|
||||
});
|
||||
map.addLayer(layer);
|
||||
map.zoomToMaxExtent();
|
||||
|
||||
// create some features
|
||||
var geometries = [
|
||||
new OpenLayers.Geometry.Point(100, 200),
|
||||
new OpenLayers.Geometry.Point(1000, 2000)
|
||||
];
|
||||
var features = [
|
||||
new OpenLayers.Feature.Vector(geometries[0].clone()),
|
||||
new OpenLayers.Feature.Vector(geometries[1].clone())
|
||||
];
|
||||
|
||||
// 2 tests
|
||||
s.merge({features: features});
|
||||
// call merge with a mocked up response
|
||||
strategy.merge({features: features});
|
||||
|
||||
// test that feature geometries have been transformed to map projection
|
||||
var from = layer.projection;
|
||||
var to = map.getProjectionObject();
|
||||
t.geom_eq(layer.features[0].geometry, features[0].geometry.transform(from, to), "[different proj] feature 0 geometry transformed");
|
||||
t.geom_eq(layer.features[1].geometry, features[1].geometry.transform(from, to), "[different proj] feature 1 geometry transformed");
|
||||
|
||||
// same as above but with same map/layer projection
|
||||
layer.destroyFeatures();
|
||||
layer.projection = map.getProjectionObject();
|
||||
|
||||
features = [
|
||||
new OpenLayers.Feature.Vector(geometries[0].clone()),
|
||||
new OpenLayers.Feature.Vector(geometries[1].clone())
|
||||
];
|
||||
|
||||
// call merge again with mocked up response
|
||||
strategy.merge({features: features});
|
||||
|
||||
// test that feature geometries have not been transformed
|
||||
t.geom_eq(layer.features[0].geometry, features[0].geometry, "[same proj] feature 0 geometry not transformed");
|
||||
t.geom_eq(layer.features[1].geometry, features[1].geometry, "[same proj] feature 1 geometry not transformed");
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@@ -13,6 +13,11 @@
|
||||
options.callback.call(options.scope, {features: featureList});
|
||||
}
|
||||
};
|
||||
|
||||
// Create a dummy layer that can act as the map base layer.
|
||||
// This will be unnecessary if #1920 is addressed or if base layer
|
||||
// handling is changed.
|
||||
var dummy = new OpenLayers.Layer(null, {isBaseLayer: true});
|
||||
|
||||
var layer = new OpenLayers.Layer.Vector("Vector Layer", {
|
||||
strategies: [new OpenLayers.Strategy.Fixed()],
|
||||
@@ -42,7 +47,7 @@
|
||||
});
|
||||
|
||||
var map = new OpenLayers.Map('map');
|
||||
map.addLayers([layer, layerp, layer2]);
|
||||
map.addLayers([dummy, layer, layerp, layer2]);
|
||||
|
||||
t.ok(layer2.events.listeners["visibilitychanged"][0].obj == s &&
|
||||
layer2.events.listeners["visibilitychanged"][0].func == s.load,
|
||||
@@ -54,6 +59,62 @@
|
||||
t.ok(layer2.events.listeners["visibilitychanged"] == false,
|
||||
"visibilitychanged listener unregistered");
|
||||
}
|
||||
|
||||
function tests_merge(t) {
|
||||
|
||||
t.plan(4);
|
||||
|
||||
var strategy = new OpenLayers.Strategy.Fixed();
|
||||
|
||||
// create map with default projection
|
||||
var map = new OpenLayers.Map("map");
|
||||
|
||||
// create layer with custom projection
|
||||
var layer = new OpenLayers.Layer.Vector(null, {
|
||||
isBaseLayer: true,
|
||||
strategies: [strategy],
|
||||
protocol: new OpenLayers.Protocol(),
|
||||
projection: new OpenLayers.Projection("EPSG:900913")
|
||||
});
|
||||
map.addLayer(layer);
|
||||
map.zoomToMaxExtent();
|
||||
|
||||
// create some features
|
||||
var geometries = [
|
||||
new OpenLayers.Geometry.Point(100, 200),
|
||||
new OpenLayers.Geometry.Point(1000, 2000)
|
||||
];
|
||||
var features = [
|
||||
new OpenLayers.Feature.Vector(geometries[0].clone()),
|
||||
new OpenLayers.Feature.Vector(geometries[1].clone())
|
||||
];
|
||||
|
||||
// call merge with a mocked up response
|
||||
strategy.merge({features: features});
|
||||
|
||||
// test that feature geometries have been transformed to map projection
|
||||
var from = layer.projection;
|
||||
var to = map.getProjectionObject();
|
||||
t.geom_eq(layer.features[0].geometry, features[0].geometry.transform(from, to), "[different proj] feature 0 geometry transformed");
|
||||
t.geom_eq(layer.features[1].geometry, features[1].geometry.transform(from, to), "[different proj] feature 1 geometry transformed");
|
||||
|
||||
// same as above but with same map/layer projection
|
||||
layer.destroyFeatures();
|
||||
layer.projection = map.getProjectionObject();
|
||||
|
||||
features = [
|
||||
new OpenLayers.Feature.Vector(geometries[0].clone()),
|
||||
new OpenLayers.Feature.Vector(geometries[1].clone())
|
||||
];
|
||||
|
||||
// call merge again with mocked up response
|
||||
strategy.merge({features: features});
|
||||
|
||||
// test that feature geometries have not been transformed
|
||||
t.geom_eq(layer.features[0].geometry, features[0].geometry, "[same proj] feature 0 geometry not transformed");
|
||||
t.geom_eq(layer.features[1].geometry, features[1].geometry, "[same proj] feature 1 geometry not transformed");
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
Reference in New Issue
Block a user