Merge pull request #12016 from MoonE/hitdetect-resolution-constant
Fix VectorLayer hitdetect problems
This commit is contained in:
@@ -11,6 +11,8 @@ import {createCanvasContext2D} from '../../dom.js';
|
|||||||
import {intersects} from '../../extent.js';
|
import {intersects} from '../../extent.js';
|
||||||
import {numberSafeCompareFunction} from '../../array.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 {import("../../size.js").Size} size Canvas size in css pixels.
|
||||||
* @param {Array<import("../../transform.js").Transform>} transforms Transforms
|
* @param {Array<import("../../transform.js").Transform>} transforms Transforms
|
||||||
@@ -34,14 +36,14 @@ export function createHitDetectionImageData(
|
|||||||
resolution,
|
resolution,
|
||||||
rotation
|
rotation
|
||||||
) {
|
) {
|
||||||
const width = size[0] / 2;
|
const width = size[0] * HIT_DETECT_RESOLUTION;
|
||||||
const height = size[1] / 2;
|
const height = size[1] * HIT_DETECT_RESOLUTION;
|
||||||
const context = createCanvasContext2D(width, height);
|
const context = createCanvasContext2D(width, height);
|
||||||
context.imageSmoothingEnabled = false;
|
context.imageSmoothingEnabled = false;
|
||||||
const canvas = context.canvas;
|
const canvas = context.canvas;
|
||||||
const renderer = new CanvasImmediateRenderer(
|
const renderer = new CanvasImmediateRenderer(
|
||||||
context,
|
context,
|
||||||
0.5,
|
HIT_DETECT_RESOLUTION,
|
||||||
extent,
|
extent,
|
||||||
null,
|
null,
|
||||||
rotation
|
rotation
|
||||||
@@ -67,6 +69,10 @@ export function createHitDetectionImageData(
|
|||||||
const color = '#' + ('000000' + index.toString(16)).slice(-6);
|
const color = '#' + ('000000' + index.toString(16)).slice(-6);
|
||||||
for (let j = 0, jj = styles.length; j < jj; ++j) {
|
for (let j = 0, jj = styles.length; j < jj; ++j) {
|
||||||
const originalStyle = styles[j];
|
const originalStyle = styles[j];
|
||||||
|
const geometry = originalStyle.getGeometryFunction()(feature);
|
||||||
|
if (!geometry || !intersects(extent, geometry.getExtent())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const style = originalStyle.clone();
|
const style = originalStyle.clone();
|
||||||
const fill = style.getFill();
|
const fill = style.getFill();
|
||||||
if (fill) {
|
if (fill) {
|
||||||
@@ -79,23 +85,18 @@ export function createHitDetectionImageData(
|
|||||||
}
|
}
|
||||||
style.setText(undefined);
|
style.setText(undefined);
|
||||||
const image = originalStyle.getImage();
|
const image = originalStyle.getImage();
|
||||||
if (image) {
|
if (image && image.getOpacity() !== 0) {
|
||||||
const imgSize = image.getImageSize();
|
const imgSize = image.getImageSize();
|
||||||
if (!imgSize) {
|
if (!imgSize) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const canvas = document.createElement('canvas');
|
const img = document.createElement('canvas');
|
||||||
canvas.width = imgSize[0];
|
img.width = imgSize[0];
|
||||||
canvas.height = imgSize[1];
|
img.height = imgSize[1];
|
||||||
const imgContext = canvas.getContext('2d', {alpha: false});
|
const imgContext = img.getContext('2d', {alpha: false});
|
||||||
imgContext.fillStyle = color;
|
imgContext.fillStyle = color;
|
||||||
const img = imgContext.canvas;
|
|
||||||
imgContext.fillRect(0, 0, img.width, img.height);
|
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(
|
style.setImage(
|
||||||
new Icon({
|
new Icon({
|
||||||
img: img,
|
img: img,
|
||||||
@@ -104,15 +105,15 @@ export function createHitDetectionImageData(
|
|||||||
anchorXUnits: IconAnchorUnits.PIXELS,
|
anchorXUnits: IconAnchorUnits.PIXELS,
|
||||||
anchorYUnits: IconAnchorUnits.PIXELS,
|
anchorYUnits: IconAnchorUnits.PIXELS,
|
||||||
offset: image.getOrigin(),
|
offset: image.getOrigin(),
|
||||||
|
opacity: 1,
|
||||||
size: image.getSize(),
|
size: image.getSize(),
|
||||||
opacity: image.getOpacity(),
|
|
||||||
scale: image.getScale(),
|
scale: image.getScale(),
|
||||||
rotation: image.getRotation(),
|
rotation: image.getRotation(),
|
||||||
rotateWithView: image.getRotateWithView(),
|
rotateWithView: image.getRotateWithView(),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const zIndex = Number(style.getZIndex());
|
const zIndex = style.getZIndex() || 0;
|
||||||
let byGeometryType = featuresByZIndex[zIndex];
|
let byGeometryType = featuresByZIndex[zIndex];
|
||||||
if (!byGeometryType) {
|
if (!byGeometryType) {
|
||||||
byGeometryType = {};
|
byGeometryType = {};
|
||||||
@@ -122,13 +123,10 @@ export function createHitDetectionImageData(
|
|||||||
byGeometryType[GeometryType.LINE_STRING] = [];
|
byGeometryType[GeometryType.LINE_STRING] = [];
|
||||||
byGeometryType[GeometryType.POINT] = [];
|
byGeometryType[GeometryType.POINT] = [];
|
||||||
}
|
}
|
||||||
const geometry = style.getGeometryFunction()(feature);
|
byGeometryType[geometry.getType().replace('Multi', '')].push(
|
||||||
if (geometry && intersects(extent, geometry.getExtent())) {
|
geometry,
|
||||||
byGeometryType[geometry.getType().replace('Multi', '')].push(
|
style
|
||||||
geometry,
|
);
|
||||||
style
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,13 +161,14 @@ export function createHitDetectionImageData(
|
|||||||
export function hitDetect(pixel, features, imageData) {
|
export function hitDetect(pixel, features, imageData) {
|
||||||
const resultFeatures = [];
|
const resultFeatures = [];
|
||||||
if (imageData) {
|
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
|
// 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
|
// for browsers returning coordinates slightly larger than the actual canvas size
|
||||||
// due to a non-integer pixel ratio.
|
// due to a non-integer pixel ratio.
|
||||||
const index =
|
const index =
|
||||||
(clamp(Math.floor(Math.round(pixel[0]) / 2), 0, imageData.width - 1) +
|
(clamp(x, 0, imageData.width - 1) +
|
||||||
clamp(Math.floor(Math.round(pixel[1]) / 2), 0, imageData.height - 1) *
|
clamp(y, 0, imageData.height - 1) * imageData.width) *
|
||||||
imageData.width) *
|
|
||||||
4;
|
4;
|
||||||
const r = imageData.data[index];
|
const r = imageData.data[index];
|
||||||
const g = imageData.data[index + 1];
|
const g = imageData.data[index + 1];
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js';
|
|||||||
import CanvasLayerRenderer from './Layer.js';
|
import CanvasLayerRenderer from './Layer.js';
|
||||||
import ExecutorGroup from '../../render/canvas/ExecutorGroup.js';
|
import ExecutorGroup from '../../render/canvas/ExecutorGroup.js';
|
||||||
import ViewHint from '../../ViewHint.js';
|
import ViewHint from '../../ViewHint.js';
|
||||||
|
import {
|
||||||
|
HIT_DETECT_RESOLUTION,
|
||||||
|
createHitDetectionImageData,
|
||||||
|
hitDetect,
|
||||||
|
} from '../../render/canvas/hitdetect.js';
|
||||||
import {
|
import {
|
||||||
apply,
|
apply,
|
||||||
makeInverse,
|
makeInverse,
|
||||||
@@ -19,10 +24,6 @@ import {
|
|||||||
intersects as intersectsExtent,
|
intersects as intersectsExtent,
|
||||||
wrapX as wrapExtentX,
|
wrapX as wrapExtentX,
|
||||||
} from '../../extent.js';
|
} from '../../extent.js';
|
||||||
import {
|
|
||||||
createHitDetectionImageData,
|
|
||||||
hitDetect,
|
|
||||||
} from '../../render/canvas/hitdetect.js';
|
|
||||||
import {
|
import {
|
||||||
defaultOrder as defaultRenderOrder,
|
defaultOrder as defaultRenderOrder,
|
||||||
getTolerance as getRenderTolerance,
|
getTolerance as getRenderTolerance,
|
||||||
@@ -325,14 +326,14 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
|||||||
const extent = this.renderedExtent_;
|
const extent = this.renderedExtent_;
|
||||||
const layer = this.getLayer();
|
const layer = this.getLayer();
|
||||||
const transforms = [];
|
const transforms = [];
|
||||||
const width = size[0] / 2;
|
const width = size[0] * HIT_DETECT_RESOLUTION;
|
||||||
const height = size[1] / 2;
|
const height = size[1] * HIT_DETECT_RESOLUTION;
|
||||||
transforms.push(
|
transforms.push(
|
||||||
this.getRenderTransform(
|
this.getRenderTransform(
|
||||||
center,
|
center,
|
||||||
resolution,
|
resolution,
|
||||||
rotation,
|
rotation,
|
||||||
0.5,
|
HIT_DETECT_RESOLUTION,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
0
|
0
|
||||||
@@ -357,7 +358,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
|||||||
center,
|
center,
|
||||||
resolution,
|
resolution,
|
||||||
rotation,
|
rotation,
|
||||||
0.5,
|
HIT_DETECT_RESOLUTION,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
offsetX
|
offsetX
|
||||||
@@ -375,7 +376,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
|||||||
center,
|
center,
|
||||||
resolution,
|
resolution,
|
||||||
rotation,
|
rotation,
|
||||||
0.5,
|
HIT_DETECT_RESOLUTION,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
offsetX
|
offsetX
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ import ReplayType from '../../render/canvas/BuilderType.js';
|
|||||||
import TileState from '../../TileState.js';
|
import TileState from '../../TileState.js';
|
||||||
import VectorTileRenderType from '../../layer/VectorTileRenderType.js';
|
import VectorTileRenderType from '../../layer/VectorTileRenderType.js';
|
||||||
import ViewHint from '../../ViewHint.js';
|
import ViewHint from '../../ViewHint.js';
|
||||||
|
import {
|
||||||
|
HIT_DETECT_RESOLUTION,
|
||||||
|
createHitDetectionImageData,
|
||||||
|
hitDetect,
|
||||||
|
} from '../../render/canvas/hitdetect.js';
|
||||||
import {
|
import {
|
||||||
apply as applyTransform,
|
apply as applyTransform,
|
||||||
create as createTransform,
|
create as createTransform,
|
||||||
@@ -28,10 +33,6 @@ import {
|
|||||||
intersects,
|
intersects,
|
||||||
} from '../../extent.js';
|
} from '../../extent.js';
|
||||||
import {clear} from '../../obj.js';
|
import {clear} from '../../obj.js';
|
||||||
import {
|
|
||||||
createHitDetectionImageData,
|
|
||||||
hitDetect,
|
|
||||||
} from '../../render/canvas/hitdetect.js';
|
|
||||||
import {
|
import {
|
||||||
getSquaredTolerance as getSquaredRenderTolerance,
|
getSquaredTolerance as getSquaredRenderTolerance,
|
||||||
renderFeature,
|
renderFeature,
|
||||||
@@ -549,16 +550,15 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
|||||||
const tileSize = toSize(
|
const tileSize = toSize(
|
||||||
tileGrid.getTileSize(tileGrid.getZForResolution(resolution))
|
tileGrid.getTileSize(tileGrid.getZForResolution(resolution))
|
||||||
);
|
);
|
||||||
const size = [tileSize[0] / 2, tileSize[1] / 2];
|
|
||||||
const rotation = this.renderedRotation_;
|
const rotation = this.renderedRotation_;
|
||||||
const transforms = [
|
const transforms = [
|
||||||
this.getRenderTransform(
|
this.getRenderTransform(
|
||||||
tileGrid.getTileCoordCenter(tile.wrappedTileCoord),
|
tileGrid.getTileCoordCenter(tile.wrappedTileCoord),
|
||||||
resolution,
|
resolution,
|
||||||
0,
|
0,
|
||||||
0.5,
|
HIT_DETECT_RESOLUTION,
|
||||||
size[0],
|
tileSize[0] * HIT_DETECT_RESOLUTION,
|
||||||
size[1],
|
tileSize[1] * HIT_DETECT_RESOLUTION,
|
||||||
0
|
0
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user