block to submit location query to google maps javascript api

Events happening in the community are now at Drupal community events on www.drupal.org.
chertzog's picture

After messing with all of the views, gmap, location, modules, and being restricted to only postal codes was not an option so i found the google maps javscript store locator tutorial found here and have successfully implemented it.

http://code.google.com/intl/da/apis/maps/articles/phpsqlsearch_v3.html

and with some help from tinem's posting regarding the same thing, i was able to get it functioning inside my drupal installation.

What im trying to do now is create a block on my site that will display on every page in the upper corner, for people to search for locations.
But what i cant figure out is how to submit the value to the javscript function when the locator page loads.
Ive tried posting the form to php variable then transferring it to a javascript variable, but i still dont know who to make it submit to the function.

Any ideas?

Comments

figured it out

chertzog's picture

if anyone wants to know, reply and i will post a tutorial on what i did.

I'd be interested

michaelsilverman's picture

Yes please post a tutorial, thanks in advance.

I would also like to see it

tinem's picture

I would also like to see it because it was my tutorial that got you started. :-)

http://www.tinemuller.dk/test_drupal/ is made this untraditional way and using Google Maps API v2 and Drupal 6

I'm now working on another site http://beta.findtoilet.dk/ with Google Maps API v3 and "more Drupal-y way" but still Drupal 6. Hope later to update it to Drupal 7. When it's finished I can compare which of the way doing these maps I like the most. Have to mention that I have hired a pro drupal-developer to help me make this the "right" way but he is very expensive.

here you go

chertzog's picture

here is the site:
http://bell.codeworkdesigns.com/

its still a work in progress, but its coming along

ok, so after tinems great tutorial on how to get the javascript api working, i needed to push it farther. There is probably a better way to do this, but with my VERY limited javascript knowledge, this was the way i figured it out.

So to make this work for my need, i am using the location module (not CCK fields though, i made a content type and associated locations with it) to insert locations into the database. This makes it easy to create new locations and remove old ones, as i can just create / delete the node. You will notice later on that in the xml page, i had to make the columns reference the location table, so i had to change the search query and other references from "lat" to "latitude" and "lng" to "longitude"

the first thing that i did was create a block that will be placed on every page. This is a standard html form that passes the inputs to the URL, no javascript yet.

<div>
<form action="/content/locator" method="get">
<strong>WHERE TO BUY </strong>
<input name="addressInput" size="10" type="text" />
<input id="radiusSelect" name="radiusSelect" type="hidden" value="25" />
<input type="submit" value="Go" /></form>
</div>

Then i needed to get the variables from the url and put them into javascript variables. I put this function in my main script page.

function gup( name ){
  name = name.replace(/]/,"\[").replace(/[/,"\]");
  var regexS = "[\?&]"+name+"=([^&#]*)";
  var regex = new RegExp( regexS );
  var results = regex.exec( window.location.href );
  if( results == null )
    return "";
  else
    return results[1];
}

So now that my address has been input and is now stored as a javascript variable, i need to tell the script to look for the variable. the "var address" line now references the function that gets the variable from the url.

function searchLocations() {  
  var address = gup('addressInput');
  var geocoder = new google.maps.Geocoder();  
  geocoder.geocode({address: address}, function(results, status) {   
   if (status == google.maps.GeocoderStatus.OK) {     
   searchLocationsNear(results[0].geometry.location);  
      } else {   
       alert(address + ' not found');  
  } 
});
}

Now that the address is being used, i needed to change the reference that gets the radius. So as before, the "var radius" line now references the url parsing function to get the radius, that we input with a hidden field.

function searchLocationsNear(center) {
     clearLocations();
     var radius = gup('radiusSelect');
     var searchUrl = '/sites/all/locator/phpsqlsearch_genxml.php?latitude=' + center.lat() + '&longitude=' + center.lng() + '&radius=' + radius;
     downloadUrl(searchUrl, function(data) {
       var xml = parseXml(data);
       var markerNodes = xml.documentElement.getElementsByTagName("marker");
       var bounds = new google.maps.LatLngBounds();
       for (var i = 0; i < markerNodes.length; i++) {
         var name = markerNodes[i].getAttribute("name");
   var street = markerNodes[i].getAttribute("street");
     var city = markerNodes[i].getAttribute("city");
     var state = markerNodes[i].getAttribute("state");
         var zip = markerNodes[i].getAttribute("zip");
         var distance = parseFloat(markerNodes[i].getAttribute("distance"));
         var latlng = new google.maps.LatLng(
              parseFloat(markerNodes[i].getAttribute("latitude")),
              parseFloat(markerNodes[i].getAttribute("longitude")));

         createOption(name, distance, i);
         createMarker(latlng, name, street, city, state );
         bounds.extend(latlng);
       }
       map.fitBounds(bounds);
       locationSelect.style.visibility = "hidden";
       locationSelect.onchange = function() {
         var markerNum = locationSelect.options[locationSelect.selectedIndex].value;
         google.maps.event.trigger(markers[markerNum], 'click');
       };
      });
    }

