diff --git a/src/ol/render/canvas/hitdetect.js b/src/ol/render/canvas/hitdetect.js index a95b77d653..d32acc468c 100644 --- a/src/ol/render/canvas/hitdetect.js +++ b/src/ol/render/canvas/hitdetect.js @@ -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} 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]; diff --git a/src/ol/renderer/canvas/VectorLayer.js b/src/ol/renderer/canvas/VectorLayer.js index c27704de4e..2f123e99df 100644 --- a/src/ol/renderer/canvas/VectorLayer.js +++ b/src/ol/renderer/canvas/VectorLayer.js @@ -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 diff --git a/src/ol/renderer/canvas/VectorTileLayer.js b/src/ol/renderer/canvas/VectorTileLayer.js index be39e0d8ef..1bd92a5a85 100644 --- a/src/ol/renderer/canvas/VectorTileLayer.js +++ b/src/ol/renderer/canvas/VectorTileLayer.js @@ -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 ), ];