Search code examples
javascriptgoogle-maps-api-3google-street-view

Setting two properties of StreetViewPanorama causes race condition?


I'm using Street View's javascript api to open views of particular locations. I want the viewer to be both at a certain point, and facing in a certain direction, so I have this call (as in the documentation):

panorama.setOptions({
    pano: data.location.pano,
    pov: mypov
});

I think that the image fetches from fulfilling the two options must get interleaved or something, because about half the time the screen ends up a mosaic of more than one image:

Jumbled image made up of random tiles from the same location

When I comment out setPov, of course the view is facing in the wrong direction, but the overlapping image tile problem is gone. Also, as soon as the user starts a mouse drag, the street view settles on the correct image tiles and throws away the incorrect ones.

Is there any way to prevent this? Or is there an "all the images are loaded" event I can listen for, and then trigger a drag event or something?

Edit: Here is a jsfiddle demo: http://jsfiddle.net/p244m3qp/11/ In my browser, if I stretch the "result" pane as large as possible, it displays the "mosaic" behavior about 1/3 to 1/2 of the animation frames.


Solution

  • I figured out how to prevent your error. http://jsfiddle.net/wf9a5m75/p244m3qp/31/

    Key point is that preload the streetview in background.

    At the first, you need to create two panorama divs.

    <script src="http://maps.googleapis.com/maps/api/js?language=en"></script>
    <div id="err"></div>
    <div id="pv-container">
      <div id="backscreen"></div>
      <div id="map-canvas"></div>
    </div>
    

    The <div id="map-canvas"/> overlaps <div id="backscreen"/> completely with CSS.

    #pv-container {
      position: relative;
      height: 500px;
      width: 100%;
    }
    #map-canvas {
      border: solid thick #ccc;
      position: absolute;
      left: 0;
      top: 0;
      bottom: 0;
      right: 0;
    }
    #backscreen {
      position: absolute;
      left: 0;
      top: 0;
      bottom: 0;
      right: 0;
      border: solid thick red;
    }
    

    You need to change the panorama position (pano and pov) for the background first, then set to the map-canvas div. For that time, you need to change the heading (or might be pitch) of background. This generates cache images inside the Google Maps API (I guess).

    function initialize() {
      var loc = {
          lat: 38.9002138,
          lng: -77.0364319
        },
        pov = {
          heading: 180,
          pitch: -5
        },
        svService = new google.maps.StreetViewService(),
        panorama = new google.maps.StreetViewPanorama(
                document.getElementById('map-canvas')),
        backscreen = new google.maps.StreetViewPanorama(
                document.getElementById('backscreen')),
        counter = 0;
    
      function updatePano(data, status) {
        if (status === google.maps.StreetViewStatus.OK) {
            var opts = {
            pano: data.location.pano,
            pov: {heading: pov.heading + 120 * (counter % 3), pitch: pov.pitch}
          };
          backscreen.setOptions(opts);
          backscreen.changed = function(key) {
            if (key === 'status' && backscreen.get('status') === 'OK') {
              var opts2 = Object.create(opts);
              opts2.heading += 5;
                backscreen.setOptions(opts2);
              setTimeout(function() {
                    panorama.setOptions(opts);
              }, 100);
    
            }
          }
        } else {
          document.getElementById('err').textContent = "Failed to get panorama";
        }
        counter = (counter + 1) % 15;
      }
    
      setInterval(function() {
        svService.getPanorama({
          location: {
            lat: loc.lat + (counter * 0.0001),
            lng: loc.lng
          },
          radius: 35
        }, updatePano);
      }, 3000);
    
    }
    
    initialize();
    

    enter image description here

    You may be interested in what happens in the background div. Here it is: enter image description here