Archive for the ‘Coding’ Category

Code for GPS Tracking with Google Maps & AJAX

March 15, 2008 - 4:42 pm No Comments

Over the past few months, my article on GPS Tracking with Google Maps & AJAX has received many hits and attracted a multitude of comments requesting that the code for it be made available. I apologize for the delay but I’ve been away on holiday and far away from my trusted laptop. Now that things are somewhat back to normal and I can spend hour upon hour on my laptop again, here is the code that so many of you have asked for. I hope it makes sense and that it helps you all with what you’re trying to achieve. Obviously I haven’t posted the entire HTML and PHP coz it’s not all relevant to the GPS plotting but I hope what I have posted gives ya’ll a general idea on how to solve this particular problem. I’m sure there are many different ways to do this but this was just one way that I tried.Please feel free to ask questions and I’ll try to answer as best as I can! :)

...

Within the head section of the page that contains the gps tracking map:

?View Code JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<script language="JavaScript">
 
function setTimer() {
   window.setTimeout("show_data();",5000);
}
 
function show_data(){
   //Append the id (just a simple count) to the requestURL
   var requestURL = "http://www.sitename.com/getGpsPoints.php";
   var count = document.getElementById("counter").value;
   count = parseInt(count, 10);
   var queries = "?id=" + count;
   var url = requestURL + queries;
 
   //Increment the hidden counter variable
   document.getElementById("counter").value = count+1; 
 
   var request = GXmlHttp.create();
   request.open("GET", url, true);
 
   request.onreadystatechange = function() {
      if (request.readyState == 4) {
         var xmlDoc = request.responseXML;
         var markers = xmlDoc.documentElement.getElementsByTagName("marker");
 
         for (var i = 0; i < markers.length; i++) {
            var point = new GPoint(parseFloat(markers[i].getAttribute("lat")), parseFloat(markers[i].getAttribute("lng")));
 
            // Draw the MapMarker
            var mapMarker = new GMarker(point);
            map.addOverlay(mapMarker);
         }
 
         // Recenter the map
         map.centerAtLatLng(point); 
      }
   }
 
   request.send(null);
 
   //Reset the timer so that the page keeps refreshing itself
   setTimer();
}
 
</script>

Within the body section of the page that contains the gps tracking map, right at the bottom just before the /body tag:

?View Code JAVASCRIPT
1
2
3
4
5
6
7
8
<script language="JavaScript">
   var query = window.location.pathname;
   if (query == "/mapping/gps-tracking-with-google-maps--ajax") {
      var map = new GMap(document.getElementById("map"));
      mapSetup();
      setTimer();
   }
</script>

Separate PHP script that queries your database to retrieve the GPS points to plot:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
    header ("content-type: text/xml");
 
    $link = mysql_connect ("localhost", "username", "password");
    if (!$link) {
        die('Could not connect: ' . mysql_error());
    }
 
    mysql_select_db ("dbname");
 
    //If no search string is passed, then we can't search
    if(empty($_GET["id"])) {
        echo " ";
    } else {
        //Remove whitespace from beginning x%x% end of passed search.
        $search = trim($_GET["id"]);
 
        //Query the DB and store the result in a variable
        $query = mysql_query("SELECT * FROM gps WHERE id=".$search);
 
        //If no rows are found...
        if(mysql_num_rows($query) == 0) {
            echo " ";
        } else {
            //Stick the returned rows into a handy array for easy use
            $row = mysql_fetch_array($query) or die(mysql_error()); 
 
            //Write out XML using values returned by the query
            echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?><markers><marker lat=\"".$row["lat"]."\" lng=\"".$row["lng"]."\" /></markers>";
        }
    }
 
    mysql_close($link);
?>
  • Share/Bookmark

Textpattern plugins and Facebook apps

August 12, 2007 - 5:37 pm 4 Comments

Since Chris and I have become addicted to Facebook, we decided it would be cool to have a plugin for our respective blogging engines (Chris uses WordPress, I use Textpattern) that would update our Facebook accounts’ mini-feeds when we posted something on our blogs. Thus we both set off on our epic missions to create Facebook applications and WordPress / Textpattern plugins that would support this behaviour.

