OpenLayers:我怎样才能阻止点击导致不应该的选择?

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

要重现,请单击包含文本

4
的蓝色标记。因为这是一个聚类标记,它聚类的所有标记都在同一坐标,所以尝试放大是没有意义的。我没有放大,而是将地图放在标记的中心。

但是,单击标记 4 会导致单击左侧的大矩形,这会触发矩形的选择。当然,这不应该发生。

如果我正在进行居中操作,我曾尝试告诉事件不要传播,但这无济于事。

我需要更改什么才能不触发选择?

function createRectangle(polygons, layerName) {
  const features = [];

  for (const [i, polygon] of polygons.entries()) {
    const feature = {
      type: "Feature",
      geometry: {
        type: "Polygon",
        coordinates: polygon
      },
      properties: {
        id: `${layerName} index ${i}`,
        layerName
      }
    };

    features.push(feature);
  }

  const json = {
    type: "FeatureCollection",
    features
  };

  return json;
}

function createPoints(points, groupName) {
  const features = [];

  for (const [i, point] of points.entries()) {
    const feature = {
      type: "Feature",
      geometry: {
        type: "Point",
        coordinates: point
      },
      properties: {
        id: `${groupName} index ${i}`,
        groupName
      }
    };

    features.push(feature);
  }

  const json = {
    type: "FeatureCollection",
    features
  };

  return json;
}

const thePoints = createPoints(
  [
    [50, 33],
    [50, 33],
    [50, 33],
    [50, 33]
  ],
  "thePoints"
);

const styles = {
  Point: new ol.style.Style({
    image: new ol.style.Circle({
      radius: 7,
      fill: new ol.style.Fill({ color: "red" })
    }),
    stroke: new ol.style.Stroke({
      color: "hsla(0, 50%, 100%, 1.0)",
      width: 5
    }),
    fill: new ol.style.Fill({
      color: "hsla(0, 50%, 50%, 1.0)"
    })
  }),
  Polygon: new ol.style.Style({
    stroke: new ol.style.Stroke({
      color: "hsla(0, 50%, 100%, 1.0)",
      width: 5
    }),
    fill: new ol.style.Fill({
      color: "hsla(0, 50%, 50%, 1.0)"
    })
  })
};

const styleFunction = function (feature) {
  const featureType = feature.getGeometry().getType();
  return styles[featureType];
};

const vectorSource = new ol.source.Vector({
  features: new ol.format.GeoJSON({
    featureProjection: "EPSG:4326" // 4326 3857
  }).readFeatures(thePoints)
});

const cluster = new ol.source.Cluster({
  distance: 30,
  minDistance: 10,
  source: vectorSource
});

const styleCache = {};
const vectorLayer = new ol.layer.Vector({
  source: cluster,
  style: function (feature) {
    const size = feature.get("features").length;
    let style = styleCache[size];
    if (!style) {
      style = new ol.style.Style({
        image: new ol.style.Circle({
          radius: 10,
          stroke: new ol.style.Stroke({
            color: "#fff"
          }),
          fill: new ol.style.Fill({
            color: "#3399CC"
          })
        }),
        text: new ol.style.Text({
          text: size.toString(),
          fill: new ol.style.Fill({
            color: "#fff"
          })
        })
      });
      styleCache[size] = style;
    }
    return style;
  },
  zIndex: 5,
  properties: {
    name: "big"
  }
});

const rectangles = createRectangle(
  [
    [
      [
        [-120, -75],
        [-120, 75],
        [45, 75],
        [45, -75]
      ]
    ]
  ],
  "rectangle"
);

const rectangleSource = new ol.source.Vector({
  features: new ol.format.GeoJSON({
    featureProjection: "EPSG:4326" // 4326 3857
  }).readFeatures(rectangles)
});

const rectangleLayer = new ol.layer.Vector({
  source: rectangleSource,
  style: styleFunction,
  zIndex: 5
});

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

map.on("click", (e) => {
  vectorLayer.getFeatures(e.pixel).then((clickedFeatures) => {
    if (clickedFeatures.length) {
      // Get clustered Coordinates
      const features = clickedFeatures[0].get("features");
      if (features.length > 1) {
        e.stopPropagation();

        const extent = ol.extent.boundingExtent(
          features.map((r) => r.getGeometry().getCoordinates())
        );
        const extentSize = ol.extent.getSize(extent);
        const isSmallExtent = extentSize[0] === 0 && extentSize[1] === 0;

        console.log("isSmallExtent", isSmallExtent);

        if (isSmallExtent) {
          const viewport = map.getViewport();
          const boundingRect = viewport.getBoundingClientRect();

          console.log("boundingRect", boundingRect);

          const centerPoint = [
            (boundingRect.left + boundingRect.right) / 2,
            (boundingRect.top + boundingRect.bottom) / 2
          ];

          console.log("centerPoint", centerPoint);

          map
            .getView()
            .centerOn(ol.extent.getCenter(extent), map.getSize(), centerPoint);
        } else {
          map
            .getView()
            .fit(extent, { duration: 1000, padding: [50, 50, 50, 50] });
        }
      }
    }
  });
});

const selected = new ol.style.Style({
  fill: new ol.style.Fill({
    color: "hsla(270, 50%, 50%, .1)"
  }),
  stroke: new ol.style.Stroke({
    color: "hsla(270, 50%, 50%, 1)",
    width: 5
  })
});

const selectSingleClick = new ol.interaction.Select({
  style: (feature) => {
    const color = "hsla(270, 50%, 50%, .1)";
    selected.getFill().setColor(color);
    return selected;
  },
  layers: [rectangleLayer],
  condition: function (e) {
    return (
      ol.events.condition.singleClick(e) &&
      map.getFeaturesAtPixel(e.pixel, {
        layerFilter: function (l) {
          return l.getZIndex() > vectorLayer.getZIndex();
        }
      }).length === 0
    );
  }
});

selectSingleClick.on("select", function (e) {
  console.log("selectSingleClick onSelect");
});

map.addInteraction(selectSingleClick);
#map {
  height: 512px;
  width: 1024px;
}
<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>

openlayers
1个回答
0
投票

您可以简单地在单击期间停用选择交互(在单击后触发 500 毫秒以确保它不是双击)

    selectSingleClick.setActive(false);
    setTimeout(() => { selectSingleClick.setActive(true); }, 600);

function createRectangle(polygons, layerName) {
  const features = [];

  for (const [i, polygon] of polygons.entries()) {
    const feature = {
      type: "Feature",
      geometry: {
        type: "Polygon",
        coordinates: polygon
      },
      properties: {
        id: `${layerName} index ${i}`,
        layerName
      }
    };

    features.push(feature);
  }

  const json = {
    type: "FeatureCollection",
    features
  };

  return json;
}

function createPoints(points, groupName) {
  const features = [];

  for (const [i, point] of points.entries()) {
    const feature = {
      type: "Feature",
      geometry: {
        type: "Point",
        coordinates: point
      },
      properties: {
        id: `${groupName} index ${i}`,
        groupName
      }
    };

    features.push(feature);
  }

  const json = {
    type: "FeatureCollection",
    features
  };

  return json;
}

const thePoints = createPoints(
  [
    [50, 33],
    [50, 33],
    [50, 33],
    [50, 33]
  ],
  "thePoints"
);

const styles = {
  Point: new ol.style.Style({
    image: new ol.style.Circle({
      radius: 7,
      fill: new ol.style.Fill({ color: "red" })
    }),
    stroke: new ol.style.Stroke({
      color: "hsla(0, 50%, 100%, 1.0)",
      width: 5
    }),
    fill: new ol.style.Fill({
      color: "hsla(0, 50%, 50%, 1.0)"
    })
  }),
  Polygon: new ol.style.Style({
    stroke: new ol.style.Stroke({
      color: "hsla(0, 50%, 100%, 1.0)",
      width: 5
    }),
    fill: new ol.style.Fill({
      color: "hsla(0, 50%, 50%, 1.0)"
    })
  })
};

