Merge pull request #12016 from MoonE/hitdetect-resolution-constant

Fix VectorLayer hitdetect problems
This commit is contained in:
MoonE
2021-02-27 20:50:31 +01:00
committed by GitHub
3 changed files with 42 additions and 42 deletions

View File

@@ -11,6 +11,8 @@ import {createCanvasContext2D} from '../../dom.js';
import {intersects} from '../../extent.js';
import {numberSafeCompareFunction} from '../../array.js';
export const HIT_DETECT_RESOLUTION = 0.5;
/**
* @param {import("../../size.js").Size} size Canvas size in css pixels.
* @param {Array<import("../../transform.js").Transform>} transforms Transforms
@@ -34,14 +36,14 @@ export function createHitDetectionImageData(
resolution,
rotation
) {
const width = size[0] / 2;
const height = size[1] / 2;
const width = size[0] * HIT_DETECT_RESOLUTION;
const height = size[1] * HIT_DETECT_RESOLUTION;
const context = createCanvasContext2D(width, height);
context.imageSmoothingEnabled = false;
const canvas = context.canvas;
const renderer = new CanvasImmediateRenderer(
context,
0.5,
HIT_DETECT_RESOLUTION,
extent,
null,
rotation
@@ -67,6 +69,10 @@ export function createHitDetectionImageData(
const color = '#' + ('000000' + index.toString(16)).slice(-6);
for (let j = 0, jj = styles.length; j < jj; ++j) {
const originalStyle = styles[j];
const geometry = originalStyle.getGeometryFunction()(feature);
if (!geometry || !intersects(extent, geometry.getExtent())) {
continue;
}
const style = originalStyle.clone();
const fill = style.getFill();
if (fill) {
@@ -79,23 +85,18 @@ export function createHitDetectionImageData(
}
style.setText(undefined);
const image = originalStyle.getImage();
if (image) {
if (image && image.getOpacity() !== 0) {
const imgSize = image.getImageSize();
if (!imgSize) {
continue;
}
const canvas = document.createElement('canvas');
canvas.width = imgSize[0];
canvas.height = imgSize[1];
const imgContext = canvas.getContext('2d', {alpha: false});
const img = document.createElement('canvas');
img.width = imgSize[0];
img.height = imgSize[1];
const imgContext = img.getContext('2d', {alpha: false});
imgContext.fillStyle = color;
const img = imgContext.canvas;
imgContext.fillRect(0, 0, img.width, img.height);
const width = imgSize ? imgSize[0] : img.width;
const height = imgSize ? imgSize[1] : img.height;
const iconContext = createCanvasContext2D(width, height);
iconContext.drawImage(img, 0, 0);
style.setImage(
new Icon({
img: img,
@@ -104,15 +105,15 @@ export function createHitDetectionImageData(
anchorXUnits: IconAnchorUnits.PIXELS,
anchorYUnits: IconAnchorUnits.PIXELS,
offset: image.getOrigin(),
opacity: 1,
size: image.getSize(),
opacity: image.getOpacity(),
scale: image.getScale(),
rotation: image.getRotation(),
rotateWithView: image.getRotateWithView(),
})
);
}
const zIndex = Number(style.getZIndex());
const zIndex = style.getZIndex() || 0;
let byGeometryType = featuresByZIndex[zIndex];
if (!byGeometryType) {
byGeometryType = {};
@@ -122,13 +123,10 @@ export function createHitDetectionImageData(
byGeometryType[GeometryType.LINE_STRING] = [];
byGeometryType[GeometryType.POINT] = [];
}
const geometry = style.getGeometryFunction()(feature);
if (geometry && intersects(extent, geometry.getExtent())) {
byGeometryType[geometry.getType().replace('Multi', '')].push(
geometry,
style
);
}
byGeometryType[geometry.getType().replace('Multi', '')].push(
geometry,
style
);
}
}
@@ -163,13 +161,14 @@ export function createHitDetectionImageData(
export function hitDetect(pixel, features, imageData) {
const resultFeatures = [];
if (imageData) {
const x = Math.floor(Math.round(pixel[0]) * HIT_DETECT_RESOLUTION);
const y = Math.floor(Math.round(pixel[1]) * HIT_DETECT_RESOLUTION);
// The pixel coordinate is clamped down to the hit-detect canvas' size to account
// for browsers returning coordinates slightly larger than the actual canvas size
// due to a non-integer pixel ratio.
const index =
(clamp(Math.floor(Math.round(pixel[0]) / 2), 0, imageData.width - 1) +
clamp(Math.floor(Math.round(pixel[1]) / 2), 0, imageData.height - 1) *
imageData.width) *
(clamp(x, 0, imageData.width - 1) +
clamp(y, 0, imageData.height - 1) * imageData.width) *
4;
const r = imageData.data[index];
const g = imageData.data[index + 1];

View File

@@ -5,6 +5,11 @@ import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js';
import CanvasLayerRenderer from './Layer.js';
import ExecutorGroup from '../../render/canvas/ExecutorGroup.js';
import ViewHint from '../../ViewHint.js';
import {
HIT_DETECT_RESOLUTION,
createHitDetectionImageData,
hitDetect,
} from '../../render/canvas/hitdetect.js';
import {
apply,
makeInverse,
@@ -19,10 +24,6 @@ import {
intersects as intersectsExtent,
wrapX as wrapExtentX,
} from '../../extent.js';
import {
createHitDetectionImageData,
hitDetect,
} from '../../render/canvas/hitdetect.js';
import {
defaultOrder as defaultRenderOrder,
getTolerance as getRenderTolerance,
@@ -325,14 +326,14 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
const extent = this.renderedExtent_;
const layer = this.getLayer();
const transforms = [];
const width = size[0] / 2;
const height = size[1] / 2;
const width = size[0] * HIT_DETECT_RESOLUTION;
const height = size[1] * HIT_DETECT_RESOLUTION;
transforms.push(
this.getRenderTransform(
center,
resolution,
rotation,
0.5,
HIT_DETECT_RESOLUTION,
width,
height,
0
@@ -357,7 +358,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
center,
resolution,
rotation,
0.5,
HIT_DETECT_RESOLUTION,
width,
height,
offsetX
@@ -375,7 +376,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
center,
resolution,
rotation,
0.5,
HIT_DETECT_RESOLUTION,
width,
height,
offsetX

View File

@@ -9,6 +9,11 @@ import ReplayType from '../../render/canvas/BuilderType.js';
import TileState from '../../TileState.js';
import VectorTileRenderType from '../../layer/VectorTileRenderType.js';
import ViewHint from '../../ViewHint.js';
import {
HIT_DETECT_RESOLUTION,
createHitDetectionImageData,
hitDetect,
} from '../../render/canvas/hitdetect.js';
import {
apply as applyTransform,
create as createTransform,
@@ -28,10 +33,6 @@ import {
intersects,
} from '../../extent.js';
import {clear} from '../../obj.js';
import {
createHitDetectionImageData,
hitDetect,
} from '../../render/canvas/hitdetect.js';
import {
getSquaredTolerance as getSquaredRenderTolerance,
renderFeature,
@@ -549,16 +550,15 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
const tileSize = toSize(
tileGrid.getTileSize(tileGrid.getZForResolution(resolution))
);
const size = [tileSize[0] / 2, tileSize[1] / 2];
const rotation = this.renderedRotation_;
const transforms = [
this.getRenderTransform(
tileGrid.getTileCoordCenter(tile.wrappedTileCoord),
resolution,
0,
0.5,
size[0],
size[1],
HIT_DETECT_RESOLUTION,
tileSize[0] * HIT_DETECT_RESOLUTION,
tileSize[1] * HIT_DETECT_RESOLUTION,
0
),
];