ok, so now we have address, and radius in the functions as javascript variables. This is where i had the most issues. I couldnt figure out how to make the script run when the page loaded.

So i noticed that the tinems javascript tutorial as well as the google one, used a "body onLoad()" function to load the default map. Then when submitted, the button had a onClick event which actually ran the script. So i needed a way to run the script on page load, seeing as everyone would be coming to the page after submitting the form in the block.

So to get the default map, and run the script on load, i created a new function (i called it "start") and made it call both the load() and searchLocations() functions.

function start(){
    load();
    searchLocations();
}

I created a content type for my locator script so that i could easily edit the template for it and add my scripts and changes to the body tag. In my body tag, instead of calling just the load() function, it now calls the start function which in turn calls both the load() and the searchLocations() functions. so in my new content type template i have a body tag that looks like:

<body class="<?php print $body_classes; ?>" onLoad="start()">

i also wanted to use a custom marker icon instead of the default red pin. notice the "var image" line, and then the line "icon:image". here is the code for that:

function createMarker(latlng, name, street, city, state) {
      var html = "<b>" + name + "</b> <br/>" + street +" "+ city + ", " + state;
     var image = '/sites/all/locator/chickenpin.png';
      var marker = new google.maps.Marker({
        map: map,
        position: latlng,
       icon: image
      });
      google.maps.event.addListener(marker, 'click', function() {
        infoWindow.setContent(html);
        infoWindow.open(map, marker);
      });
      markers.push(marker);
    }

so now here is all of the code:

phpsql_search_genxml.php:

<?php
 

require("db_cred.php");

// Get parameters from URL
$center_lat = $_GET["latitude"];
$center_lng = $_GET["longitude"];
$radius = $_GET["radius"];

// Start XML file, create parent node
$dom = new DOMDocument("1.0");
$node = $dom->createElement("markers");
$parnode = $dom->appendChild($node);

// Opens a connection to a mySQL server
$connection=mysql_connect (localhost, $user, $pass);
if (!
$connection) {
  die(
"Not connected : " . mysql_error());
}

// Set the active mySQL database
$db_selected = mysql_select_db($db, $connection);
if (!
$db_selected) {
  die (
"Can\'t use db : " . mysql_error());
}

// Search the rows in the markers table
$query = sprintf("SELECT name, street, city, province, postal_code, latitude, longitude, ( 3959 * acos( cos( radians('%s') ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( latitude ) ) ) ) AS distance FROM location HAVING distance < '%s' ORDER BY distance LIMIT 0 , 20",
 
mysql_real_escape_string($center_lat),
 
mysql_real_escape_string($center_lng),
 
mysql_real_escape_string($center_lat),
 
mysql_real_escape_string($radius));
$result = mysql_query($query);

if (!
$result) {
  die(
"Invalid query: " . mysql_error());
}

header("Content-type: text/xml");

// Iterate through the rows, adding XML nodes for each
while ($row = @mysql_fetch_assoc($result)){
 
$node = $dom->createElement("marker");
 
$newnode = $parnode->appendChild($node);
 
$newnode->setAttribute("name", $row['name']);
 
$newnode->setAttribute("street", $row['street']);
 
$newnode->setAttribute("city", $row['city']);
 
$newnode->setAttribute("state", $row['province']);
 
$newnode->setAttribute("zip", $row['postal_code']);
 
$newnode->setAttribute("latitude", $row['latitude']);
 
$newnode->setAttribute("longitude", $row['longitude']);
 
$newnode->setAttribute("distance", $row['distance']);
}

echo
$dom->saveXML();
?>

locate.js:

//<![CDATA[
    var map;
    var markers = [];
    var infoWindow;
    var locationSelect;
  
function gup( name ){
  name = name.replace(/[[]/,"\[").replace(/[]]/,"\]");
  var regexS = "[\?&]"+name+"=([^&#]*)";
  var regex = new RegExp( regexS );
  var results = regex.exec( window.location.href );
  if( results == null )
    return "";
  else
    return results[1];
}

function load() {
      map = new google.maps.Map(document.getElementById("map"), {
        center: new google.maps.LatLng(40, -100),
        zoom: 4,
        mapTypeId: 'roadmap',
        mapTypeControlOptions: {style: google.maps.MapTypeControlStyle.DROPDOWN_MENU}
      });
      infoWindow = new google.maps.InfoWindow();
     
      locationSelect = document.getElementById("locationSelect");
      locationSelect.onchange = function() {
        var markerNum = locationSelect.options[locationSelect.selectedIndex].value;
        if (markerNum != "none"){
          google.maps.event.trigger(markers[markerNum], 'click');
        }
      };
   }

