diff --git a/examples/wrapDateLine.html b/examples/wrapDateLine.html
new file mode 100644
index 0000000000..7a4cf8b12f
--- /dev/null
+++ b/examples/wrapDateLine.html
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+ This is an example that shows wrapping the date line. Wrapping the
+ date line is an option on the layer.
+
+
+
diff --git a/lib/OpenLayers/BaseTypes.js b/lib/OpenLayers/BaseTypes.js
index 1b426f5c1b..70eb1e53c9 100644
--- a/lib/OpenLayers/BaseTypes.js
+++ b/lib/OpenLayers/BaseTypes.js
@@ -299,6 +299,32 @@ OpenLayers.LonLat.prototype = {
return equals;
},
+ /**
+ * @param {OpenLayers.Bounds} maxExtent
+ *
+ * @returns A copy of this lonlat, but wrapped around the "dateline" (as
+ * specified by the borders of maxExtent)
+ * @type OpenLayers.LonLat
+ */
+ wrapDateLine: function(maxExtent) {
+
+ var newLonLat = this.clone();
+
+ if (maxExtent) {
+ //shift right?
+ while (newLonLat.lon < maxExtent.left) {
+ newLonLat.lon += maxExtent.getWidth();
+ }
+
+ //shift left?
+ while (newLonLat.lon > maxExtent.right) {
+ newLonLat.lon -= maxExtent.getWidth();
+ }
+ }
+
+ return newLonLat;
+ },
+
/** @final @type String */
CLASS_NAME: "OpenLayers.LonLat"
};
@@ -666,6 +692,50 @@ OpenLayers.Bounds.prototype = {
return quadrant;
},
+ /**
+ * @param {OpenLayers.Bounds} maxExtent
+ * @param {Object} options
+ * @option {float} leftTolerance Allow for a margin of error with the
+ * 'left' value of this bound.
+ * Default is 0
+ * @option {float} rightTolerance Allow for a margin of error with the
+ * 'right' value of this bound.
+ * Default is 0
+ *
+ * @returns A copy of this bounds, but wrapped around the "dateline" (as
+ * specified by the borders of maxExtent). Note that this
+ * function only returns a different bounds value if this bounds
+ * is *entirely* outside of the maxExtent. If this bounds
+ * straddles the dateline (is part in/part out of maxExtent),
+ * the returned bounds will be merely a copy of this one.
+ * @type OpenLayers.Bounds
+ */
+ wrapDateLine: function(maxExtent, options) {
+ options = options || new Object();
+
+ var leftTolerance = options.leftTolerance || 0;
+ var rightTolerance = options.rightTolerance || 0;
+
+ var newBounds = this.clone();
+
+ if (maxExtent) {
+
+ //shift right?
+ while ( newBounds.left < maxExtent.left &&
+ (newBounds.right - rightTolerance) <= maxExtent.left ) {
+ newBounds = newBounds.add(maxExtent.getWidth(), 0);
+ }
+
+ //shift left?
+ while ( (newBounds.left + leftTolerance) >= maxExtent.right &&
+ newBounds.right > maxExtent.right ) {
+ newBounds = newBounds.add(-maxExtent.getWidth(), 0);
+ }
+ }
+
+ return newBounds;
+ },
+
/** @final @type String */
CLASS_NAME: "OpenLayers.Bounds"
};
diff --git a/lib/OpenLayers/Layer.js b/lib/OpenLayers/Layer.js
index 3900fd9f71..76cf8f420a 100644
--- a/lib/OpenLayers/Layer.js
+++ b/lib/OpenLayers/Layer.js
@@ -139,6 +139,12 @@ OpenLayers.Layer.prototype = {
/** @type Boolean */
displayOutsideMaxExtent: false,
+
+ /** wrapDateLine -- #487 for more info.
+ *
+ * @type @Boolean
+ */
+ wrapDateLine: false,
/**
@@ -165,6 +171,10 @@ OpenLayers.Layer.prototype = {
this.events = new OpenLayers.Events(this, this.div,
this.EVENT_TYPES);
}
+
+ if (this.wrapDateLine) {
+ this.displayOutsideMaxExtent = true;
+ }
},
/**
@@ -616,6 +626,10 @@ OpenLayers.Layer.prototype = {
lonlat = new OpenLayers.LonLat(center.lon + delta_x * res ,
center.lat - delta_y * res);
+
+ if (this.wrapDateLine) {
+ lonlat = lonlat.wrapDateLine(this.maxExtent);
+ }
} // else { DEBUG STATEMENT }
}
return lonlat;
@@ -641,23 +655,6 @@ OpenLayers.Layer.prototype = {
return px;
},
- /**
- * Adjusts the extent of a bounds in map units by the layer's gutter
- * in pixels.
- *
- * @param {OpenLayers.Bounds} bounds
- * @type OpenLayers.Bounds
- * @return A bounds adjusted in height and width by the gutter
- */
- adjustBoundsByGutter: function(bounds) {
- var mapGutter = this.gutter * this.map.getResolution();
- bounds = new OpenLayers.Bounds(bounds.left - mapGutter,
- bounds.bottom - mapGutter,
- bounds.right + mapGutter,
- bounds.top + mapGutter);
- return bounds;
- },
-
/**
* Sets the opacity for the entire layer (all images)
* @param {Float} opacity
@@ -681,6 +678,38 @@ OpenLayers.Layer.prototype = {
this.div.style.zIndex = zIdx;
},
+ /**
+ * This function will take a bounds, and if wrapDateLine option is set
+ * on the layer, it will return a bounds which is wrapped around the world.
+ * We do not wrap for bounds which *cross* the maxExtent.left/right, only
+ * bounds which are entirely to the left or entirely to the right.
+ *
+ * @param {OpenLayers.Bounds} bounds
+ * @private
+ */
+ adjustBounds: function (bounds) {
+
+ if (this.gutter) {
+ // Adjust the extent of a bounds in map units by the
+ // layer's gutter in pixels.
+ var mapGutter = this.gutter * this.map.getResolution();
+ bounds = new OpenLayers.Bounds(bounds.left - mapGutter,
+ bounds.bottom - mapGutter,
+ bounds.right + mapGutter,
+ bounds.top + mapGutter);
+ }
+
+ if (this.wrapDateLine) {
+ // wrap around the date line, within the limits of rounding error
+ var wrappingOptions = {
+ 'rightTolerance':this.getResolution()
+ };
+ bounds = bounds.wrapDateLine(this.maxExtent, wrappingOptions);
+
+ }
+ return bounds;
+ },
+
/** @final @type String */
CLASS_NAME: "OpenLayers.Layer"
};
diff --git a/lib/OpenLayers/Layer/KaMap.js b/lib/OpenLayers/Layer/KaMap.js
index a1e736e124..3d6530c51e 100644
--- a/lib/OpenLayers/Layer/KaMap.js
+++ b/lib/OpenLayers/Layer/KaMap.js
@@ -49,6 +49,7 @@ OpenLayers.Layer.KaMap.prototype =
* @type String
*/
getURL: function (bounds) {
+ bounds = this.adjustBounds(bounds);
var mapRes = this.map.getResolution();
var scale = Math.round((this.map.getScale() * 10000)) / 10000;
var pX = Math.round(bounds.left / mapRes);
diff --git a/lib/OpenLayers/Layer/MapServer.js b/lib/OpenLayers/Layer/MapServer.js
index c45268c7bd..cca83298a9 100644
--- a/lib/OpenLayers/Layer/MapServer.js
+++ b/lib/OpenLayers/Layer/MapServer.js
@@ -87,9 +87,7 @@ OpenLayers.Layer.MapServer.prototype =
* @type String
*/
getURL: function (bounds) {
- if(this.gutter) {
- bounds = this.adjustBoundsByGutter(bounds);
- }
+ bounds = this.adjustBounds(bounds);
// Make a list, so that getFullRequestString uses literal ","
var extent = [bounds.left, bounds. bottom, bounds.right, bounds.top];
diff --git a/lib/OpenLayers/Layer/TMS.js b/lib/OpenLayers/Layer/TMS.js
index 9be25faee3..cce60e73ea 100644
--- a/lib/OpenLayers/Layer/TMS.js
+++ b/lib/OpenLayers/Layer/TMS.js
@@ -71,6 +71,7 @@ OpenLayers.Layer.TMS.prototype =
* @type String
*/
getURL: function (bounds) {
+ bounds = this.adjustBounds(bounds);
var res = this.map.getResolution();
var x = (bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w);
var y = (bounds.bottom - this.tileOrigin.lat) / (res * this.tileSize.h);
diff --git a/lib/OpenLayers/Layer/WMS.js b/lib/OpenLayers/Layer/WMS.js
index 0e87d27d52..8e0407b57c 100644
--- a/lib/OpenLayers/Layer/WMS.js
+++ b/lib/OpenLayers/Layer/WMS.js
@@ -94,9 +94,7 @@ OpenLayers.Layer.WMS.prototype =
* @type String
*/
getURL: function (bounds) {
- if(this.gutter) {
- bounds = this.adjustBoundsByGutter(bounds);
- }
+ bounds = this.adjustBounds(bounds);
return this.getFullRequestString(
{BBOX:bounds.toBBOX(),
WIDTH:this.imageSize.w,
diff --git a/lib/OpenLayers/Layer/WorldWind.js b/lib/OpenLayers/Layer/WorldWind.js
index 5dd34f8b39..dee1784cfd 100644
--- a/lib/OpenLayers/Layer/WorldWind.js
+++ b/lib/OpenLayers/Layer/WorldWind.js
@@ -69,6 +69,7 @@ OpenLayers.Layer.WorldWind.prototype =
* @type String
*/
getURL: function (bounds) {
+ bounds = this.adjustBounds(bounds);
var zoom = this.getZoom();
var extent = this.map.getMaxExtent();
var deg = this.lzd/Math.pow(2,this.getZoom());
diff --git a/lib/OpenLayers/Map.js b/lib/OpenLayers/Map.js
index ecf9d71936..5879d805e3 100644
--- a/lib/OpenLayers/Map.js
+++ b/lib/OpenLayers/Map.js
@@ -1168,8 +1168,30 @@ OpenLayers.Map.prototype = {
* @param {OpenLayers.Bounds} bounds
*/
zoomToExtent: function(bounds) {
- this.setCenter(bounds.getCenterLonLat(),
- this.getZoomForExtent(bounds));
+ var center = bounds.getCenterLonLat();
+ if (this.baseLayer.wrapDateLine) {
+ var maxExtent = this.getMaxExtent();
+
+ //fix straddling bounds (in the case of a bbox that straddles the
+ // dateline, it's left and right boundaries will appear backwards.
+ // we fix this by allowing a right value that is greater than the
+ // max value at the dateline -- this allows us to pass a valid
+ // bounds to calculate zoom)
+ //
+ bounds = bounds.clone();
+ while (bounds.right < bounds.left) {
+ bounds.right += maxExtent.getWidth();
+ }
+ //if the bounds was straddling (see above), then the center point
+ // we got from it was wrong. So we take our new bounds and ask it
+ // for the center. Because our new bounds is at least partially
+ // outside the bounds of maxExtent, the new calculated center
+ // might also be. We don't want to pass a bad center value to
+ // setCenter, so we have it wrap itself across the date line.
+ //
+ center = bounds.getCenterLonLat().wrapDateLine(maxExtent);
+ }
+ this.setCenter(center, this.getZoomForExtent(bounds));
},
/** Zoom to the full extent and recenter.
diff --git a/tests/BaseTypes/test_Bounds.html b/tests/BaseTypes/test_Bounds.html
index bbdca1ed45..197828f3aa 100644
--- a/tests/BaseTypes/test_Bounds.html
+++ b/tests/BaseTypes/test_Bounds.html
@@ -379,6 +379,98 @@
(bounds.top == object.y)), "obj Point to extends correclty modifies right and top");
}
+
+
+ function test_16_Bounds_wrapDateLine(t) {
+ t.plan( 13 );
+
+ var testBounds, wrappedBounds, desiredBounds;
+
+ var maxExtent = new OpenLayers.Bounds(-10,-10,10,10);
+ var exactBounds = maxExtent.clone();
+ var simpleBounds = new OpenLayers.Bounds( -5,-5,5,5);
+
+
+
+ //bad maxextent
+ testBounds = simpleBounds.clone();
+ wrappedBounds = testBounds.wrapDateLine(null);
+ t.ok(wrappedBounds.equals(simpleBounds), "wrapping a bounds with a bad maxextent does nothing");
+
+
+
+ //exactly inside
+ testBounds = exactBounds.clone();
+ wrappedBounds = testBounds.wrapDateLine(maxExtent);
+ t.ok(wrappedBounds.equals(exactBounds), "wrapping a bounds precisely within (equal to) maxextent does nothing");
+
+
+ //inside
+ testBounds = simpleBounds.clone();
+ wrappedBounds = testBounds.wrapDateLine(maxExtent);
+ t.ok(wrappedBounds.equals(simpleBounds), "wrapping a bounds within maxextent does nothing");
+
+// LEFT //
+
+ //straddling left
+ testBounds = simpleBounds.add(-10,0);
+ wrappedBounds = testBounds.wrapDateLine(maxExtent);
+ t.ok(wrappedBounds.equals(testBounds), "wrapping a bounds that straddles the left of maxextent does nothing");
+
+ //left rightTolerance
+ testBounds = simpleBounds.add(-14,0);
+ wrappedBounds =
+ testBounds.wrapDateLine(maxExtent, {'rightTolerance': 1} );
+ desiredBounds = simpleBounds.add(6,0);
+ t.ok(wrappedBounds.equals(desiredBounds), "wrapping a bounds rightTolerance left of maxextent works");
+
+ //exactly left
+ testBounds = exactBounds.add(-20,0);
+ wrappedBounds = testBounds.wrapDateLine(maxExtent);
+ t.ok(wrappedBounds.equals(exactBounds), "wrapping an exact bounds once left of maxextent works");
+
+ //left
+ testBounds = simpleBounds.add(-20,0);
+ wrappedBounds = testBounds.wrapDateLine(maxExtent);
+ t.ok(wrappedBounds.equals(simpleBounds), "wrapping a bounds once left of maxextent works");
+
+ //way left
+ testBounds = simpleBounds.add(-200,0);
+ wrappedBounds = testBounds.wrapDateLine(maxExtent);
+ t.ok(wrappedBounds.equals(simpleBounds), "wrapping a bounds way left of maxextent works");
+
+// RIGHT //
+
+ //straddling right
+ testBounds = simpleBounds.add(10,0);
+ wrappedBounds = testBounds.wrapDateLine(maxExtent);
+ t.ok(wrappedBounds.equals(testBounds), "wrapping a bounds that straddles the right of maxextent does nothing");
+
+ //right leftTolerance
+ testBounds = simpleBounds.add(14,0);
+ wrappedBounds =
+ testBounds.wrapDateLine(maxExtent, {'leftTolerance': 1} );
+ desiredBounds = simpleBounds.add(-6,0);
+ t.ok(wrappedBounds.equals(desiredBounds), "wrapping a bounds leftTolerance right of maxextent works");
+
+ //exactly right
+ testBounds = exactBounds.add(20,0);
+ wrappedBounds = testBounds.wrapDateLine(maxExtent);
+ t.ok(wrappedBounds.equals(exactBounds), "wrapping an exact bounds once right of maxextent works");
+
+ //right
+ testBounds = simpleBounds.add(20,0);
+ wrappedBounds = testBounds.wrapDateLine(maxExtent);
+ t.ok(wrappedBounds.equals(simpleBounds), "wrapping a bounds once right of maxextent works");
+
+ //way right
+ testBounds = simpleBounds.add(200,0);
+ wrappedBounds = testBounds.wrapDateLine(maxExtent);
+ t.ok(wrappedBounds.equals(simpleBounds), "wrapping a bounds way right of maxextent works");
+
+
+
+ }
// -->
diff --git a/tests/BaseTypes/test_LonLat.html b/tests/BaseTypes/test_LonLat.html
index d1fa92e5f5..3248ef17c3 100644
--- a/tests/BaseTypes/test_LonLat.html
+++ b/tests/BaseTypes/test_LonLat.html
@@ -88,6 +88,50 @@
t.ok( lonlat.equals(ll), "lonlat is set correctly");
}
+ function test_08_LonLat_wrapDateLine(t) {
+ t.plan( 6 );
+
+ var goodLL = new OpenLayers.LonLat(0,0);
+ var testLL, wrappedLL;
+
+ //bad maxextent
+ var maxExtent = null;
+
+ testLL = goodLL.clone();
+ wrappedLL = testLL.wrapDateLine(maxExtent);
+ t.ok(wrappedLL.equals(goodLL), "wrapping a ll with a bad maxextent does nothing");
+
+
+ //good maxextent
+ maxExtent = new OpenLayers.Bounds(-10,-10,10,10);
+
+ //inside
+ testLL = goodLL.clone();
+ wrappedLL = testLL.wrapDateLine(maxExtent);
+ t.ok(wrappedLL.equals(goodLL), "wrapping a ll within the maxextent does nothing");
+
+ //left
+ testLL = goodLL.add(-20,0);
+ wrappedLL = testLL.wrapDateLine(maxExtent);
+ t.ok(wrappedLL.equals(goodLL), "wrapping a ll once left of maxextent works");
+
+ //way left
+ testLL = goodLL.add(-200,0);
+ wrappedLL = testLL.wrapDateLine(maxExtent);
+ t.ok(wrappedLL.equals(goodLL), "wrapping a ll way left of maxextent works");
+
+ //right
+ testLL = goodLL.add(20,0);
+ wrappedLL = testLL.wrapDateLine(maxExtent);
+ t.ok(wrappedLL.equals(goodLL), "wrapping a ll once right of maxextent works");
+
+ //way right
+ testLL = goodLL.add(200,0);
+ wrappedLL = testLL.wrapDateLine(maxExtent);
+ t.ok(wrappedLL.equals(goodLL), "wrapping a ll way right of maxextent works");
+
+ }
+
// -->
diff --git a/tests/Layer/test_WrapDateLine.html b/tests/Layer/test_WrapDateLine.html
new file mode 100644
index 0000000000..aac91045f8
--- /dev/null
+++ b/tests/Layer/test_WrapDateLine.html
@@ -0,0 +1,176 @@
+
+
+
+
+
+
+
+
+
diff --git a/tests/list-tests.html b/tests/list-tests.html
index 14a794634e..5ff89a9dfc 100644
--- a/tests/list-tests.html
+++ b/tests/list-tests.html
@@ -49,6 +49,7 @@
Layer/test_TMS.html
Layer/test_Vector.html
Layer/test_GML.html
+ Layer/test_WrapDateLine.html
test_Tile.html
Tile/test_Image.html
test_Control.html