diff --git a/src/ol/renderer/canvas/VectorLayer.js b/src/ol/renderer/canvas/VectorLayer.js index beef39b2f3..472333c8c9 100644 --- a/src/ol/renderer/canvas/VectorLayer.js +++ b/src/ol/renderer/canvas/VectorLayer.js @@ -361,7 +361,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer { const center = viewState.center.slice(); const extent = buffer(frameStateExtent, vectorLayerRenderBuffer * resolution); - const loadExtent = extent.slice(); + const loadExtents = [extent.slice()]; const projectionExtent = viewState.projection.getExtent(); if (vectorSource.getWrapX() && viewState.projection.canWrapX() && @@ -377,8 +377,15 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer { extent[2] = projectionExtent[2] + gutter; const worldsAway = Math.floor((center[0] - projectionExtent[0]) / worldWidth); center[0] -= (worldsAway * worldWidth); + const loadExtent = loadExtents[0]; loadExtent[0] -= (worldsAway * worldWidth); loadExtent[2] -= (worldsAway * worldWidth); + // If the extent crosses the date line, we load data for both edges of the worlds + if (loadExtent[0] < projectionExtent[0] && loadExtent[2] < projectionExtent[2]) { + loadExtents.push([loadExtent[0] + worldWidth, loadExtent[1], loadExtent[2] + worldWidth, loadExtent[3]]); + } else if (loadExtent[0] > projectionExtent[0] && loadExtent[2] > projectionExtent[2]) { + loadExtents.push([loadExtent[0] - worldWidth, loadExtent[1], loadExtent[2] - worldWidth, loadExtent[3]]); + } } if (!this.dirty_ && @@ -401,10 +408,14 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer { const userProjection = getUserProjection(); let userTransform; if (userProjection) { - vectorSource.loadFeatures(toUserExtent(loadExtent, projection), resolution, userProjection); + for (let i = 0, ii = loadExtents.length; i < ii; ++i) { + vectorSource.loadFeatures(toUserExtent(loadExtents[i], projection), resolution, userProjection); + } userTransform = getTransformFromProjections(userProjection, projection); } else { - vectorSource.loadFeatures(loadExtent, resolution, projection); + for (let i = 0, ii = loadExtents.length; i < ii; ++i) { + vectorSource.loadFeatures(loadExtents[i], resolution, projection); + } } const squaredTolerance = getSquaredRenderTolerance(resolution, pixelRatio); diff --git a/test/spec/ol/renderer/canvas/vectorlayer.test.js b/test/spec/ol/renderer/canvas/vectorlayer.test.js index 05e7c011b6..f2fabaddd8 100644 --- a/test/spec/ol/renderer/canvas/vectorlayer.test.js +++ b/test/spec/ol/renderer/canvas/vectorlayer.test.js @@ -221,10 +221,11 @@ describe('ol.renderer.canvas.VectorLayer', function() { }); describe('#prepareFrame and #compose', function() { - let frameState, projExtent, renderer, worldWidth, buffer, loadExtent; - const loader = function(extent) { - loadExtent = extent; - }; + let frameState, projExtent, renderer, worldWidth, buffer, loadExtents; + + function loader(extent) { + loadExtents.push(extent); + } beforeEach(function() { const layer = new VectorLayer({ @@ -239,7 +240,7 @@ describe('ol.renderer.canvas.VectorLayer', function() { projExtent = projection.getExtent(); worldWidth = getWidth(projExtent); buffer = layer.getRenderBuffer(); - loadExtent = undefined; + loadExtents = []; frameState = { viewHints: [], viewState: { @@ -263,7 +264,10 @@ describe('ol.renderer.canvas.VectorLayer', function() { projExtent[0] - worldWidth + buffer, -10000, projExtent[2] + worldWidth - buffer, 10000 ], buffer)); - expect(loadExtent).to.eql(bufferExtent(frameState.extent, buffer)); + expect(loadExtents.length).to.be(2); + expect(loadExtents[0]).to.eql(bufferExtent(frameState.extent, buffer)); + const otherExtent = [projExtent[2] - 10000, -10000, projExtent[2] + 10000, 10000]; + expect(loadExtents[1]).to.eql(bufferExtent(otherExtent, buffer)); }); it('sets correct extent for viewport less than 1 world wide', function() { @@ -274,7 +278,10 @@ describe('ol.renderer.canvas.VectorLayer', function() { projExtent[0] - worldWidth + buffer, -10000, projExtent[2] + worldWidth - buffer, 10000 ], buffer)); - expect(loadExtent).to.eql(bufferExtent(frameState.extent, buffer)); + expect(loadExtents.length).to.be(2); + expect(loadExtents[0]).to.eql(bufferExtent(frameState.extent, buffer)); + const otherExtent = [projExtent[0] - 10000 + worldWidth, -10000, projExtent[2] - 10000 + worldWidth, 10000]; + expect(loadExtents[1]).to.eql(bufferExtent(otherExtent, buffer)); }); it('sets correct extent for viewport more than 1 world wide', function() { @@ -285,7 +292,8 @@ describe('ol.renderer.canvas.VectorLayer', function() { projExtent[0] - worldWidth + buffer, -10000, projExtent[2] + worldWidth - buffer, 10000 ], buffer)); - expect(loadExtent).to.eql(bufferExtent(frameState.extent, buffer)); + expect(loadExtents.length).to.be(1); + expect(loadExtents[0]).to.eql(bufferExtent(frameState.extent, buffer)); }); it('sets correct extent for viewport more than 2 worlds wide, one world away', function() { @@ -298,11 +306,12 @@ describe('ol.renderer.canvas.VectorLayer', function() { projExtent[0] - 2 * worldWidth - 10000, -10000, projExtent[2] + 2 * worldWidth + 10000, 10000 ], buffer)); + expect(loadExtents.length).to.be(1); const normalizedExtent = [projExtent[0] - 2 * worldWidth + worldWidth - 10000, -10000, projExtent[0] + 2 * worldWidth + worldWidth + 10000, 10000]; - expect(loadExtent).to.eql(bufferExtent(normalizedExtent, buffer)); + expect(loadExtents[0]).to.eql(bufferExtent(normalizedExtent, buffer)); }); - it('sets correct extent for small viewport near dateline, one world away', function() { + it('sets correct extent for small viewport, one world away', function() { setExtent([-worldWidth - 10000, -10000, -worldWidth + 10000, 10000]); renderer.prepareFrame(frameState); @@ -310,8 +319,9 @@ describe('ol.renderer.canvas.VectorLayer', function() { projExtent[0] - worldWidth + buffer, -10000, projExtent[2] + worldWidth - buffer, 10000 ], buffer)); + expect(loadExtents.length).to.be(1); const normalizedExtent = [-10000, -10000, 10000, 10000]; - expect(loadExtent).to.eql(bufferExtent(normalizedExtent, buffer)); + expect(loadExtents[0]).to.eql(bufferExtent(normalizedExtent, buffer)); }); it('sets replayGroupChanged correctly', function() { @@ -344,90 +354,6 @@ describe('ol.renderer.canvas.VectorLayer', function() { }); - describe('#prepareFrame with a loadWrapX: false source', function() { - let frameState, projExtent, renderer, worldWidth, buffer, loadExtent; - const loader = function(extent) { - loadExtent = extent; - }; - - beforeEach(function() { - const layer = new VectorLayer({ - source: new VectorSource({ - wrapX: true, - loadWrapX: false, - loader: loader, - strategy: bboxStrategy - }) - }); - renderer = new CanvasVectorLayerRenderer(layer); - const projection = getProjection('EPSG:3857'); - projExtent = projection.getExtent(); - worldWidth = getWidth(projExtent); - buffer = layer.getRenderBuffer(); - loadExtent = undefined; - frameState = { - viewHints: [], - viewState: { - center: [0, 0], - projection: projection, - resolution: 1, - rotation: 0 - } - }; - }); - - it('loads 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(bufferExtent([ - projExtent[0] - worldWidth + buffer, - -10000, projExtent[2] + worldWidth - buffer, 10000 - ], buffer)); - expect(loadExtent).to.eql(bufferExtent(frameState.extent, buffer)); - }); - - it('loads 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(bufferExtent([ - projExtent[0] - worldWidth + buffer, - -10000, projExtent[2] + worldWidth - buffer, 10000 - ], buffer)); - expect(loadExtent).to.eql(bufferExtent(frameState.extent, buffer)); - }); - - it('loads 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(bufferExtent([ - projExtent[0] - worldWidth + buffer, - -10000, projExtent[2] + worldWidth - buffer, 10000 - ], buffer)); - expect(loadExtent).to.eql(bufferExtent(frameState.extent, buffer)); - }); - - it('loads 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(bufferExtent([ - projExtent[0] - 2 * worldWidth - 10000, - -10000, projExtent[2] + 2 * worldWidth + 10000, 10000 - ], buffer)); - expect(loadExtent).to.eql(bufferExtent(frameState.extent, buffer)); - }); - - }); - describe('hit detection', function() { it('with no fill and transparent fill', function() {