function searchLocations() {  
var address = gup('addressInput');
  var geocoder = new google.maps.Geocoder();  
  geocoder.geocode({address: address}, function(results, status) {   
   if (status == google.maps.GeocoderStatus.OK) {     
   searchLocationsNear(results[0].geometry.location);  
      } else {   
       alert(address + ' not found');  
  } 
});
}
 

   function clearLocations() {
     infoWindow.close();
     for (var i = 0; i < markers.length; i++) {
       markers[i].setMap(null);
     }
     markers.length = 0;
     locationSelect.innerHTML = "";
     var option = document.createElement("option");
     option.value = "none";
     option.innerHTML = "See all results:";
     locationSelect.appendChild(option);
   }

   function searchLocationsNear(center) {
     clearLocations();
     var radius = gup('radiusSelect');
     var searchUrl = '/sites/all/locator/phpsqlsearch_genxml.php?latitude=' + center.lat() + '&longitude=' + center.lng() + '&radius=' + radius;
     downloadUrl(searchUrl, function(data) {
       var xml = parseXml(data);
       var markerNodes = xml.documentElement.getElementsByTagName("marker");
       var bounds = new google.maps.LatLngBounds();
       for (var i = 0; i < markerNodes.length; i++) {
         var name = markerNodes[i].getAttribute("name");
  var street = markerNodes[i].getAttribute("street");
     var city = markerNodes[i].getAttribute("city");
     var state = markerNodes[i].getAttribute("state");
         var zip = markerNodes[i].getAttribute("zip");
         var distance = parseFloat(markerNodes[i].getAttribute("distance"));
         var latlng = new google.maps.LatLng(
              parseFloat(markerNodes[i].getAttribute("latitude")),
              parseFloat(markerNodes[i].getAttribute("longitude")));

         createOption(name, distance, i);
         createMarker(latlng, name, street, city, state, zip );
         bounds.extend(latlng);
       }
       map.fitBounds(bounds);
       locationSelect.style.visibility = "hidden";
       locationSelect.onchange = function() {
         var markerNum = locationSelect.options[locationSelect.selectedIndex].value;
         google.maps.event.trigger(markers[markerNum], 'click');
       };
      });
    }
 
    function createMarker(latlng, name, street, city, state, zip) {
      var html = "<b>" + name + "</b> <br/>" + street +"<br/>"+ city + ", " + state+" " + zip ;
     var image = '/sites/all/locator/chickenpin.png';
      var marker = new google.maps.Marker({
        map: map,
        position: latlng,
       icon: image
      });
      google.maps.event.addListener(marker, 'click', function() {
        infoWindow.setContent(html);
        infoWindow.open(map, marker);
      });
      markers.push(marker);
    }

    function createOption(name, distance, num) {
      var option = document.createElement("option");
      option.value = num;
      option.innerHTML = name + "(" + distance.toFixed(1) + ")";
      locationSelect.appendChild(option);
    }

    function downloadUrl(url, callback) {
      var request = window.ActiveXObject ?
          new ActiveXObject('Microsoft.XMLHTTP') :
          new XMLHttpRequest;

      request.onreadystatechange = function() {
        if (request.readyState == 4) {
          request.onreadystatechange = doNothing;
          callback(request.responseText, request.status);
        }
      };

      request.open('GET', url, true);
      request.send(null);
    }

    function parseXml(str) {
      if (window.ActiveXObject) {
        var doc = new ActiveXObject('Microsoft.XMLDOM');
        doc.loadXML(str);
        return doc;
      } else if (window.DOMParser) {
        return (new DOMParser).parseFromString(str, 'text/xml');
      }
    }

    function doNothing() {}

my locator page(this is just the code that i put in the body of my node):

<div class="locatesearch">
   <form action="/content/locator" method="get">
        <table border="0" cellpadding="0" cellspacing="0" style="width: 300px; ">
            <tbody>
              <tr>
                 <td>
                      Location:</td>
                  <td>
                     <input name="addressInput" size="10" type="text" /></td>
                 <td>
                     Radius:</td>
                 <td>
                     <select id="radiusSelect" name="radiusSelect">
                                                      <option value="10">10mi</option>
                                                      <option value="20">20mi</option>
                                                      <option value="50">50mi</option>
                                                      <option value="100">100mi</option>
                                                      <option value="200">200mi</option>
                                               </select></td>
                    <td>
                     <input id="btnSearch" type="submit" value="Go" /></td>
               </tr>
            </tbody>
     </table>
</form>
</div>
<div>
<select id="locationSelect" style="width:100%;visibility:hidden"></select></div>
<div id="map" style="width: 600px; height: 400px"></div> 

and in the node type template i have the following:

<?php
<head>
  <?
php print $head; ?>

  <title><?php print $head_title; ?></title>
  <?php print $styles; ?>
  <?php print $scripts; ?>
   <script src="http://maps.google.com/maps/api/js?sensor=false&region=US" type="text/javascript"></script>
<script src="/sites/all/locator/locate.js" type="text/javascript"></script>
  <script type="text/javascript"><?php /* Needed to avoid Flash of Unstyled Content in IE */ ?> </script>
  <script language='JavaScript'>         
function start(){
   load();
    searchLocations();
}
</script>
</head>
<body class="<?php print $body_classes; ?>" onLoad="start()">

I think thats it. If you have any questions post and i will answer to the best of my ability.

Chris

Location and Mapping

Group organizers

Group categories

Wiki type

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: