【问题标题】:OpenLayers: Move vector label with mouseOpenLayers:用鼠标移动矢量标签
【发布时间】:2021-04-29 00:47:58
【问题描述】:

我正在使用 OpenLayers V4,我正在尝试查看是否可以允许用户单击要素的矢量标签并将其移动/拖动到他们选择的位置。我最初的想法是捕捉用户点击标签的时间,然后随着用户鼠标指针的移动,动态计算并设置标签(ol.style.Text)的 offsetX 和 offsetY 属性。为了实现这一点,我需要捕获用户单击标签而不是功能本身的时间。主要问题是我找不到区分这一点的方法。看起来标签是矢量特征的一部分,因为单击特征会突出显示特征和标签,反之亦然。

总之,我的问题有两个方面:

  1. 有人知道如何在 OpenLayers 4 中创建用户可拖动的矢量标签吗?
  2. 有没有一种方法可以检测/区分用户单击矢量特征本身还是矢量标签。

注意:我熟悉叠加层,并意识到它们可能更容易使用,因为它们具有 setPosition 属性,但我的 web 地图的构建方式需要显示每个要素的矢量标签,而不是叠加层

【问题讨论】:

  • 我认为这只能通过复制图层来完成,一个显示没有标签的特征,另一个填充了特征的克隆并只显示标签。为了保持图层同步,功能需要唯一的 ID。解决方案的细节将取决于如果移动要素,标签会发生什么变化,以及要素和标签之间的像素偏移是在地图缩放时发生变化还是保持固定。
  • 与@Mike 的答案相同,但使用具有相同来源的 2 层(不要克隆功能)。一层为点样式,一层为标签。然后你可以在第二层使用带有 layerFilter 的 forEachFeatureAtPixel ...
  • 如果您要拖动标签(例如,使用修改或翻译交互),您将需要克隆,否则您将更改两个图层中的几何形状。
  • @Mike 的想法是改变文本样式的 offsetX/offsetY 而不是特征的坐标。您还可以为要素上的标签使用第二个几何图形。
  • 感谢大家的意见。我想我意识到我想做的事情是不可能使用矢量标签的。看起来我需要将标签移动到叠加层,以便它们可以移动

标签: vector label openlayers highlight


【解决方案1】:

可以在 OpenLayers 6 中使用矢量标签,其中修改交互可以访问其样式函数中正在修改的特征,并且可以使用偏移标签的命中检测,但在版本 4 中不可用。在此示例中标签移动具有它们的特征,但也可以独立于特征移动。需要克隆以避免在移动标签时更改特征几何形状。然后将标签几何图形恢复并用偏移量替换以进行样式设置。当一个特征被移动时,它的标签克隆会保持同步。

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/css/ol.css" type="text/css">
    <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/build/ol.js"></script>
    <style>
      html, body, .map {
        margin: 0;
        padding: 0;
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <div id="map" class="map"></div>
    <script>

var white = [255, 255, 255, 1];
var blue = [0, 153, 255, 1];
var width = 3;

var modifyStyle = new ol.style.Style({
  image: new ol.style.Circle({
    radius: width * 2,
    fill: new ol.style.Fill({
      color: blue
    }),
    stroke: new ol.style.Stroke({
      color: white,
      width: width / 2
    })
  }),
  zIndex: Infinity
});

var labelStyle = new ol.style.Style({
  text: new ol.style.Text({
    offsetY: 10,
    font: '12px Calibri,sans-serif',
    fill: new ol.style.Fill({
      color: '#000',
    }),
    stroke: new ol.style.Stroke({
      color: '#fff',
      width: 3,
    }),
    backgroundFill: new ol.style.Fill({
      color: 'rgba(0 ,0, 0, 0)',
    }),
  }),
});

var featureLayer = new ol.layer.Vector({
  source: new ol.source.Vector({
    url: 'https://mikenunn.net/data/world_cities.geojson',
    format: new ol.format.GeoJSON(),
  }),
});

var labelLayer = new ol.layer.Vector({
  source: new ol.source.Vector(),
  renderBuffer: 1e3,
  style: function (feature) {
    labelStyle.getText().setOffsetX(feature.get('offsetX') || 0);
    labelStyle.getText().setOffsetY((feature.get('offsetY') || 0) - 10);
    labelStyle.getText().setText(feature.get('CITY_NAME'));
    return labelStyle;
  },
});

featureLayer.getSource().on('addfeature', function(event) {
  var id = event.feature.getId();
  var feature = event.feature.clone();
  feature.setId(id);
  labelLayer.getSource().addFeature(feature);
});

featureLayer.getSource().on('removefeature', function(event) {
  var id = event.feature.getId();
  var source = labelLayer.getSource();
  source.removeFeature(source.getFeatureById(id));
});

var defaultStyle = new ol.interaction.Modify({
  source: featureLayer.getSource()
}).getOverlay().getStyleFunction();

var featureModify = new ol.interaction.Modify({
  source: featureLayer.getSource(),
  style: function(feature) {
    feature.get('features').forEach( function(modifyFeature) {
      var id = modifyFeature.getId();
      var geometry = feature.getGeometry().clone();
      labelLayer.getSource().getFeatureById(id).setGeometry(geometry);
    });
    return defaultStyle(feature);
  }
});

var labelModify = new ol.interaction.Modify({
  source: labelLayer.getSource(),
  hitDetection: labelLayer,
  style: function(feature) {
    var styleFeature;
    feature.get('features').forEach( function(modifyFeature) {
      var id = modifyFeature.getId();
      styleGeometry = featureLayer.getSource().getFeatureById(id).getGeometry();
    });
    modifyStyle.setGeometry(styleGeometry);
    return modifyStyle;
  }
});

labelModify.on('modifyend', function(event) {
  event.features.forEach( function(feature) {
    var id = feature.getId();
    var labelCoordinates = feature.getGeometry().getCoordinates();
    var geometry = featureLayer.getSource().getFeatureById(id).getGeometry().clone();
    var featureCoordinates = geometry.getCoordinates();
    var resolution = map.getView().getResolution();
    var offsetX = (labelCoordinates[0] - featureCoordinates[0]) / resolution + (feature.get('offsetX') || 0);
    var offsetY = (featureCoordinates[1] - labelCoordinates[1]) / resolution + (feature.get('offsetY') || 0);
    feature.set('offsetX', offsetX, true);
    feature.set('offsetY', offsetY, true);
    feature.setGeometry(geometry);
  });
});

var map = new ol.Map({
  layers: [featureLayer, labelLayer],
  interactions: ol.interaction.defaults().extend([labelModify, featureModify]),
  target: 'map',
  view: new ol.View({
    center: ol.proj.fromLonLat([5, 51]),
    zoom: 8
  })
});

    </script>
  </body>
</html>

【讨论】:

  • 这太棒了!这次真是万分感谢。我们将不得不考虑升级到 Ol6
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-26
  • 2020-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-13
相关资源
最近更新 更多