簡體   English   中英

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

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

使用Google地球插件,我希望能夠允許用戶在相機移動時選擇地面上的地標,但我不確定這是如何實現的。 看來當你調用setAbstractView()時,即使flyToSpeed設置為SPEED_TELEPORT,Google Earth插件也會忽略除GEGlobe之外的所有鼠標按下事件。

這是代碼,略有改動(來自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) {
}

如果你注釋掉第56行,其中每個frameend都調用了tick(),那么一切都與未改變的代碼一樣:你可以成功地拖動地點標記。 但是當第56行進入時,你不能。 所以問題實際上是使用setAbstractView保持mousedown事件不會傳播到地球或任何地標或功能被點擊。

有任何想法嗎? 這有解決方法嗎?

問題不是由setAbstractView方法引起的,而是由於通過framend重復調用tick方法framend

為了解釋,您已將tick方法設置為frameend事件的事件處理程序。 然后tick方法立即更新視圖,觸發frameend事件,無限制地...

此模式導致瀏覽器消息循環出現問題,實際上它阻止了其他拖動事件。 可以把它想象成一個導致死鎖的非常緊湊的循環。 要使用它,您可以使用值為0的setTimeout來執行代碼。 這樣,在處理完所有其他待處理的拖動消息之前,不會處理動畫。

關鍵部分是對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);
};

在這里,我為你做了一個完整的例子http://jsfiddle.net/fraser/JFLaT/

我測試了它,它在Windows 8上的Chrome,IE,Firefox和OSX上的Chrome,Safari,Firefox上運行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM