简体   繁体   English

setAbstractView()可防止mousedown事件传播到KmlFeatures

[英]setAbstractView() prevents mousedown events from propagating to KmlFeatures

Using the Google Earth plugin, I want to be able to allow the user to select placemarks on the ground while the camera is moving, but am not sure how this is possible. 使用Google地球插件,我希望能够允许用户在相机移动时选择地面上的地标,但我不确定这是如何实现的。 It seems that when you call setAbstractView(), even with the flyToSpeed set to SPEED_TELEPORT, the Google Earth plugin ignores any mouse down events except for those to the GEGlobe. 看来当你调用setAbstractView()时,即使flyToSpeed设置为SPEED_TELEPORT,Google Earth插件也会忽略除GEGlobe之外的所有鼠标按下事件。

Here's the code, altered slightly (from http://code.google.com/apis/ajax/playground/#draggable_placemark ) to illustrate my issue: 这是代码,略有改动(来自http://code.google.com/apis/ajax/playground/#draggable_placemark )来说明我的问题:

var ge;

var placemark;
var dragInfo = null;
var la;
var lat = 37;
var lon = -122;

google.load("earth", "1");

function init() {
  google.earth.createInstance('map3d', initCallback, failureCallback);
}

function tick() {
  la.set(lat, lon,
    0, // altitude
    ge.ALTITUDE_RELATIVE_TO_GROUND,
    0, // heading
    0, // straight-down tilt
    5000 // range (inverse of zoom)
    );
  ge.getView().setAbstractView(la);
  lon = lon + 0.00000001;
}

function initCallback(instance) {
  ge = instance;
  ge.getWindow().setVisibility(true);

  // add a navigation control
  ge.getNavigationControl().setVisibility(ge.VISIBILITY_AUTO);

  // add some layers
  ge.getLayerRoot().enableLayerById(ge.LAYER_BORDERS, true);
  ge.getLayerRoot().enableLayerById(ge.LAYER_ROADS, true);

  // create the placemark
  placemark = ge.createPlacemark('');

  var point = ge.createPoint('');
  point.setLatitude(lat);
  point.setLongitude(lon);
  placemark.setGeometry(point);

  // add the placemark to the earth DOM
  ge.getFeatures().appendChild(placemark);

  // look at the placemark we created
  la = ge.createLookAt('');
  placemark.setName('Drag Me!');
  ge.getOptions().setFlyToSpeed(ge.SPEED_TELEPORT);
  tick();

  // Comment this next line out and the drag works as expected.
  google.earth.addEventListener(ge, "frameend", tick);

  // listen for mousedown on the window (look specifically for point placemarks)
  google.earth.addEventListener(ge.getWindow(), 'mousedown', function(event) {
    console.log("target type = " + event.getTarget().getType());
    if (event.getTarget().getType() == 'KmlPlacemark' &&
        event.getTarget().getGeometry().getType() == 'KmlPoint') {
      //event.preventDefault();
      var placemark = event.getTarget();

      dragInfo = {
        placemark: event.getTarget(),
        dragged: false
      };
    }
  });

  // listen for mousemove on the globe
  google.earth.addEventListener(ge.getGlobe(), 'mousemove', function(event) {
    if (dragInfo) {
      event.preventDefault();
      var point = dragInfo.placemark.getGeometry();
      point.setLatitude(event.getLatitude());
      point.setLongitude(event.getLongitude());
      dragInfo.dragged = true;
    }
  });

  // listen for mouseup on the window
  google.earth.addEventListener(ge.getWindow(), 'mouseup', function(event) {
    if (dragInfo) {
      if (dragInfo.dragged) {
        // if the placemark was dragged, prevent balloons from popping up
        event.preventDefault();
      }

      dragInfo = null;
    }
  });

  document.getElementById('installed-plugin-version').innerHTML =
    ge.getPluginVersion().toString();
}

function failureCallback(errorCode) {
}

​ If you comment out line 56, where tick() is called at each frameend, everything works as in the unaltered code: you can successfully drag the place mark. 如果你注释掉第56行,其中每个frameend都调用了tick(),那么一切都与未改变的代码一样:你可以成功地拖动地点标记。 But when line 56 is in, you can't. 但是当第56行进入时,你不能。 So the problem is really with setAbstractView keeping mousedown events from propagating to either the globe or whatever placemark or feature was being clicked. 所以问题实际上是使用setAbstractView保持mousedown事件不会传播到地球或任何地标或功能被点击。

Any ideas? 有任何想法吗? Is there a workaround for this? 这有解决方法吗?

The issue isn't caused by the setAbstractView method, it is caused because of the repeated calls to the tick method via framend . 问题不是由setAbstractView方法引起的,而是由于通过framend重复调用tick方法framend

To explain, you have set up the tick method as an event handler for the frameend event. 为了解释,您已将tick方法设置为frameend事件的事件处理程序。 Then the tick method updates the view immediately, triggering the frameend event, ad infinitum ... 然后tick方法立即更新视图,触发frameend事件,无限制地...

This pattern causes an issue with the browser message loop, in effect it is blocking the other drag events. 此模式导致浏览器消息循环出现问题,实际上它阻止了其他拖动事件。 Think of it like a very tight loop that is causing a deadlock. 可以把它想象成一个导致死锁的非常紧凑的循环。 To work it you can use setTimeout with a value of 0 to execute the code. 要使用它,您可以使用值为0的setTimeout来执行代码。 This way the animation won't be processed until all other pending drag messages are processed. 这样,在处理完所有其他待处理的拖动消息之前,不会处理动画。

The key part is a the modification to your tick() method. 关键部分是对tick()方法的修改。

function tick() {
  // prevent deadlock
  setTimeout(function () {
    la.set(lat, lon, 0, ge.ALTITUDE_RELATIVE_TO_GROUND, 0, 0, 5000);
    ge.getView().setAbstractView(la);
    lon += 0.00001;
  }, 0);
};

Here, I made a fully working example for you http://jsfiddle.net/fraser/JFLaT/ 在这里,我为你做了一个完整的例子http://jsfiddle.net/fraser/JFLaT/

I tested it and it is working in Chrome, IE, Firefox on Windows 8 and Chrome, Safari, Firefox on OSX. 我测试了它,它在Windows 8上的Chrome,IE,Firefox和OSX上的Chrome,Safari,Firefox上运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM