diff --git a/src/ol/render/VectorContext.js b/src/ol/render/VectorContext.js index bad1facc35..c7fcca15dd 100644 --- a/src/ol/render/VectorContext.js +++ b/src/ol/render/VectorContext.js @@ -100,15 +100,15 @@ class VectorContext { /** * @param {import("../style/Image.js").default} imageStyle Image style. - * @param {Object=} opt_sharedData Shared data for combined decluttering with a text style. + * @param {import("../render/canvas.js").DeclutterImageWithText=} opt_declutterImageWithText Shared data for combined decluttering with a text style. */ - setImageStyle(imageStyle, opt_sharedData) {} + setImageStyle(imageStyle, opt_declutterImageWithText) {} /** * @param {import("../style/Text.js").default} textStyle Text style. - * @param {Object=} opt_sharedData Shared data for combined decluttering with an image style. + * @param {import("../render/canvas.js").DeclutterImageWithText=} opt_declutterImageWithText Shared data for combined decluttering with an image style. */ - setTextStyle(textStyle, opt_sharedData) {} + setTextStyle(textStyle, opt_declutterImageWithText) {} } export default VectorContext; diff --git a/src/ol/render/canvas.js b/src/ol/render/canvas.js index 27435dcd4c..783b8aa05f 100644 --- a/src/ol/render/canvas.js +++ b/src/ol/render/canvas.js @@ -77,6 +77,10 @@ import {toString} from '../transform.js'; * @property {!Object} [strokeStates] The stroke states (decluttering). */ +/** + * @typedef {Object} DeclutterImageWithText + */ + /** * @const * @type {string} diff --git a/src/ol/render/canvas/Executor.js b/src/ol/render/canvas/Executor.js index 8bef5052dd..d7a049c00b 100644 --- a/src/ol/render/canvas/Executor.js +++ b/src/ol/render/canvas/Executor.js @@ -49,6 +49,10 @@ import {transform2D} from '../../geom/flat/transform.js'; * @property {import("../../transform.js").Transform} canvasTransform */ +/** + * @typedef {{0: CanvasRenderingContext2D, 1: number, 2: import("../canvas.js").Label|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement, 3: ImageOrLabelDimensions, 4: number, 5: Array<*>, 6: Array<*>}} ReplayImageOrLabelArgs + */ + /** * @type {import("../../extent.js").Extent} */ @@ -64,12 +68,11 @@ const p3 = []; const p4 = []; /** - * @param {Array<*>} replayImageOrLabelArgs Arguments to replayImageOrLabel + * @param {ReplayImageOrLabelArgs} replayImageOrLabelArgs Arguments to replayImageOrLabel * @return {BBox} Declutter bbox. */ function getDeclutterBox(replayImageOrLabelArgs) { - return /** @type {ImageOrLabelDimensions} */ (replayImageOrLabelArgs[3]) - .declutterBox; + return replayImageOrLabelArgs[3].declutterBox; } class Executor { @@ -724,7 +727,7 @@ class Executor { let rotation = /** @type {number} */ (instruction[11]); const scale = /** @type {import("../../size.js").Size} */ (instruction[12]); let width = /** @type {number} */ (instruction[13]); - const sharedData = instruction[14]; + const declutterImageWithText = /** @type {import("../canvas.js").DeclutterImageWithText} */ (instruction[14]); if (!image && instruction.length >= 19) { // create label images @@ -801,6 +804,7 @@ class Executor { backgroundFill || backgroundStroke, feature ); + /** @type {ReplayImageOrLabelArgs} */ const args = [ context, contextScale, @@ -816,13 +820,15 @@ class Executor { ]; let imageArgs; let imageDeclutterBox; - if (opt_declutterTree && sharedData) { - if (!sharedData[d]) { - sharedData[d] = args; + if (opt_declutterTree && declutterImageWithText) { + if (!declutterImageWithText[d]) { + // We now have the image for an image+text combination. + declutterImageWithText[d] = args; + // Don't render anything for now, wait for the text. continue; } - imageArgs = sharedData[d]; - delete sharedData[d]; + imageArgs = declutterImageWithText[d]; + delete declutterImageWithText[d]; imageDeclutterBox = getDeclutterBox(imageArgs); if (opt_declutterTree.collides(imageDeclutterBox)) { continue; @@ -835,9 +841,11 @@ class Executor { continue; } if (imageArgs) { + // We now have image and text for an image+text combination. if (opt_declutterTree) { opt_declutterTree.insert(imageDeclutterBox); } + // Render the image before we render the text. this.replayImageOrLabel_.apply(this, imageArgs); } if (opt_declutterTree) { @@ -902,6 +910,7 @@ class Executor { viewRotationFromTransform ? 0 : this.viewRotation_ ); drawChars: if (parts) { + /** @type {Array} */ const replayImageOrLabelArgs = []; let c, cc, chars, label, part; if (strokeKey) { diff --git a/src/ol/render/canvas/ImageBuilder.js b/src/ol/render/canvas/ImageBuilder.js index 855d80e886..2a2819b104 100644 --- a/src/ol/render/canvas/ImageBuilder.js +++ b/src/ol/render/canvas/ImageBuilder.js @@ -95,9 +95,9 @@ class CanvasImageBuilder extends CanvasBuilder { /** * Data shared with a text builder for combined decluttering. * @private - * @type {Object} + * @type {import("../canvas.js").DeclutterImageWithText} */ - this.sharedData_ = undefined; + this.declutterImageWithText_ = undefined; } /** @@ -132,7 +132,7 @@ class CanvasImageBuilder extends CanvasBuilder { (this.scale_[1] * this.pixelRatio) / this.imagePixelRatio_, ], Math.ceil(this.width_ * this.imagePixelRatio_), - this.sharedData_, + this.declutterImageWithText_, ]); this.hitDetectionInstructions.push([ CanvasInstruction.DRAW_IMAGE, @@ -150,7 +150,7 @@ class CanvasImageBuilder extends CanvasBuilder { this.rotation_, this.scale_, this.width_, - this.sharedData_, + this.declutterImageWithText_, ]); this.endGeometry(feature); } @@ -187,7 +187,7 @@ class CanvasImageBuilder extends CanvasBuilder { (this.scale_[1] * this.pixelRatio) / this.imagePixelRatio_, ], Math.ceil(this.width_ * this.imagePixelRatio_), - this.sharedData_, + this.declutterImageWithText_, ]); this.hitDetectionInstructions.push([ CanvasInstruction.DRAW_IMAGE, @@ -205,7 +205,7 @@ class CanvasImageBuilder extends CanvasBuilder { this.rotation_, this.scale_, this.width_, - this.sharedData_, + this.declutterImageWithText_, ]); this.endGeometry(feature); } @@ -255,7 +255,7 @@ class CanvasImageBuilder extends CanvasBuilder { this.rotation_ = imageStyle.getRotation(); this.scale_ = imageStyle.getScaleArray(); this.width_ = size[0]; - this.sharedData_ = opt_sharedData; + this.declutterImageWithText_ = opt_sharedData; } } diff --git a/src/ol/render/canvas/TextBuilder.js b/src/ol/render/canvas/TextBuilder.js index 55a602c74a..e124a496b6 100644 --- a/src/ol/render/canvas/TextBuilder.js +++ b/src/ol/render/canvas/TextBuilder.js @@ -142,9 +142,9 @@ class CanvasTextBuilder extends CanvasBuilder { /** * Data shared with an image builder for combined decluttering. * @private - * @type {Object} + * @type {import("../canvas.js").DeclutterImageWithText} */ - this.sharedData_ = undefined; + this.declutterImageWithText_ = undefined; } /** @@ -335,7 +335,7 @@ class CanvasTextBuilder extends CanvasBuilder { this.textRotation_, [1, 1], NaN, - this.sharedData_, + this.declutterImageWithText_, padding == defaultPadding ? defaultPadding : padding.map(function (p) { @@ -367,7 +367,7 @@ class CanvasTextBuilder extends CanvasBuilder { this.textRotation_, [scale, scale], NaN, - this.sharedData_, + this.declutterImageWithText_, padding, !!textState.backgroundFill, !!textState.backgroundStroke, @@ -586,7 +586,7 @@ class CanvasTextBuilder extends CanvasBuilder { : '|' + getUid(fillState.fillStyle) : ''; } - this.sharedData_ = opt_sharedData; + this.declutterImageWithText_ = opt_sharedData; } } diff --git a/src/ol/renderer/vector.js b/src/ol/renderer/vector.js index 7452b56b9e..2c626a9eb2 100644 --- a/src/ol/renderer/vector.js +++ b/src/ol/renderer/vector.js @@ -346,10 +346,11 @@ function renderPointGeometry( ) { const imageStyle = style.getImage(); const textStyle = style.getText(); - let sharedData; + /** @type {import("../render/canvas.js").DeclutterImageWithText} */ + let declutterImageWithText; if (opt_declutterBuilderGroup) { builderGroup = opt_declutterBuilderGroup; - sharedData = + declutterImageWithText = imageStyle && textStyle && textStyle.getText() ? {} : undefined; } if (imageStyle) { @@ -360,7 +361,7 @@ function renderPointGeometry( style.getZIndex(), BuilderType.IMAGE ); - imageReplay.setImageStyle(imageStyle, sharedData); + imageReplay.setImageStyle(imageStyle, declutterImageWithText); imageReplay.drawPoint(geometry, feature); } if (textStyle && textStyle.getText()) { @@ -368,7 +369,7 @@ function renderPointGeometry( style.getZIndex(), BuilderType.TEXT ); - textReplay.setTextStyle(textStyle, sharedData); + textReplay.setTextStyle(textStyle, declutterImageWithText); textReplay.drawText(geometry, feature); } } @@ -389,10 +390,11 @@ function renderMultiPointGeometry( ) { const imageStyle = style.getImage(); const textStyle = style.getText(); - let sharedData; + /** @type {import("../render/canvas.js").DeclutterImageWithText} */ + let declutterImageWithText; if (opt_declutterBuilderGroup) { builderGroup = opt_declutterBuilderGroup; - sharedData = + declutterImageWithText = imageStyle && textStyle && textStyle.getText() ? {} : undefined; } if (imageStyle) { @@ -403,7 +405,7 @@ function renderMultiPointGeometry( style.getZIndex(), BuilderType.IMAGE ); - imageReplay.setImageStyle(imageStyle, sharedData); + imageReplay.setImageStyle(imageStyle, declutterImageWithText); imageReplay.drawMultiPoint(geometry, feature); } if (textStyle && textStyle.getText()) { @@ -411,7 +413,7 @@ function renderMultiPointGeometry( style.getZIndex(), BuilderType.TEXT ); - textReplay.setTextStyle(textStyle, sharedData); + textReplay.setTextStyle(textStyle, declutterImageWithText); textReplay.drawText(geometry, feature); } }