forEachFeatureAtPixel 无法正常工作

forEachFeatureAtPixel does not work properly

我有以下代码, 基本上我有两层,一个 osm laryer,一个向量层,首先我使用 ol.interaction.draw 在地图上的两个随机位置单击,将两个 id 为 1 和 id 2 的特征节点添加到向量层中,然后切换到交互拖动 select 'Drag Point' (左上角),想法是当将两个节点中的任何一个拖到另一个节点上时,被拖动的节点将变成绿色节点,我可以通过拖动来做到这一点节点 id 1 到节点 id 2 很容易,但是当我尝试将节点 id 2 拖到节点 id 1 时,它需要比相反更高的精度。两个节点之间的唯一区别是节点 id 1 在节点 id 2 之前创建。 我在这里看到的问题是在 forEachFeatureAtPixel 中,当将节点 id 2 拖到节点 id 1 上时,它很少检测到(或者很少回调 return 节点 id 1)特征节点 id 1。 我在这个问题上花了很长时间。仍然无法弄清楚为什么。非常感谢任何帮助。 谢谢

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE HTML>
<html>
  <head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Draw and Modify Features</title>
    <link rel="stylesheet" href="https://openlayers.org/en/v3.20.1/css/ol.css" type="text/css">
    <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
    <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
    <script src="https://openlayers.org/en/v3.20.1/build/ol-debug.js"></script>
  </head>
  <body>
   <form class="form-inline">
        <select id="type">
        <option value="DrawPoint">Draw Point</option>
        <option value="DragPoint">Drag Point</option>
      </select>
    </form>
    <div id="map" class="map"></div>
   
   <script>
   var raster = new ol.layer.Tile({
  source: new ol.source.OSM()
 });

var map = new ol.Map({
  layers: [raster],
  target: 'map',
  view: new ol.View({
   center: [-11000000, 4600000],
   zoom: 4
  })
 });
var circle_style = new ol.style.Style({
  image: new ol.style.Circle({
   radius: 5,
   fill: new ol.style.Fill({
    color: 'rgba(255, 0, 0, 2)'
   })
  })
 });
var overlap_style = new ol.style.Style({
     image: new ol.style.Circle({
      radius: 8,
      fill: new ol.style.Fill({
       color: 'rgba(0, 255, 0, 2)'
      })
     })
    });
var features = new ol.Collection();
var featureOverlay = new ol.layer.Vector({
  source: new ol.source.Vector({
   features: features
  }),
  style: circle_style
 });
featureOverlay.setMap(map);

window.app = {};
var app = window.app;

/**
 * @constructor
 * @extends {ol.interaction.Pointer}
 */
app.Drag = function () {

 ol.interaction.Pointer.call(this, {
  handleDownEvent: app.Drag.prototype.handleDownEvent,
  handleDragEvent: app.Drag.prototype.handleDragEvent,
  handleMoveEvent: app.Drag.prototype.handleMoveEvent,
  handleUpEvent: app.Drag.prototype.handleUpEvent
 });


 this.coordinate12_ = null;

 
 this.cursor_ = 'pointer';

 
 this.feature_ = null;

 
 this.previousCursor_ = undefined;

};
ol.inherits(app.Drag, ol.interaction.Pointer);
app.Drag.prototype.handleDownEvent = function (evt) {
 var map = evt.map;
 
 var feature = map.forEachFeatureAtPixel(evt.pixel,
   function (feature, layer) {
   return feature;
  });

 if (feature) {
  console.log("down: node_id: " + feature.getProperties()['id']);
  this.coordinate12_ = evt.coordinate;
  this.feature_ = feature;
 }

 return !!feature;
};

