david hall icon

Geoblogging using an xml file

Last update: 25 February 2010

A method of geotagging when using Textpattern. (This work-through is an updated text to that on TextBook)

Based on the method described by David Ramos, but uses a newer Google AJAX API Version 1 and Maps API v2, plus includes some extras.

Information is entered into Custom Fields, extracted from your web pages, gathered in an XML file, which then in turn serves up the goods to the map javascript. Data may be entered directly into the XML file to provide non-linked markers and non-point specific area area links may also be constructed, all to a variable zoom level.

A screen shot of the resultant map, showing the three supplied markers, with popup containing an image (linked back to article - but could be linked anywhere) text and zoom function, and the marker mouseover text (not all browsers will support the rounded corners and shadow):

example map

The actual map page code has been drawn together from the tutorials and code samples on the informative Google Concepts pages, and although not having as many bells and whistles as are available, does the basic job of linking a blog/image articles to specific map markers, and back. See Google API Concepts

The previous problem with this method has been the linking from your page link to centre on a specific point and zoom level on your map.

Additionally, this method places ICBM meta content into the head section of your site (it could use geo.position - I just prefer ICBM) thus activating the increasingly popular geo-detecting software provided by iCab and the Firefox MiniMap plugin. (They both use our GeoTagIcon - cheers guys!)

Getting Started

Grab yourself an API key from Google, this will be valid for a single "directory" or domain and you have to have a Google Account. API Sign Up

    In Textpattern, set-up new:
  • Map Page
  • Map Style (if different to the Default)
  • Map Section - using the Page and Style you have just set-up above

Insert the following in the head of your Map page, with your newly acquired API Key ***

Note there is a variable (true_or_false) sensor parameter to indicate whether the application uses a sensor to determine the user's location. I've set this to false explicitly.


<script src="http://maps.google.com/maps?file=api&v=2&sensor=false&key=*your key*" type="text/javascript"></script>

Create a div for the map using this line of HTML in the body of the page, the size and overall appearance can be governed by your new Map Style. Also add a Message div for co-ordinates - we will come on to that later.


<div id="map"></div>
<div id="message"></div>

Javascript Map Code

    Now to insert the script to govern the map which includes tools to:
  • parse the latitude, longitude and zoom url information presented to the script
  • provide for custom markers
  • show marker mouse-over tooltips
  • set the initial type of map presented and controls available
  • build the map using variables from your Custom Fields
  • inserts popup information including zoom function, and
  • describes the map centre as you move around

I will break down the code according to the numbering above, to illustrate the variable bits, but grab the complete javascript and past it into your Map page immediately before the end body tag.

Do not try assembling the following chunks, they are not complete - it will not work.

1. In line #15 (of the downloaded txt file) you may fix the variable zoom that the links show and not pass it in the url, to a level to suit you - the alternative line you will have to paste-in, is after OR in this code section below (it's not in the complete download).
Here we also set the lat/lng/zmn co-ordinates for the overall map view - play with them to suit yourself - they are all set to 1.


var lat = parseFloat(url.lat);
var lng = parseFloat(url.lng);
var zmn = parseFloat(url.zmn); OR var zmn = 11;
var vars = url.vars;
}
else {
    var lat = 1;
    var lng = 1;
    var zmn = 1;
};

2. Custom Markers are described in groups with an end string which groups them by name. Three markers are shown below with the end string of three, just duplicate and change the name for more.

(The markers in the txt file correspond to the icons and the shadow provided here - ftp them to your image file - don't do this via the Textpattern interface - they'll get assigned a number and things will get very confusing!)


