diff --git a/examples/image-vector-layer.js b/examples/image-vector-layer.js index 16966e28ba..0a9ef82870 100644 --- a/examples/image-vector-layer.js +++ b/examples/image-vector-layer.js @@ -21,6 +21,7 @@ const style = new Style({ const map = new Map({ layers: [ new VectorImageLayer({ + imageRatio: 2, source: new VectorSource({ url: 'data/geojson/countries.geojson', format: new GeoJSON() diff --git a/src/ol/layer/VectorImage.js b/src/ol/layer/VectorImage.js index 42678c778d..297d6d2e67 100644 --- a/src/ol/layer/VectorImage.js +++ b/src/ol/layer/VectorImage.js @@ -2,10 +2,13 @@ * @module ol/layer/VectorImage */ import BaseVectorLayer from './BaseVector.js'; +import {assign} from '../obj.js'; import CanvasVectorImageLayerRenderer from '../renderer/canvas/VectorImageLayer.js'; /** * @typedef {import("./BaseVector.js").Options} Options + * @property {number} [imageRatio=1] Ratio by which the rendered extent should be larger than the + * viewport extent A larger ratio avoids cut images during panning, but will cause a decrease in performance. */ @@ -23,7 +26,25 @@ class VectorImageLayer extends BaseVectorLayer { * @param {Options=} opt_options Options. */ constructor(opt_options) { + const options = opt_options ? opt_options : /** @type {Options} */ ({}); + + const baseOptions = assign({}, options); + delete baseOptions.imageRatio; super(opt_options); + + /** + * @type {number} + * @private + */ + this.imageRatio_ = options.imageRatio !== undefined ? options.imageRatio : 1; + + } + + /** + * @return {number} Ratio between rendered extent size and viewport extent size. + */ + getImageRatio() { + return this.imageRatio_; } /** diff --git a/src/ol/renderer/canvas/VectorImageLayer.js b/src/ol/renderer/canvas/VectorImageLayer.js index 0fb933b564..c2d00d6d2c 100644 --- a/src/ol/renderer/canvas/VectorImageLayer.js +++ b/src/ol/renderer/canvas/VectorImageLayer.js @@ -4,7 +4,7 @@ import ImageCanvas from '../../ImageCanvas.js'; import ViewHint from '../../ViewHint.js'; import {equals} from '../../array.js'; -import {getHeight, getWidth, isEmpty} from '../../extent.js'; +import {getHeight, getWidth, isEmpty, scaleFromCenter} from '../../extent.js'; import {assign} from '../../obj.js'; import CanvasImageLayerRenderer from './ImageLayer.js'; import CanvasVectorLayerRenderer from './VectorLayer.js'; @@ -33,6 +33,12 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer { */ this.vectorRenderer_ = new CanvasVectorLayerRenderer(layer); + /** + * @private + * @type {number} + */ + this.layerImageRatio_ = layer.getImageRatio(); + } /** @@ -53,7 +59,11 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer { const hints = frameState.viewHints; const vectorRenderer = this.vectorRenderer_; - const renderedExtent = frameState.extent; + let renderedExtent = frameState.extent; + if (this.layerImageRatio_ !== 1) { + renderedExtent = renderedExtent.slice(0); + scaleFromCenter(renderedExtent, this.layerImageRatio_); + } if (!hints[ViewHint.ANIMATING] && !hints[ViewHint.INTERACTING] && !isEmpty(renderedExtent)) { let skippedFeatures = this.skippedFeatures_; diff --git a/test/spec/ol/renderer/canvas/vectorimage.test.js b/test/spec/ol/renderer/canvas/vectorimage.test.js index 5948f40a44..a3a0b48593 100644 --- a/test/spec/ol/renderer/canvas/vectorimage.test.js +++ b/test/spec/ol/renderer/canvas/vectorimage.test.js @@ -1,6 +1,9 @@ import VectorImageLayer from '../../../../../src/ol/layer/VectorImage.js'; import VectorSource from '../../../../../src/ol/source/Vector.js'; import CanvasVectorImageLayerRenderer from '../../../../../src/ol/renderer/canvas/VectorImageLayer.js'; +import {get as getProjection} from '../../../../../src/ol/proj.js'; +import {scaleFromCenter} from '../../../../../src/ol/extent.js'; + describe('ol/renderer/canvas/VectorImageLayer', function() { @@ -18,4 +21,36 @@ describe('ol/renderer/canvas/VectorImageLayer', function() { }); + describe('#prepareFrame', function() { + + it('sets correct extent with imageRatio = 2', function() { + const layer = new VectorImageLayer({ + imageRatio: 2, + source: new VectorSource() + }); + const renderer = new CanvasVectorImageLayerRenderer(layer); + const projection = getProjection('EPSG:3857'); + const projExtent = projection.getExtent(); + const extent = [ + projExtent[0] - 10000, -10000, projExtent[0] + 10000, 10000 + ]; + const frameState = { + extent: extent, + skippedFeatureUids: {}, + viewHints: [], + viewState: { + projection: projection, + resolution: 1, + rotation: 0 + } + }; + renderer.prepareFrame(frameState, {}); + const expected = renderer.image_.getExtent(); + + scaleFromCenter(extent, 2); + + expect(expected).to.eql(extent); + }); + }); + });