如何在 openlayers 3 中的图标周围添加可点击的边距?

How to add clickable margins around an icon in openlayers 3?

我正在使用 openlayers 3 来显示带有一些带有小图标的标记的地图。单击其中一个后,浏览器将切换到与该标记关联的另一个页面。

标记当前作为特征实现:

const style = new ol.style.Style({
    image: new ol.style.Icon({
        anchor: [0.5, 1.0],
        anchorXUnits: 'fraction',
        anchorYUnits: 'fraction',
        src: img_url,
    })
});

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

feature.setStyle(style);

这是我的点击处理程序:

map.on("click", e => {
    map.forEachFeatureAtPixel(e.pixel, (feature) => {
        window.location.href = "/s/" + feature.getId();
        return true; // stop after first feature
    });
});

不幸的是,图标非常小,因此很难在 iPad 等基于触摸的界面上点击。

是否有一种公认的方法可以使目标变大?我的想法如下:

有更好的方法吗?

我的建议是在图标周围创建一个不可见的正方形,例如:

const style = [
  new ol.style.Style({
    image: new ol.style.Icon({
      anchor: [0.5, 1.0],
      anchorXUnits: 'fraction',
      anchorYUnits: 'fraction',
      src: img_url,
    })
  }),
  new ol.style.Style({
    image: new ol.style.RegularShape({
      stroke: new ol.style.Stroke({ color: [0, 0, 0, 0] }),
      points: 4,
      radius: 50, // <--------- control its size
      angle: Math.PI / 4
    })
  })
];

我最初尝试了 Jonatas 的方法,即添加更大的样式。这很好用。需要注意的是,在单击某个特征时,我们必须找出最接近的特征,因为它们很容易重叠。

在发现 getClosestFeatureToCoordinate() 方法后,我终于决定采用稍微不同的方法。我在 click 处理程序中执行所有操作:

map.on("click", event => {
    const distance = feature => {
        const coords = feature.getGeometry().getCoordinates();
        const pixel = map.getPixelFromCoordinate(coords);
        const distSquared = Math.pow(event.pixel[0] - pixel[0], 2)
                          + Math.pow(event.pixel[1] - pixel[1], 2);
        return distSquared;
    };

    const clickedFeature = { feat: null, dist: Infinity };

    /* See if we clicked on a feature. If yes, take closest */
    map.forEachFeatureAtPixel(event.pixel, (feature) => {
        const dist = distance(feature);
        if (dist < clickedFeature.dist) {
            clickedFeature.feat = feature;
            clickedFeature.dist = dist;
        }
    });

    /* If we are touch-based, we also take into account clicks that happen nearby */
    if (!clickedFeature.feat) {
        if (ol.has.TOUCH) {
            const coords = this._map.getCoordinateFromPixel(event.pixel);
            const closestFeat = this._featureSource.getClosestFeatureToCoordinate(coords);

            const dist = distance(closestFeat);
            /* touch size taken from Apple's guidelines */
            if (dist < Math.pow(22,2)) {
                clickedFeature.feat = closestFeat;
                clickedFeature.dist = dist;
            }
        }
    }

    /* go to station */
    if (clickedFeature.feat) {
        window.location.href = "/s/" + clickedFeature.feat.getId();
    }
});