200 tips!!Featuring tips, tutorials and code to help you build better sites using Textpattern

Geo blogging for your site

Based on the code described by Matt Davis I have incorporated some of the previous work done for the xml driven map and hope to add some extras as time goes on.

Overview

Information is entered into Textpattern’s Custom Fields, extracted from your web pages, and processed using jQuery (which has been available from release 4.0.5) via the javascript linked to in the head of your map Page. (Ensure you put the link there, as it’s not in the default Textpattern template.)

<script src="http://yoursite.com/textpattern/jquery.js" type="text/javascript"></script>

I have provided the GeoTagIcon to use for the post link (but it could be any link you like) which links directly to a particular marker, at a particular zoom level. The code parses the url information to do this, whilst the collection of markers are all plotted on the map using the javascript, hence the map page may be accessed in an overall or specific view. The url parsing also allows a link to more general view of an area on your map, which does not necessarily have to contain markers.

A working map may be viewed here

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 – 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 (or add 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&amp;v=2&amp;sensor=false&amp;key=***" type="text/javascript"></script>

Create a div for the map using this line of HTML, where you want 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 the map centre co-ordinates.

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

Javascript Map Code

Now to insert the script to govern the map which includes tools to:

  1. parse the latitude, longitude and zoom url information presented to the script
  2. provides for a crosshair cursor
  3. show marker title on mouse-over
  4. set the initial type of map presented and controls available
  5. build the map using variables from your Custom Fields
  6. inserts popup information including zoom function, and
  7. describes the map centre as you move around
  8. contains a section for xml/rss – polylines and Twitter feeds etc.

I will break down the code according to the numbering above, to illustrate the variable bits, but copy the complete javascript (below – or download from here ) and past it into your Map page, within the head section.

<script type="text/JavaScript">
	$(document).ready(function() {

	    var mypoint;

	      if (GBrowserIsCompatible()) {
	        var map = new google.maps.Map2(document.getElementById("map"), {draggableCursor:"crosshair"});
		map.addControl(new google.maps.HierarchicalMapTypeControl());
		map.addMapType(G_PHYSICAL_MAP);
		map.addMapType(G_SATELLITE_3D_MAP);
		var mapui = map.getDefaultUI();
		map.setUI(mapui);
		google.maps.Event.addListener (map, "moveend", function() {
	          var center = map.getCenter();
	          document.getElementById("message").innerHTML = center.toString();
		});

		geoXmlNamibiaF = new GGeoXml("http://api.flickr.com/services/feeds/geo/?id=40178719@N00&lang=en-us&format=rss_200");
		map.addOverlay(geoXmlNamibiaF);
		geoXmlNamibia = new GGeoXml("http://davidhall.me/trails/NamibiaRgs.kml");
		map.addOverlay(geoXmlNamibia);
		geoXmlTwitter = new GGeoXml("https://twitter.com/statuses/user_timeline/11508012.rss");
		map.addOverlay(geoXmlTwitter);

	<txp:article_custom limit="99"  lat="_%" long="_%">
	        mypoint = new google.maps.LatLng(<txp:custom_field name="lat" />, <txp:custom_field name="long" />);
	        var marker<txp:article_id /> = new google.maps.Marker((mypoint), ({title:"<txp:title />"}));
	        google.maps.Event.addListener(marker<txp:article_id />, "click", function() {
	        marker<txp:article_id />.openInfoWindowHtml('<txp:article_image wraptag="p" thumbnail="1" /><h2><txp:permlink><txp:title /></txp:permlink></h2><small><txp:excerpt /></small><h2><a href="/map/?lat=<txp:custom_field name="lat" />+lng=<txp:custom_field name="long" />+zmn=15">+</a>&nbsp;&nbsp;Zoom&nbsp;&nbsp;<a href="/map/?lat=<txp:custom_field name="lat" />+lng=<txp:custom_field name="long" />+zmn=8">-</a></h2>');});
	        map.addOverlay(marker<txp:article_id />);
	</txp:article_custom>

	if (location.search.substring(1)) {
		var qs = location.search.substring(1);
		var nv = qs.split('+');
		var url = new Object();
			for(i = 0; i < nv.length; i++) {
	    		eq = nv[i].indexOf('=');
	    		url[nv[i].substring(0,eq).toLowerCase()] = unescape(nv[i].substring(eq + 1));
	  		}
		var lat = parseFloat(url.lat);
		var lng = parseFloat(url.lng);
		var mypoint = new google.maps.LatLng(lat, lng);
		var zmn = parseFloat(url.zmn);
		map.setCenter(mypoint, zmn, G_PHYSICAL_MAP);
		}
	else {
		var mypoint = new google.maps.LatLng(54.04003822492974, -2.010498046875);
		var zmn = 5;
		map.setCenter(mypoint, zmn, G_PHYSICAL_MAP);
		}
	  }

	});
</script>

Break down

1 In line #44 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). Doing this will do away with the Textpattern zmn Custom field.
Here we also set the lat/lng/zmn co-ordinates for the overall starting point of the map view, after the else – play with them to suit yourself – they are all set to my preference.

var lat = parseFloat(url.lat);
var lng = parseFloat(url.lng);
var mypoint = new google.maps.LatLng(lat, lng);
var zmn = parseFloat(url.zmn); OR var zmn = 11;
map.setCenter(mypoint, zmn, G_PHYSICAL_MAP);
}
else {
var mypoint = new google.maps.LatLng(54.04003822492974, -2.010498046875);
var zmn = 5;
map.setCenter(mypoint, zmn, G_PHYSICAL_MAP);
}