Here I’ll relate my experience with my Textpattern plugin. I’ll leave Chris to talk about his experience with WordPress.

So yeah, basically, my experience was a nightmare.

This was my first attempt ever at writing a Textpattern plugin so I am by no means an expert at this. It took me a while to figure out how to compile my php code so that I could deploy it to my Textpattern instance on my web server. Then it took me another while to figure out how to hook into Textpattern ‘events’. I must say, the documentation for this is really poor and I found myself trawling through the Textpattern source to figure out what functions did what. Not pretty. The best (and only) sites I found that helped me somewhat were this article on threshold state and this Textpattern source repository.

When I finally figured out how to call the ‘register_callback’ functions and that I had to use ‘article’ as the event I wanted to register my own events against, I was able to get stuck into it.

My next challenge was how to add a checkbox to the ‘write’ tab of the admin screens. I wanted a checkbox that when checked, would essentially call my code to notify my facebook account of my post. If it wasn’t checked, it wouldn’t notify facebook. However, adding a checkbox and positioning it where ever I want in the flow of elements on the page was NOT an easy task. Below is a sample of the code I had to use to get this to work:

1
2
3
4
5
6
7
8
9
10
function mdt_event_insert_checkbox($buffer) {
   $fb_notify = graf('<small><label for="notify_facebook">'.
      checkbox("notify_facebook", '1', '1', '', 'notify_facebook').
      'Notify Facebook?</label>&nbsp;');
 
   $find = '<input type="submit"';
   $replace = $fb_notify.$find;
 
   return str_replace($find, $replace, $buffer);
}

NASTY! I had to find the ‘Save’ button, then replace the HTML with my new HTML that includes the checkbox. OMG.

Anyway, I finally got that working (see screenshot below).

Next I needed to grab the title of the new post, the friendly-url to the article on my site and the excerpt of the new article. This again was no easy task. The following code seems to do the trick:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function current_url() {
   return 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
}
 
function get_latest_post() {
   include_once txpath.'/publish/taghandlers.php';
 
   // get the latest article posted
   $rs = safe_row("ID, Title, Excerpt", 'textpattern', "1=1 ORDER BY LastMod DESC LIMIT 0,1");
 
   $title = ' has blogged: ' . urlencode(stripslashes(urldecode('<a href="' . permlinkurl_id($rs['ID']) . '">'))) . substr($rs['Title'], 0, 45) . '</a>';
   $msg = substr($rs['Excerpt'], 0, 180);
   $url = current_url();
 
   if (strtolower($step) == "publish") {
   $url = $url . "?event=article";
 
   } elseif (strtolower($step) == "edit") {
      $url = $url . "?event=articlex%x%step=editx%x%ID=" . $rs['ID'];
   }
}

So now the tricky part – how to connect to Facebook, log in as myself and call the Facebook API function that updates my ‘mini-feed’ with some content. I first attempted this by embedding the Facebook API into the Textpattern plugin so that the integration would be completely seamless. This, however, was difficult on many levels. First of all, I couldn’t get the Facebook API to compile into my Textpattern plugin. The php compiler would tell me that certain server variables weren’t defined, etc etc. I did iron out all those error messages and warnings eventually though and finally got the code to compile. However, I later realized that this was never going to be a feasible solution because in order for this to work, my Facebook developers’ API key and secret key would need to be hard-coded into the Textpattern plugin and if I were ever to make this Textpattern plugin public (which I intend to do), I would be sharing my API and secret keys, something I don’t necessarily want to do. Doh! So I had to change my thinking somewhat.

The solution to this was to basically write the Facebook part of the plugin as a totally separate web application and have the Textpattern plugin call this web app, passing through to it the title, url and excerpt in the form of a query string. This method lets the Facebook web application handle all the Facebook functionality (logging in and authenticating, remembering you once you’re logged in, calling the appropriate API functions, etc etc) and the Textpattern plugin basically doesn’t need to know anything about Facebook.

What a mission.

However, it all seems to be working now and I’ve used it once already. Those of you who are on Facebook and have added me as a friend will be able to see little posts on my mini-feed (on my profile page) saying “Annie has blogged…” with a link through to this article. Very cool :) When I am comfortable that things are working as intended and I tidy things up enough to make my Textpattern plugin publicly available, I’ll put it up on my here somewhere for people to grab.

Phew

  • Share/Bookmark

An example Prolog program

April 9, 2007 - 3:27 pm No Comments

Way back at university (like, 3 years ago), I did a couple of papers that covered Prolog. Unlike most procedural top-down programming languages that us software developers are used to using, Prolog is a logic programming language. A typical Prolog program consists of facts, rules and queries. Although I don’t have a Prolog interpreter on my machine at the moment, we used SICStus Prolog on NetBSD at university.

Speaking of SICStus Prolog – apparently it now has integrated support for developing web based applications using a new module called PrologBeans. Using this module, SICStus Prolog can be called from a Java-based application server. Awesome!!

Anyway, for those interested in what Prolog looks like, below is an old assignment that I submitted for a course on Artificial Intelligence. If I remember correctly, the assignment was for us to simulate a robot cleaning dishes. We were asked to implement all the facts and rules, in Prolog, for such a robot. When the robot encounters dirty dishes, it is supposed to clean them. If it encounters wet dishes, it is meant to dry them.

When the program is run with an initial state, the output is a list of steps that the robot would take according to the prolog rules written in the program.

Below is the code for this program.

?View Code PROLOG
%-*-prolog-*-
% operator(-Op, -Pre, -Del, -Add)
%   operator definitions
%   Pre is a list of state preconditions
%   After Op is applied
%     Del gets deleted from state
%     Add gets added to state
 
operator(putDirtyDishFromBench(X),
        pre: [dirty(X), at(X,bench)],
        del: [at(X,bench)],
        add: [at(X,sink)]).
 
operator(putDirtyDishFromDrainer(X),
        pre: [dirty(X), at(X,drainer)],
        del: [at(X,drainer)],
        add: [at(X,sink)]).
 
operator(putDryDishInSink(X),
        pre: [dry(X), at(X,drainer)],
        del: [dry(X), at(X,drainer)],
        add: [cleanButWet(X), at(X,sink)]).
 
operator(putDryDishInCupboardFromDrainer(X),
        pre: [dry(X), at(X,drainer)],
        del: [at(X,drainer)],
        add: [at(X,cupboard)]).
 
operator(putDryDishInCupboardFromBench(X),
        pre: [dry(X), at(X,bench)],
        del: [at(X,bench)],
        add: [at(X,cupboard)]).
 
operator(putCleanButWetDishFromSink(X),
        pre: [cleanButWet(X), at(X,sink)],
        del: [at(X,sink)],
        add: [at(X,drainer)]).
 
operator(putCleanButWetDishFromBench(X),
        pre: [cleanButWet(X), at(X,bench)],
        del: [at(X,bench)],
        add: [at(X,drainer)]).
 
operator(pickUpTool(X,Y),
        pre: [holding(X)],
        del: [holding(X)],
        add: [holding(Y)]).
 
operator(processInSink(X),
        pre: [dirty(X), at(X, sink), holding(dishbrush)],
        del: [dirty(X)],
        add: [cleanButWet(X)]).
 
operator(processInDrainer(X),
        pre: [cleanButWet(X), at(X, drainer), holding(teatowel)],
        del: [cleanButWet(X)],
        add: [dry(X)]).
 
% instantiate(?Operator)
%   Makes Operator ground (including its pre, del and add lists)
 
instantiate(putDirtyDishFromBench(X)) :- dish(X).
instantiate(putDirtyDishFromDrainer(X)) :- dish(X).
instantiate(putDryDishInSink(X)) :- dish(X).
instantiate(putDryDishInCupboardFromDrainer(X)) :- dish(X).
instantiate(putDryDishInCupboardFromBench(X)) :- dish(X).
instantiate(putCleanButWetDishFromSink(X)) :- dish(X).
instantiate(putCleanButWetDishFromBench(X)) :- dish(X).
instantiate(pickUpTool(X,Y)) :- tool(X), tool(Y), X\==Y.
instantiate(processInSink(X)) :- dish(X).
instantiate(processInDrainer(X)) :- dish(X).
 
% dish(?Object)
%   Object is a dish
dish(dish1).
dish(dish2).
dish(dish3).
dish(dish4).
dish(dish5).
 
