openlayers icon indicating copy to clipboard operation
openlayers copied to clipboard

hasFeatureAtPixel() fails in Samsung Internet Browser on Android

Open richnic opened this issue 2 years ago • 4 comments

Describe the bug I use hasFeatureAtPixel() and forEachFeatureAtPixel() to display an overlay when a point is clicked or under the mouse pointer. The lower left corner of the overlay is positioned at the screen coordinate where the mouse action occurred. Because hitTolerance is set to 0, the bottom left corner of the overlay should always be above a point. This works perfectly in desktop browsers. But in Samsung Internet Browser v16.2.5.4 on Android 10 something may have changed, because for several weeks the overlay sometimes appears after tapping onto the display far away from any point:

Screenshot_20220508-113734_Samsung Internet

How can this happen? And can you give me a tip to work around this problem?

To Reproduce Here is my code:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css"
  href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/css/ol.css">
<title>Feature@Pixel</title>
<style>
  #map, html { height: 100%; width: 100%; margin: 0; }
  body { height: 100%; margin: 0; font: 14px Arial; }
  #popup { position: absolute; background-color: #EEE; padding: 5px; bottom: 0; min-width: 60px; }
</style>
<script
  src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/build/ol.js">
</script>
</head>
<body>
<div id="map"></div>
<div id="popup"><div id="popup-content"></div></div>
<script>
  var map = new ol.Map({
    layers: [new ol.layer.Tile({source: new ol.source.OSM({maxZoom: 16})})],
    target: 'map',
    view: new ol.View({center: ol.proj.fromLonLat([2, 2]), zoom: 6})
  });
  var circ = new ol.style.Style({
    image: new ol.style.Circle({
      fill: new ol.style.Fill({color: 'red'}),
      radius: 16,
      stroke: new ol.style.Stroke({color: 'black', width: 2})
    })
  });
  var pts = [0, 2, 4, 6].map(function(n) {
    return new ol.Feature({geometry: new ol.geom.Point(ol.proj.fromLonLat([n << 1 & 4, n & 4]))});
  });
  map.addLayer(new ol.layer.Vector({style: circ, source: new ol.source.Vector({features: pts})}));
  var overlay = new ol.Overlay({element: document.getElementById('popup')});
  map.addOverlay(overlay);
  map.on(['pointermove', 'singleclick'], function (event) {
    if (map.hasFeatureAtPixel(event.pixel, {hitTolerance: 0}) === true) {
      document.getElementById('popup-content').innerHTML = event.pixel.map(Math.round).toString();
      overlay.setPosition(event.coordinate);
    }
    else { overlay.setPosition(undefined); }
  });
</script>
</body>
</html>

Expected behavior The overlay should never open if you tap outside of a point.

richnic avatar May 08 '22 11:05 richnic

I've created a sandbox for others to try this in

https://codesandbox.io/s/openlayers-bug-13653-xen0uy?file=/src/index.js

I've removed the 'pointermove' event and just left the 'singleclick' just to make it a bit easier to debug and can confirm it does happen on Samsung Internet Browser, and doesn't happen on other browsers I've tried it in (Edge Mobile, Edge Desktop, Chrome Desktop).

I'll try and take a further look later but for now I can't figure out what's causing the issue, so I thought I'd share the sandbox in case anyone else wants to look

RobQuincey avatar Jun 10 '22 11:06 RobQuincey

tried and work also with chrome, safari, FF on mac ...

jipexu avatar Jun 10 '22 13:06 jipexu

I think I've hit the limits of my debugging capability and can't figure it out. Whatever is going wrong is buried deep and I'm not particularly au fait with the inners of the library. I did discover that even if you set the pixel to a constant value, e.g.

const testPixel = [241,141];
console.log(map.hasFeatureAtPixel(testPixel, {hitTolerance: 0}))

The same issue occurs. It will, seemingly randomly, return true and false even though the same pixel is being passed in.

Someone smarter than me may be able to take it from here.

RobQuincey avatar Jun 12 '22 16:06 RobQuincey

I too have this issue and tried to debug it at bit more in depth. I think I narrowed it down to context.getImageData(0, 0, contextSize, contextSize).data; returning something which looks like garbage in "featureCallback" in "ExecutorGroup.js".

cwitting avatar Jun 13 '22 17:06 cwitting