diff --git a/src/ol/layer/Base.js b/src/ol/layer/Base.js index 994ee5544c..60c5cab6c9 100644 --- a/src/ol/layer/Base.js +++ b/src/ol/layer/Base.js @@ -93,7 +93,8 @@ class BaseLayer extends BaseObject { /** @type {import("./Layer.js").State} */ const state = this.state_ || /** @type {?} */ ({ layer: this, - managed: opt_managed === undefined ? true : opt_managed + managed: opt_managed === undefined ? true : opt_managed, + hasOverlay: false }); state.opacity = clamp(Math.round(this.getOpacity() * 100) / 100, 0, 1); state.sourceState = this.getSourceState(); diff --git a/src/ol/layer/Layer.js b/src/ol/layer/Layer.js index a1dfe0aad5..b286a99ad4 100644 --- a/src/ol/layer/Layer.js +++ b/src/ol/layer/Layer.js @@ -45,6 +45,7 @@ import SourceState from '../source/State.js'; * @property {SourceState} sourceState * @property {boolean} visible * @property {boolean} managed + * @property {boolean} hasOverlay Set by the renderer when an overlay for points and text is used. * @property {import("../extent.js").Extent} [extent] * @property {number} zIndex * @property {number} maxResolution diff --git a/src/ol/renderer/Composite.js b/src/ol/renderer/Composite.js index 6d707a9706..49727a68c5 100644 --- a/src/ol/renderer/Composite.js +++ b/src/ol/renderer/Composite.js @@ -87,9 +87,11 @@ class CompositeMapRenderer extends MapRenderer { const viewResolution = frameState.viewState.resolution; this.children_.length = 0; + let hasOverlay = false; let previousElement = null; for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) { const layerState = layerStatesArray[i]; + hasOverlay = hasOverlay || layerState.hasOverlay; frameState.layerIndex = i; if (!visibleAtResolution(layerState, viewResolution) || (layerState.sourceState != SourceState.READY && layerState.sourceState != SourceState.UNDEFINED)) { @@ -98,8 +100,15 @@ class CompositeMapRenderer extends MapRenderer { const layer = layerState.layer; const element = layer.render(frameState, previousElement); + if (!element) { + continue; + } + if ((element !== previousElement || i == ii - 1) && element.childElementCount === 2 && !hasOverlay) { + element.removeChild(element.lastElementChild); + } if (element !== previousElement) { this.children_.push(element); + hasOverlay = false; previousElement = element; } } diff --git a/src/ol/renderer/canvas/VectorTileLayer.js b/src/ol/renderer/canvas/VectorTileLayer.js index a5e1cc772e..df50af3a29 100644 --- a/src/ol/renderer/canvas/VectorTileLayer.js +++ b/src/ol/renderer/canvas/VectorTileLayer.js @@ -226,6 +226,8 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer { * @inheritDoc */ prepareFrame(frameState) { + const layerState = frameState.layerStatesArray[frameState.layerIndex]; + layerState.hasOverlay = true; const layerRevision = this.getLayer().getRevision(); if (this.renderedLayerRevision_ != layerRevision) { this.renderedTiles.length = 0; diff --git a/test/spec/ol/layer/group.test.js b/test/spec/ol/layer/group.test.js index f329eabac2..f7737b09a1 100644 --- a/test/spec/ol/layer/group.test.js +++ b/test/spec/ol/layer/group.test.js @@ -39,6 +39,7 @@ describe('ol.layer.Group', function() { opacity: 1, visible: true, managed: true, + hasOverlay: false, sourceState: 'ready', extent: undefined, zIndex: 0, @@ -158,6 +159,7 @@ describe('ol.layer.Group', function() { opacity: 0.5, visible: false, managed: true, + hasOverlay: false, sourceState: 'ready', extent: undefined, zIndex: 10, @@ -199,6 +201,7 @@ describe('ol.layer.Group', function() { opacity: 0.5, visible: false, managed: true, + hasOverlay: false, sourceState: 'ready', extent: groupExtent, zIndex: 0, @@ -239,6 +242,7 @@ describe('ol.layer.Group', function() { opacity: 0.3, visible: false, managed: true, + hasOverlay: false, sourceState: 'ready', extent: groupExtent, zIndex: 10, @@ -255,6 +259,7 @@ describe('ol.layer.Group', function() { opacity: 0, visible: false, managed: true, + hasOverlay: false, sourceState: 'ready', extent: undefined, zIndex: 0, @@ -269,6 +274,7 @@ describe('ol.layer.Group', function() { opacity: 1, visible: true, managed: true, + hasOverlay: false, sourceState: 'ready', extent: undefined, zIndex: 0, @@ -441,6 +447,7 @@ describe('ol.layer.Group', function() { opacity: 0.25, visible: false, managed: true, + hasOverlay: false, sourceState: 'ready', extent: undefined, zIndex: 0, diff --git a/test/spec/ol/layer/layer.test.js b/test/spec/ol/layer/layer.test.js index 010a289687..655d923dbb 100644 --- a/test/spec/ol/layer/layer.test.js +++ b/test/spec/ol/layer/layer.test.js @@ -49,6 +49,7 @@ describe('ol.layer.Layer', function() { opacity: 1, visible: true, managed: true, + hasOverlay: false, sourceState: 'ready', extent: undefined, zIndex: 0, @@ -84,6 +85,7 @@ describe('ol.layer.Layer', function() { opacity: 0.5, visible: false, managed: true, + hasOverlay: false, sourceState: 'ready', extent: undefined, zIndex: 10, @@ -182,6 +184,7 @@ describe('ol.layer.Layer', function() { opacity: 0.33, visible: false, managed: true, + hasOverlay: false, sourceState: 'ready', extent: undefined, zIndex: 10, @@ -198,6 +201,7 @@ describe('ol.layer.Layer', function() { opacity: 0, visible: false, managed: true, + hasOverlay: false, sourceState: 'ready', extent: undefined, zIndex: 0, @@ -212,6 +216,7 @@ describe('ol.layer.Layer', function() { opacity: 1, visible: true, managed: true, + hasOverlay: false, sourceState: 'ready', extent: undefined, zIndex: 0, diff --git a/test/spec/ol/renderer/canvas/vectortilelayer.test.js b/test/spec/ol/renderer/canvas/vectortilelayer.test.js index 7c49141c4b..4ae5fbdfb8 100644 --- a/test/spec/ol/renderer/canvas/vectortilelayer.test.js +++ b/test/spec/ol/renderer/canvas/vectortilelayer.test.js @@ -19,6 +19,8 @@ import Text from '../../../../../src/ol/style/Text.js'; import {createXYZ} from '../../../../../src/ol/tilegrid.js'; import VectorTileRenderType from '../../../../../src/ol/layer/VectorTileRenderType.js'; import {getUid} from '../../../../../src/ol/util.js'; +import TileLayer from '../../../../../src/ol/layer/Tile.js'; +import XYZ from '../../../../../src/ol/source/XYZ.js'; describe('ol.renderer.canvas.VectorTileLayer', function() { @@ -39,6 +41,7 @@ describe('ol.renderer.canvas.VectorTileLayer', function() { target.style.height = '256px'; document.body.appendChild(target); map = new Map({ + pixelRatio: 1, view: new View({ center: [0, 0], zoom: 0 @@ -203,6 +206,25 @@ describe('ol.renderer.canvas.VectorTileLayer', function() { expect(Object.keys(tile.executorGroups)[1]).to.be(getUid(layer2)); }); + it('reuses render container and adds and removes overlay context', function(done) { + map.getLayers().insertAt(0, new TileLayer({ + source: new XYZ({ + url: 'rendering/ol/data/tiles/osm/{z}/{x}/{y}.png' + }) + })); + map.once('postcompose', function(e) { + expect(e.frameState.layerStatesArray[1].hasOverlay).to.be(true); + }); + map.once('rendercomplete', function() { + expect(document.querySelector('.ol-layers').childElementCount).to.be(1); + expect(document.querySelector('.ol-layer').childElementCount).to.be(2); + map.removeLayer(map.getLayers().item(1)); + map.renderSync(); + expect(document.querySelector('.ol-layer').childElementCount).to.be(1); + done(); + }); + }); + }); describe('#prepareFrame', function() {