% tool(?Object)
%   Object is a tool
tool(dishbrush).
tool(teatowel).
tool(nothing).
 
% location(?Object)
%   Object is a location
location(bench).
location(sink).
location(drainer).
location(cupboard).

An example of how to use this prolog program:

?View Code PROLOG
TESTDISHES1:
 
testdishes1 :-  goal_stack_plan([at(dish1, bench), dirty(dish1),
                              holding(nothing)],
                              [at(dish1, cupboard), dry(dish1)],
                        Plan, FinalState,
                        []).

And the plan found by the program when TESTDISHES1 is run:

?View Code PROLOG
PLAN FOUND FOR TESTDISHES1:
====================================
Plan to achieve [at(dish1,cupboard),dry(dish1)]
Starting at [at(dish1,bench),dirty(dish1),holding(nothing)]
    putDirtyDishFromBench(dish1)
    pickUpTool(nothing,teatowel)
    pickUpTool(teatowel,dishbrush)
    processInSink(dish1)
    putCleanButWetDishFromSink(dish1)
    pickUpTool(dishbrush,teatowel)
    processInDrainer(dish1)
    putDryDishInCupboardFromDrainer(dish1)
Ending in state: [holding(teatowel),dry(dish1),at(dish1,cupboard)]
====================================
yes
| ?-

If this looks like something you might wanna have a go with, try looking at this tutorial.

  • Share/Bookmark

I’ve been quoted… about VB.NET

April 3, 2007 - 5:06 am 1 Comment

This morning one of my fellow developers sent me a link to this article on Rowan Simpson’s (formerly the Software Development team lead at Trade Me, now heading up the Trade Me Products team) blog.

How exciting!! I’m famous!! :)

But seriously, writing code in VB.NET just frustrates me and that email I sent our dev group was one of a few instances (perhaps one of the more curious ones) where VB.NET just doesn’t seem to rate next to C#. I mean, the recent introduction of the using statement… come on! C# has had this for aaaaaaaaaaaages. And the fact that operator overloading has only JUST been introduced to VB.NET – again, C# has has this for ages. And language support for unsigned types (UInteger, ULong, and UShort) has again, only just been introduced in .NET 2 for dear ol’ VB.NET. I’m sure I was using unsigned types about 8 years ago at university (ok, so that might have been in Java, but still?!!?).

However, what frustrates me the most about VB.NET is probably the fact that I feel like I’m writing an essay in English when coding… Brackets are good! Semi-colons are good! And sticking to the OOP terminology that many programmers out there have learnt to love over the years must be good!

Oh well, better get back to my screeds of VB.NET – we have an early deploy tomorrow morning wooohoooo!!!

  • Share/Bookmark

IE Conditional CSS Comments

March 28, 2007 - 6:58 pm No Comments

I know this has blogged about many times over, but I recently came across this really handy CSS hack (yes, I think this qualifies as a hack) specifically for styling sites in IE.

Basically, only Internet Explorer (5 and onwards) on Windows can read these ‘comments’. Therefore, any CSS styles written within them are only interpreted and applied by IE. And better yet – you can write ‘if’ statements within these comments so that your CSS styles are only applied to particular versions of IE.

Pretty handy huh?

Here’s a quick example:



<!--[if gt IE 5]> table#content { width: 100%; !important; }
<![endif]-->

Here are the different ‘if’ operators:


<!--[if IE]> This comment applies to all versions of IE from 5 to 7.
<![endif]-->


<!--[if IE 6]> This comment applies to version 6 of IE.
<![endif]-->


<!--[if lt IE 6]> This comment applies to versions of IE less than version 6.
<![endif]-->


<!--[if lte IE 6]> This comment applies to versions of IE less than or equal to version 6.
<![endif]-->


<!--[if gt IE 6]> This comment applies to versions of IE greater than version 6.
<![endif]-->


<!--[if gte IE 6]> This comment applies to versions of IE greater than or equal to version 6.
<![endif]-->

