在模式中重复使用 Google 地图街景

Reuse a Google Maps street view inside of a modal

我正在 Rails 开发网络应用程序。当我打开一个标记时,会弹出一个模态框,其中包含一个街景视图。我可以打开一个或两个标记,但之后我收到一个错误,指出 WebGL 遇到了障碍。我试图在网上寻找资源,但没有任何意义。有关更多信息,请参见下面的图片。任何帮助将不胜感激。

First image with error

这是我的控制台日志的图像:

这是我的网络应用程序中的 JavaScript 代码。

<script type="text/javascript">
var handler = Gmaps.build('Google', {
    markers: {
        clusterer: {
            gridSize: 60,
            maxZoom: 20,
            styles: [
                {
                    textSize: 10,
                    textColor: '#ff0000',
                    url: 'assets/creative/m1.png',
                    height: 60,
                    width: 60,
                },
                {
                    textSize: 14,
                    textColor: '#ffff00',
                    url: 'assets/creative/m2.png',
                    height: 60,
                    width: 60,
                },
                {
                    textSize: 18,
                    textColor: '#0000ff',
                    url: 'assets/creative/m3.png',
                    width: 60,
                    height: 60,
                },
            ],
        },
    },
});

var handler2 = Gmaps.build('Google');
var current;
function initialize() {
    handler.buildMap({ internal: {id: 'map'} }, function () {
        markers_json = <%= raw @hash.to_json %>;
        markers = _.map(markers_json, function (marker_json) {
            marker = handler.addMarker(marker_json);
            handler.fitMapToBounds();
            _.extend(marker, marker_json);
            return marker;
        });

        getLocation();

        markers.map(function (elem, index) {
            google.maps.event.addListener(elem.getServiceObject(), 'click', function (evt) {
                var id = elem.id,
                    number = elem.number,
                    name = elem.name,
                    zipcode = elem.zipcode,
                    tabid = elem.tabid,
                    latitude = elem.latitude,
                    longitude = elem.longitude;

                $('.name').html('<h3 class=\'panel-title\'><i class=\'fa fa-id-card\'></i>' + number + '</h3>');
                $('.paneltb').html('<thead><tr><th>Panel</th><th>Location</th><th>Tab ID</th><th>Zip Code</th><th>Latitude</th><th>Longitude</th></tr></thead><tbody><tr><td>' + number + '</td><td>' + name + '</td><td>' + tabid + '</td><td>' + zipcode + '</td><td>' + latitude + '</td><td>' + longitude + '</td></tr></tbody>');

                pos = new google.maps.LatLng(latitude, longitude);

                var div = document.getElementById('map2');
                var sv = new google.maps.StreetViewPanorama(div);
                sv.setPosition(pos);
                sv.setVisible(true);

                // find the heading by looking from the google car pos to the venue pos
                var service = new google.maps.StreetViewService();
                service.getPanoramaByLocation(pos, 50, function (result, status) {
                    if (status == google.maps.StreetViewStatus.OK)
                    {
                        carPos = result.location.latLng;
                        heading = google.maps.geometry.spherical.computeHeading(carPos, pos);
                        sv.setPov({ heading: heading, pitch: 0, zoom: 1 });
                    }
                });

                $('#myModal').modal('show');
                current = elem;
            });
        });
    });
    // Create the search box and link it to the UI element.
}

function getLocation() {
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(displayOnMap);
    } else {
        navigator.geolocation.getCurrentPosition(displayOnMapError);
    }
}

function displayOnMap(position) {
    marker2 = handler.addMarker({
        lat: position.coords.latitude,
        lng: position.coords.longitude,
        picture: {
            url: "<%= asset_path 'creative/1499326997_Untitled-2-01.png' %>",
            width: 48,
            height: 48,
        },
        infowindow: 'You are Here!',
    });
    handler.map.centerOn(marker2);
    handler.getMap().setZoom(10);
}

function displayOnMapError(position) {
    marker2 = handler.addMarker({
        lat: 34.0522,
        lng: -118.2437,
        picture: {
            url: "<%= asset_path 'creative/1499326997_Untitled-2-01.png' %>",
            width: 48,
            height: 48,
        },
    });
    handler.map.centerOn(marker2);
    handler.getMap().setZoom(10);
}

initialize();
</script>

这是让模式弹出我需要的信息的原始代码。

