Flying around with Google Earth

javaScript: Flying around and asynchronicity in  google Earth  get it now

This relates to Data Driven Mapping applications and the javaScript 'howTo' section.

Flying around a marker and the complications of asynchronicity

Most of the things in Google Earth happen asynchronously. That means that handling events and time outs is a fairly signifcant task when working with Earth.  The VizMap applications provide the capability of flying round a spot. Flying is halted by clicking on the marker. This means dealing with the 'frameend' event, to control the smooth animation to the next viewpoint, and 'viewchangeend' so as to wait for the display to settle down before plotting balloons.  In addition, I found that setting event listeners with the method of a custom object as the handler didn't work (I never found out why),  and I also discovered that firefox cannot handle (without crashing) changing a Dom element while it is still dealing with an information balloon (IE and Chrome seemed very happy with it).

Here is the Royal Family application in the middle of flying around Buckingham Palace. The flying is to stop when the queen's picture is clicked. This also needs to return the viewing range to the default height, and to bring up the info balloon for this spot.


Walkthrough

Flying around is initialized as follows. We need to change the viewing range, remove any balloons on the screen and handle the 'framend' event. frameend is fired at the end of the animated sequence that will be caused by mcpherFly(spot).
 mcpherSpot.prototype.initFlyAround = function() {
  var spot = this;
  // been asked to rotate around the spot
  if (!spot.flying) {
   var vm = spot.parent;
   var ve = vm.ve;
   var ge = ve.ge;
   spot.flying = true;
   ge.setBalloon(null);
   spot.lookAt.setRange(parseFloat(vm.control.flyrange)); 
   ge.getOptions().setFlyToSpeed(parseFloat(vm.control.flyspeed));
   spot.initialLookAtHeading = spot.lookAt.getHeading();
   google.earth.addEventListener(ge, 'frameend', 
     function () { mcpherFly(spot); });
   vm.statusUpdate('..flying around '+spot.title,true);
   mcpherFly(spot);
  }  
 }
spot.fly needs to adjust the heading (the compass direction we are looking at the spot from). This will cause the view to rotate (asynchronously),  and the handler for frameend we set up previously will kick us back here when done. 
 function mcpherFly(spot){
  // whats the point of this?
  // seems that i can't addevent listener of spot.fly directly...
  spot.fly();
 }
 mcpherSpot.prototype.fly = function() { 
  // changing the heading and re- do
  var spot = this;
  if (spot.flying){
   var vm = spot.parent;
   var ve=vm.ve;
   var ge = ve.ge;
   var newHeading = spot.lookAt.getHeading() + 
   parseFloat(vm.control.flyincrement);
   if (newHeading > 360) {
    newHeading -= 360;
   }
   spot.lookAt.setHeading(newHeading);
   ve.showLookAt(spot);

  }
  return (spot.flying);
 }
We already have an event handler set up to deal with clicking on the marker. 
   google.earth.addEventListener(spot.placemark, 'click', 
     function(e)  { mcpherClicks(e,spot,false); } );
We are going to also handle stopping flying around in that same handler. If there is some flying going on, we need to stop it, and then set up another handler to work on the clicks after everything caused by the flying has settled down. Dealing with click versus double click is explained in  Click events in Google Earth. Note the use of preventDefault to stop Earth reacting to a click with its own default behavior.
 function mcpherClicks(e,spot,plot){
  
  if(e.preventDefault)e.preventDefault();
  if(e.stopPropagation)e.stopPropagation();
  if (spot.flying){
   var ge = spot.parent.ve.ge;
   spot.stopFlyAround();
   google.earth.addEventListener(ge.getView(), 
     'viewchangeend', mcpherFlyingClicks(spot,plot));
  }
  else {
   spot.dealWithClicks(plot);
  }
 }
According to the Google Earth API documentation, the 'viewchangeend' event is not a reliable indicator that everything is absolutely over, so it recommends waiting a bit till there are no more of these events fired. When the timeout eventually executes below, we know that the flying has subsided, so we can move to deal with the clicks. 
 function mcpherFlyingClicks(spot,plot){
  var vm = spot.parent;
  var ge = vm.ve.ge;
  if(spot.timer) clearTimeout(spot.timer);
     spot.timer = setTimeout( function(){
         spot.dealWithClicks(plot);
         }, 100);
 }

There is a similar problem to deal with when handling the plotting of balloons. This is explained in Creating a tabbed Google Mapping InfoWindow
Comments