Let renderer decide whether to snapToPixel or not, also for text

This commit is contained in:
ahocevar
2018-08-09 18:16:25 +02:00
parent f382ddf230
commit b9aceb23ac
8 changed files with 35 additions and 45 deletions

View File

@@ -88,12 +88,6 @@ class CanvasImageReplay extends CanvasReplay {
*/ */
this.scale_ = undefined; this.scale_ = undefined;
/**
* @private
* @type {boolean|undefined}
*/
this.snapToPixel_ = undefined;
/** /**
* @private * @private
* @type {number|undefined} * @type {number|undefined}
@@ -131,14 +125,14 @@ class CanvasImageReplay extends CanvasReplay {
// Remaining arguments to DRAW_IMAGE are in alphabetical order // Remaining arguments to DRAW_IMAGE are in alphabetical order
this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_, this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_,
this.originX_, this.originY_, this.rotateWithView_, this.rotation_, 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([ this.hitDetectionInstructions.push([
CanvasInstruction.DRAW_IMAGE, myBegin, myEnd, this.hitDetectionImage_, CanvasInstruction.DRAW_IMAGE, myBegin, myEnd, this.hitDetectionImage_,
// Remaining arguments to DRAW_IMAGE are in alphabetical order // Remaining arguments to DRAW_IMAGE are in alphabetical order
this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_, this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_,
this.originX_, this.originY_, this.rotateWithView_, this.rotation_, this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
this.scale_, this.snapToPixel_, this.width_ this.scale_, this.width_
]); ]);
this.endGeometry(pointGeometry, feature); this.endGeometry(pointGeometry, feature);
} }
@@ -161,14 +155,14 @@ class CanvasImageReplay extends CanvasReplay {
// Remaining arguments to DRAW_IMAGE are in alphabetical order // Remaining arguments to DRAW_IMAGE are in alphabetical order
this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_, this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_,
this.originX_, this.originY_, this.rotateWithView_, this.rotation_, 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([ this.hitDetectionInstructions.push([
CanvasInstruction.DRAW_IMAGE, myBegin, myEnd, this.hitDetectionImage_, CanvasInstruction.DRAW_IMAGE, myBegin, myEnd, this.hitDetectionImage_,
// Remaining arguments to DRAW_IMAGE are in alphabetical order // Remaining arguments to DRAW_IMAGE are in alphabetical order
this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_, this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_,
this.originX_, this.originY_, this.rotateWithView_, this.rotation_, this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
this.scale_, this.snapToPixel_, this.width_ this.scale_, this.width_
]); ]);
this.endGeometry(multiPointGeometry, feature); this.endGeometry(multiPointGeometry, feature);
} }
@@ -190,7 +184,6 @@ class CanvasImageReplay extends CanvasReplay {
this.originY_ = undefined; this.originY_ = undefined;
this.rotateWithView_ = undefined; this.rotateWithView_ = undefined;
this.rotation_ = undefined; this.rotation_ = undefined;
this.snapToPixel_ = undefined;
this.width_ = undefined; this.width_ = undefined;
} }
@@ -215,7 +208,6 @@ class CanvasImageReplay extends CanvasReplay {
this.rotateWithView_ = imageStyle.getRotateWithView(); this.rotateWithView_ = imageStyle.getRotateWithView();
this.rotation_ = imageStyle.getRotation(); this.rotation_ = imageStyle.getRotation();
this.scale_ = imageStyle.getScale(); this.scale_ = imageStyle.getScale();
this.snapToPixel_ = imageStyle.getSnapToPixel();
this.width_ = size[0]; this.width_ = size[0];
} }
} }

View File

@@ -156,12 +156,6 @@ class CanvasImmediateRenderer extends VectorContext {
*/ */
this.imageScale_ = 0; this.imageScale_ = 0;
/**
* @private
* @type {boolean}
*/
this.imageSnapToPixel_ = false;
/** /**
* @private * @private
* @type {number} * @type {number}
@@ -261,12 +255,8 @@ class CanvasImmediateRenderer extends VectorContext {
rotation += this.viewRotation_; rotation += this.viewRotation_;
} }
for (let i = 0, ii = pixelCoordinates.length; i < ii; i += 2) { for (let i = 0, ii = pixelCoordinates.length; i < ii; i += 2) {
let x = pixelCoordinates[i] - this.imageAnchorX_; const x = pixelCoordinates[i] - this.imageAnchorX_;
let y = pixelCoordinates[i + 1] - this.imageAnchorY_; const y = pixelCoordinates[i + 1] - this.imageAnchorY_;
if (this.imageSnapToPixel_) {
x = Math.round(x);
y = Math.round(y);
}
if (rotation !== 0 || this.imageScale_ != 1) { if (rotation !== 0 || this.imageScale_ != 1) {
const centerX = x + this.imageAnchorX_; const centerX = x + this.imageAnchorX_;
const centerY = y + this.imageAnchorY_; const centerY = y + this.imageAnchorY_;
@@ -856,7 +846,6 @@ class CanvasImmediateRenderer extends VectorContext {
this.imageRotateWithView_ = imageStyle.getRotateWithView(); this.imageRotateWithView_ = imageStyle.getRotateWithView();
this.imageRotation_ = imageStyle.getRotation(); this.imageRotation_ = imageStyle.getRotation();
this.imageScale_ = imageStyle.getScale() * this.pixelRatio_; this.imageScale_ = imageStyle.getScale() * this.pixelRatio_;
this.imageSnapToPixel_ = imageStyle.getSnapToPixel();
this.imageWidth_ = imageSize[0]; this.imageWidth_ = imageSize[0];
} }
} }

View File

@@ -533,6 +533,7 @@ class CanvasReplay extends VectorContext {
* @param {Object<string, boolean>} skippedFeaturesHash Ids of features * @param {Object<string, boolean>} skippedFeaturesHash Ids of features
* to skip. * to skip.
* @param {Array<*>} instructions Instructions array. * @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 {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 * @param {module:ol/extent~Extent=} opt_hitExtent Only check features that intersect this
* extent. * extent.
@@ -544,6 +545,7 @@ class CanvasReplay extends VectorContext {
transform, transform,
skippedFeaturesHash, skippedFeaturesHash,
instructions, instructions,
snapToPixel,
featureCallback, featureCallback,
opt_hitExtent opt_hitExtent
) { ) {
@@ -672,14 +674,13 @@ class CanvasReplay extends VectorContext {
const rotateWithView = /** @type {boolean} */ (instruction[11]); const rotateWithView = /** @type {boolean} */ (instruction[11]);
let rotation = /** @type {number} */ (instruction[12]); let rotation = /** @type {number} */ (instruction[12]);
const scale = /** @type {number} */ (instruction[13]); const scale = /** @type {number} */ (instruction[13]);
const snapToPixel = /** @type {boolean} */ (instruction[14]); const width = /** @type {number} */ (instruction[14]);
const width = /** @type {number} */ (instruction[15]);
let padding, backgroundFill, backgroundStroke; let padding, backgroundFill, backgroundStroke;
if (instruction.length > 16) { if (instruction.length > 16) {
padding = /** @type {Array<number>} */ (instruction[16]); padding = /** @type {Array<number>} */ (instruction[15]);
backgroundFill = /** @type {boolean} */ (instruction[17]); backgroundFill = /** @type {boolean} */ (instruction[16]);
backgroundStroke = /** @type {boolean} */ (instruction[18]); backgroundStroke = /** @type {boolean} */ (instruction[17]);
} else { } else {
padding = defaultPadding; padding = defaultPadding;
backgroundFill = backgroundStroke = false; backgroundFill = backgroundStroke = false;
@@ -853,11 +854,12 @@ class CanvasReplay extends VectorContext {
* @param {number} viewRotation View rotation. * @param {number} viewRotation View rotation.
* @param {Object<string, boolean>} skippedFeaturesHash Ids of features * @param {Object<string, boolean>} skippedFeaturesHash Ids of features
* to skip. * 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.viewRotation_ = viewRotation;
this.replay_(context, transform, 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; this.viewRotation_ = viewRotation;
return this.replay_(context, transform, skippedFeaturesHash, return this.replay_(context, transform, skippedFeaturesHash,
this.hitDetectionInstructions, opt_featureCallback, opt_hitExtent); this.hitDetectionInstructions, true, opt_featureCallback, opt_hitExtent);
} }
/** /**

View File

@@ -353,6 +353,7 @@ class CanvasReplayGroup extends ReplayGroup {
* @param {module:ol/transform~Transform} transform Transform. * @param {module:ol/transform~Transform} transform Transform.
* @param {number} viewRotation View rotation. * @param {number} viewRotation View rotation.
* @param {Object<string, boolean>} skippedFeaturesHash Ids of features to skip. * @param {Object<string, boolean>} skippedFeaturesHash Ids of features to skip.
* @param {boolean} snapToPixel Snap point symbols and test to integer pixel.
* @param {Array<module:ol/render/ReplayType>=} opt_replayTypes Ordered replay types to replay. * @param {Array<module:ol/render/ReplayType>=} opt_replayTypes Ordered replay types to replay.
* Default is {@link module:ol/render/replay~ORDER} * Default is {@link module:ol/render/replay~ORDER}
* @param {Object<string, module:ol/render/canvas~DeclutterGroup>=} opt_declutterReplays Declutter replays. * @param {Object<string, module:ol/render/canvas~DeclutterGroup>=} opt_declutterReplays Declutter replays.
@@ -362,6 +363,7 @@ class CanvasReplayGroup extends ReplayGroup {
transform, transform,
viewRotation, viewRotation,
skippedFeaturesHash, skippedFeaturesHash,
snapToPixel,
opt_replayTypes, opt_replayTypes,
opt_declutterReplays opt_declutterReplays
) { ) {
@@ -393,7 +395,7 @@ class CanvasReplayGroup extends ReplayGroup {
declutter.push(replay, transform.slice(0)); declutter.push(replay, transform.slice(0));
} }
} else { } else {
replay.replay(context, transform, viewRotation, skippedFeaturesHash); replay.replay(context, transform, viewRotation, skippedFeaturesHash, snapToPixel);
} }
} }
} }
@@ -486,8 +488,9 @@ export function getCircleArray(radius) {
* @param {!Object<string, Array<*>>} declutterReplays Declutter replays. * @param {!Object<string, Array<*>>} declutterReplays Declutter replays.
* @param {CanvasRenderingContext2D} context Context. * @param {CanvasRenderingContext2D} context Context.
* @param {number} rotation Rotation. * @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 zs = Object.keys(declutterReplays).map(Number).sort(numberSafeCompareFunction);
const skippedFeatureUids = {}; const skippedFeatureUids = {};
for (let z = 0, zz = zs.length; z < zz; ++z) { 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;) { for (let i = 0, ii = replayData.length; i < ii;) {
const replay = replayData[i++]; const replay = replayData[i++];
const transform = replayData[i++]; const transform = replayData[i++];
replay.replay(context, transform, rotation, skippedFeatureUids); replay.replay(context, transform, rotation, skippedFeatureUids, snapToPixel);
} }
} }
} }

View File

@@ -337,7 +337,7 @@ class CanvasTextReplay extends CanvasReplay {
this.instructions.push([CanvasInstruction.DRAW_IMAGE, begin, end, this.instructions.push([CanvasInstruction.DRAW_IMAGE, begin, end,
label, (anchorX - this.textOffsetX_) * pixelRatio, (anchorY - this.textOffsetY_) * pixelRatio, label, (anchorX - this.textOffsetX_) * pixelRatio, (anchorY - this.textOffsetY_) * pixelRatio,
this.declutterGroup_, label.height, 1, 0, 0, this.textRotateWithView_, this.textRotation_, this.declutterGroup_, label.height, 1, 0, 0, this.textRotateWithView_, this.textRotation_,
1, true, label.width, 1, label.width,
textState.padding == defaultPadding ? textState.padding == defaultPadding ?
defaultPadding : textState.padding.map(function(p) { defaultPadding : textState.padding.map(function(p) {
return p * pixelRatio; return p * pixelRatio;
@@ -347,7 +347,7 @@ class CanvasTextReplay extends CanvasReplay {
this.hitDetectionInstructions.push([CanvasInstruction.DRAW_IMAGE, begin, end, this.hitDetectionInstructions.push([CanvasInstruction.DRAW_IMAGE, begin, end,
label, (anchorX - this.textOffsetX_) * pixelRatio, (anchorY - this.textOffsetY_) * pixelRatio, label, (anchorX - this.textOffsetX_) * pixelRatio, (anchorY - this.textOffsetY_) * pixelRatio,
this.declutterGroup_, label.height, 1, 0, 0, this.textRotateWithView_, this.textRotation_, 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 !!textState.backgroundFill, !!textState.backgroundStroke
]); ]);
} }

View File

@@ -158,11 +158,13 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
replayContext.translate(drawOffsetX, drawOffsetY); replayContext.translate(drawOffsetX, drawOffsetY);
} }
const viewHints = frameState.viewHints;
const snapToPixel = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]);
const width = frameState.size[0] * pixelRatio; const width = frameState.size[0] * pixelRatio;
const height = frameState.size[1] * pixelRatio; const height = frameState.size[1] * pixelRatio;
rotateAtOffset(replayContext, -rotation, rotateAtOffset(replayContext, -rotation,
width / 2, height / 2); width / 2, height / 2);
replayGroup.replay(replayContext, transform, rotation, skippedFeatureUids); replayGroup.replay(replayContext, transform, rotation, skippedFeatureUids, snapToPixel);
if (vectorSource.getWrapX() && projection.canWrapX() && if (vectorSource.getWrapX() && projection.canWrapX() &&
!containsExtent(projectionExtent, extent)) { !containsExtent(projectionExtent, extent)) {
let startX = extent[0]; let startX = extent[0];
@@ -173,7 +175,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
--world; --world;
offsetX = worldWidth * world; offsetX = worldWidth * world;
transform = this.getTransform(frameState, offsetX); transform = this.getTransform(frameState, offsetX);
replayGroup.replay(replayContext, transform, rotation, skippedFeatureUids); replayGroup.replay(replayContext, transform, rotation, skippedFeatureUids, snapToPixel);
startX += worldWidth; startX += worldWidth;
} }
world = 0; world = 0;
@@ -182,7 +184,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
++world; ++world;
offsetX = worldWidth * world; offsetX = worldWidth * world;
transform = this.getTransform(frameState, offsetX); transform = this.getTransform(frameState, offsetX);
replayGroup.replay(replayContext, transform, rotation, skippedFeatureUids); replayGroup.replay(replayContext, transform, rotation, skippedFeatureUids, snapToPixel);
startX -= worldWidth; startX -= worldWidth;
} }
} }

View File

@@ -4,6 +4,7 @@
import {getUid} from '../../util.js'; import {getUid} from '../../util.js';
import LayerType from '../../LayerType.js'; import LayerType from '../../LayerType.js';
import TileState from '../../TileState.js'; import TileState from '../../TileState.js';
import ViewHint from '../../ViewHint.js';
import {createCanvasContext2D} from '../../dom.js'; import {createCanvasContext2D} from '../../dom.js';
import {listen, unlisten} from '../../events.js'; import {listen, unlisten} from '../../events.js';
import EventType from '../../events/EventType.js'; import EventType from '../../events/EventType.js';
@@ -341,6 +342,8 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
if (declutterReplays) { if (declutterReplays) {
this.declutterTree_.clear(); this.declutterTree_.clear();
} }
const viewHints = frameState.viewHints;
const snapToPixel = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]);
const tiles = this.renderedTiles; const tiles = this.renderedTiles;
const tileGrid = source.getTileGridForProjection(frameState.viewState.projection); const tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
const clips = []; const clips = [];
@@ -390,14 +393,14 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
context.clip(); context.clip();
} }
} }
replayGroup.replay(context, transform, rotation, {}, replayTypes, declutterReplays); replayGroup.replay(context, transform, rotation, {}, snapToPixel, replayTypes, declutterReplays);
context.restore(); context.restore();
clips.push(currentClip); clips.push(currentClip);
zs.push(currentZ); zs.push(currentZ);
} }
} }
if (declutterReplays) { if (declutterReplays) {
replayDeclutter(declutterReplays, context, rotation); replayDeclutter(declutterReplays, context, rotation, snapToPixel);
} }
if (rotation) { if (rotation) {
rotateAtOffset(context, rotation, rotateAtOffset(context, rotation,
@@ -466,7 +469,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
scaleTransform(transform, pixelScale, -pixelScale); scaleTransform(transform, pixelScale, -pixelScale);
translateTransform(transform, -tileExtent[0], -tileExtent[3]); translateTransform(transform, -tileExtent[0], -tileExtent[3]);
const replayGroup = sourceTile.getReplayGroup(layer, tile.tileCoord.toString()); const replayGroup = sourceTile.getReplayGroup(layer, tile.tileCoord.toString());
replayGroup.replay(context, transform, 0, {}, replays); replayGroup.replay(context, transform, 0, {}, true, replays);
} }
} }
} }

View File

@@ -280,7 +280,6 @@ describe('ol.rendering.layer.Tile', function() {
evt.element.on('render', function(e) { evt.element.on('render', function(e) {
e.vectorContext.setImageStyle(new CircleStyle({ e.vectorContext.setImageStyle(new CircleStyle({
radius: 5, radius: 5,
snapToPixel: false,
fill: new Fill({color: 'yellow'}), fill: new Fill({color: 'yellow'}),
stroke: new Stroke({color: 'red', width: 1}) stroke: new Stroke({color: 'red', width: 1})
})); }));