$(".name").html("<h3 class='panel-title'><i class='fa fa-id-card'></i>"+number+"</h3>");
$(".paneltb").html("<thead><tr><th>Panel</th><th>Location</th><th>Tab ID</th><th>Zip Code</th><th>Latitude</th><th>Longitude</th></tr></thead><tbody><tr><td>"+number+"</td><td>"+ name + "</td><td>"+tabid+"</td><td>"+zipcode+"</td><td>"+latitude+"</td><td>"+longitude+"</td></tr></tbody>");

$('#myModal').modal('show');
current = elem;

为了在模式中添加街景,添加了以下代码:

pos = new google.maps.LatLng( latitude, longitude );

var div = document.getElementById('map2');
var sv = new google.maps.StreetViewPanorama(div);
sv.setPosition(pos);
sv.setVisible(true);

// find the heading by looking from the google car pos to the venue pos
var service = new google.maps.StreetViewService();
service.getPanoramaByLocation(pos, 50, function (result, status) {
    if (status == google.maps.StreetViewStatus.OK) {   
        carPos = result.location.latLng;
        heading = google.maps.geometry.spherical.computeHeading(carPos, pos);
        sv.setPov({ heading: heading, pitch: 0, zoom: 1 });
    }
});

为了将当前的纬度和经度传递到街景中,我不得不将它放在调用模态的同一函数中。

更新

我不知道如何设置 var sv = new google.maps.StreetViewPanorama(div); 所以它被设置一次并且相同的地图被调用的模态的每个实例重复使用而不是尝试启动和重新启动一个新实例。

更新 2

我不知道如何初始化这部分:

var sv = new google.maps.StreetViewPanorama(div);

因此,当我打开模式时,它不会呈现新地图,它只是重复使用同一张地图。我倾向于编写另一个函数,但我需要一些指导。

更新 3

我注意到的另一件事是,当我单击一个标记时,它会在模式中显示填充其正方形的街景。当我点击另一个时,有时它根本不会显示,但在大多数情况下,它会显示但在角落里非常小,如下图所示:

我还注意到来自 Google 地图的 class widget-scene-canvas 的代码在我点击超过不同时间的第一张地图。

这个问题实际上与 webGL 和 JS 无关(好吧有点不相关),因为我猜测每次你点击一个位置时,你都在初始化一个新的 webGL 实例并且不是重用你以前的地图(之前初始化过),这就是为什么你只能"open 1 or 2 before webGL hits a snag"。

这对浏览器来说变得异常沉重,所以它决定是时候去吃午饭了。

我猜你想做的是使用 ajax 渲染一张新地图,然后派上用场的是能够破坏之前初始化的地图,但不幸的是,Google 地图 API 没有销毁地图实例的功能(Mapbox 和其他 api 有)。但是google官方解释为:

Hi everyone,

First, apologies that we've been silent on this issue up to now.

Next, there's an easy work around, which is to reuse your Map instances. If there's a good reason why you can't do this I'd love to know.

