diff --git a/lib/OpenLayers/BaseTypes/Bounds.js b/lib/OpenLayers/BaseTypes/Bounds.js index ebcfbfaa09..5935ccbe1a 100644 --- a/lib/OpenLayers/BaseTypes/Bounds.js +++ b/lib/OpenLayers/BaseTypes/Bounds.js @@ -354,14 +354,37 @@ OpenLayers.Bounds = OpenLayers.Class({ * * Parameters: * ll - {} + * options - {Object} Optional parameters + * + * Acceptable options: * inclusive - {Boolean} Whether or not to include the border. * Default is true. + * worldBounds - {} 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 - {} 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 - {} 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; diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index e5fa551c9f..6cbac3b2e9 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -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; diff --git a/lib/OpenLayers/Map.js b/lib/OpenLayers/Map.js index 3c83d56732..3315494bf3 100644 --- a/lib/OpenLayers/Map.js +++ b/lib/OpenLayers/Map.js @@ -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); } diff --git a/lib/OpenLayers/Renderer.js b/lib/OpenLayers/Renderer.js index 6a35b3f34c..a1b1a92342 100644 --- a/lib/OpenLayers/Renderer.js +++ b/lib/OpenLayers/Renderer.js @@ -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 + * ). + */ + featureDx: 0, + /** * Constructor: OpenLayers.Renderer * @@ -122,12 +130,21 @@ OpenLayers.Renderer = OpenLayers.Class({ * Parameters: * extent - {} * 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 - {} Bounds of the feature + * worldBounds - {} 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 diff --git a/lib/OpenLayers/Renderer/Canvas.js b/lib/OpenLayers/Renderer/Canvas.js index d9e7828469..a9a87bb788 100644 --- a/lib/OpenLayers/Renderer/Canvas.js +++ b/lib/OpenLayers/Renderer/Canvas.js @@ -70,6 +70,25 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { } }, + /** + * Method: setExtent + * Set the visible part of the layer. + * + * Parameters: + * extent - {} + * 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]); } diff --git a/lib/OpenLayers/Renderer/Elements.js b/lib/OpenLayers/Renderer/Elements.js index 12b036bf13..31b9d53c95 100644 --- a/lib/OpenLayers/Renderer/Elements.js +++ b/lib/OpenLayers/Renderer/Elements.js @@ -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 method compares this value (which is the one + * from the previous 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 * {} 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 - {} + * 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 diff --git a/lib/OpenLayers/Renderer/SVG.js b/lib/OpenLayers/Renderer/SVG.js index f7f53bf08e..b2d475a4f0 100644 --- a/lib/OpenLayers/Renderer/SVG.js +++ b/lib/OpenLayers/Renderer/SVG.js @@ -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; } diff --git a/lib/OpenLayers/Renderer/VML.js b/lib/OpenLayers/Renderer/VML.js index 88c6f292fb..7f9783d4aa 100644 --- a/lib/OpenLayers/Renderer/VML.js +++ b/lib/OpenLayers/Renderer/VML.js @@ -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 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; }, diff --git a/tests/BaseTypes/Bounds.html b/tests/BaseTypes/Bounds.html index 1c607f339a..b436005d1c 100644 --- a/tests/BaseTypes/Bounds.html +++ b/tests/BaseTypes/Bounds.html @@ -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 diff --git a/tests/Tile.html b/tests/Tile.html index ee6a80fb45..9c0743a8d9 100644 --- a/tests/Tile.html +++ b/tests/Tile.html @@ -3,11 +3,31 @@ diff --git a/tests/Tile/BackBufferable.html b/tests/Tile/BackBufferable.html index 22d1a1e3bd..97275891e7 100644 --- a/tests/Tile/BackBufferable.html +++ b/tests/Tile/BackBufferable.html @@ -3,41 +3,67 @@ diff --git a/tests/manual/dateline-sketch.html b/tests/manual/dateline-sketch.html index f2e4a0a859..1be1f36a06 100644 --- a/tests/manual/dateline-sketch.html +++ b/tests/manual/dateline-sketch.html @@ -14,35 +14,8 @@ - - +

OpenLayers sketch handlers crossing the dateline example

@@ -58,5 +31,36 @@ function init(){
+ + diff --git a/tests/manual/dateline-smallextent.html b/tests/manual/dateline-smallextent.html index ed80a8a9e7..1d05e849cf 100644 --- a/tests/manual/dateline-smallextent.html +++ b/tests/manual/dateline-smallextent.html @@ -4,7 +4,7 @@ - OpenLayers: Sketch handlers crossing the dateline + OpenLayers: Overlay layer extents crossing the dateline