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.
- I created a folder seminarorte inside the positions folder because my content type is named Seminarorte.
- Inside seminarorte I created a folder admin because I want to override the admin form.
- 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