Search code examples
openlayers

How can I getFeatures with Point geometry with a Text Style?


In the code snippet, I have added a single Point feature with a text Style (brokenStyle).

I would like to know when my cursor moves over this feature, but getFeatures always returns an empty list.

If I use workingStyle instead, which uses the Circle style, I will see Hit Feature appear in the console.

Why does the text style not work in this case? If I want to use the text style, will I need to also use a transparent circle or square so getFeatures will work? What is common practice in this situation?

ol.proj.get("EPSG:4326").setExtent([-180, -85, 180, 85]);

const osm = new ol.source.OSM();
osm.setTileGridForProjection(
  "EPSG:4326",
  ol.tilegrid.createXYZ({ extent: [-180, -90, 180, 90] })
);

const feature = new ol.Feature({
  geometry: new ol.geom.Point([0, 45])
});

const source = new ol.source.Vector();
source.addFeatures([feature]);

const brokenStyle = new ol.style.Style({
  text: new ol.style.Text({
    text: "X",
    scale: 1.0,
    textBaseline: "bottom",
    fill: new ol.style.Fill({ color: "#000000" }),
    stroke: new ol.style.Stroke({ color: "black", width: 1 })
  })
});

const workingStyle = new ol.style.Style({
  image: new ol.style.Circle({
    radius: 5,
    stroke: new ol.style.Stroke({
      color: "black",
      width: 2
    }),
    fill: new ol.style.Fill({
      color: "black"
    })
  })
});

const vectorLayer = new ol.layer.Vector({
  source,
  style: (feature) => {
    return brokenStyle;
  }
});

const map = new ol.Map({
  target: "map",
  layers: [
    new ol.layer.Tile({
      source: osm
    }),
    vectorLayer
  ],
  view: new ol.View({
    projection: "EPSG:4326",
    center: [0, 0],
    zoom: 0
  })
});

map.on("pointermove", (e) => {
  const pixel = e.pixel;

  vectorLayer.getFeatures(e.pixel).then((hitFeatures) => {
    if (hitFeatures.length > 0) {
      console.log("Hit Feature");
    }
  });
});
#map {
  aspect-ratio: 360/170;
  background-color: blue;
  margin: 32px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/7.3.0/ol.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/7.3.0/dist/ol.min.js"></script>
<div id="map"></div>


Solution

  • "Text is not considered" https://openlayers.org/en/latest/apidoc/module-ol_layer_Vector-VectorLayer.html#getFeatures so you will need to use map.getFeaturesAtPixel() instead:

    map.on("pointermove", (e) => {
      const pixel = e.pixel;
    
      const hitFeatures = map.getFeaturesAtPixel(e.pixel, {
       layerFilter: (l) => l === vectorLayer
      )
      if (hitFeatures.length > 0) {
        console.log("Hit Feature");
      }
    });