There are a couple of gotchas you should be aware of before you use this great little hack.

  • Only IE on Windows will interpret these comments. Read: this hack will not work for IE on a Mac. If you need to style something for IE on a Mac, think about checking for the user agent using whatever script you’re programming in, if you’re using one at all, and including styles based on that instead.
  • Conditional statements just use the normal HTML comments and therefore can only be used in HTML pages. Read: this hack won’t work when written in a CSS file.

    I know the pain web designers and developers go through trying to get their sites to look the same in all browsers (trust me, I know!) so it might be quite tempting to use this hack all over your code. But keep in mind that this is just a hack and you should try to find more standards compliant ways of styling your sites using CSS that works well in all browsers (or at least that are important to you).

    • Share/Bookmark

Send MSN messages programmatically

March 18, 2007 - 5:07 pm 4 Comments
I’m sure there is a need out there to send messages to MSN programmatically. So I’m gonna find out how plausible it is and whether I can find a use for it myself :)

I recently came across a simple PHP class for sending MSN messages called sendMsg written by FanaticLive. Below is a form that uses this class to send a message from the ‘sender’ to the ‘recipient’ that you enter.

In order for this process to work, the specified recipient must have the sender in their MSN contact list (approved or not) and the recipient must be online. If you don’t want to enter your email and password into this form (and I totally understand if you don’t) then try using the test user. Only thing is you’ll have to temporarily add the test user – msn.tester@mindtrip.co.nz – to your contact list on MSN.

So go on, try it… you know you want to :)

Now I have to come up with a cool idea for why I might actually want to programmatically send MSN messages… hmm….
Update: Looks like some cunning spammers have decided to use this form to send spam out, not that it’s working. So HA spammers, take that. I’ve logged all your IP addresses and the fact that none of your spam got through. Anyway, I’m not impressed, spammers suck. So thanks to them, I’m taking this form down. If anyone wants to see the code for it, just leave me a message and I’ll send it to you.

  • Share/Bookmark

GPS Tracking with Google Maps & AJAX

August 25, 2005 - 10:45 am 19 Comments

“Real-Time” tracking of GPS locations on a web site is actually quite hard to achieve. In order to see a dot moving around on an online map, the page would need to be constantly refreshing itself. The refresh would initiate a request back to the server where server-side code would grab the new coordinates of the GPS unit out of a database, redraw the map with a dot on it, and send the whole image back to the user’s browser. Whether the refreshing is caused by the page itself or a hidden iframe on the page somewhere, a full roundtrip to the server every few seconds would soon become super annoying, even if it did mean the user got to see a neat dot ‘seemingly’ moving around on a map.

So how do we get around this? Ideally, we would just want to redraw the ‘dot’, not the whole map and definitely not the whole page. Can this be done? Yes! How? Using AJAX.

No, AJAX isn’t a cleaning product. And believe it or not it isn’t even a new technology. AJAX stands for “Asynchronous JavaScript and XML” and is described by WikiPedia as:

A term describing a web development technique for creating interactive web applications using a combination of:

*HTML (or XHTML) and CSS for presenting information *The Document Object Model manipulated through JavaScript to dynamically display and interact with the information presented *The XMLHttpRequest object to exchange data asynchronously with the web server. (XML is commonly used, although any text format will work, including preformatted HTML, plain text, and JSON)

AJAX essentially allows calls to be made to the server without the user ‘noticing’. The call itself does not cause the page to refresh at all. The developer can make the page do whatever they wish with the response from the server. Most often developers will manipulate the page’s appearance using JavaScript, the DOM and CSS.

So how can AJAX be applied to online mapping? Well, using AJAX we can make ‘asynchronous’ calls to some server-side logic that can grab the newest position of the GPS unit out of a database. The coordinates can then be passed back to our page in an XML string. Client-side JavaScript in our page will interpret the XML and create a ‘img’ element that looks like a dot, using CSS to place it at the correct pixel location on the map.

Since I don’t have a real GPS unit to test this with, I have populated a database table with some fake GPS coordinates. To date I’ve tried this using MapInfo’s MapXtreme 2004 (ASP.NET in C#, plenty of JavaScript, CSS and a horrible little Access DB) which worked a treat. I’ve also tried it using a Google Map which you can see below. (If the dot has stopped moving, refresh the page using Ctrl+F5 – I only have about 10 points in my fake GPS unit db table.)

 

If anyone wants to see my code, please see this article.

  • Share/Bookmark