I'm labeling this as won't fix, because this is technically difficult. We're not really sure in how many places we're leaking :-( Additionally, we'd probably need to introduce some sort of map.destroy() method. Otherwise, how are we to know whether you're planning to reuse the map? Javascript doesn't have destructors, so we can't know you've thrown away your reference to the object.

Sorry to be the bearer of bad news.

因此,您需要确保的是,您不会在每次渲染新部分时都初始化新地图。而是重用您最初初始化的那个。

你的问题在这里:

var sv = new google.maps.StreetViewPanorama(div);

而且您没有展示您如何调用弹出窗口,所以我无法真正为您建议路径。让我知道这对你是否有意义。

我发现我遇到的问题不止一个,确切地说我有三个。感谢 我能够弄清楚每次打开模态时我都需要在模态内调整我的地图大小。打开模式后放置的脚本是:

$("#myModal").on("shown.bs.modal", function () {
    google.maps.event.trigger(sv, "resize");
});  

第二个问题发生时,我注意到当我打开模式时某些位置会呈现 google 街道地图,而其他位置会呈现 google 街道地图,但它像这张图片一样是纯黑色:

我发现我需要将渲染的街道地图的缩放比例更改为 0,因为它与汽车的 pov 的缩放比例为 1,并且我的地图中的一些纬度和经度无法缩放,而其他可以而这一切都取决于 google 汽车在哪里拍照。这是代码通知,其中显示 zoom 我将其从 1 缩放更改为 0:

var service = new google.maps.StreetViewService();
        service.getPanoramaByLocation( pos, 50, function(result, status) {
            if (status == google.maps.StreetViewStatus.OK) 
            {   
                carPos = result.location.latLng;
                heading = google.maps.geometry.spherical.computeHeading( carPos, pos );
                sv.setPov( { heading: heading, pitch: 0, zoom: 0 } );
            }
        })

我需要修复的最后一件事是 webGL 遇到了一个不断弹出的障碍错误。在对我进行进一步调查后,我注意到我是在网络应用程序中还是只是在探索 google 地图,它无论如何都会弹出。通常 chrome 似乎是一个错误,所以我特别看了这篇文章 https://www.xtremerain.com/fix-rats-webgl-hit-snag-chrome/ 我按照第一个示例并从高级设置中禁用(见下文)。

Use hardware acceleration when available

之后我回去测试了地图,每个位置打开时都显示 google 街道地图,并且不再出现 webgl hit a snag 错误。

这是我的网络应用程序地图部分的最终代码:

var handler = Gmaps.build('Google', {
               markers:
                      {clusterer: {
                        gridSize: 60,
                        maxZoom: 20,
                        styles: [ {
                          textSize: 10,
                          textColor: '#ff0000',
                          url: 'assets/creative/m1.png',
                          height: 60,
                          width: 60 }
                        , {
                          textSize: 14, 
                          textColor: '#ffff00',
                          url:'assets/creative/m2.png',
                          height: 60,
                          width: 60 }
                        , {
                         textSize: 18, 
                         textColor: '#0000ff',
                         url: 'assets/creative/m3.png',
                         width: 60,
                         height: 60}
                        ]}}
            });

var current;
function initialize(){
  handler.buildMap({ internal: {id: 'map'} }, function() {

    markers_json = <%=raw @hash.to_json %>;
    markers = _.map(markers_json, function(marker_json){
      marker = handler.addMarker(marker_json);
      handler.fitMapToBounds();
      _.extend(marker, marker_json);
      return marker;
    });

    getLocation();



    markers.map(function(elem, index) {

      google.maps.event.addListener(elem.getServiceObject(), "click", function(evt) {
        var id = elem.id,
            number = elem.number,
            name = elem.name,
            zipcode = elem.zipcode,
            tabid = elem.tabid,
            latitude = elem.latitude,
            longitude = elem.longitude



         $(".name").html("<h3 class='panel-title'><i class='fa fa-id-card'></i>"+number+"</h3>")
         $(".paneltb").html("<thead><tr><th>Panel</th><th>Location</th><th>Tab ID</th><th>Zip Code</th><th>Latitude</th><th>Longitude</th></tr></thead><tbody><tr><td>"+number+"</td><td>"+ name + "</td><td>"+tabid+"</td><td>"+zipcode+"</td><td>"+latitude+"</td><td>"+longitude+"</td></tr></tbody>")


        pos = new google.maps.LatLng( latitude, longitude );
        var div = document.getElementById('map2');
        var sv = new google.maps.StreetViewPanorama(div);



        sv.setPosition( pos );
        sv.setVisible( true );

        // find the heading by looking from the google car pos to the venue pos
        var service = new google.maps.StreetViewService();
        service.getPanoramaByLocation( pos, 50, function(result, status) {
            if (status == google.maps.StreetViewStatus.OK) 
            {   
                carPos = result.location.latLng;
                heading = google.maps.geometry.spherical.computeHeading( carPos, pos );
                sv.setPov( { heading: heading, pitch: 0, zoom: 0 } );
            }
        })

        $('#myModal').modal('show')

            current = elem;

      $("#myModal").on("shown.bs.modal", function () {
    google.maps.event.trigger(sv, "resize");
});  

        });
    })
  });
    // Create the search box and link it to the UI element.


}
function getLocation(){
  if(navigator.geolocation){
    navigator.geolocation.getCurrentPosition(displayOnMap);
  }
  else{
    navigator.geolocation.getCurrentPosition(displayOnMapError);
  }
};
function displayOnMap(position){

  marker2 = handler.addMarker({
    lat: position.coords.latitude,
    lng: position.coords.longitude,
    picture: {
        url: "<%= asset_path 'creative/1499326997_Untitled-2-01.png' %>",
        width:  48,
        height: 48
        },
    infowindow:  "You are Here!"
  });
  handler.map.centerOn(marker2);
  handler.getMap().setZoom(10);
};

function displayOnMapError(position){

  marker2 = handler.addMarker({
    lat: 34.0522,
    lng: -118.2437,
    picture: {
        url: "<%= asset_path 'creative/1499326997_Untitled-2-01.png' %>",
        width:  48,
        height: 48
        }
  });
  handler.map.centerOn(marker2);
  handler.getMap().setZoom(10);
};




initialize();