2 Line #7 gives the crosshairs in place of the normal cursor, I like it because you can accurately focus on a point and double click on it, to get the precise coordinates read out below the map. If you would rather have the usual hand cursor, use the second line here:

var map = new google.maps.Map2(document.getElementById("map"), {draggableCursor:"crosshair"});
OR
var map = new google.maps.Map2(document.getElementById("map"));

3 Line #27 gives the mouseover title of the marker/blog post, again if you don’t want them, substitute the second line here:

var marker<txp:article_id /> = new google.maps.Marker((mypoint), ({title:"<txp:title />"}));
OR
var marker<txp:article_id /> = new google.maps.Marker(mypoint);

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 lines #45 and #50 and refer to Google Controls for info on the controls available. I’ve included the EARTH view at #10 if your browser supports it and you have the plugin installed.

5 The Textpattern Custom Fieldslat, long and zmn and the Article image field carry the information from your post to the script, via the tags in the script. The Article image field may use both a Textpattern ID number of an image uploaded within Textpattern, or a link to an image file in your home directory i.e. /images/photo.jpg – but remember the size, the code uses the thumbnail (see line #29) of a Textpattern uploaded image (so remember to create one if it doesn’t automatically), or create a suitably sized image for a map bubble.

6 Information gathered in the map bubble is governed here, starting line #29. All styled from your Textpattern stylesheet, so you can draw-in what information you want, and link it. Note I’ve used small to style the blog post excerpt, as it reads better than p in my installation. There is a built-in zoom feature (below), again styled from the Txp stylesheet, set the bubble zoom levels you want here.

<h2><a href="/map/?lat=<txp:custom_field name="lat" />+lng=<txp:custom_field name="long" />+zmn=15">+</a>&nbsp;&nbsp;Zoom&nbsp;&nbsp;<a href="/map/?lat=<txp:custom_field name="lat" />+lng=<txp:custom_field name="long" />+zmn=8">-</a></h2>

7 Starting line #13, describes the listener that follows the centre of the map and displays the co-ordinates below the map in my example – the Message div in the map page body.

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

8 There is a section I’ve bolted-on to display xml/rss feeds, the code includes a Flickr feed (I know they don’t validate!), polyline and my Twitter feed, starting line #18, substitute with whatever you like:

geoXmlNamibiaF = new GGeoXml("http://api.flickr.com/services/feeds/geo/?id=40178719@N00&lang=en-us&format=rss_200");
map.addOverlay(geoXmlNamibiaF);
geoXmlNamibia = new GGeoXml("http://davidhall.me/trails/NamibiaRgs.kml");
map.addOverlay(geoXmlNamibia);
geoXmlTwitter = new GGeoXml("https://twitter.com/statuses/user_timeline/11508012.rss");
map.addOverlay(geoXmlTwitter);

Making it work

Grab Matt Davis’s excellent msd_google_map plugin for an efficient way of geocoding directly into the lat and long fields. An Extensions tab will be formed in Textpattern and there you can set the start coordinates the locating map displays to suit your own patch, enter custom-1 and custom-2 in ID of Latitude Custom Field and ID of Longitude Custom Field respectively. There is a thread on Textpattern forum, if you have any problems.

In Admin > Preferences > Advanced tab the Custom Fields 1-3 should be: (Skip the zmn field if you fixed the zmn in #44. At a later date, I may have a go at adding more fields for custom markers etc.)

  1. lat
  2. long
  3. zmn

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">
<a href="<txp:site_url />map/?lat=<txp:custom_field name="lat" />+lng=<txp:custom_field name="long" />+zmn=<txp:custom_field name="zmn" />"><img src="/images/geotag.png" alt="" border="0" title="view on map" /></a>
</txp:if_custom_field>

Included is the code for inserting a GeoTag icon (remember to ftp it to your images folder).

Note: If you used a fixed zoom level in your code, then you should really remove +zmn=<txp:custom_field name="zmn" /> from the above. Alternatively, you can fix the zoom level here using +zmn=11 instead, to disable zoom level parsing of the javascript code.

To show an area without a marker, use something like the following link in body of your blog post (leave the zmn parsing in place):

!/images/geotag.png!:http://carbonestate.eu/map/?lat=56.524843918030456+lng=-5.875968933105469+zmn=10

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 – this links to Google Maps (well it does in iCab):

<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>
comments powered by Disqus