在 OpenLayers 中的复合样式中禁用 hitDetectionRenderer

问题描述 投票:0回答:1

除了点本身之外,我还想围绕点特征绘制一个圆。但是,我不希望圆圈可点击。仅通过单击点本身,我想获取指针事件。

例如在我的样式函数中,它是为矢量图层定义的:

styleFunction = (feature, res) => {
const featureCoordinates = feature.getGeometry().getCoordinates()
const pointStyle = new Style({
            image: new CircleStyle({
                fill: new Fill({
                    color: 'rgba(200,180,150,0.5)'
                }),
                radius: 10,
                stroke: new Stroke({
                    color: 'red,
                    width: 3
                }),
            }),
});

const nearSearch300m = new Style({
                    geometry: new Circle(featureCoordinates, 300 / pointresolution),
                    stroke: new Stroke({
                        color: 'blue',
                        width: 2,
                        lineDash: [2, 3]
                    })
                });

return [pointStyle, nearSearch300m]

实际上,我的合成样式有中点、阴影、文本标签和四个带有标签的同心圆。

从性能角度来看,能够使用尽可能简单的命中检测图像(例如留下文本标签而不进行检测)会更好吗?就我而言,我可以为点背景阴影样式启用命中检测,并从其他样式禁用它。

我尝试定义一个自定义

hitDetectionRenderer = (coordinates, state) => {...
来手动绘制一个10px半径的圆并将其设置为两种样式,但这似乎并不能解决问题。

我还尝试了为 Style hitDetectionRenderer 设置 null 的所有可能版本,但没有成功。

怎样才能达到圆圈对点击事件没有反应的效果?

openlayers
1个回答
0
投票

hitDetectionRenderer
仅覆盖使用
renderer
选项创建的样式。

您可以在两层中使用源代码,将一层设置为您想要检测的样式,另一层设置为您不想检测的样式,然后使用图层过滤器进行命中检测:

<html>
<head>
  <style>
    html, body, .map {
      margin: 0;
      padding: 0;
      width: 100%;
      height: 100%;
    }
  </style>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ol.js"></script>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/ol.css">
</head>
<body>
  <div id="map" class="map"></div>
  <script>
{

const {Circle: CircleStyle, Fill, Stroke, Style} = ol.style;
const {Feature, Map, View} = ol;
const {OSM, Vector: VectorSource} = ol.source;
const {Point, Circle} = ol.geom;
const {ScaleLine, defaults: {defaults: defaultControls}} = ol.control;
const {Tile: TileLayer, Vector: VectorLayer} = ol.layer;
const {fromLonLat, getPointResolution} = ol.proj;

const center = fromLonLat([18.955, 69.652]);

const source = new VectorSource({
  features: [
    new Feature(new Point(center)),
  ],
});

const map = new Map({
  target: 'map',
  controls: defaultControls().extend([new ScaleLine()]),
  layers: [
    new TileLayer({
      source: new OSM(),
    }),
    new VectorLayer({
      source: source,
      style: [
        new Style({
          image: new CircleStyle({
            fill: new Fill({
              color: 'rgba(200,180,150,0.5)',
            }),
            radius: 10,
            stroke: new Stroke({
              color: 'red',
              width: 3,
            }),
          }),
        }),
      ],
    }),
    new VectorLayer({
      source: source,
      style: [
        new Style({
          geometry: (feature) => {
            const featureCoordinates = feature.getGeometry().getCoordinates();
            const pointresolution = getPointResolution(
              map.getView().getProjection(),
              1,
              featureCoordinates,
            );
            return new Circle(featureCoordinates, 300 / pointresolution);
          },
          stroke: new Stroke({
            color: 'blue',
            width: 2,
            lineDash: [2, 3],
          }),
        }),
      ],
    }),
  ],
  view: new View({
    center: center,
    zoom: 14,
  }),
});

map.on('pointermove', (e) => {
  map.getTargetElement().style.cursor = map.hasFeatureAtPixel(
    e.pixel,
    {layerFilter: (l) => l === map.getLayers().item(1)},
  ) ? 'pointer' : '';
});


}
  </script>
</body>

</html>

或者您可以使用单个图层,其中包含您不希望通过

renderer
选项和 void
hitDetectionRenderer
检测到的样式。 传递给
renderer
函数的像素坐标需要用于重新创建几何图形,然后可以使用矢量上下文方法来设计几何图形

<html>
<head>
  <style>
    html, body, .map {
      margin: 0;
      padding: 0;
      width: 100%;
      height: 100%;
    }
  </style>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ol.js"></script>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/ol.css">
</head>
<body>
  <div id="map" class="map"></div>
  <script>
{

const {Circle: CircleStyle, Fill, Stroke, Style} = ol.style;
const {Feature, Map, View} = ol;
const {OSM, Vector: VectorSource} = ol.source;
const {Point, Circle} = ol.geom;
const {ScaleLine, defaults: {defaults: defaultControls}} = ol.control;
const {Tile: TileLayer, Vector: VectorLayer} = ol.layer;
const {fromLonLat, getPointResolution} = ol.proj;
const {toContext} = ol.render;

const center = fromLonLat([18.955, 69.652]);

const source = new VectorSource({
  features: [
    new Feature(new Point(center)),
  ],
});

const map = new Map({
  target: 'map',
  controls: defaultControls().extend([new ScaleLine()]),
  layers: [
    new TileLayer({
      source: new OSM(),
    }),
    new VectorLayer({
      source: source,
      style: [
        new Style({
          image: new CircleStyle({
            fill: new Fill({
              color: 'rgba(200,180,150,0.5)',
            }),
            radius: 10,
            stroke: new Stroke({
              color: 'red',
              width: 3,
            }),
          }),
        }),
        new Style({
          geometry: (feature) => {
            const featureCoordinates = feature.getGeometry().getCoordinates();
            const pointresolution = getPointResolution(
              map.getView().getProjection(),
              1,
              featureCoordinates,
            );
            return new Circle(featureCoordinates, 300 / pointresolution);
          },
          renderer: (coordinates, state) => {
            const [[x, y], [x1, y1]] = coordinates;
            const dx = x1 - x;
            const dy = y1 - y;
            const radius = Math.sqrt(dx * dx + dy * dy);
            const vectorContext = toContext(
              state.context,
              {pixelRatio: state.pixelRatio},
            );
            vectorContext.setStyle(
              new Style({
                stroke: new Stroke({
                  color: 'blue',
                  width: 2,
                  lineDash: [2, 3],
                }),
              }),
            );
            vectorContext.drawGeometry(
              new Circle([x, y], radius),
            );
          },
          hitDetectionRenderer: () => {},
        }),
      ],
    }),
  ],
  view: new View({
    center: center,
    zoom: 14,
  }),
});

map.on('pointermove', (e) => {
  map.getTargetElement().style.cursor = map.hasFeatureAtPixel(
    e.pixel,
  ) ? 'pointer' : '';
});


}
  </script>
</body>

</html>

© www.soinside.com 2019 - 2024. All rights reserved.