diff --git a/rendering/cases/layer-image-extent-rotation-geographic/expected.png b/rendering/cases/layer-image-extent-rotation-geographic/expected.png new file mode 100644 index 0000000000..2a11dce941 Binary files /dev/null and b/rendering/cases/layer-image-extent-rotation-geographic/expected.png differ diff --git a/rendering/cases/layer-image-extent-rotation-geographic/main.js b/rendering/cases/layer-image-extent-rotation-geographic/main.js new file mode 100644 index 0000000000..41a59fffa4 --- /dev/null +++ b/rendering/cases/layer-image-extent-rotation-geographic/main.js @@ -0,0 +1,34 @@ +import Map from '../../../src/ol/Map.js'; +import View from '../../../src/ol/View.js'; +import Static from '../../../src/ol/source/ImageStatic.js'; +import { + get as getProjection, + transformExtent, + useGeographic +} from '../../../src/ol/proj.js'; +import ImageLayer from '../../../src/ol/layer/Image.js'; + +useGeographic(); + +const center = [-122.416667, 37.783333]; +const extent = [-123.1, 37.1, -122.1, 37.9]; + +new Map({ + pixelRatio: 1, + target: 'map', + layers: [new ImageLayer({ + source: new Static({ + url: '/data/tiles/osm/5/5/12.png', + imageExtent: transformExtent([-123, 37, -122, 38], 'EPSG:4326', 'EPSG:3857'), + projection: getProjection('EPSG:3857') + }), + extent + })], + view: new View({ + center, + zoom: 8, + rotation: Math.PI / 4 + }) +}); + +render(); diff --git a/rendering/cases/layer-tile-extent-geographic/expected.png b/rendering/cases/layer-tile-extent-geographic/expected.png new file mode 100644 index 0000000000..a07e264668 Binary files /dev/null and b/rendering/cases/layer-tile-extent-geographic/expected.png differ diff --git a/rendering/cases/layer-tile-extent-geographic/main.js b/rendering/cases/layer-tile-extent-geographic/main.js new file mode 100644 index 0000000000..ea56577f79 --- /dev/null +++ b/rendering/cases/layer-tile-extent-geographic/main.js @@ -0,0 +1,41 @@ +/** + * Tile layers get clipped to their extent. + */ + +import Map from '../../../src/ol/Map.js'; +import View from '../../../src/ol/View.js'; +import TileLayer from '../../../src/ol/layer/Tile.js'; +import XYZ from '../../../src/ol/source/XYZ.js'; +import {useGeographic} from '../../../src/ol/proj.js'; + +useGeographic(); + +const center = [7, 50]; +const extent = [2, 47, 10, 53]; + +new Map({ + target: 'map', + view: new View({ + center: center, + zoom: 3 + }), + layers: [ + new TileLayer({ + source: new XYZ({ + url: '/data/tiles/satellite/{z}/{x}/{y}.jpg', + maxZoom: 3 + }), + extent: extent + }), + new TileLayer({ + source: new XYZ({ + url: '/data/tiles/stamen-labels/{z}/{x}/{y}.png', + minZoom: 3, + maxZoom: 5 + }), + extent: extent + }) + ] +}); + +render(); diff --git a/rendering/cases/layer-vector-extent-geographic/expected.png b/rendering/cases/layer-vector-extent-geographic/expected.png new file mode 100644 index 0000000000..4fa17ea1f8 Binary files /dev/null and b/rendering/cases/layer-vector-extent-geographic/expected.png differ diff --git a/rendering/cases/layer-vector-extent-geographic/main.js b/rendering/cases/layer-vector-extent-geographic/main.js new file mode 100644 index 0000000000..e726a1c0c8 --- /dev/null +++ b/rendering/cases/layer-vector-extent-geographic/main.js @@ -0,0 +1,27 @@ +import Map from '../../../src/ol/Map.js'; +import View from '../../../src/ol/View.js'; +import GeoJSON from '../../../src/ol/format/GeoJSON.js'; +import VectorLayer from '../../../src/ol/layer/Vector.js'; +import VectorSource from '../../../src/ol/source/Vector.js'; +import {useGeographic} from '../../../src/ol/proj.js'; + +useGeographic(); + +new Map({ + target: 'map', + view: new View({ + center: [0, 0], + zoom: 1 + }), + layers: [ + new VectorLayer({ + extent: [-50, -45, 50, 45], + source: new VectorSource({ + url: '/data/countries.json', + format: new GeoJSON() + }) + }) + ] +}); + +render(); diff --git a/src/ol/renderer/canvas/ImageLayer.js b/src/ol/renderer/canvas/ImageLayer.js index 9034e8bd07..4a59dfa480 100644 --- a/src/ol/renderer/canvas/ImageLayer.js +++ b/src/ol/renderer/canvas/ImageLayer.js @@ -4,6 +4,7 @@ import {ENABLE_RASTER_REPROJECTION} from '../../reproj/common.js'; import ViewHint from '../../ViewHint.js'; import {containsExtent, intersects} from '../../extent.js'; +import {fromUserExtent} from '../../proj.js'; import {getIntersection, isEmpty} from '../../extent.js'; import CanvasLayerRenderer from './Layer.js'; import {compose as composeTransform, makeInverse, toString as transformToString} from '../../transform.js'; @@ -50,7 +51,7 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer { let renderedExtent = frameState.extent; if (layerState.extent !== undefined) { - renderedExtent = getIntersection(renderedExtent, layerState.extent); + renderedExtent = getIntersection(renderedExtent, fromUserExtent(layerState.extent, viewState.projection)); } if (!hints[ViewHint.ANIMATING] && !hints[ViewHint.INTERACTING] && !isEmpty(renderedExtent)) { @@ -116,12 +117,13 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer { } // clipped rendering if layer extent is set - const extent = layerState.extent; - const clipped = extent !== undefined && - !containsExtent(extent, frameState.extent) && - intersects(extent, frameState.extent); - if (clipped) { - this.clipUnrotated(context, frameState, extent); + let clipped = false; + if (layerState.extent) { + const layerExtent = fromUserExtent(layerState.extent, viewState.projection); + clipped = !containsExtent(layerExtent, frameState.extent) && intersects(layerExtent, frameState.extent); + if (clipped) { + this.clipUnrotated(context, frameState, layerExtent); + } } const img = image.getImage(); diff --git a/src/ol/renderer/canvas/TileLayer.js b/src/ol/renderer/canvas/TileLayer.js index 80a799edf9..1e79f7723c 100644 --- a/src/ol/renderer/canvas/TileLayer.js +++ b/src/ol/renderer/canvas/TileLayer.js @@ -2,6 +2,7 @@ * @module ol/renderer/canvas/TileLayer */ import {getUid} from '../../util.js'; +import {fromUserExtent} from '../../proj.js'; import TileRange from '../../TileRange.js'; import TileState from '../../TileState.js'; import {createEmpty, equals, getIntersection, getTopLeft} from '../../extent.js'; @@ -147,10 +148,11 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer { const tileGrid = tileSource.getTileGridForProjection(projection); const z = tileGrid.getZForResolution(viewResolution, tileSource.zDirection); const tileResolution = tileGrid.getResolution(z); - let extent = frameState.extent; - if (layerState.extent) { - extent = getIntersection(extent, layerState.extent); + let extent = frameState.extent; + const layerExtent = layerState.extent && fromUserExtent(layerState.extent, projection); + if (layerExtent) { + extent = getIntersection(extent, fromUserExtent(layerState.extent, projection)); } const tilePixelRatio = tileSource.getTilePixelRatio(pixelRatio); @@ -249,8 +251,8 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer { context.clearRect(0, 0, width, height); } - if (layerState.extent) { - this.clipUnrotated(context, frameState, layerState.extent); + if (layerExtent) { + this.clipUnrotated(context, frameState, layerExtent); } this.preRender(context, frameState); diff --git a/src/ol/renderer/canvas/VectorLayer.js b/src/ol/renderer/canvas/VectorLayer.js index 7726a03c7e..d2bb0c0a48 100644 --- a/src/ol/renderer/canvas/VectorLayer.js +++ b/src/ol/renderer/canvas/VectorLayer.js @@ -3,7 +3,8 @@ */ import {getUid} from '../../util.js'; import ViewHint from '../../ViewHint.js'; -import {buffer, createEmpty, containsExtent, getWidth} from '../../extent.js'; +import {buffer, createEmpty, containsExtent, getWidth, intersects as intersectsExtent} from '../../extent.js'; +import {fromUserExtent} from '../../proj.js'; import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js'; import ExecutorGroup, {replayDeclutter} from '../../render/canvas/ExecutorGroup.js'; import CanvasLayerRenderer from './Layer.js'; @@ -129,10 +130,13 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer { const vectorSource = this.getLayer().getSource(); // clipped rendering if layer extent is set - const clipExtent = layerState.extent; - const clipped = clipExtent !== undefined; - if (clipped) { - this.clip(context, frameState, clipExtent); + let clipped = false; + if (layerState.extent) { + const layerExtent = fromUserExtent(layerState.extent, projection); + clipped = !containsExtent(layerExtent, frameState.extent) && intersectsExtent(layerExtent, frameState.extent); + if (clipped) { + this.clip(context, frameState, layerExtent); + } }