StreetView any address !!!

I've just received a request from a user to allow him to see the Google StreetView of our clients in out Client forms. This will be useful specially for delivery cases, allowing the team to know how the street looks like, and to better plan the deliveries of merchandises.

I found several samples, but all of them needed the GPS coordinates, the Latitude and Longitude to make it work.

After making some researches, I've found the solution in the JAYCODE DESIGN blog, from Jordan Clist.

"Everyone loves the streetview service that Google maps provides. Naturally the Google API provides the ability to embed streetview within a web application if you feed it the right data and co-ordinates.

What it doesn't do naturally and easily is automatically point the streetview camera an address.
This is something that I thought would be simple but was actually more difficult than it sounds.

Although it is fairly simple to create a streetview panorama at a given GPS point, what is more complicated is to ensure that the streetview camera is pointing in the correct direction (point of view, or yaw)."

Making it work was a little bit tricky, because the original sample provided worked only with some addresses already known by Google. That made it to fail in most cases, because of the spellings, or even a comma put in the wrong place.

So I used another Google Maps API, the "Google Maps Directions API", that is originally used to tell us the routes that we can take between 2 directions. This API works very well with not so well formatted directions, and returns Google's version of the direction.
I adapted a sample Mike Gagnon, from his article published at http://atoutfox.org "Calculer la distance entre 2 adresses, et montrer l'itineraire complet"
After getting this direction, I pass it to the Script from Jordan Clist and Voila!
It works!!!

Copy and paste the codes below, and save it to a PRG and call it "GOOGLESTREETVIEW.PRG"

And to test it, type in your command window"

=GoogleStreetView("Arche du Triumph")

or of course passing the full address:

=GoogleStreetView("Place Charles de Gaulle, 75008, Paris, France")

Cool isn't it? 

Now, just adapt the codes from the PRG to fit your needs. You may show the HTML in your forms using the WebBrowser control. Some other simple changes could be applied by just changing the Zoom values, and the Frame sizes.

Download VFPGoogleStreetView.prg from here

* Author: Cesar VFPIMAGING - www.vfpimaging.blogspot.com
* Description:
* Gets GoogleMaps full address, from the destination variable filled with the most complete info
* Creates a HTML / AJAX
* Thanks to Jordan Clist, code adapted from the one he posted in his blog:
* http://www.jaycodesign.co.nz/js/using-google-maps-to-show-a-streetview-of-a-house-based-on-an-address/
* Thanks to Mike Gagnon for his article published at http://atoutfox.org/articles.asp?ACTION=FCONSULTER&ID=0000000807
* "Calculer la distance entre 2 adresses, et montrer l'itineraire complet"

LPARAMETERS tcDestination

LOCAL lcFullURL, lcResponse, lcRouteParameters
tcDestination          = EVL(tcDestination, "")

lcRouteParameters = "origin=" + STRTRAN(UPPER(ALLTRIM(tcDestination)), " ", "%20") + ;
    "&destination=" + STRTRAN(UPPER(ALLTRIM(tcDestination)), " ", "%20")

* Documentation at http://code.google.com/apis/maps/documentation/directions/)

* Build up the full URL with the required parameters
lcFullURL = "http://maps.googleapis.com/maps/api/directions/xml?" + lcRouteParameters + ;

* Test with all MSXML Versions
* Can also apply the info from http://support.microsoft.com/kb/278674/en-us
* to determine what version of MSXML is installed in the machine
    loXML = CREATEOBJECT("MSXML2.ServerXMLHTTP.4.0") && Could use version 3.0, 4.0, 5.0, 6.0
        loXML = CREATEOBJECT("MSXML2.ServerXMLHTTP.3.0")
            loXML = CREATEOBJECT("MSXML2.ServerXMLHTTP.5.0")
                loXML = CREATEOBJECT("MSXML2.ServerXMLHTTP.6.0")

loXML.OPEN("POST", lcFullURL, .F.)
loXML.SetRequestHeader("Content-Type", "application/xml")
lcResponse = loXML.ResponseText

LOCAL lcAddress, lcHTML
lcAddress = STREXTRACT(lcResponse, "<end_address>", "</end_address>")

<!DOCTYPE html>
     body {
          font-family: helvetica;
     .map_container {
          width: 800px;
     #map_canvas_cont, #pano_cont {
          float: left;
          width: 750px;
          height: 400px;
          margin: 20px;

     #pano, #map_canvas {
          width: 100%;
          height: 100%;

<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&region=us"></script>

          <div class="map_container">

          <div id="pano_cont">
                    <div id="pano"></div>

     <div id="map_canvas_cont">
                    <div id="map_canvas"></div>
     <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>

          var panorama;
          var addLatLng;
          var showPanoData;
          var panorama;

          function load_map_and_street_view_from_address(address) {
             // Check if GPS has been locally cached.
               var geocoder = new google.maps.Geocoder();
               console.log("new geocoder");
               geocoder.geocode( { 'address': address}, function(results, status) {
                   if (status == google.maps.GeocoderStatus.OK) {

                         var gps = results[0].geometry.location;
                         create_map_and_streetview(gps.lat(), gps.lng(), 'map_canvas', 'pano');

       function showPanoData(panoData, status) {
           if (status != google.maps.StreetViewStatus.OK) {
               $('#pano').html('No StreetView Picture Available').attr('style', 'text-align:center;font-weight:bold').show();
           var angle = computeAngle(addLatLng, panoData.location.latLng);

           var panoOptions = {
              position: addLatLng,
              addressControl: false,
              linksControl: false,
              panControl: false,
              zoomControlOptions: {
               style: google.maps.ZoomControlStyle.SMALL
              pov: {
               heading: angle,
               pitch: 10,
               zoom: 1
              enableCloseButton: false,


     function  create_map_and_streetview(lat, lng, map_id, street_view_id) {

          panorama = new google.maps.StreetViewPanorama(document.getElementById("pano"));
          addLatLng = new google.maps.LatLng(lat,lng);
          var service = new google.maps.StreetViewService();
          service.getPanoramaByLocation(addLatLng, 50, showPanoData);

         var myOptions = {
               zoom: 16,
               center: addLatLng,
               mapTypeId: google.maps.MapTypeId.ROADMAP,
               backgroundColor: 'transparent',
               streetViewControl: false,
               keyboardShortcuts: false
         console.log("Create map marker")
         var map = new google.maps.Map(document.getElementById(map_id), myOptions);
          var marker = new google.maps.Marker({
                    animation: google.maps.Animation.DROP,
                    position: addLatLng
          console.log("Create map marker 2")

     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;
          console.log("before $");
          $(document).ready(function() {
               console.log("doc ready");



* Save the HTML to a local file on the disk
LOCAL lcFile
lcFile = ADDBS(GETENV("TEMP")) + SYS(2015) + ".htm"

* Show the StreetView
RUN /N6 Explorer.EXE &lcFile.


  1. Thanks! I don't need now, but...who knows?

  2. Great job, but when I try to navigate from inside a VFP app (via Web Browser OCX) I get an error message: SCRIPT ERROR LINE 137 CHARACTER 11 'CONSOLE' ISN´T DEFINED - CODE:0
    Do you know how to fix that?
    I have to say that when I navigate directly from any browser, I get no error at all