如何在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();
    }
});

最新更新