app.Drag.prototype.handleDragEvent = function (evt) {

 var map = evt.map;
 fs = featureOverlay.getSource().getFeatures();
 
 var feature = map.forEachFeatureAtPixel(evt.pixel,
   function (feature, layer) {
   return feature;
  });
 
 if (!(feature === undefined)) {
  console.log("drag: node_id: " + feature.getProperties()['id']);
  // console.log("this:" + this.feature_.getId()+ " o: " +  feature.getId());
  if (this.feature_.getProperties()['id'] != feature.getProperties()['id']) {
   console.log("green: node_id: " + feature.getProperties()['id']);
   this.feature_.setStyle(overlap_style);
  } else {
   this.feature_.setStyle(circle_style);
  }
 }

 var deltaX = evt.coordinate[0] - this.coordinate12_[0];
 var deltaY = evt.coordinate[1] - this.coordinate12_[1];

 var geometry = /** @type {ol.geom.SimpleGeometry} */
  (this.feature_.getGeometry());
 geometry.translate(deltaX, deltaY);

 this.coordinate12_[0] = evt.coordinate[0];
 this.coordinate12_[1] = evt.coordinate[1];
};
app.Drag.prototype.handleMoveEvent = function (evt) {
 if (this.cursor_) {
  var map = evt.map;
  var feature = map.forEachFeatureAtPixel(evt.pixel,
    function (feature, layer) {
    if (this.feature_ != null) 
    {
     console.log("move forEachFeatureAtPixel: node_id: " + feature.getProperties()['id']);
    }
    return feature;
   });
  var element = evt.map.getTargetElement();
  if (feature) {
      if (this.feature_ != null) 
    {
     console.log("move forEachFeatureAtPixel: node_id: " + feature.getProperties()['id']);
    }
   if (element.style.cursor != this.cursor_) {
    this.previousCursor_ = element.style.cursor;
    element.style.cursor = this.cursor_;
   }
  } else if (this.previousCursor_ !== undefined) {
   element.style.cursor = this.previousCursor_;
   this.previousCursor_ = undefined;
  }
 }
};

/**
 * @param {ol.MapBrowserEvent} evt Map browser event.
 * @return {boolean} `false` to stop the drag sequence.
 */
app.Drag.prototype.handleUpEvent = function (evt) {
 this.coordinate12_ = null;
 this.feature_ = null;
 return false;
};
var draw = new ol.interaction.Draw({
  features: features,
  type: ('Point')
 });
var drag = new app.Drag();
var id_count = 0;
draw.on('drawend', function(e) {
  e.feature.setProperties({
    'id': ++id_count
  })
  console.log(e.feature, e.feature.getProperties());
});
map.addInteraction(draw);

var typeSelect = document.getElementById('type');
typeSelect.value = 'DrawPoint';
typeSelect.onchange = function () {
 if (typeSelect.value == 'DrawPoint')
 {
  map.removeInteraction(drag);
  map.addInteraction(draw);
 }else
 {
  map.removeInteraction(draw);
  map.addInteraction(drag);
 }
};
   </script>
  </body>
</html>