var redIcon = new GIcon();
redIcon.image = "images/red.png";
redIcon.shadow = "images/shadow.png";
redIcon.iconSize = new GSize(12, 20);
redIcon.shadowSize = new GSize(22, 20);
redIcon.iconAnchor = new GPoint(6, 20);
redIcon.infoWindowAnchor = new GPoint(5, 1);
var blueIcon = new GIcon();
blueIcon.image = "images/blue.png";
blueIcon.shadow = "images/shadow.png";
blueIcon.iconSize = new GSize(12, 20);
blueIcon.shadowSize = new GSize(22, 20);
blueIcon.iconAnchor = new GPoint(6, 20);
blueIcon.infoWindowAnchor = new GPoint(5, 1);
var greenIcon = new GIcon();
greenIcon.image = "images/green.png";
greenIcon.shadow = "images/shadow.png";
greenIcon.iconSize = new GSize(12, 20);
greenIcon.shadowSize = new GSize(22, 20);
greenIcon.iconAnchor = new GPoint(6, 20);
greenIcon.infoWindowAnchor = new GPoint(5, 1);

var myIcon = [];
myIcon["1"] = redIcon;
myIcon["2"] = greenIcon;
myIcon["3"] = blueIcon;
markerGroups = {"1": [], "2": [], "3":[]};

3. Style your Tooltips in the CSS file (updated box shadow for Firefox, also Opera - in the hope Opera gets back some of the CSS support it once seemed to have?) e.g:


.tooltip {
    text-align:center;
    font-size:0.8em;
    white-space:nowrap;
    display:block;
    padding:2px;
    font-weight:bold;
    background:#333333;
        -webkit-border-radius:5px;
        -moz-border-radius:5px;
        -o-border-radius:5px;
        -khtml-border-radius:5px;
            -webkit-box-shadow: 2px 5px 6px #666666;
            -moz-box-shadow: 2px 5px 6px #666666;
            -o-box-shadow: 2px 5px 6px #666666;
            -khtml-box-shadow: 2px 5px 6px #666666;
    color:#61C402;
}

4. There are options as to the type of map available and the controls on the map. It is set for initial display of the Physical Map, see line #108 and Google Controls for info on the controls available.

A alternative to set the initial view to the normal Google Map view, is to replace PHYSICAL with NORMAL. I've included the EARTH view if your browser supports it and you have the plugin installed.


map = new google.maps.Map2(document.getElementById("map"));
map.setCenter(new google.maps.LatLng(lat,lng), zmn, G_PHYSICAL_MAP);
map.addControl(new google.maps.LargeMapControl());
map.addControl(new google.maps.HierarchicalMapTypeControl());
map.addMapType(G_PHYSICAL_MAP);
map.addMapType(G_SATELLITE_3D_MAP);

5. The main block of the code takes the variables and builds the map, please note the abbreviations used in the code, as we will use these in the Form and Custom Fields later.

