diff --git a/src/ol/renderer/canvas/canvasvectorlayerrenderer.js b/src/ol/renderer/canvas/canvasvectorlayerrenderer.js index 7b4a89b065..4439778d9d 100644 --- a/src/ol/renderer/canvas/canvasvectorlayerrenderer.js +++ b/src/ol/renderer/canvas/canvasvectorlayerrenderer.js @@ -135,6 +135,8 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame = skippedFeatureUids); startX -= worldWidth; } + // restore original transform for render and compose events + transform = this.getTransform(frameState, 0); } if (replayContext != context) { @@ -236,9 +238,15 @@ ol.renderer.canvas.VectorLayer.prototype.prepareFrame = if (vectorSource.getWrapX() && viewState.projection.canWrapX() && !ol.extent.containsExtent(projectionExtent, frameState.extent)) { - // do not clip when the view crosses the -180° or 180° meridians - extent[0] = projectionExtent[0]; - extent[2] = projectionExtent[2]; + // For the replay group, we need an extent that intersects the real world + // (-180° to +180°). To support geometries in a coordinate range from -540° + // to +540°, we add at least 1 world width on each side of the projection + // extent. If the viewport is wider than the world, we need to add half of + // the viewport width to make sure we cover the whole viewport. + var worldWidth = ol.extent.getWidth(projectionExtent); + var buffer = Math.max(ol.extent.getWidth(extent) / 2, worldWidth); + extent[0] = projectionExtent[0] - buffer; + extent[2] = projectionExtent[2] + buffer; } if (!this.dirty_ && diff --git a/test/spec/ol/proj/epsg3857projection.test.js b/test/spec/ol/proj/epsg3857projection.test.js index a832168740..50255ddacb 100644 --- a/test/spec/ol/proj/epsg3857projection.test.js +++ b/test/spec/ol/proj/epsg3857projection.test.js @@ -3,12 +3,9 @@ goog.provide('ol.test.proj.EPSG3857'); describe('ol.proj.EPSG3857', function() { - beforeEach(function() { - ol.proj.common.add(); - }); - afterEach(function() { ol.proj.clearAllProjections(); + ol.proj.common.add(); }); describe('getPointResolution', function() { diff --git a/test/spec/ol/proj/proj.test.js b/test/spec/ol/proj/proj.test.js index de7ba4935a..374ac5bcb0 100644 --- a/test/spec/ol/proj/proj.test.js +++ b/test/spec/ol/proj/proj.test.js @@ -2,12 +2,9 @@ goog.provide('ol.test.proj'); describe('ol.proj', function() { - beforeEach(function() { - ol.proj.common.add(); - }); - afterEach(function() { ol.proj.clearAllProjections(); + ol.proj.common.add(); }); describe('projection equivalence', function() { diff --git a/test/spec/ol/renderer/canvas/canvasvectorlayerrenderer.test.js b/test/spec/ol/renderer/canvas/canvasvectorlayerrenderer.test.js index 5a97a9d89e..e2e1e6f759 100644 --- a/test/spec/ol/renderer/canvas/canvasvectorlayerrenderer.test.js +++ b/test/spec/ol/renderer/canvas/canvasvectorlayerrenderer.test.js @@ -91,14 +91,88 @@ describe('ol.renderer.canvas.VectorLayer', function() { }); }); + describe('#prepareFrame', function() { + var frameState, projExtent, renderer, worldWidth, buffer; + + beforeEach(function() { + var layer = new ol.layer.Vector({ + source: new ol.source.Vector({wrapX: true}) + }); + renderer = new ol.renderer.canvas.VectorLayer(layer); + var projection = ol.proj.get('EPSG:3857'); + projExtent = projection.getExtent(); + worldWidth = ol.extent.getWidth(projExtent); + buffer = layer.getRenderBuffer(); + frameState = { + skippedFeatureUids: {}, + viewHints: [], + viewState: { + projection: projection, + resolution: 1, + rotation: 0 + } + }; + }); + + it('sets correct extent for small viewport near dateline', function() { + + frameState.extent = + [projExtent[0] - 10000, -10000, projExtent[0] + 10000, 10000]; + renderer.prepareFrame(frameState, {}); + expect(renderer.replayGroup_.maxExtent_).to.eql(ol.extent.buffer([ + projExtent[0] - worldWidth + buffer, + -10000, projExtent[2] + worldWidth - buffer, 10000 + ], buffer)); + + }); + + it('sets correct extent for viewport less than 1 world wide', function() { + + frameState.extent = + [projExtent[0] - 10000, -10000, projExtent[1] - 10000, 10000]; + renderer.prepareFrame(frameState, {}); + expect(renderer.replayGroup_.maxExtent_).to.eql(ol.extent.buffer([ + projExtent[0] - worldWidth + buffer, + -10000, projExtent[2] + worldWidth - buffer, 10000 + ], buffer)); + }); + + it('sets correct extent for viewport more than 1 world wide', function() { + + frameState.extent = + [2 * projExtent[0] - 10000, -10000, 2 * projExtent[1] + 10000, 10000]; + renderer.prepareFrame(frameState, {}); + expect(renderer.replayGroup_.maxExtent_).to.eql(ol.extent.buffer([ + projExtent[0] - worldWidth + buffer, + -10000, projExtent[2] + worldWidth - buffer, 10000 + ], buffer)); + }); + + it('sets correct extent for viewport more than 2 worlds wide', function() { + + frameState.extent = [ + projExtent[0] - 2 * worldWidth - 10000, + -10000, projExtent[1] + 2 * worldWidth + 10000, 10000 + ]; + renderer.prepareFrame(frameState, {}); + expect(renderer.replayGroup_.maxExtent_).to.eql(ol.extent.buffer([ + projExtent[0] - 2 * worldWidth - 10000, + -10000, projExtent[2] + 2 * worldWidth + 10000, 10000 + ], buffer)); + }); + + }); + }); goog.require('ol.Feature'); goog.require('ol.Map'); goog.require('ol.View'); +goog.require('ol.extent'); goog.require('ol.geom.Point'); goog.require('ol.layer.Vector'); +goog.require('ol.proj'); goog.require('ol.renderer.canvas.VectorLayer'); goog.require('ol.source.Vector'); goog.require('ol.style.Style');