设置 StreetViewPanorama 的两个属性会导致竞争条件?

Setting two properties of StreetViewPanorama causes race condition?

我正在使用街景视图的 javascript api 打开特定位置的视图。我希望观众既在某个点,又面向某个方向,所以我有这个调用(如 documentation):

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

我认为从满足这两个选项中获取的图像必须交错或类似的东西,因为大约一半的时间屏幕最终会变成一张以上图像的马赛克:

当我注释掉setPov时,当然视图朝向错误的方向,但是重叠图像块的问题已经消失。此外,只要用户开始拖动鼠标,街景就会选择正确的图像块并丢弃不正确的图像块。

有什么办法可以避免这种情况吗?或者有没有我可以监听的 "all the images are loaded" 事件,然后触发拖动事件什么的?

编辑:这是一个 jsfiddle 演示:http://jsfiddle.net/p244m3qp/11/ 在我的浏览器中,如果我尽可能大地拉伸 "result" 窗格,它会显示大约 1/3 到 1/2 动画帧的 "mosaic" 行为。

我想出了如何防止你的错误。 http://jsfiddle.net/wf9a5m75/p244m3qp/31/

重点是在后台预加载街景。

首先,您需要创建两个全景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>

与 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;
}

您需要先更改背景的全景位置(pano 和 pov),然后设置为 map-canvas div。 那时,您需要更改背景的标题(或可能是间距)。 这会在 Google 地图 API 中生成缓存图像(我猜)。

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();

您可能对后台发生的事情感兴趣 div。 这里是:

@wf9a5m75 的回答对我来说不太有用,但它引导我朝着正确的方向前进,这最终在 Chrome 中起作用:我替换了单个调用

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

有两个强制串行调用:

panorama.setPano(pano);
panorama.changed = function(key) {
    if (key === 'status') {
        // Just listen once!
        panorama.changed = function() {};
        panorama.setPov(mypov);
   }
};

所以加载需要两倍的时间,但至少它看起来并不可怕......

编辑: 看起来这是一个 known bug - 看起来你可以减少竞争条件的命中率,但不能真正阻止它。 :(