Using google street view with a marker, how do I point the POV at a marker?
Asked Answered
D

3

8

I have a simple street view working to show me a street view given an address:

var geocoder = new google.maps.Geocoder();
var address = "344 Laguna Dr, Milpitas, CA  95035";
geocoder.geocode( { 'address': address}, 
    function(results, status) {
        //alert (results);
    if (status == google.maps.GeocoderStatus.OK) {
        //alert(results[0].geometry.location);
        myStreetView = new google.maps.StreetViewPanorama(document.getElementById("map_canvas"));
        myStreetView.setPosition(results[0].geometry.location);
        var marker = new google.maps.Marker({
            position: results[0].geometry.location, 
            map: myStreetView, 
            title:address
        });
        //alert ("yay");
    } else {
        alert("Geocode was not successful for the following reason: " + status);
    }
});

As you can see, I add a marker for the address onto the street view. My question is, the street view is pointing north, and the marker is to the south. For a non-specific address, how do I designate that the street view should point at the marker for the address instead of pointing north by default?

Demonize answered 7/7, 2010 at 20:9 Comment(0)
M
4

The reason for this is that the street view POV is, by default the direction the truck was facing when the image was shot (go figure). You need to get the location of the truck and the location of the house and calculate a "heading" from the first location to the second, then set your street-view location to that of the truck with the heading you just calculated:

// adrloc=target address
// svwloc=street-view truck location
svwService.getPanoramaByLocation(adrloc,svwdst,function(dta,sts) {
    if(sts==google.maps.StreetViewStatus.OK) {
        var svwloc=dta.location.latLng;
        var svwhdg=google.maps.geometry.spherical.computeHeading(svwloc,adrloc);
        var svwmap=avwMap.getStreetView();
        svwmap.setPosition(svwloc);
        svwmap.setPov({ heading: svwhdg, pitch: 0 });
        svwMarker=new google.maps.Marker({ map:svwmap, position: adrloc });
        svwmap.setVisible(true);
        }
    else {
        ...
        }

Another trick/trap using street view is that you need to obtain the closest street view to your address location by repeatedly calling getPanoramaByLocation with an increasing distance until you are either successful or reach some maximum distance. I solve this using this code:

var SVW_MAX=100; // maximum street-view distance in meters
var SVW_INC=10;  // increment street-view distance in meters
var svwService=new google.maps.StreetViewService(); // street view service
var svwMarker=null; // street view marker

// NOTE: avwMap is the aerial view map, code not shown
...
resolveStreetView(avwMap.getCenter(),SVW_INC); 
...

var resolveStreetView=function(adrloc,svwdst) {
    svwService.getPanoramaByLocation(adrloc,svwdst,function(dta,sts) {
        if(sts==google.maps.StreetViewStatus.OK) {
            var svwloc=dta.location.latLng;
            var svwhdg=google.maps.geometry.spherical.computeHeading(svwloc,adrloc);
            var svwmap=avwMap.getStreetView();
            svwmap.setPosition(svwloc);
            svwmap.setPov({ heading: svwhdg, pitch: 0 });
            svwMarker=new google.maps.Marker({ map:svwmap, position: adrloc });
            svwmap.setVisible(true);
            }
        else if(svwdst<SVW_MAX) {
            resolveStreetView(adrloc,svwdst+SVW_INC);
            }
        });
    }
Merkle answered 3/10, 2013 at 0:38 Comment(0)
B
3

Check out this sample. Even though its for V2, you can reuse the code. Basically, you'll need to call computeAngle(markerLatLng, streetviewPanoLatLng), and set the Street View pano's yaw to the returned value.

function computeAngle(endLatLng, startLatLng) {
  var DEGREE_PER_RADIAN = 57.2957795;
  var RADIAN_PER_DEGREE = 0.017453;

  var dlat = endLatLng.lat() - startLatLng.lat();
  var dlng = endLatLng.lng() - startLatLng.lng();
  // We multiply dlng with cos(endLat), since the two points are very closeby,
  // so we assume their cos values are approximately equal.
  var yaw = Math.atan2(dlng * Math.cos(endLatLng.lat() * RADIAN_PER_DEGREE), dlat)
         * DEGREE_PER_RADIAN;
  return wrapAngle(yaw);
}

function wrapAngle(angle) {
  if (angle >= 360) {
    angle -= 360;
  } else if (angle < 0) {
    angle += 360;
  }
  return angle;
 }
Bodhisattva answered 8/7, 2010 at 23:28 Comment(2)
Having same problem here. This answer does work in the linked example, but doesn't solve the OP's problem. Both marker and panorama are set to exactly same position (results[0].geometry.location), so computeAngle always returns 0. Yet on the actual panorama, the marker is displayed not exactly where the camera is (which is in the middle of the road), but on a side of the road, against an actual building.Deuteronomy
This was also asked here: groups.google.com/group/google-maps-js-api-v3/browse_thread/… with an answer pointing to a working example at: geoapis.appspot.com/agdnZW9hcGlzchMLEgtFeGFtcGxlQ29kZRjRiQIMChanell
M
2

Simple example based off your code:

  1. get the location to look at (using the geocoder)
  2. get the location of the StreetViewPanorama (using the getLocation() method once its status has changed, alternative would be to use the results of the getPosition() method).
  3. use the computeHeading method of the geometry library to compute the heading from the camera to the address.
  4. set that heading using the setPov() method.
  5. delay so the marker goes to the correct place (removing this leaves the marker in the upper left hand corner). Not needed if not using markers.
function geocodeAddress() {
  var address = "344 Laguna Dr, Milpitas, CA  95035";
  geocoder.geocode({
    'address': address
  }, function(results, status) {
    //alert (results);
    if (status == google.maps.GeocoderStatus.OK) {
      //alert(results[0].geometry.location);
      myStreetView = new google.maps.StreetViewPanorama(document.getElementById("map_canvas"));
      myStreetView.setPosition(results[0].geometry.location);
      google.maps.event.addListenerOnce(myStreetView, 'status_changed', function() {
        var heading = google.maps.geometry.spherical.computeHeading(myStreetView.getLocation().latLng, results[0].geometry.location);
        myStreetView.setPov({
          heading: heading,
          pitch: 0
        });
        setTimeout(function() {
          marker = new google.maps.Marker({
            position: results[0].geometry.location,
            map: myStreetView,
            title: address
          });
          if (marker && marker.setMap) marker.setMap(myStreetView);
        }, 500);
      });

    } else {
      alert("Geocode was not successful for the following reason: " + status);
    }
  });
  google.maps.event.addDomListener(document.getElementById('geoBtn'), 'click', geocodeAddress);
}

working fiddle

working code snippet:

var geocoder = new google.maps.Geocoder();
var myStreetView = null;
var marker = null;

function geocodeAddress() {
  // var address = "344 Laguna Dr, Milpitas, CA  95035";
  var address = document.getElementById('address').value;
  geocoder.geocode({
    'address': address
  }, function(results, status) {
    //alert (results);
    if (status == google.maps.GeocoderStatus.OK) {
      //alert(results[0].geometry.location);
      myStreetView = new google.maps.StreetViewPanorama(document.getElementById("map_canvas"));
      myStreetView.setPosition(results[0].geometry.location);
      google.maps.event.addListenerOnce(myStreetView, 'status_changed', function() {
        var heading = google.maps.geometry.spherical.computeHeading(myStreetView.getLocation().latLng, results[0].geometry.location);
        myStreetView.setPov({
          heading: heading,
          pitch: 0
        });
        setTimeout(function() {
          marker = new google.maps.Marker({
            position: results[0].geometry.location,
            map: myStreetView,
            title: address
          });
          if (marker && marker.setMap) marker.setMap(myStreetView);
        }, 500);
      });

    } else {
      alert("Geocode was not successful for the following reason: " + status);
    }
  });
  google.maps.event.addDomListener(document.getElementById('geoBtn'), 'click', geocodeAddress);
}
google.maps.event.addDomListener(window, 'load', geocodeAddress);
html,
body,
#map_canvas {
  height: 100%;
  width: 100%;
}
<script src="http://maps.google.com/maps/api/js?libraries=geometry&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<input id="address" type="text" value="344 Laguna Dr, Milpitas, CA  95035" />
<input id="geoBtn" type="button" value="Go" />
<div id="map_canvas"></div>
Medea answered 27/12, 2014 at 2:25 Comment(4)
Thanks, this mostly worked for me except both arguments to geometry.spherical.computeHeading need to be instances of LatLng. myStreetView.getLocation().latLng returns a LatLng instance, but you also need to create a new instance from your location, new google.maps.LatLng(results[0].geometry.location).Bituminous
results[0].geometry.location is also already a google.maps.LatLng objectMedea
Yes you're right, if you're using the geocoder library to get the location it returns a LatLng. I was directly hitting the geocode api endpoint when I wrote that comment, but have since switched to using the geocoder.Bituminous
The answer is using the geocoder library, not the web service.Medea

© 2022 - 2024 — McMap. All rights reserved.