防止正在移动的特征(第一个或第二个)从 map.forEachFeatureAtPixel 方法返回。 请参阅下面的工作代码片段。

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE HTML>
<html>
  <head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Draw and Modify Features</title>
    <link rel="stylesheet" href="https://openlayers.org/en/v3.20.1/css/ol.css" type="text/css">
    <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
    <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
    <script src="https://openlayers.org/en/v3.20.1/build/ol-debug.js"></script>
  </head>
  <body>
   <form class="form-inline">
        <select id="type">
        <option value="DrawPoint">Draw Point</option>
        <option value="DragPoint">Drag Point</option>
      </select>
    </form>
    <div id="map" class="map"></div>
   
   <script>
    var raster = new ol.layer.Tile({
  source: new ol.source.OSM()
 });

 var map = new ol.Map({
  layers: [raster],
  target: 'map',
  view: new ol.View({
   center: [-11000000, 4600000],
   zoom: 4
  })
 });
 var circle_style = new ol.style.Style({
  image: new ol.style.Circle({
   radius: 5,
   fill: new ol.style.Fill({
    color: 'rgba(255, 0, 0, 2)'
   })
  })
 });
 
 var overlap_style = new ol.style.Style({
  image: new ol.style.Circle({
   radius: 8,
   fill: new ol.style.Fill({
    color: 'rgba(0, 255, 0, 2)'
   })
  })
 });
 var features = new ol.Collection();
 var featureOverlay = new ol.layer.Vector({
  source: new ol.source.Vector({
   features: features
  }),
  style: circle_style
 });
 featureOverlay.setMap(map);

 window.app = {};
 var app = window.app;

 /**
  * @constructor
  * @extends {ol.interaction.Pointer}
  */
 var dragFeature;
 app.Drag = function () {

  ol.interaction.Pointer.call(this, {
   handleDownEvent: app.Drag.prototype.handleDownEvent,
   handleDragEvent: app.Drag.prototype.handleDragEvent,
   handleMoveEvent: app.Drag.prototype.handleMoveEvent,
   handleUpEvent: app.Drag.prototype.handleUpEvent
  });


  this.coordinate12_ = null;
  this.cursor_ = 'pointer';
  this.previousCursor_ = undefined;

 };
 ol.inherits(app.Drag, ol.interaction.Pointer);
 app.Drag.prototype.handleDownEvent = function (evt) {
  var map = evt.map;
  
  var feature = map.forEachFeatureAtPixel(evt.pixel,
    function (feature, layer) {
    return feature;
   });

  if (feature) {
   //console.log("down: node_id: " + feature.getProperties()['id']);
   this.coordinate12_ = evt.coordinate;
   //this.feature_ = feature;
   dragFeature = feature;
  }

  return !!feature;
 };

 app.Drag.prototype.handleDragEvent = function (evt) {

  var map = evt.map;
  fs = featureOverlay.getSource().getFeatures();
  
  // Filter the feature 
  var feature = map.forEachFeatureAtPixel(evt.pixel,
    function (feature, layer) {
    if ( feature.getProperties()['id'] != dragFeature.getProperties()['id'] ) {
     return feature;
    }
   });
  
  if (!(feature === undefined)) {
   console.log("------------------- drag: node_id: " + feature.getProperties()['id']);
   // console.log("this:" + this.feature_.getId()+ " o: " +  feature.getId());
   if (dragFeature.getProperties()['id'] != feature.getProperties()['id']) {
    console.log("green: node_id: " + feature.getProperties()['id']);
    dragFeature.setStyle(overlap_style);
   }
  }
  else {
    dragFeature.setStyle(circle_style);
   }

  var deltaX = evt.coordinate[0] - this.coordinate12_[0];
  var deltaY = evt.coordinate[1] - this.coordinate12_[1];

  var geometry = /** @type {ol.geom.SimpleGeometry} */
   (dragFeature.getGeometry());
  geometry.translate(deltaX, deltaY);

  this.coordinate12_[0] = evt.coordinate[0];
  this.coordinate12_[1] = evt.coordinate[1];
 };
 app.Drag.prototype.handleMoveEvent = function (evt) {
  if (this.cursor_) {
   var map = evt.map;
   var feature = map.forEachFeatureAtPixel(evt.pixel,
     function (feature, layer) {
     if (dragFeature != null) 
     {
      //console.log("move forEachFeatureAtPixel: node_id: " + feature.getProperties()['id']);
     }
     return feature;
    });
   var element = evt.map.getTargetElement();
   if (feature) {
    if (dragFeature != null) 
     {
      //console.log("move forEachFeatureAtPixel: node_id: " + feature.getProperties()['id']);
     }
    if (element.style.cursor != this.cursor_) {
     this.previousCursor_ = element.style.cursor;
     element.style.cursor = this.cursor_;
    }
   } else if (this.previousCursor_ !== undefined) {
    element.style.cursor = this.previousCursor_;
    this.previousCursor_ = undefined;
   }
  }
 };

 /**
  * @param {ol.MapBrowserEvent} evt Map browser event.
  * @return {boolean} `false` to stop the drag sequence.
  */
 app.Drag.prototype.handleUpEvent = function (evt) {
  this.coordinate12_ = null;
  //this.feature_ = null;
  dragFeature = null;
  return false;
 };
 var draw = new ol.interaction.Draw({
   features: features,
   type: ('Point')
  });
 var drag = new app.Drag();
 var id_count = 0;
 draw.on('drawend', function(e) {
   e.feature.setProperties({
  'id': ++id_count
   })
   //console.log(e.feature, e.feature.getProperties());
 });
 map.addInteraction(draw);

 var typeSelect = document.getElementById('type');
 typeSelect.value = 'DrawPoint';
 typeSelect.onchange = function () {
  if (typeSelect.value == 'DrawPoint')
  {
   map.removeInteraction(drag);
   map.addInteraction(draw);
  }else
  {
   map.removeInteraction(draw);
   map.addInteraction(drag);
  }
 };
   </script>
  </body>
</html>