const styleFunction = function (feature) {
  const featureType = feature.getGeometry().getType();
  return styles[featureType];
};

const vectorSource = new ol.source.Vector({
  features: new ol.format.GeoJSON({
    featureProjection: "EPSG:4326" // 4326 3857
  }).readFeatures(thePoints)
});

const cluster = new ol.source.Cluster({
  distance: 30,
  minDistance: 10,
  source: vectorSource
});

const styleCache = {};
const vectorLayer = new ol.layer.Vector({
  source: cluster,
  style: function (feature) {
    const size = feature.get("features").length;
    let style = styleCache[size];
    if (!style) {
      style = new ol.style.Style({
        image: new ol.style.Circle({
          radius: 10,
          stroke: new ol.style.Stroke({
            color: "#fff"
          }),
          fill: new ol.style.Fill({
            color: "#3399CC"
          })
        }),
        text: new ol.style.Text({
          text: size.toString(),
          fill: new ol.style.Fill({
            color: "#fff"
          })
        })
      });
      styleCache[size] = style;
    }
    return style;
  },
  zIndex: 5,
  properties: {
    name: "big"
  }
});

const rectangles = createRectangle(
  [
    [
      [
        [-120, -75],
        [-120, 75],
        [45, 75],
        [45, -75]
      ]
    ]
  ],
  "rectangle"
);

const rectangleSource = new ol.source.Vector({
  features: new ol.format.GeoJSON({
    featureProjection: "EPSG:4326" // 4326 3857
  }).readFeatures(rectangles)
});

const rectangleLayer = new ol.layer.Vector({
  source: rectangleSource,
  style: styleFunction,
  zIndex: 5
});

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

let selectSingleClick;
map.on("click", (e) => {
  vectorLayer.getFeatures(e.pixel).then((clickedFeatures) => {
    if (clickedFeatures.length) {
      // Get clustered Coordinates
      const features = clickedFeatures[0].get("features");
      if (features.length > 1) {
        selectSingleClick.setActive(false);
        setTimeout(() => { selectSingleClick.setActive(true); }, 600);

        const extent = ol.extent.boundingExtent(
          features.map((r) => r.getGeometry().getCoordinates())
        );
        const extentSize = ol.extent.getSize(extent);
        const isSmallExtent = extentSize[0] === 0 && extentSize[1] === 0;

        console.log("isSmallExtent", isSmallExtent);

        if (isSmallExtent) {
          const viewport = map.getViewport();
          const boundingRect = viewport.getBoundingClientRect();

          console.log("boundingRect", boundingRect);

          const centerPoint = [
            (boundingRect.left + boundingRect.right) / 2,
            (boundingRect.top + boundingRect.bottom) / 2
          ];

          console.log("centerPoint", centerPoint);

          map
            .getView()
            .centerOn(ol.extent.getCenter(extent), map.getSize(), centerPoint);
        } else {
          map
            .getView()
            .fit(extent, { duration: 1000, padding: [50, 50, 50, 50] });
        }
      }
    }
  });
});

const selected = new ol.style.Style({
  fill: new ol.style.Fill({
    color: "hsla(270, 50%, 50%, .1)"
  }),
  stroke: new ol.style.Stroke({
    color: "hsla(270, 50%, 50%, 1)",
    width: 5
  })
});

selectSingleClick = new ol.interaction.Select({
  style: (feature) => {
    const color = "hsla(270, 50%, 50%, .1)";
    selected.getFill().setColor(color);
    return selected;
  },
  layers: [rectangleLayer],
  condition: function (e) {
    return (
      ol.events.condition.singleClick(e) &&
      map.getFeaturesAtPixel(e.pixel, {
        layerFilter: function (l) {
          return l.getZIndex() > vectorLayer.getZIndex();
        }
      }).length === 0
    );
  }
});

selectSingleClick.on("select", function (e) {
  console.log("selectSingleClick onSelect");
});

map.addInteraction(selectSingleClick);
#map {
  height: 512px;
  width: 1024px;
}
<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>

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