diff --git a/src/ol/render/canvas/ImageReplay.js b/src/ol/render/canvas/ImageReplay.js index 4442109e2b..6fc9e6b310 100644 --- a/src/ol/render/canvas/ImageReplay.js +++ b/src/ol/render/canvas/ImageReplay.js @@ -88,12 +88,6 @@ class CanvasImageReplay extends CanvasReplay { */ this.scale_ = undefined; - /** - * @private - * @type {boolean|undefined} - */ - this.snapToPixel_ = undefined; - /** * @private * @type {number|undefined} @@ -131,14 +125,14 @@ class CanvasImageReplay extends CanvasReplay { // Remaining arguments to DRAW_IMAGE are in alphabetical order this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_, this.originX_, this.originY_, this.rotateWithView_, this.rotation_, - this.scale_ * this.pixelRatio, this.snapToPixel_, this.width_ + this.scale_ * this.pixelRatio, this.width_ ]); this.hitDetectionInstructions.push([ CanvasInstruction.DRAW_IMAGE, myBegin, myEnd, this.hitDetectionImage_, // Remaining arguments to DRAW_IMAGE are in alphabetical order this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_, this.originX_, this.originY_, this.rotateWithView_, this.rotation_, - this.scale_, this.snapToPixel_, this.width_ + this.scale_, this.width_ ]); this.endGeometry(pointGeometry, feature); } @@ -161,14 +155,14 @@ class CanvasImageReplay extends CanvasReplay { // Remaining arguments to DRAW_IMAGE are in alphabetical order this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_, this.originX_, this.originY_, this.rotateWithView_, this.rotation_, - this.scale_ * this.pixelRatio, this.snapToPixel_, this.width_ + this.scale_ * this.pixelRatio, this.width_ ]); this.hitDetectionInstructions.push([ CanvasInstruction.DRAW_IMAGE, myBegin, myEnd, this.hitDetectionImage_, // Remaining arguments to DRAW_IMAGE are in alphabetical order this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_, this.originX_, this.originY_, this.rotateWithView_, this.rotation_, - this.scale_, this.snapToPixel_, this.width_ + this.scale_, this.width_ ]); this.endGeometry(multiPointGeometry, feature); } @@ -190,7 +184,6 @@ class CanvasImageReplay extends CanvasReplay { this.originY_ = undefined; this.rotateWithView_ = undefined; this.rotation_ = undefined; - this.snapToPixel_ = undefined; this.width_ = undefined; } @@ -215,7 +208,6 @@ class CanvasImageReplay extends CanvasReplay { this.rotateWithView_ = imageStyle.getRotateWithView(); this.rotation_ = imageStyle.getRotation(); this.scale_ = imageStyle.getScale(); - this.snapToPixel_ = imageStyle.getSnapToPixel(); this.width_ = size[0]; } } diff --git a/src/ol/render/canvas/Immediate.js b/src/ol/render/canvas/Immediate.js index 8896e9320a..3592e7f96f 100644 --- a/src/ol/render/canvas/Immediate.js +++ b/src/ol/render/canvas/Immediate.js @@ -156,12 +156,6 @@ class CanvasImmediateRenderer extends VectorContext { */ this.imageScale_ = 0; - /** - * @private - * @type {boolean} - */ - this.imageSnapToPixel_ = false; - /** * @private * @type {number} @@ -261,12 +255,8 @@ class CanvasImmediateRenderer extends VectorContext { rotation += this.viewRotation_; } for (let i = 0, ii = pixelCoordinates.length; i < ii; i += 2) { - let x = pixelCoordinates[i] - this.imageAnchorX_; - let y = pixelCoordinates[i + 1] - this.imageAnchorY_; - if (this.imageSnapToPixel_) { - x = Math.round(x); - y = Math.round(y); - } + const x = pixelCoordinates[i] - this.imageAnchorX_; + const y = pixelCoordinates[i + 1] - this.imageAnchorY_; if (rotation !== 0 || this.imageScale_ != 1) { const centerX = x + this.imageAnchorX_; const centerY = y + this.imageAnchorY_; @@ -856,7 +846,6 @@ class CanvasImmediateRenderer extends VectorContext { this.imageRotateWithView_ = imageStyle.getRotateWithView(); this.imageRotation_ = imageStyle.getRotation(); this.imageScale_ = imageStyle.getScale() * this.pixelRatio_; - this.imageSnapToPixel_ = imageStyle.getSnapToPixel(); this.imageWidth_ = imageSize[0]; } } diff --git a/src/ol/render/canvas/Replay.js b/src/ol/render/canvas/Replay.js index 5d40a154f4..3fea0bdd79 100644 --- a/src/ol/render/canvas/Replay.js +++ b/src/ol/render/canvas/Replay.js @@ -533,6 +533,7 @@ class CanvasReplay extends VectorContext { * @param {Object} skippedFeaturesHash Ids of features * to skip. * @param {Array<*>} instructions Instructions array. + * @param {boolean} snapToPixel Snap point symbols and text to integer pixels. * @param {function((module:ol/Feature|module:ol/render/Feature)): T|undefined} featureCallback Feature callback. * @param {module:ol/extent~Extent=} opt_hitExtent Only check features that intersect this * extent. @@ -544,6 +545,7 @@ class CanvasReplay extends VectorContext { transform, skippedFeaturesHash, instructions, + snapToPixel, featureCallback, opt_hitExtent ) { @@ -672,14 +674,13 @@ class CanvasReplay extends VectorContext { const rotateWithView = /** @type {boolean} */ (instruction[11]); let rotation = /** @type {number} */ (instruction[12]); const scale = /** @type {number} */ (instruction[13]); - const snapToPixel = /** @type {boolean} */ (instruction[14]); - const width = /** @type {number} */ (instruction[15]); + const width = /** @type {number} */ (instruction[14]); let padding, backgroundFill, backgroundStroke; if (instruction.length > 16) { - padding = /** @type {Array} */ (instruction[16]); - backgroundFill = /** @type {boolean} */ (instruction[17]); - backgroundStroke = /** @type {boolean} */ (instruction[18]); + padding = /** @type {Array} */ (instruction[15]); + backgroundFill = /** @type {boolean} */ (instruction[16]); + backgroundStroke = /** @type {boolean} */ (instruction[17]); } else { padding = defaultPadding; backgroundFill = backgroundStroke = false; @@ -853,11 +854,12 @@ class CanvasReplay extends VectorContext { * @param {number} viewRotation View rotation. * @param {Object} skippedFeaturesHash Ids of features * to skip. + * @param {boolean} snapToPixel Snap point symbols and text to integer pixels. */ - replay(context, transform, viewRotation, skippedFeaturesHash) { + replay(context, transform, viewRotation, skippedFeaturesHash, snapToPixel) { this.viewRotation_ = viewRotation; this.replay_(context, transform, - skippedFeaturesHash, this.instructions, undefined, undefined); + skippedFeaturesHash, this.instructions, snapToPixel, undefined, undefined); } /** @@ -883,7 +885,7 @@ class CanvasReplay extends VectorContext { ) { this.viewRotation_ = viewRotation; return this.replay_(context, transform, skippedFeaturesHash, - this.hitDetectionInstructions, opt_featureCallback, opt_hitExtent); + this.hitDetectionInstructions, true, opt_featureCallback, opt_hitExtent); } /** diff --git a/src/ol/render/canvas/ReplayGroup.js b/src/ol/render/canvas/ReplayGroup.js index 0e431c6288..5062984ab4 100644 --- a/src/ol/render/canvas/ReplayGroup.js +++ b/src/ol/render/canvas/ReplayGroup.js @@ -353,6 +353,7 @@ class CanvasReplayGroup extends ReplayGroup { * @param {module:ol/transform~Transform} transform Transform. * @param {number} viewRotation View rotation. * @param {Object} skippedFeaturesHash Ids of features to skip. + * @param {boolean} snapToPixel Snap point symbols and test to integer pixel. * @param {Array=} opt_replayTypes Ordered replay types to replay. * Default is {@link module:ol/render/replay~ORDER} * @param {Object=} opt_declutterReplays Declutter replays. @@ -362,6 +363,7 @@ class CanvasReplayGroup extends ReplayGroup { transform, viewRotation, skippedFeaturesHash, + snapToPixel, opt_replayTypes, opt_declutterReplays ) { @@ -393,7 +395,7 @@ class CanvasReplayGroup extends ReplayGroup { declutter.push(replay, transform.slice(0)); } } else { - replay.replay(context, transform, viewRotation, skippedFeaturesHash); + replay.replay(context, transform, viewRotation, skippedFeaturesHash, snapToPixel); } } } @@ -486,8 +488,9 @@ export function getCircleArray(radius) { * @param {!Object>} declutterReplays Declutter replays. * @param {CanvasRenderingContext2D} context Context. * @param {number} rotation Rotation. + * @param {boolean} snapToPixel Snap point symbols and text to integer pixels. */ -export function replayDeclutter(declutterReplays, context, rotation) { +export function replayDeclutter(declutterReplays, context, rotation, snapToPixel) { const zs = Object.keys(declutterReplays).map(Number).sort(numberSafeCompareFunction); const skippedFeatureUids = {}; for (let z = 0, zz = zs.length; z < zz; ++z) { @@ -495,7 +498,7 @@ export function replayDeclutter(declutterReplays, context, rotation) { for (let i = 0, ii = replayData.length; i < ii;) { const replay = replayData[i++]; const transform = replayData[i++]; - replay.replay(context, transform, rotation, skippedFeatureUids); + replay.replay(context, transform, rotation, skippedFeatureUids, snapToPixel); } } } diff --git a/src/ol/render/canvas/TextReplay.js b/src/ol/render/canvas/TextReplay.js index c7bec1ec27..3edd9f3156 100644 --- a/src/ol/render/canvas/TextReplay.js +++ b/src/ol/render/canvas/TextReplay.js @@ -337,7 +337,7 @@ class CanvasTextReplay extends CanvasReplay { this.instructions.push([CanvasInstruction.DRAW_IMAGE, begin, end, label, (anchorX - this.textOffsetX_) * pixelRatio, (anchorY - this.textOffsetY_) * pixelRatio, this.declutterGroup_, label.height, 1, 0, 0, this.textRotateWithView_, this.textRotation_, - 1, true, label.width, + 1, label.width, textState.padding == defaultPadding ? defaultPadding : textState.padding.map(function(p) { return p * pixelRatio; @@ -347,7 +347,7 @@ class CanvasTextReplay extends CanvasReplay { this.hitDetectionInstructions.push([CanvasInstruction.DRAW_IMAGE, begin, end, label, (anchorX - this.textOffsetX_) * pixelRatio, (anchorY - this.textOffsetY_) * pixelRatio, this.declutterGroup_, label.height, 1, 0, 0, this.textRotateWithView_, this.textRotation_, - 1 / pixelRatio, true, label.width, textState.padding, + 1 / pixelRatio, label.width, textState.padding, !!textState.backgroundFill, !!textState.backgroundStroke ]); } diff --git a/src/ol/renderer/canvas/VectorLayer.js b/src/ol/renderer/canvas/VectorLayer.js index 136aba67d1..7888dcbe00 100644 --- a/src/ol/renderer/canvas/VectorLayer.js +++ b/src/ol/renderer/canvas/VectorLayer.js @@ -158,11 +158,13 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer { replayContext.translate(drawOffsetX, drawOffsetY); } + const viewHints = frameState.viewHints; + const snapToPixel = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]); const width = frameState.size[0] * pixelRatio; const height = frameState.size[1] * pixelRatio; rotateAtOffset(replayContext, -rotation, width / 2, height / 2); - replayGroup.replay(replayContext, transform, rotation, skippedFeatureUids); + replayGroup.replay(replayContext, transform, rotation, skippedFeatureUids, snapToPixel); if (vectorSource.getWrapX() && projection.canWrapX() && !containsExtent(projectionExtent, extent)) { let startX = extent[0]; @@ -173,7 +175,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer { --world; offsetX = worldWidth * world; transform = this.getTransform(frameState, offsetX); - replayGroup.replay(replayContext, transform, rotation, skippedFeatureUids); + replayGroup.replay(replayContext, transform, rotation, skippedFeatureUids, snapToPixel); startX += worldWidth; } world = 0; @@ -182,7 +184,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer { ++world; offsetX = worldWidth * world; transform = this.getTransform(frameState, offsetX); - replayGroup.replay(replayContext, transform, rotation, skippedFeatureUids); + replayGroup.replay(replayContext, transform, rotation, skippedFeatureUids, snapToPixel); startX -= worldWidth; } } diff --git a/src/ol/renderer/canvas/VectorTileLayer.js b/src/ol/renderer/canvas/VectorTileLayer.js index 9e69471731..b696b772ca 100644 --- a/src/ol/renderer/canvas/VectorTileLayer.js +++ b/src/ol/renderer/canvas/VectorTileLayer.js @@ -4,6 +4,7 @@ import {getUid} from '../../util.js'; import LayerType from '../../LayerType.js'; import TileState from '../../TileState.js'; +import ViewHint from '../../ViewHint.js'; import {createCanvasContext2D} from '../../dom.js'; import {listen, unlisten} from '../../events.js'; import EventType from '../../events/EventType.js'; @@ -341,6 +342,8 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer { if (declutterReplays) { this.declutterTree_.clear(); } + const viewHints = frameState.viewHints; + const snapToPixel = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]); const tiles = this.renderedTiles; const tileGrid = source.getTileGridForProjection(frameState.viewState.projection); const clips = []; @@ -390,14 +393,14 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer { context.clip(); } } - replayGroup.replay(context, transform, rotation, {}, replayTypes, declutterReplays); + replayGroup.replay(context, transform, rotation, {}, snapToPixel, replayTypes, declutterReplays); context.restore(); clips.push(currentClip); zs.push(currentZ); } } if (declutterReplays) { - replayDeclutter(declutterReplays, context, rotation); + replayDeclutter(declutterReplays, context, rotation, snapToPixel); } if (rotation) { rotateAtOffset(context, rotation, @@ -466,7 +469,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer { scaleTransform(transform, pixelScale, -pixelScale); translateTransform(transform, -tileExtent[0], -tileExtent[3]); const replayGroup = sourceTile.getReplayGroup(layer, tile.tileCoord.toString()); - replayGroup.replay(context, transform, 0, {}, replays); + replayGroup.replay(context, transform, 0, {}, true, replays); } } } diff --git a/test/rendering/ol/layer/tile.test.js b/test/rendering/ol/layer/tile.test.js index 9f93c67092..fcb01b3694 100644 --- a/test/rendering/ol/layer/tile.test.js +++ b/test/rendering/ol/layer/tile.test.js @@ -280,7 +280,6 @@ describe('ol.rendering.layer.Tile', function() { evt.element.on('render', function(e) { e.vectorContext.setImageStyle(new CircleStyle({ radius: 5, - snapToPixel: false, fill: new Fill({color: 'yellow'}), stroke: new Stroke({color: 'red', width: 1}) }));