Merge pull request #11 from ahocevar/3526

Dateline handling improvements for vector layers. Thanks @tschaub for the great collaboration on this. r=tschaub (closes #3526)
This commit is contained in:
ahocevar
2011-10-12 23:06:47 -07:00
20 changed files with 690 additions and 267 deletions

View File

@@ -354,14 +354,37 @@ OpenLayers.Bounds = OpenLayers.Class({
*
* Parameters:
* ll - {<OpenLayers.LonLat>}
* options - {Object} Optional parameters
*
* Acceptable options:
* inclusive - {Boolean} Whether or not to include the border.
* Default is true.
* worldBounds - {<OpenLayers.Bounds>} If a worldBounds is provided, the
* ll will be considered as contained if it exceeds the world bounds,
* but can be wrapped around the dateline so it is contained by this
* bounds.
*
* Returns:
* {Boolean} The passed-in lonlat is within this bounds.
*/
containsLonLat:function(ll, inclusive) {
return this.contains(ll.lon, ll.lat, inclusive);
containsLonLat: function(ll, options) {
if (typeof options === "boolean") {
options = {inclusive: options};
}
options = options || {};
var contains = this.contains(ll.lon, ll.lat, options.inclusive),
worldBounds = options.worldBounds;
if (worldBounds && !contains) {
var worldWidth = worldBounds.getWidth();
ll = ll.clone();
var worldCenterX = (worldBounds.left + worldBounds.right) / 2;
var worldsAway = Math.round((ll.lon - worldCenterX) / worldWidth);
ll.lon -= (worldsAway * worldWidth);
contains = this.containsLonLat(
ll, {inclusive: options.inclusive}
);
}
return contains;
},
/**
@@ -424,48 +447,79 @@ OpenLayers.Bounds = OpenLayers.Class({
*
* Parameters:
* bounds - {<OpenLayers.Bounds>} The target bounds.
* options - {Object} Optional parameters.
*
* Acceptable options:
* inclusive - {Boolean} Treat coincident borders as intersecting. Default
* is true. If false, bounds that do not overlap but only touch at the
* border will not be considered as intersecting.
* worldBounds - {<OpenLayers.Bounds>} If a worldBounds is provided, two
* bounds will be considered as intersecting if they intersect when
* shifted to within the world bounds. This applies only to bounds that
* cross or are completely outside the world bounds.
*
* Returns:
* {Boolean} The passed-in bounds object intersects this bounds.
*/
intersectsBounds:function(bounds, inclusive) {
if (inclusive == null) {
inclusive = true;
intersectsBounds:function(bounds, options) {
if (typeof options === "boolean") {
options = {inclusive: options};
}
options = options || {};
if (options.worldBounds) {
var self = this.wrapDateLine(options.worldBounds);
bounds = bounds.wrapDateLine(options.worldBounds);
} else {
self = this;
}
if (options.inclusive == null) {
options.inclusive = true;
}
var intersects = false;
var mightTouch = (
this.left == bounds.right ||
this.right == bounds.left ||
this.top == bounds.bottom ||
this.bottom == bounds.top
self.left == bounds.right ||
self.right == bounds.left ||
self.top == bounds.bottom ||
self.bottom == bounds.top
);
// if the two bounds only touch at an edge, and inclusive is false,
// then the bounds don't *really* intersect.
if (inclusive || !mightTouch) {
if (options.inclusive || !mightTouch) {
// otherwise, if one of the boundaries even partially contains another,
// inclusive of the edges, then they do intersect.
var inBottom = (
((bounds.bottom >= this.bottom) && (bounds.bottom <= this.top)) ||
((this.bottom >= bounds.bottom) && (this.bottom <= bounds.top))
((bounds.bottom >= self.bottom) && (bounds.bottom <= self.top)) ||
((self.bottom >= bounds.bottom) && (self.bottom <= bounds.top))
);
var inTop = (
((bounds.top >= this.bottom) && (bounds.top <= this.top)) ||
((this.top > bounds.bottom) && (this.top < bounds.top))
((bounds.top >= self.bottom) && (bounds.top <= self.top)) ||
((self.top > bounds.bottom) && (self.top < bounds.top))
);
var inLeft = (
((bounds.left >= this.left) && (bounds.left <= this.right)) ||
((this.left >= bounds.left) && (this.left <= bounds.right))
((bounds.left >= self.left) && (bounds.left <= self.right)) ||
((self.left >= bounds.left) && (self.left <= bounds.right))
);
var inRight = (
((bounds.right >= this.left) && (bounds.right <= this.right)) ||
((this.right >= bounds.left) && (this.right <= bounds.right))
((bounds.right >= self.left) && (bounds.right <= self.right)) ||
((self.right >= bounds.left) && (self.right <= bounds.right))
);
intersects = ((inBottom || inTop) && (inLeft || inRight));
}
// document me
if (options.worldBounds && !intersects) {
var world = options.worldBounds;
var width = world.getWidth();
var selfCrosses = !world.containsBounds(self);
var boundsCrosses = !world.containsBounds(bounds);
if (selfCrosses && !boundsCrosses) {
bounds = bounds.add(-width, 0);
intersects = self.intersectsBounds(bounds, {inclusive: options.inclusive});
} else if (boundsCrosses && !selfCrosses) {
self = self.add(-width, 0);
intersects = bounds.intersectsBounds(self, {inclusive: options.inclusive});
}
}
return intersects;
},
@@ -573,8 +627,9 @@ OpenLayers.Bounds = OpenLayers.Class({
* 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.
* out of maxExtent), the returned bounds will always
* cross the left edge of the given maxExtent.
*.
*/
wrapDateLine: function(maxExtent, options) {
options = options || {};
@@ -585,18 +640,26 @@ OpenLayers.Bounds = OpenLayers.Class({
var newBounds = this.clone();
if (maxExtent) {
var width = maxExtent.getWidth();
//shift right?
while ( newBounds.left < maxExtent.left &&
(newBounds.right - rightTolerance) <= maxExtent.left ) {
newBounds = newBounds.add(maxExtent.getWidth(), 0);
}
//shift right?
while (newBounds.left < maxExtent.left &&
newBounds.right - rightTolerance <= maxExtent.left ) {
newBounds = newBounds.add(width, 0);
}
//shift left?
while ( (newBounds.left + leftTolerance) >= maxExtent.right &&
//shift left?
while (newBounds.left + leftTolerance >= maxExtent.right &&
newBounds.right > maxExtent.right ) {
newBounds = newBounds.add(-maxExtent.getWidth(), 0);
}
newBounds = newBounds.add(-width, 0);
}
// crosses right only? force left
var newLeft = newBounds.left + leftTolerance;
if (newLeft < maxExtent.right && newLeft > maxExtent.left &&
newBounds.right - rightTolerance > maxExtent.right) {
newBounds = newBounds.add(-width, 0);
}
}
return newBounds;

View File

@@ -517,15 +517,9 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
*/
calculateGridLayout: function(bounds, origin, resolution) {
bounds = bounds.clone();
if (this.map.baseLayer.wrapDateLine) {
var maxExtent = this.map.getMaxExtent(),
width = maxExtent.getWidth();
// move the bounds one world width to the right until the origin is
// within the world extent
while (bounds.left < maxExtent.left) {
bounds.left += width;
bounds.right += width;
}
var map = this.map;
if (map.wrapDateLine) {
bounds = bounds.wrapDateLine(map.getMaxExtent());
}
var tilelon = resolution * this.tileSize.w;

View File

@@ -1909,7 +1909,8 @@ OpenLayers.Map = OpenLayers.Class({
var valid = false;
if (lonlat != null) {
var maxExtent = this.getMaxExtent();
valid = maxExtent.containsLonLat(lonlat);
var worldBounds = this.baseLayer.wrapDateLine && maxExtent;
valid = maxExtent.containsLonLat(lonlat, {worldBounds: worldBounds});
}
return valid;
},
@@ -2223,10 +2224,7 @@ OpenLayers.Map = OpenLayers.Class({
}
//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.
// for the center.
//
center = bounds.getCenterLonLat().wrapDateLine(maxExtent);
}

View File

@@ -73,6 +73,14 @@ OpenLayers.Renderer = OpenLayers.Class({
*/
map: null,
/**
* Property: featureDx
* {Number} Feature offset in x direction. Will be calculated for and
* applied to the current feature while rendering (see
* <calculateFeatureDx>).
*/
featureDx: 0,
/**
* Constructor: OpenLayers.Renderer
*
@@ -122,12 +130,21 @@ OpenLayers.Renderer = OpenLayers.Class({
* Parameters:
* extent - {<OpenLayers.Bounds>}
* resolutionChanged - {Boolean}
*
* Returns:
* {Boolean} true to notify the layer that the new extent does not exceed
* the coordinate range, and the features will not need to be redrawn.
* False otherwise.
*/
setExtent: function(extent, resolutionChanged) {
this.extent = extent.clone();
if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) {
this.extent = extent.wrapDateLine(this.map.getMaxExtent());
}
if (resolutionChanged) {
this.resolution = null;
}
return true;
},
/**
@@ -179,11 +196,18 @@ OpenLayers.Renderer = OpenLayers.Class({
if (feature.geometry) {
var bounds = feature.geometry.getBounds();
if(bounds) {
if (!bounds.intersectsBounds(this.extent)) {
var worldBounds;
if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) {
worldBounds = this.map.getMaxExtent();
}
if (!bounds.intersectsBounds(this.extent, {worldBounds: worldBounds})) {
style = {display: "none"};
} else {
this.calculateFeatureDx(bounds, worldBounds);
}
var rendered = this.drawGeometry(feature.geometry, style, feature.id);
if(style.display != "none" && style.label && rendered !== false) {
var location = feature.geometry.getCentroid();
if(style.labelXOffset || style.labelYOffset) {
var xOffset = isNaN(style.labelXOffset) ? 0 : style.labelXOffset;
@@ -200,6 +224,29 @@ OpenLayers.Renderer = OpenLayers.Class({
}
},
/**
* Method: calculateFeatureDx
* {Number} Calculates the feature offset in x direction. Looking at the
* center of the feature bounds and the renderer extent, we calculate how
* many world widths the two are away from each other. This distance is
* used to shift the feature as close as possible to the center of the
* current enderer extent, which ensures that the feature is visible in the
* current viewport.
*
* Parameters:
* bounds - {<OpenLayers.Bounds>} Bounds of the feature
* worldBounds - {<OpenLayers.Bounds>} Bounds of the world
*/
calculateFeatureDx: function(bounds, worldBounds) {
this.featureDx = 0;
if (worldBounds) {
var worldWidth = worldBounds.getWidth(),
rendererCenterX = (this.extent.left + this.extent.right) / 2,
featureCenterX = (bounds.left + bounds.right) / 2,
worldsAway = Math.round((featureCenterX - rendererCenterX) / worldWidth);
this.featureDx = worldsAway * worldWidth;
}
},
/**
* Method: drawGeometry

View File

@@ -70,6 +70,25 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
}
},
/**
* Method: setExtent
* Set the visible part of the layer.
*
* Parameters:
* extent - {<OpenLayers.Bounds>}
* resolutionChanged - {Boolean}
*
* Returns:
* {Boolean} true to notify the layer that the new extent does not exceed
* the coordinate range, and the features will not need to be redrawn.
* False otherwise.
*/
setExtent: function() {
OpenLayers.Renderer.prototype.setExtent.apply(this, arguments);
// always redraw features
return false;
},
/**
* Method: eraseGeometry
* Erase a geometry from the renderer. Because the Canvas renderer has
@@ -141,8 +160,15 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
style = this.applyDefaultSymbolizer(style || feature.style);
// don't render if display none or feature outside extent
var bounds = feature.geometry.getBounds();
rendered = (style.display !== "none") && !!bounds &&
bounds.intersectsBounds(this.extent);
var worldBounds;
if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) {
worldBounds = this.map.getMaxExtent();
}
var intersects = bounds && bounds.intersectsBounds(this.extent, {worldBounds: worldBounds});
rendered = (style.display !== "none") && !!bounds && intersects;
if (rendered) {
// keep track of what we have rendered for redraw
this.features[feature.id] = [feature, style];
@@ -573,7 +599,7 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
getLocalXY: function(point) {
var resolution = this.getResolution();
var extent = this.extent;
var x = (point.x / resolution + (-extent.left / resolution));
var x = ((point.x - this.featureDx) / resolution + (-extent.left / resolution));
var y = ((extent.top / resolution) - point.y / resolution);
return [x, y];
},
@@ -659,12 +685,15 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
this.hitContext.clearRect(0, 0, width, height);
}
var labelMap = [];
var feature, style;
var feature, geometry, style;
var worldBounds = (this.map.baseLayer && this.map.baseLayer.wrapDateLine) && this.map.getMaxExtent();
for (var id in this.features) {
if (!this.features.hasOwnProperty(id)) { continue; }
feature = this.features[id][0];
geometry = feature.geometry;
this.calculateFeatureDx(geometry.getBounds(), worldBounds);
style = this.features[id][1];
this.drawGeometry(feature.geometry, style, feature.id);
this.drawGeometry(geometry, style, feature.id);
if(style.label) {
labelMap.push([feature, style]);
}

View File

@@ -373,6 +373,28 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
*/
xmlns: null,
/**
* Property: xOffset
* {Number} Offset to apply to the renderer viewport translation in x
* direction. If the renderer extent's center is on the right of the
* dateline (i.e. exceeds the world bounds), we shift the viewport to the
* left by one world width. This avoids that features disappear from the
* map viewport. Because our dateline handling logic in other places
* ensures that extents crossing the dateline always have a center
* exceeding the world bounds on the left, we need this offset to make sure
* that the same is true for the renderer extent in pixel space as well.
*/
xOffset: 0,
/**
* Property: rightOfDateLine
* {Boolean} Keeps track of the location of the map extent relative to the
* date line. The <setExtent> method compares this value (which is the one
* from the previous <setExtent> call) with the current position of the map
* extent relative to the date line and updates the xOffset when the extent
* has moved from one side of the date line to the other.
*/
/**
* Property: Indexer
* {<OpenLayers.ElementIndexer>} An instance of OpenLayers.ElementsIndexer
@@ -458,6 +480,41 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
this.indexer.clear();
}
},
/**
* Method: setExtent
* Set the visible part of the layer.
*
* Parameters:
* extent - {<OpenLayers.Bounds>}
* resolutionChanged - {Boolean}
*
* Returns:
* {Boolean} true to notify the layer that the new extent does not exceed
* the coordinate range, and the features will not need to be redrawn.
* False otherwise.
*/
setExtent: function(extent, resolutionChanged) {
var coordSysUnchanged = OpenLayers.Renderer.prototype.setExtent.apply(this, arguments);
var resolution = this.getResolution();
if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) {
coordSysUnchanged = this.featureDx === 0;
var rightOfDateLine,
world = this.map.getMaxExtent();
if (world.right > extent.left && world.right < extent.right) {
rightOfDateLine = true;
} else if (world.left > extent.left && world.left < extent.right) {
rightOfDateLine = false;
}
if (rightOfDateLine !== this.rightOfDateLine || resolutionChanged) {
coordSysUnchanged = false;
this.xOffset = rightOfDateLine === true ?
world.getWidth() / resolution : 0;
}
this.rightOfDateLine = rightOfDateLine;
}
return coordSysUnchanged;
},
/**
* Method: getNodeType

View File

@@ -114,12 +114,11 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* False otherwise.
*/
setExtent: function(extent, resolutionChanged) {
OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,
arguments);
var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments);
var resolution = this.getResolution();
var left = -extent.left / resolution;
var top = extent.top / resolution;
var resolution = this.getResolution(),
left = -extent.left / resolution,
top = extent.top / resolution;
// If the resolution has changed, start over changing the corner, because
// the features will redraw.
@@ -130,15 +129,15 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
var extentString = "0 0 " + this.size.w + " " + this.size.h;
this.rendererRoot.setAttributeNS(null, "viewBox", extentString);
this.translate(0, 0);
this.translate(this.xOffset, 0);
return true;
} else {
var inRange = this.translate(left - this.left, top - this.top);
inRange = this.translate(left - this.left + this.xOffset, top - this.top);
if (!inRange) {
// recenter the coordinate system
this.setExtent(extent, true);
}
return inRange;
return coordSysUnchanged && inRange;
}
},
@@ -505,7 +504,7 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
*/
drawCircle: function(node, geometry, radius) {
var resolution = this.getResolution();
var x = (geometry.x / resolution + this.left);
var x = ((geometry.x - this.featureDx) / resolution + this.left);
var y = (this.top - geometry.y / resolution);
if (this.inValidRange(x, y)) {
@@ -615,7 +614,7 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
*/
drawRectangle: function(node, geometry) {
var resolution = this.getResolution();
var x = (geometry.x / resolution + this.left);
var x = ((geometry.x - this.featureDx) / resolution + this.left);
var y = (this.top - geometry.y / resolution);
if (this.inValidRange(x, y)) {
@@ -681,7 +680,7 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
drawText: function(featureId, style, location) {
var resolution = this.getResolution();
var x = (location.x / resolution + this.left);
var x = ((location.x - this.featureDx) / resolution + this.left);
var y = (location.y / resolution - this.top);
var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "text");
@@ -833,9 +832,9 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
var resolution = this.getResolution();
var maxX = this.MAX_PIXEL - this.translationParameters.x;
var maxY = this.MAX_PIXEL - this.translationParameters.y;
var x1 = goodComponent.x / resolution + this.left;
var x1 = (goodComponent.x - this.featureDx) / resolution + this.left;
var y1 = this.top - goodComponent.y / resolution;
var x2 = badComponent.x / resolution + this.left;
var x2 = (badComponent.x - this.featureDx) / resolution + this.left;
var y2 = this.top - badComponent.y / resolution;
var k;
if (x2 < -maxX || x2 > maxX) {
@@ -862,7 +861,7 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
*/
getShortString: function(point) {
var resolution = this.getResolution();
var x = (point.x / resolution + this.left);
var x = ((point.x - this.featureDx) / resolution + this.left);
var y = (this.top - point.y / resolution);
if (this.inValidRange(x, y)) {
@@ -908,7 +907,7 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
var id = this.container.id + "-" + graphicName;
// check if symbol already exists in the defs
var existing = document.getElementById(id)
var existing = document.getElementById(id);
if (existing != null) {
return existing;
}

View File

@@ -90,8 +90,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* the coordinate range, and the features will not need to be redrawn.
*/
setExtent: function(extent, resolutionChanged) {
OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,
arguments);
var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments);
var resolution = this.getResolution();
var left = (extent.left/resolution) | 0;
@@ -106,7 +105,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
}
var org = left + " " + top;
var org = (left - this.xOffset) + " " + top;
this.root.coordorigin = org;
var roots = [this.root, this.vectorRoot, this.textRoot];
var root;
@@ -121,7 +120,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
// matches the display Y axis of the map
this.root.style.flip = "y";
return true;
return coordSysUnchanged;
},
@@ -226,7 +225,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
var yOffset = (style.graphicYOffset != undefined) ?
style.graphicYOffset : -(0.5 * height);
node.style.left = (((geometry.x/resolution - this.offset.x)+xOffset) | 0) + "px";
node.style.left = ((((geometry.x - this.featureDx)/resolution - this.offset.x)+xOffset) | 0) + "px";
node.style.top = (((geometry.y/resolution - this.offset.y)-(yOffset+height)) | 0) + "px";
node.style.width = width + "px";
node.style.height = height + "px";
@@ -483,9 +482,9 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
var resolution = this.getResolution();
var scaledBox =
new OpenLayers.Bounds((bbox.left/resolution - this.offset.x) | 0,
new OpenLayers.Bounds(((bbox.left - this.featureDx)/resolution - this.offset.x) | 0,
(bbox.bottom/resolution - this.offset.y) | 0,
(bbox.right/resolution - this.offset.x) | 0,
((bbox.right - this.featureDx)/resolution - this.offset.x) | 0,
(bbox.top/resolution - this.offset.y) | 0);
// Set the internal coordinate system to draw the path
@@ -652,7 +651,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
if(!isNaN(geometry.x)&& !isNaN(geometry.y)) {
var resolution = this.getResolution();
node.style.left = (((geometry.x /resolution - this.offset.x) | 0) - radius) + "px";
node.style.left = ((((geometry.x - this.featureDx) /resolution - this.offset.x) | 0) - radius) + "px";
node.style.top = (((geometry.y /resolution - this.offset.y) | 0) - radius) + "px";
var diameter = radius * 2;
@@ -718,7 +717,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
var comp, x, y;
for (var i = 0; i < numComponents; i++) {
comp = geometry.components[i];
x = (comp.x/resolution - this.offset.x) | 0;
x = ((comp.x - this.featureDx)/resolution - this.offset.x) | 0;
y = (comp.y/resolution - this.offset.y) | 0;
parts[i] = " " + x + "," + y + " l ";
}
@@ -754,7 +753,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
second = null;
for (i=0, ii=points.length; i<ii; i++) {
comp = points[i];
x = (comp.x / resolution - this.offset.x) | 0;
x = ((comp.x - this.featureDx) / resolution - this.offset.x) | 0;
y = (comp.y / resolution - this.offset.y) | 0;
pathComp = " " + x + "," + y;
path.push(pathComp);
@@ -801,7 +800,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
drawRectangle: function(node, geometry) {
var resolution = this.getResolution();
node.style.left = ((geometry.x/resolution - this.offset.x) | 0) + "px";
node.style.left = (((geometry.x - this.featureDx)/resolution - this.offset.x) | 0) + "px";
node.style.top = ((geometry.y/resolution - this.offset.y) | 0) + "px";
node.style.width = ((geometry.width/resolution) | 0) + "px";
node.style.height = ((geometry.height/resolution) | 0) + "px";
@@ -823,7 +822,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox");
var resolution = this.getResolution();
label.style.left = ((location.x/resolution - this.offset.x) | 0) + "px";
label.style.left = (((location.x - this.featureDx)/resolution - this.offset.x) | 0) + "px";
label.style.top = ((location.y/resolution - this.offset.y) | 0) + "px";
label.style.flip = "y";
@@ -900,7 +899,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
var comp, x, y;
for (var i=0, len=geometry.components.length; i<len; i++) {
comp = geometry.components[i];
x = (comp.x / resolution - this.offset.x) | 0;
x = ((comp.x - this.featureDx) / resolution - this.offset.x) | 0;
y = (comp.y / resolution - this.offset.y) | 0;
if ((i%3)==0 && (i/3)==0) {
path.push("m");

View File

@@ -175,29 +175,10 @@ OpenLayers.Tile = OpenLayers.Class({
var withinMaxExtent = false,
maxExtent = this.layer.maxExtent;
if (maxExtent) {
// prepare up to 3 versions of the layer's maxExtent, to make sure
// that the intersectsBounds check below catches all cases of
// extents that cross the dateline:
// (1) left bound positive, right bound negative (wrapped)
// (2) left bound positive, right bound positive (exceeding world)
// (3) left bound negative (exceeding world), right bound positive
var maxExtents = [maxExtent];
if (this.layer.map.baseLayer.wrapDateLine) {
if (maxExtent.left > maxExtent.right) {
var worldWidth = this.layer.map.getMaxExtent().getWidth();
maxExtent = this.layer.maxExtent.clone();
maxExtent.left -= worldWidth;
maxExtents.push(maxExtent);
maxExtent = this.layer.maxExtent.clone();
maxExtent.right += worldWidth;
maxExtents.push(maxExtent);
}
}
for (var i=maxExtents.length-1; i>=0; --i) {
if (this.bounds.intersectsBounds(maxExtents[i], false)) {
withinMaxExtent = true;
break;
}
var map = this.layer.map;
var worldBounds = map.baseLayer.wrapDateLine && map.getMaxExtent();
if (this.bounds.intersectsBounds(maxExtent, {inclusive: false, worldBounds: worldBounds})) {
withinMaxExtent = true;
}
}
@@ -213,9 +194,13 @@ OpenLayers.Tile = OpenLayers.Class({
*/
setBounds: function(bounds) {
bounds = bounds.clone();
if (this.layer.map && this.layer.map.baseLayer.wrapDateLine) {
var worldExtent = this.layer.map.getMaxExtent();
bounds = bounds.wrapDateLine(worldExtent);
if (this.layer.map.baseLayer.wrapDateLine) {
var worldExtent = this.layer.map.getMaxExtent(),
tolerance = this.layer.map.getResolution();
bounds = bounds.wrapDateLine(worldExtent, {
leftTolerance: tolerance,
rightTolerance: tolerance
});
}
this.bounds = bounds;
},

View File

@@ -124,6 +124,43 @@
t.eq( bounds.containsLonLat(ll), bounds.contains(ll.lon, ll.lat), "containsLonLat works");
}
function test_containsLonLat_wraped(t) {
var worldBounds = new OpenLayers.Bounds(-180, -90, 180, 90);
var cases = [{
ll: [0, 0], bbox: [-10, -10, 10, 10], contained: true
}, {
ll: [20, 0], bbox: [-10, -10, 10, 10], contained: false
}, {
ll: [360, 0], bbox: [-10, -10, 10, 10], contained: true
}, {
ll: [380, 0], bbox: [-10, -10, 10, 10], contained: false
}, {
ll: [725, 5], bbox: [-10, -10, 10, 10], contained: true
}, {
ll: [-355, -5], bbox: [-10, -10, 10, 10], contained: true
}, {
ll: [-715, 5], bbox: [-10, -10, 10, 10], contained: true
}, {
ll: [-735, 5], bbox: [-10, -10, 10, 10], contained: false
}, {
ll: [-180 * 50, 5], bbox: [-10, -10, 10, 10], contained: true
}];
var len = cases.length;
t.plan(len);
var c, bounds, loc;
for (var i=0; i<len; ++i) {
c = cases[i];
loc = new OpenLayers.LonLat(c.ll[0], c.ll[1]);
bounds = new OpenLayers.Bounds.fromArray(c.bbox);
t.eq(bounds.containsLonLat(loc, {worldBounds: worldBounds}), c.contained, "case " + i);
}
}
function test_Bounds_fromString(t) {
t.plan( 12 );
@@ -555,7 +592,8 @@
//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");
desiredBounds = testBounds.add(-maxExtent.getWidth(), 0)
t.ok(wrappedBounds.equals(desiredBounds), "wrapping a bounds that straddles the right of maxextent moves extent to left side of the world");
//right leftTolerance
testBounds = simpleBounds.add(14,0);

View File

@@ -1386,54 +1386,86 @@
}
function test_Map_zoomToExtent(t) {
t.plan(8);
t.plan(9);
var m = {
'baseLayer': {
'wrapDateLine': false
},
'setCenter': function(center, zoomLevel) {
g_Center = center;
g_ZoomLevel = zoomLevel;
},
'getZoomForExtent': function(bounds, closest) {
t.ok(bounds.equals(g_ToCenterBounds), "bounds correctly passed into getZoomForExtent()");
t.ok(closest == g_Closest, "closest correctly passed along to getZoomForExtent()");
return g_ZoomLevelReturn;
}
};
//no wrapDateLine
g_ZoomLevelReturn = {};
g_Bounds = new OpenLayers.Bounds(-20,-15,0,5);
g_ExpectedCenter = new OpenLayers.LonLat(-10,-5);
g_Closest = {};
g_ToCenterBounds = g_Bounds;
var args = [g_Bounds, g_Closest];
OpenLayers.Map.prototype.zoomToExtent.apply(m, args);
var map = new OpenLayers.Map("map");
var layer = new OpenLayers.Layer(null, {isBaseLayer: true});
map.addLayer(layer);
t.ok(g_Center.equals(g_ExpectedCenter), "setCenter called on correct center");
t.ok(g_ZoomLevel == g_ZoomLevelReturn, "correctly passes along zoom level as returned from getZoomForExtent()");
//wrapDateLine
m.baseLayer.wrapDateLine = true;
m.getMaxExtent = function() { return new OpenLayers.Bounds(-200,-200,200,200); };
g_ZoomLevelReturn = {};
g_BoundsCenter = {};
g_Bounds = new OpenLayers.Bounds(160,-60,-60,60);
g_ExpectedCenter = new OpenLayers.LonLat(-150,0);
g_Closest = {};
g_ToCenterBounds = new OpenLayers.Bounds(160,-60,340,60);
var args = [g_Bounds, g_Closest];
OpenLayers.Map.prototype.zoomToExtent.apply(m, args);
t.ok(g_Center.equals(g_ExpectedCenter), "setCenter called on correct center");
t.ok(g_ZoomLevel == g_ZoomLevelReturn, "correctly passes along zoom level as returned from getZoomForExtent()");
var bounds = new OpenLayers.Bounds(-160, 15, -50, 69);
var center;
// default for closest
map.zoomToExtent(bounds);
center = map.getCenter();
t.eq(center.lon, -105, "a) correct x");
t.eq(center.lat, 42, "a) correct y");
t.eq(map.getZoom(), 2, "a) correct zoom");
// false for closest
map.zoomToExtent(bounds, false);
center = map.getCenter();
t.eq(center.lon, -105, "b) correct x");
t.eq(center.lat, 42, "b) correct y");
t.eq(map.getZoom(), 2, "b) correct zoom");
// true for closest
map.zoomToExtent(bounds, true);
center = map.getCenter();
t.eq(center.lon, -105, "c) correct x");
t.eq(center.lat, 42, "c) correct y");
t.eq(map.getZoom(), 3, "c) correct zoom");
map.destroy();
}
function test_Map_zoomToExtent_wrapped(t) {
t.plan(9);
var map = new OpenLayers.Map("map");
var layer = new OpenLayers.Layer(null, {isBaseLayer: true, wrapDateLine: true});
map.addLayer(layer);
var bounds, center;
var cases = [{
// real world
bbox: [120, -20, 140, 0],
center: [130, -10]
}, {
// one world to the right
bbox: [220, -45, 240, 45],
center: [-130, 0]
}, {
// two worlds to the right
bbox: [550, -15, 560, 5],
center: [-165, -5]
}, {
// one world to the left
bbox: [-240, -15, -220, 5],
center: [130, -5]
}, {
// two worlds to the left
bbox: [-600, -15, -580, 5],
center: [130, -5]
}];
var num = cases.length;
t.plan(num * 2);
var c, bounds, center;
for (var i=0; i<num; ++i) {
c = cases[i];
bounds = OpenLayers.Bounds.fromArray(c.bbox);
map.zoomToExtent(bounds);
center = map.getCenter();
t.eq(center.lon, c.center[0], "y: " + bounds);
t.eq(center.lat, c.center[1], "x: " + bounds);
}
map.destroy();
}
function test_allOverlays(t) {

View File

@@ -24,6 +24,7 @@
t.plan(2);
var r = new OpenLayers.Renderer();
r.map = {};
var extent = new OpenLayers.Bounds(1,2,3,4);
r.resolution = 1;
r.setExtent(extent, true);
@@ -52,6 +53,21 @@
t.eq(resolution, map.getResolution(), "resolution matches the map resolution");
t.eq(r.resolution, resolution, "resolution is correctly set");
}
function test_calculateFeatureDx(t) {
t.plan(4);
var r = new OpenLayers.Renderer();
r.extent = new OpenLayers.Bounds(177, -2, 183, 2);
var worldBounds = new OpenLayers.Bounds(-180,-90,180,90);
r.calculateFeatureDx(new OpenLayers.Bounds(179,-1,181,1), worldBounds);
t.eq(r.featureDx, 0, "no offset for feature inside extent");
r.calculateFeatureDx(new OpenLayers.Bounds(-181,-1,-179,1), worldBounds);
t.eq(r.featureDx, -360, "negative offset for feature on other end of world");
r.calculateFeatureDx(new OpenLayers.Bounds(359,-1,361,1), worldBounds);
t.eq(r.featureDx, 360, "positive offset for feature that is one world away");
r.calculateFeatureDx(new OpenLayers.Bounds(719,-1,721,1), worldBounds);
t.eq(r.featureDx, 720, "correct offset for feature that is two worlds away");
}
function test_Renderer_destroy(t) {
t.plan(5);

View File

@@ -3,6 +3,24 @@
<script src="../OLLoader.js"></script>
<script type="text/javascript">
var supported = OpenLayers.Renderer.Canvas.prototype.supported();
var map, layer;
function setUp() {
map = new OpenLayers.Map("map");
layer = new OpenLayers.Layer.Vector(null, {
isBaseLayer: true,
renderers: ["Canvas"]
});
map.addLayer(layer);
map.setCenter(new OpenLayers.LonLat(0, 0));
}
function tearDown() {
map.destroy();
map = null;
layer = null;
}
function test_Renderer_Canvas_constructor(t) {
if (!supported) { t.plan(0); return; }
t.plan(2);
@@ -18,16 +36,17 @@
function test_Renderer_Canvas_setextent(t) {
if (!supported) { t.plan(0); return; }
t.plan(2);
var el = document.body;
el.id = "foo";
var r = new OpenLayers.Renderer.Canvas(el.id);
setUp();
var r = layer.renderer;
var extent = new OpenLayers.Bounds(1,2,3,4);
r.resolution = 1;
r.setExtent(extent, true);
t.ok(r.extent.equals(extent), "extent is correctly set");
t.eq(r.resolution, null, "resolution nullified");
r.destroy();
tearDown();
}
function test_Renderer_Canvas_setsize(t) {
@@ -124,18 +143,8 @@
}
t.plan(10);
var layer = new OpenLayers.Layer.Vector(null, {
isBaseLayer: true,
renderers: ["Canvas"]
});
var map = new OpenLayers.Map({
div: "map",
controls: [],
layers: [layer],
center: new OpenLayers.LonLat(0, 0),
zoom: 0
});
setUp();
var renderer = layer.renderer;
var count = 0;
@@ -192,7 +201,7 @@
t.eq(count, 1, "d) redraw is called when drawing a feature without bounds");
renderer.clear();
map.destroy();
tearDown();
}

View File

@@ -616,7 +616,40 @@
tearDown();
}
function test_setExtent(t) {
t.plan(10);
setUp();
var resolution = 1;
var r = create_renderer();
r.map = {
getMaxExtent: function() {
return new OpenLayers.Bounds(-180,-90,180,90);
},
getResolution: function() {
return resolution;
},
baseLayer: {wrapDateLine: true}
}
r.setExtent(new OpenLayers.Bounds(179, -1, 182, 1), true);
t.eq(r.rightOfDateLine, true, "on the right side of the dateline");
t.eq(r.xOffset, r.map.getMaxExtent().getWidth(), "correct xOffset");
r.setExtent(new OpenLayers.Bounds(179.5, -1, 182.5, 1), false);
t.eq(r.rightOfDateLine, true, "still on the right side of the dateline");
t.eq(r.xOffset, r.map.getMaxExtent().getWidth(), "still correct xOffset");
resolution = 2;
r.setExtent(new OpenLayers.Bounds(178, -2, 184, 2), true);
t.eq(r.rightOfDateLine, true, "still on the right side of the dateline");
t.eq(r.xOffset, r.map.getMaxExtent().getWidth() / resolution, "xOffset adjusted for new resolution");
r.setExtent(new OpenLayers.Bounds(-184, -2, 178, 2), false);
t.eq(r.rightOfDateLine, false, "on the left side of the dateline");
t.eq(r.xOffset, 0, "no xOffset");
r.setExtent(new OpenLayers.Bounds(178, -2, 184, 2), true);
t.eq(r.rightOfDateLine, true, "back on the right side of the dateline");
t.eq(r.xOffset, r.map.getMaxExtent().getWidth() / resolution, "correct xOffset");
tearDown();
}
</script>
</head>

View File

@@ -3,11 +3,31 @@
<script src="OLLoader.js"></script>
<script type="text/javascript">
var tile;
var map, layer;
function setUp() {
map = new OpenLayers.Map("map");
layer = new OpenLayers.Layer(null, {
isBaseLayer: true
});
map.addLayer(layer)
map.setCenter(new OpenLayers.LonLat(0, 0));
}
function tearDown() {
map.destroy();
map = null;
layer = null;
}
function test_Tile_constructor (t) {
t.plan( 12 );
var layer = {}; // bogus layer
setUp();
var dummy = {};
var position = new OpenLayers.Pixel(10,20);
var bounds = new OpenLayers.Bounds(1,2,3,4);
var url = "bobob";
@@ -15,31 +35,30 @@
tile = new OpenLayers.Tile(layer, position, bounds, url, size);
t.ok( tile instanceof OpenLayers.Tile, "new OpenLayers.Tile returns Tile object" );
t.eq( tile.layer, layer, "tile.layer set correctly");
t.ok( tile.position.equals(position), "tile.position set correctly");
t.ok( tile.position != position, "tile.position set not by reference");
t.ok( tile.bounds.equals(bounds), "tile.bounds set correctly");
t.ok( tile.bounds != bounds, "tile.bounds set not by reference");
t.eq( tile.url, url, "tile.url set correctly");
t.ok( tile.size.equals(size), "tile.size is set correctly" );
t.ok( tile.size != size, "tile.size set not by reference");
t.ok(tile instanceof OpenLayers.Tile, "new OpenLayers.Tile returns Tile object");
t.ok(tile.layer === layer, "tile.layer set correctly");
t.ok(tile.position.equals(position), "tile.position set correctly");
t.ok(tile.position != position, "tile.position set not by reference");
t.ok(tile.bounds.equals(bounds), "tile.bounds set correctly");
t.ok(tile.bounds != bounds, "tile.bounds set not by reference");
t.eq(tile.url, url, "tile.url set correctly");
t.ok(tile.size.equals(size), "tile.size is set correctly");
t.ok(tile.size != size, "tile.size set not by reference");
t.ok( tile.id != null, "tile is given an id");
t.ok(tile.id != null, "tile is given an id");
t.ok(OpenLayers.String.startsWith(tile.id, "Tile_"),
"tile's id starts correctly");
t.ok( tile.events != null, "tile's events intitialized");
t.ok(tile.events != null, "tile's events intitialized");
tearDown();
}
function test_Tile_destroy(t) {
t.plan( 6 );
setUp();
var layer = {
SUPPORTED_TRANSITIONS: [],
events: {
unregister: function() {}
}
}; // bogus layer
var position = new OpenLayers.Pixel(10,20);
var bounds = new OpenLayers.Bounds(1,2,3,4);
var url = "bobob";
@@ -59,6 +78,9 @@
t.ok(tile.position == null, "tile.position set to null");
t.ok(tile.events == null, "tile.events set to null");
tearDown();
}
</script>

View File

@@ -3,41 +3,67 @@
<script src="../OLLoader.js"></script>
<script type="text/javascript">
var tile;
var layer = new OpenLayers.Layer.WMS(
var map, layer;
function setUp() {
map = new OpenLayers.Map("map");
layer = new OpenLayers.Layer.WMS(
"WMS",
window.location.href + "#",
null,
{transitionEffect: "resize"});
{transitionEffect: "resize"}
);
map.addLayer(layer)
map.setCenter(new OpenLayers.LonLat(0, 0));
}
function tearDown() {
map.destroy();
map = null;
layer = null;
}
var position = new OpenLayers.Pixel(20,30);
var bounds = new OpenLayers.Bounds(1,2,3,4);
function test_initialize (t) {
t.plan(2);
setUp();
tile = new OpenLayers.Tile.Image(layer, position, bounds, null);
t.eq(tile.backBufferData, {}, "back buffer data initialized");
t.eq(tile.size.w, 256, "size object with default width created");
tearDown();
}
function test_backBufferMode(t) {
t.plan(4);
var l;
var map = new OpenLayers.Map("map");
l = new OpenLayers.Layer.WMS('', window.location.href + '#');
map.addLayer(l);
map.zoomToMaxExtent();
tile = new OpenLayers.Tile.Image(l, position, bounds, null);
t.eq(tile.backBufferMode, 0,
'backBufferMode correctly set [tiled]');
l = new OpenLayers.Layer.WMS('', window.location.href + '#',
null, {singleTile: true});
map.addLayer(l);
tile = new OpenLayers.Tile.Image(l, position, bounds, null);
t.eq(tile.backBufferMode, 1,
'backBufferMode correctly set [singleTile]');
l = new OpenLayers.Layer.WMS('', window.location.href + '#',
null, {transitionEffect: 'resize'});
map.addLayer(l);
tile = new OpenLayers.Tile.Image(l, position, bounds, null);
t.eq(tile.backBufferMode, 2,
'backBufferMode correctly set [tiled, transition]');
@@ -45,17 +71,18 @@
l = new OpenLayers.Layer.WMS('', window.location.href + '#',
null, {singleTile: true,
transitionEffect: 'resize'});
map.addLayer(l);
tile = new OpenLayers.Tile.Image(l, position, bounds, null);
t.eq(tile.backBufferMode, 3,
'backBufferMode correctly set [singleTile, transition]');
map.destroy();
}
function test_setBackBufferData(t) {
t.plan(2);
setUp();
var map = new OpenLayers.Map("map");
map.addLayer(layer);
map.zoomToMaxExtent();
tile = new OpenLayers.Tile.Image(layer, position, bounds, null);
tile.draw();
// moveTo calls setBackBufferData
@@ -65,16 +92,15 @@
"bounds stored correctly");
t.eq(tile.backBufferData.resolution, map.getResolution(),
"resolution stored correctly");
map.removeLayer(layer);
map.destroy();
tearDown();
}
function test_updateBackBuffer(t) {
t.plan(1);
var map = new OpenLayers.Map("map");
map.addLayer(layer);
map.zoomToMaxExtent();
setUp();
tile = new OpenLayers.Tile.Image(layer, position, bounds, null);
tile.draw();
tile.isLoading = false;
@@ -82,15 +108,14 @@
tile.updateBackBuffer();
t.eq(tile.backBufferData.tile.style.width, (layer.tileSize.w*2)+"%",
"backBuffer frame correctly resized");
map.removeLayer(layer);
map.destroy();
tearDown();
}
function test_removeBackBuffer(t) {
t.plan(2);
var map = new OpenLayers.Map("map");
map.addLayer(layer);
map.zoomToMaxExtent();
setUp();
tile = new OpenLayers.Tile.Image(layer, position, bounds, null);
tile.draw();
tile.isLoading = false;
@@ -102,8 +127,8 @@
"backBuffer reference removed");
t.ok(backBuffer.parentNode !== layer.div,
"backBuffer removed from layer");
map.removeLayer(layer);
map.destroy();
tearDown();
}
function test_updateBackBuffer_scaled_layer(t) {
@@ -118,6 +143,13 @@
var map = new OpenLayers.Map('map', {
resolutions: [32, 16, 8, 4, 2, 1]
});
var layer = new OpenLayers.Layer.WMS(
"WMS",
window.location.href + "#",
null,
{transitionEffect: "resize"}
);
var serverResolitions = layer.serverResolutions;
layer.serverResolutions = [32, 16, 8];

View File

@@ -5,12 +5,27 @@
var isMozilla = (navigator.userAgent.indexOf("compatible") == -1);
var tile;
var map, layer;
function setUp() {
map = new OpenLayers.Map("map");
layer = new OpenLayers.Layer(null, {
isBaseLayer: true
});
map.addLayer(layer)
map.setCenter(new OpenLayers.LonLat(0, 0));
}
function tearDown() {
map.destroy();
map = null;
layer = null;
}
function test_Tile_Image_constructor (t) {
t.plan( 6 );
var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://labs.metacarta.com/wms/vmap0?", {layers: 'basic'});
setUp();
var position = new OpenLayers.Pixel(20,30);
var bounds = new OpenLayers.Bounds(1,2,3,4);
var url = "http://www.openlayers.org/dev/tests/tileimage";
@@ -23,6 +38,8 @@
t.ok( tile.bounds.equals(bounds), "tile.bounds is set correctly");
t.eq( tile.url, url, "tile.url is set correctly");
t.ok( tile.size.equals(size), "tile.size is set correctly");
tearDown();
}
function test_destroy_observers(t) {

View File

@@ -3,11 +3,27 @@
<script src="../OLLoader.js"></script>
<script type="text/javascript">
var tile;
var map, layer;
function setUp() {
map = new OpenLayers.Map("map");
layer = new OpenLayers.Layer(null, {
isBaseLayer: true
});
map.addLayer(layer)
map.setCenter(new OpenLayers.LonLat(0, 0));
}
function tearDown() {
map.destroy();
map = null;
layer = null;
}
function test_Tile_WFS_constructor (t) {
t.plan( 8 );
setUp();
var layer = {}; // bogus layer
var position = new OpenLayers.Pixel(10,20);
var bounds = new OpenLayers.Bounds(1,2,3,4);
var url = "bobob";
@@ -16,7 +32,7 @@
tile = new OpenLayers.Tile.WFS(layer, position, bounds, url, size);
t.ok( tile instanceof OpenLayers.Tile.WFS, "new OpenLayers.Tile.WFS returns Tile.WFS object" );
t.eq( tile.layer, layer, "tile.layer set correctly");
t.ok( tile.layer === layer, "tile.layer set correctly");
t.ok( tile.position.equals(position), "tile.position set correctly");
t.ok( tile.bounds.equals(bounds), "tile.bounds set correctly");
t.eq( tile.url, url, "tile.url set correctly");
@@ -24,10 +40,13 @@
t.ok( tile.id != null, "tile is given an id");
t.ok( tile.events != null, "tile's events intitialized");
tearDown();
}
function test_Tile_WFS_requestSuccess(t) {
t.plan(2);
setUp();
var tile = {
'request': {}
@@ -37,12 +56,6 @@
t.ok(tile.request == null, "request property on tile set to null");
var layer = {
SUPPORTED_TRANSITIONS: [],
events: {
unregister: function() {}
}
}; // bogus layer
var position = new OpenLayers.Pixel(10,20);
var bounds = new OpenLayers.Bounds(1,2,3,4);
var url = "bobob";
@@ -53,6 +66,7 @@
tile.requestSuccess({'requestText': '<xml><foo /></xml>'});
t.ok(true, "Didn't fail after calling requestSuccess on destroyed tile.");
tearDown();
}
function test_Tile_WFS_loadFeaturesForRegion(t) {
@@ -88,13 +102,8 @@
function test_Tile_WFS_destroy(t) {
t.plan(9);
setUp();
var layer = {
SUPPORTED_TRANSITIONS: [],
events: {
unregister: function() {}
}
}; // bogus layer
var position = new OpenLayers.Pixel(10,20);
var bounds = new OpenLayers.Bounds(1,2,3,4);
var url = "bobob";
@@ -127,43 +136,75 @@
tile.requestSuccess({'requestText': '<xml><foo /></xml>'});
t.ok(true, "Didn't fail after calling requestSuccess on destroyed tile.");
tearDown();
}
function test_nonxml_format(t) {
t.plan(1);
t.plan(2);
setUp();
var data = '{"type":"Feature", "id":"OpenLayers.Feature.Vector_135", "properties":{}, "geometry":{"type":"Point", "coordinates":[118.125, -18.6328125]}, "crs":{"type":"OGC", "properties":{"urn":"urn:ogc:def:crs:OGC:1.3:CRS84"}}}'
var position = new OpenLayers.Pixel(10,20);
var bounds = new OpenLayers.Bounds(1,2,3,4);
var url = "bobob";
var size = new OpenLayers.Size(5,6);
var tile = new OpenLayers.Tile.WFS({
vectorMode: true,
var log = [];
var l = new OpenLayers.Layer(null, {
vectorMode: true,
formatObject: new OpenLayers.Format.GeoJSON(),
addFeatures: function(features) {
t.eq(features.length, 1, "GeoJSON format returned a single feature which was added.")
log.push(features);
}
}, position, bounds, url, size);
})
map.addLayer(l);
var tile = new OpenLayers.Tile.WFS(l, position, bounds, url, size);
tile.requestSuccess({responseText: data});
t.eq(log.length, 1, "one call logged")
t.eq(log[0] && log[0].length, 1, "GeoJSON format returned a single feature which was added.");
tearDown();
}
function test_xml_string_and_dom(t) {
t.plan(2);
t.plan(4);
setUp();
var data = '<?xml version="1.0" encoding="ISO-8859-1" ?><wfs:FeatureCollection xmlns:bsc="http://www.bsc-eoc.org/bsc" xmlns:wfs="http://www.opengis.net/wfs" xmlns:gml="http://www.opengis.net/gml" xmlns:ogc="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengeospatial.net//wfs/1.0.0/WFS-basic.xsd http://www.bsc-eoc.org/bsc http://www.bsc-eoc.org/cgi-bin/bsc_ows.asp?SERVICE=WFS&amp;VERSION=1.0.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=OWLS&amp;OUTPUTFORMAT=XMLSCHEMA"> <gml:boundedBy> <gml:Box srsName="EPSG:4326"> <gml:coordinates>-94.989723,43.285833 -74.755001,51.709520</gml:coordinates> </gml:Box> </gml:boundedBy> <gml:featureMember> <bsc:OWLS> <gml:boundedBy> <gml:Box srsName="EPSG:4326"> <gml:coordinates>-94.142500,50.992777 -94.142500,50.992777</gml:coordinates> </gml:Box> </gml:boundedBy> <bsc:msGeometry> <gml:Point srsName="EPSG:4326"> <gml:coordinates>-94.142500,50.992777</gml:coordinates> </gml:Point> </bsc:msGeometry> <bsc:ROUTEID>ON_2</bsc:ROUTEID> <bsc:ROUTE_NAME>Suffel Road</bsc:ROUTE_NAME> <bsc:LATITUDE>50.9927770</bsc:LATITUDE> <bsc:LONGITUDE>-94.1425000</bsc:LONGITUDE> </bsc:OWLS> </gml:featureMember></wfs:FeatureCollection>';
var position = new OpenLayers.Pixel(10,20);
var bounds = new OpenLayers.Bounds(1,2,3,4);
var url = "bobob";
var size = new OpenLayers.Size(5,6);
var tile = new OpenLayers.Tile.WFS({
}, position, bounds, url, size);
var l = new OpenLayers.Layer();
map.addLayer(l);
var tile = new OpenLayers.Tile.WFS(l, position, bounds, url, size);
var log = [];
tile.addResults = function(results) {
t.eq(results.length, 1, "results count is correct when passing in XML as a string into non-vectormode");
log.push(results);
}
tile.requestSuccess({responseText: data});
t.eq(log.length, 1, "first call logged");
t.eq(log[0] && log[0].length, 1, "results count is correct when passing in XML as a string into non-vectormode");
log.length = 0;
tile.addResults = function(results) {
t.eq(results.length, 1, "results count is correct when passing in XML as DOM into non-vectormode");
log.push(results);
}
tile.requestSuccess({responseXML: OpenLayers.Format.XML.prototype.read(data)});
t.eq(log.length, 1, "second call logged");
t.eq(log[0] && log[0].length, 1, "results count is correct when passing in XML as DOM into non-vectormode");
tearDown();
}
</script>
</head>

View File

@@ -14,35 +14,8 @@
</style>
<script src="../../lib/OpenLayers.js"></script>
<script type="text/javascript">
// make map available for easy debugging
var map;
function init(){
var options = {
projection: new OpenLayers.Projection("EPSG:900913"),
units: "m",
maxResolution: 156543.0339,
maxExtent: new OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508)
};
map = new OpenLayers.Map('map', options);
var osm = new OpenLayers.Layer.OSM(
"OSM", null, {wrapDateLine: true}
);
var vector = new OpenLayers.Layer.Vector("Editable Vectors");
map.addLayers([osm, vector]);
map.addControl(new OpenLayers.Control.EditingToolbar(vector));
var extent = new OpenLayers.Bounds(15849982.183008, -11368938.517442, -14206280.326992, -1350184.3474418);
map.zoomToExtent(extent);
}
</script>
</head>
<body onload="init()">
<body>
<h1 id="title">OpenLayers sketch handlers crossing the dateline example</h1>
<div id="tags">
@@ -58,5 +31,36 @@ function init(){
<div id="docs">
</div>
<script type="text/javascript">
var map = new OpenLayers.Map('map');
var base = new OpenLayers.Layer.WMS("marble",
"http://demo.opengeo.org/geoserver/wms",
{layers: "topp:naturalearth"},
{wrapDateLine: true}
);
// allow testing of specific renderers via "?renderer=Canvas", etc
var renderer = OpenLayers.Util.getParameters(window.location.href).renderer;
renderer = (renderer) ? [renderer] : OpenLayers.Layer.Vector.prototype.renderers;
var vector = new OpenLayers.Layer.Vector("Editable Vectors", {renderers: renderer});
map.addLayers([base, vector]);
var wkt = new OpenLayers.Format.WKT();
var f = wkt.read("POLYGON((210.8828125 39.7265625,151.8203125 36.2109375,152.171875 -9.4921875,219.3203125 -10.546875,210.8828125 39.7265625))");
var f2 = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(-190, 0));
vector.addFeatures([f, f2]);
map.addControl(new OpenLayers.Control.EditingToolbar(vector));
map.setCenter(new OpenLayers.LonLat(-179, 0), 2);
</script>
</body>
</html>

View File

@@ -4,7 +4,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<meta name="apple-mobile-web-app-capable" content="yes">
<title>OpenLayers: Sketch handlers crossing the dateline</title>
<title>OpenLayers: Overlay layer extents crossing the dateline</title>
<link rel="stylesheet" href="../../theme/default/style.css" type="text/css">
<link rel="stylesheet" href="../../examples/style.css" type="text/css">
<style type="text/css">
@@ -22,19 +22,26 @@ var map;
function init(){
map = new OpenLayers.Map('map');
var osm = new OpenLayers.Layer.OSM(
"OSM", null,
var base = new OpenLayers.Layer.WMS("marble",
"http://demo.opengeo.org/geoserver/wms",
{layers: "topp:naturalearth"},
{wrapDateLine: true}
);
var extent = new OpenLayers.Bounds(15849982.183008, -11368938.517442, -14206280.326992, -1350184.3474419);
var extent = new OpenLayers.Bounds(142.3828125,-70.902270266175,233.6171875,-12.039326531729);
var wms = new OpenLayers.Layer.WMS( "world",
"http://demo.opengeo.org/geoserver/wms",
{layers: 'world', transparent: true},
{maxExtent: extent}
);
var vector = new OpenLayers.Layer.Vector();
vector.addFeatures([
new OpenLayers.Feature.Vector(extent.toGeometry())
]);
map.addLayers([osm, wms]);
map.addLayers([base, wms, vector]);
map.addControl(new OpenLayers.Control.LayerSwitcher());
map.zoomToExtent(extent);
}
@@ -44,9 +51,10 @@ function init(){
<h1 id="title">OpenLayers overlays crossing the dateline test</h1>
<p id="shortdesc">
The overlay has an extent smaller than the world extent. The base layer
is configured with wrapDateLine set to true. New Zealand and a part of
Australia should always be visible on the map.
The overlay has an extent smaller than the world extent, but exceeds
the world extent. The base layer is configured with wrapDateLine set to
true. The area inside the orange rectangle should always contain tiles
from the world layer, regardless of the zoom level.
</p>
<div id="map" class="smallmap"></div>
</body>