diff --git a/src/ol/PluggableMap.js b/src/ol/PluggableMap.js index b73e6489ba..46e3233525 100644 --- a/src/ol/PluggableMap.js +++ b/src/ol/PluggableMap.js @@ -39,7 +39,7 @@ import {create as createTransform, apply as applyTransform} from './transform.js * @property {boolean} animate * @property {import("./transform.js").Transform} coordinateToPixelTransform * @property {null|import("./extent.js").Extent} extent - * @property {Array<*>} declutterItems + * @property {Array} declutterItems * @property {import("./coordinate.js").Coordinate} focus * @property {number} index * @property {Array} layerStatesArray @@ -54,6 +54,13 @@ import {create as createTransform, apply as applyTransform} from './transform.js */ +/** + * @typedef {Object} DeclutterItems + * @property {Array<*>} items Declutter items of an executor. + * @property {number} opacity Layer opacity. + */ + + /** * @typedef {function(PluggableMap, ?FrameState): any} PostRenderFunction */ diff --git a/src/ol/render.js b/src/ol/render.js index c413506596..fb48e303bd 100644 --- a/src/ol/render.js +++ b/src/ol/render.js @@ -122,9 +122,10 @@ export function renderDeclutterItems(frameState, declutterTree) { } const items = frameState.declutterItems; for (let z = items.length - 1; z >= 0; --z) { - const zIndexItems = items[z]; + const item = items[z]; + const zIndexItems = item.items; for (let i = 0, ii = zIndexItems.length; i < ii; i += 3) { - declutterTree = zIndexItems[i].renderDeclutter(zIndexItems[i + 1], zIndexItems[i + 2], declutterTree); + declutterTree = zIndexItems[i].renderDeclutter(zIndexItems[i + 1], zIndexItems[i + 2], item.opacity, declutterTree); } } items.length = 0; diff --git a/src/ol/render/canvas/Executor.js b/src/ol/render/canvas/Executor.js index 0ae1c224a5..afb0198a8c 100644 --- a/src/ol/render/canvas/Executor.js +++ b/src/ol/render/canvas/Executor.js @@ -416,10 +416,11 @@ class Executor extends Disposable { /** * @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group. * @param {import("../../Feature.js").FeatureLike} feature Feature. + * @param {number} opacity Layer opacity. * @param {?} declutterTree Declutter tree. * @return {?} Declutter tree. */ - renderDeclutter(declutterGroup, feature, declutterTree) { + renderDeclutter(declutterGroup, feature, opacity, declutterTree) { if (declutterGroup && declutterGroup.length > 5) { const groupCount = declutterGroup[4]; if (groupCount == 1 || groupCount == declutterGroup.length - 5) { @@ -438,13 +439,19 @@ class Executor extends Disposable { declutterTree.insert(box); for (let j = 5, jj = declutterGroup.length; j < jj; ++j) { const declutterData = /** @type {Array} */ (declutterGroup[j]); - if (declutterData) { - if (declutterData.length > 11) { - this.replayTextBackground_(declutterData[0], - declutterData[13], declutterData[14], declutterData[15], declutterData[16], - declutterData[11], declutterData[12]); - } - drawImage.apply(undefined, declutterData); + const context = declutterData[0]; + const currentAlpha = context.globalAlpha; + if (currentAlpha !== opacity) { + context.globalAlpha = opacity; + } + if (declutterData.length > 11) { + this.replayTextBackground_(declutterData[0], + declutterData[13], declutterData[14], declutterData[15], declutterData[16], + declutterData[11], declutterData[12]); + } + drawImage.apply(undefined, declutterData); + if (currentAlpha !== opacity) { + context.globalAlpha = currentAlpha; } } } diff --git a/src/ol/render/canvas/ExecutorGroup.js b/src/ol/render/canvas/ExecutorGroup.js index ea28923ee6..1d74dd0eb1 100644 --- a/src/ol/render/canvas/ExecutorGroup.js +++ b/src/ol/render/canvas/ExecutorGroup.js @@ -430,10 +430,11 @@ export function getCircleArray(radius) { * @param {!Object>} declutterReplays Declutter replays. * @param {CanvasRenderingContext2D} context Context. * @param {number} rotation Rotation. + * @param {number} opacity Opacity. * @param {boolean} snapToPixel Snap point symbols and text to integer pixels. - * @param {Array>} declutterItems Declutter items. + * @param {Array} declutterItems Declutter items. */ -export function replayDeclutter(declutterReplays, context, rotation, snapToPixel, declutterItems) { +export function replayDeclutter(declutterReplays, context, rotation, opacity, snapToPixel, declutterItems) { const zs = Object.keys(declutterReplays).map(Number).sort(numberSafeCompareFunction); const skippedFeatureUids = {}; for (let z = 0, zz = zs.length; z < zz; ++z) { @@ -443,7 +444,10 @@ export function replayDeclutter(declutterReplays, context, rotation, snapToPixel const executor = executorData[i++]; if (executor !== currentExecutor) { currentExecutor = executor; - declutterItems.push(executor.declutterItems); + declutterItems.push({ + items: executor.declutterItems, + opacity: opacity + }); } const transform = executorData[i++]; executor.execute(context, transform, rotation, skippedFeatureUids, snapToPixel); diff --git a/src/ol/renderer/canvas/Layer.js b/src/ol/renderer/canvas/Layer.js index 568ba6edd8..d47c1908fb 100644 --- a/src/ol/renderer/canvas/Layer.js +++ b/src/ol/renderer/canvas/Layer.js @@ -79,7 +79,7 @@ class CanvasLayerRenderer extends LayerRenderer { useContainer(target, transform, opacity) { const layerClassName = this.getLayer().getClassName(); let container, context; - if (target) { + if (target && target.style.opacity === '') { const canvas = target.firstElementChild; if (canvas instanceof HTMLCanvasElement) { context = canvas.getContext('2d'); diff --git a/src/ol/renderer/canvas/VectorLayer.js b/src/ol/renderer/canvas/VectorLayer.js index 5e872c63cc..9246bf3c6c 100644 --- a/src/ol/renderer/canvas/VectorLayer.js +++ b/src/ol/renderer/canvas/VectorLayer.js @@ -164,7 +164,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer { if (declutterReplays) { const viewHints = frameState.viewHints; const hifi = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]); - replayDeclutter(declutterReplays, context, rotation, hifi, frameState.declutterItems); + replayDeclutter(declutterReplays, context, rotation, 1, hifi, frameState.declutterItems); } if (clipped) { @@ -174,8 +174,9 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer { this.postRender(context, frameState); const opacity = layerState.opacity; - if (opacity !== parseFloat(canvas.style.opacity)) { - canvas.style.opacity = opacity; + const container = this.container; + if (opacity !== parseFloat(container.style.opacity)) { + container.style.opacity = opacity === 1 ? '' : opacity; } return this.container; diff --git a/src/ol/renderer/canvas/VectorTileLayer.js b/src/ol/renderer/canvas/VectorTileLayer.js index e463b2aff7..a0263b0315 100644 --- a/src/ol/renderer/canvas/VectorTileLayer.js +++ b/src/ol/renderer/canvas/VectorTileLayer.js @@ -478,7 +478,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer { } } if (declutterReplays) { - replayDeclutter(declutterReplays, context, rotation, hifi, frameState.declutterItems); + replayDeclutter(declutterReplays, context, rotation, layerState.opacity, hifi, frameState.declutterItems); } return this.container;