6. Information gathered in the Marker Popup bubble is governed here (starting line #139) again note the abbreviations used later, but here is the article title (label) which automatically links back to the post, an image (with hyperlink) and selected text from the Custom Fields: img, url and txt and the built in zoom feature. Set the zoom levels you want here.


var html = '<div class="markerinfo">';
html += '<h2><a href="' + url + '">' + label + '</h2></a>';
html += '<a href="' + url + '">img src="' + img + '" height="50" class="image"></a><br />';
html += '<p>' + txt + '</p>';
html += '<h3><a href="#" onClick="map.setCenter(new google.maps.LatLng(' + lat + ',' + lng + '), 15)">+</a>  Zoom  <a href="javascript:map.setZoom(7);">-</a></h3></div>';

7. Starting line #152 describes the listener that follows the centre of the map and displays the co-ordinates below the map in my example - this is why the Message div was entered in the page body.


google.maps.Event.addListener (map, "moveend", function() {
    var center = map.getCenter();
    document.getElementById("message").innerHTML = center.toString();

8. Additional code after line #158 - google.setOnLoadCallback(initialize); - sets up the ability to toggle marker groups using checkboxes:


function toggleGroup(type) {
    for (var i = 0; i < markerGroups[type].length; i++) {
        var marker = markerGroups[type][i];
        if (marker.isHidden()) {
            marker.show();
        }
        else {
        marker.hide();
        }
    }
}

and the code used within the body of the page to control this - a sort of control key :


<form name="marker_checkbox" action="#">
        <input type="checkbox" id="redCheckbox" onclick="toggleGroup('1')" checked="checked" /><label for="redCheckbox"><img src="images/red.png" alt="" title="Red Markers" /></label>
        <input type="checkbox" id="blueCheckbox" onclick="toggleGroup('2')" checked="checked" /><label for="blueCheckbox"><img src="images/blue.png" alt="" title="Blue Markers" /></label>
        <input type="checkbox" id="greenCheckbox" onclick="toggleGroup('3')" checked="checked" /><label for="greenCheckbox"><img src="images/green.png" alt="" title="Green Markers" /></label>
        </form>

Making it work

Create a new Textpattern page called Mapdata and paste in the following. (Because Textpattern outputs it's content as text/html the standard code hs been changed to accept this, at line #127).


<?xml version="1.0" encoding="ISO-8859-1" ?>
<markers>
<txp:article_custom form="mapdata" limit="999" />
</markers>
    In Admin > Preferences > Advanced fill-in Custom Fields 1-6 with:
  • lat
  • long
  • txt
  • url
  • img
  • icn

In Presentation > Forms create a new one called mapdata and save as Type: article with the following in:


<txp:if_custom_field name="lat">
<marker lat="<txp:custom_field name="lat" />" lng="<txp:custom_field name="long" />" label="<txp:title />"
txt="<txp:custom_field name="txt" />" url="<txp:custom_field name="url" />" img="<txp:custom_field name="img" />" icn="<txp:custom_field name="icn" />">
</marker>
</txp:if_custom_field>

Now this will create the markers on your map, but to create a link from your page to a specific map point, add the following to your default article form:


<txp:if_custom_field name="lat">
<p><a href="<txp:site_url />map?lat=<txp:custom_field name="lat" />+lng=<txp:custom_field name="long" />+zmn=11"><img src="/images/geotag_16.png" alt="" border="0" title="map view" /></a></p>
</txp:if_custom_field>

Included is the code for inserting a GeoTag icon (remember to ftp it to your images folder). If you like you could add text to the link by including the tag for the txt Custom Field.

Note: If you used a fixed zoom level in your code, then you should remove +zmn=11 from the above. I have put the fixed level here to enable me to send links set at a point and zoom level (governed by the url), to show an area without a marker.

If you want a variable zoom for every link, create another Custom Field for zmn and add the relevant txp:custom_field name="zmn" tag to the Default Form.

Meta Content

To place the ICBM content in the document head, place the following in the head section of the page - which will probably be your blog page:


<txp:if_individual_article>
<txp:if_custom_field name="lat">
<meta name="ICBM" content="<txp:custom_field name="lat" />, <txp:custom_field name="long" />" />
</txp:if_custom_field>
</txp:if_individual_article>

Hints and Tricks

See Matt Davis's msd_google_map plugin for an efficient way of geocoding directly into the lat and long fields, with a thread on Textpattern forum. You can easily set the start coordinates, under the Extensions tab, for the plugin to suit your own patch. Otherwise there are a few sites on the net that will give you the co-ordinates for latitude and longitude, i.e. Map Maker - when yours is up and running, you can estimate the centre co-ordinates reasonably accurate from there.
If the markers don't show when viewing the map in general it is probably because you are linking to it using the Textpattern generated <txp:section /> list, which adds a trailing '/'. Set up your own link list and leave it of i.e. yoursite/map and your markers will appear.
You can hyperlink the image (Opera is presently stubbornly refusing to show these images) within a popup bubble to anywhere, but remember if you just put in say the name of an article it will go to your own site. To break-out, you have to put the full url in i.e. put the http:// first into the url field:
url field

Before you drive yourself nuts with links etc. from your popups, set you Preferences to simple/pretty urls:
perm link

Watch the use of the trailing or prefix '/' - in my setup all the links entered in the image field or the script itself only work without the pre '/' - the map disappears if one sneaks-in. Linking images from the body of your html page, may behave quite differently…

2009-11-25