10 years ago
10
Topic
Introduction
This is a tutorial for geocoding addresses in forms (site form or admin form) using the Google Maps API and a custom position override in your form template.




It is aimed at users that are familiar with position overrides or want to learn how to do it.



I write this because, after an update of Joomla and Seblod, I havd problems with the commercial field plugin Address to Coordinates.
So I wrote my own code to achieve the same thing in a more elegant and flexible way. The idea and parts of the code are based on the great work of Ryan Cramer for his fabulous CMS ProcessWire.

What you will get

A map with a marker that represents the position of the address. It is draggable for fine tuning and will update latitude and longitude on drag.
In the example the data from input fields "Seminarort Str.", "Seminarort PLZ" and "Seminarort Ort" is used to calculate the geolocation.

How to Setup the whole thing
Step 1: Create a content type in SEBLOD with your custom fields for the location


My content type is called Seminarorte, since I'm German. We will need this name later in Step 2 for the position override. You can see the custom fields in the mainbody position of the admin form that we will use later on. In this example they are: semort_street for stret and No., semort_plz for postcode and semort_ort for city.

Our map will go into the position right-c. We will need this information later on for the position override. This is just my example, you can choose any position you like. The field in position right-c is just a dummy to make the position show up later in our form. You can put any field in there.
In the "Template" Tab, be sure to choose the default seb_one template.





Step 2: The template position override
Remember that we used the standard seb_one template for our admin form? On your server in the folder templates you will find the folder seb_one. This is where all the files for the seb_one template live and where we will place the files for our position override.
Within the seb_one folder is a folder named positions. This is where we will place the files for our override.

  1. I created a folder seminarorte inside the positions folder because my content type is named Seminarorte.
  2. Inside seminarorte I created a folder admin because I want to override the admin form.
  3. inside the admin folder I created a file right-c.php because I want to override the position right-c.

This is the structure I ended up with

Of course you have to adjust the names of your folders and files to your situation.




Step 3: The code for the position override.
This is the code for my right-c.php file:
<?php
// No Direct Access
defined( '_JEXEC' ) or die;
$document = JFactory::getDocument();
$document->addScript( 'http://maps.googleapis.com/maps/api/js?sensor=false&language=de' ); //add Google Maps JS
$buttonText = 'Geodaten berechnen'; //name of the calculate button
?>
<a id="calculate" class="btn btn-success btn-medium"><?php echo $buttonText; ?></a>
<div id="notes" class="well" style="display:none;margin: 3px 0;"></div>
<div id="map_canvas" style="width:100%;height:300px;"></div>
<script type="text/javascript">
/**
 * Display a Google Map and pinpoint a location 
 * Based on InputFieldMApMArker code from Ryan Cramer at http://www.processwire.com
 */
(function($) {
$(document).ready(function() {
    var map = $('#map_canvas'); //id of your map canvas div
    var lat = $("#semort_lat"); //name of your latitude field
    var lng = $("#semort_lng"); //name of your longitude field
    var defaultLat = '53.3825449'; //default value for latitude
    var defaultLng = '9.88735769'; //default value for latitude
    var street = $('#semort_street'); //name of your street and no. adrress field
    var postcode = $('#semort_plz'); //name of your poscode field
    var city = $('#semort_ort'); //name of your city field
    var notes = $('#notes'); //container where success message gets put out
    var zoom = 14; //adjust zoom level here
    var message = '<h3 style="color:green">Geodaten erfolgreich angepasst<br>Bitte speichern</h3>'; //define success message
    //start processing data
    latVal = lat.val();
    lngVal = lng.val();
    if (latVal == '') {
        latVal = defaultLat;
        lngVal = defaultLng;
    }
    initmap('map_canvas', lat, lng, zoom, 'ROADMAP'); //change ROADMAP to SATELLITE if you like
    function initmap(mapId, lat, lng, zoomFactor, mapType) {
    var options = {
        zoom: zoomFactor,
        draggable: true, 
        center: null,
        mapTypeId: google.maps.MapTypeId.HYBRID,
        scrollwheel: false,    
        mapTypeControlOptions: {
            style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
        },
        scaleControl: false
    };    
        if(mapType == 'SATELLITE') options.mapTypeId = google.maps.MapTypeId.SATELLITE; 
            else if(mapType == 'ROADMAP') options.mapTypeId = google.maps.MapTypeId.ROADMAP; 
        options.center = new google.maps.LatLng(latVal, lngVal);
        var map = new google.maps.Map(document.getElementById(mapId), options);     
        var marker = new google.maps.Marker({
            position: options.center, 
            map: map,
            draggable: options.draggable    
        }); 
        google.maps.event.addListener(marker, 'dragend', function(event) {     //this recalculates lat and lng 
            var geocoder = new google.maps.Geocoder();                        //when you drag the marker
            var position = this.getPosition();    
            lat.val(position.lat());
            lng.val(position.lng());
                geocoder.geocode({ 'latLng': position }, function(results, status) {
                    if(status == google.maps.GeocoderStatus.OK && results[0]) {
                    }
                    notes.html(message);
                    notes.show();
                    lat.css({'color': 'green'});
                    lng.css({'color': 'green'});
                });
        });
        $('#calculate').click(function() {
            addr = street.val() + ' ' + postcode.val() + ' ' + city.val(); //generate address string from input fields
            var geocoder = new google.maps.Geocoder();
            geocoder.geocode({ 'address': addr}, function(results, status) {
                if(status == google.maps.GeocoderStatus.OK && results[0]) {
                    var position = results[0].geometry.location;
                    map.setCenter(position);
                    marker.setPosition(position);
                    lat.val(position.lat());
                    lng.val(position.lng());
                }
                notes.html(message);
                notes.show();
                lat.css({'color': 'green'});
                lng.css({'color': 'green'});
            });
            return true;    
        }); 
    };
});
})(jQuery);
</script>
You will have to adjust some variables to your needs. The code is pretty well commented so you see where you have to put what.
Most important is that you change the variables for the names of your input fields.
In my example:
    var lat = $("#semort_lat"); //name of your latitude field
    var lng = $("#semort_lng"); //name of your longitude field
    var defaultLat = '53.3825449'; //default value for latitude
    var defaultLng = '9.88735769'; //default value for latitude
    var street = $('#semort_street'); //name of your street and no. adrress field
    var postcode = $('#semort_plz'); //name of your poscode field
    var city = $('#semort_ort'); //name of your city field
These are jQuery selectors. So where it says #semort_lat, this selects my input field for latitude. If your field has the name my_latitude, you would change the code to
var lat = $("#my_latitude"); //name of your latitude field


Conclusion
That wasn't too hard, was it?
Once you have filled in the correct names for your fields, you saved and uploaded the file to your server, the map should work. You can now enter address information and then press the calculate button and the sript will geocode your address and put latitude and longitude values in your respective fields. Then you hit Save and lat and lng are saved to your database.

I hope this is useful for some of you. If you have any questions, just ask. I will try to answer them here.
I think this code can be turned into a nice field plugin. But my programming skills are not well enough developed to do this myself. So if anyone feels they would like to make a plugin, I would be very happy.

Side note
I wrote this because I got frustrated with the official commercial Seblod Address to Coordinates field plugin. I bought it for one of my client's site. After updating Joomla from 3.1.1 to 3.2.1 and Seblod from 3.1.2 to the latest version, that plugin refused to work. My debugging lead nowhere. Sometimes the plugin would save lat/lng, then again it stopped doing it's job. I contacted the devs and thought I might get some help because this is a commersial product. But I would have to buy commercial support from them so they can fix my problem. Their support is certainly excellent once you pay for it but it is also rather pricy. So I decided to use existing code from another CMS, my restricted knowledge of PHP and JS, my knowledge of position overrides and put this together to have a working solution.
What comes in as a nice extra is the draggable marker that rewrites the lat/lng positions. So people can fine tune the position.

Have fun
gerhard

Get a VIP membership
10 years ago
0
Level 1
Hi Zwergo,
your welcome. Putting this together took me less time than bug tracking and solving my problems with the commercial plugin. So I thought I just share it here.
116 Posts
nycxav
10 years ago
0
Level 1
Kudos, I had the same problem and once more you're the one who provides me with a working solution.
Vielen Dank.
10 years ago
2
Level 1
Hi nycxav,

glad it helped. Quite a few Germans here in the forum. Seblod seems popular in Germany.

Interesting that you also ran into the problems with the original address to coordinates plugin. Could you describe, when this happened? Was it after an upgrade of Joomla/Seblod or after moving to a new server? And have you contacted the developers about the problem? Would be great to get your feedback so we can add an issue to the tracker and let the devs know. This is a commercial plugin so they really should fix the problem.

Cheers
Gerhard
10 years ago
0
Level 2
You dont need this plugin if you use custom templates.

Here is a code snippet to get coordinates from an address:

$strasse = $cck->get( 'yourstreetfield' )->value;
$plz = $cck->get( 'yourplzfield' )->value;
$ort = $cck->get( 'yourlocationfield' )->value;
$bundesland = $cck->get( 'yourstatefield' )->value;
$land = $cck->get( 'impressum_land' )->value;
$address = $strasse.' '.$plz.' '.$ort;
$address = urlencode($address);
$request_url = "http://maps.googleapis.com/maps/api/geocode/xml?address=".$address."&sensor=true";
$xml = simplexml_load_file($request_url) or die("url not loading");
$status = $xml->status;
if ($status=="OK") {
$Lat = $xml->result->geometry->location->lat;
$Lon = $xml->result->geometry->location->lng;
$LatLng = "$Lat,$Lon";
echo $LatLng;
}
116 Posts
nycxav
10 years ago
0
Level 2
Hi,

I don't know exactly when it stopped working because I didn't notice immediately, but probably after a minor upgrade between Joomla 3.0.x and 3.1.x because that's the only change on the site.
No I haven't contacted the developer and yes I should do it and they should fix it but it was kind of low on my priority list.

Thanks.
X.
10 years ago
0
Level 1
Hello Juergen,

thanks for your code. Very helpful. And I agree, with custom template we don't need the commercial plugin. But it is still good for people who are not accustomed to position overrides.

Haven't tried your code yet. Does it also allow to drag the marker and then write back the Lat/Lng position for fine tuning?

Cheers
Gerhard
10 years ago
1
Level 1
Well done, Gebeer! nice tutorial.
One small question - is it possible to place initial marker on the map automatically (based on user's IP or GPS location) and fill long/latitude fields ?
When I use a tablet or smartphone, Google does this for me -  so user's location is taken automatically. 
10 years ago
0
Level 2
Hi terveg,

sure you can do this.

Have a read over at the Google Maps API about getting Geolocation.

Should be fairly easy to add this to my code.
31 Posts
Catastrophix
8 years ago
0
Level 1

Thank you VERY much for this. Very elegant and customisable

8 years ago
0
Level 1

Thank you very much. This is exactly what i was looking for.

This is exactly what i expected from Map Template (30 Euro). Unfortunally i haven`t noticed, that Map is only for List and Search and NOT for Forms and Content Type.

Even the Gateway from Geofactory 5 (myjoom) doesn`t work with seblod forms.

In standard joomla articles they have a button for geocoding.

So, i`m very happy and thankful for this tut.

And i hope, that someone can program a plugin.

Get a Book for SEBLOD