My aim was to create as much static content as possible, and to keep the CGI script as simple (dumb) as possible. That way, I minimize the resource usage on the computer running the CGI, which in turn will be able to handle many parallel requests efficiently. (This goal did not, however, keep the CGI from growing to more than 1,000 lines...)
For each incoming request, the CGI only opens one file - the control file - which is a simple text file that can be read and parsed in a straightforward way. In many cases it does not even have to be read in its entirety.
Here is a control file for a very short journey:
Shieldaig:Lochcarron::A896:4 256:192:mm:1200:1100:40:43:[some omissions] tiny:small:medium:large tiny:small:medium:large:huge 01.jpg:217:863:31x8:N57°31.43':W005°38.74':989162962:38:191 02.jpg:217:864:31x8:N57°31.22':W005°38.78':989162993:51:236 03.jpg:217:866:31x8,32x8:N57°31.04':W005°38.89':989163019:55:171 04.jpg:216:868:31x8,32x8:N57°31.00':W005°38.86':989163024:55:163 You are at a junction. d:1.0::360:A896:Lochcarron:kenmorejunction-shieldaig:f7f4 |
There is some configuration information at the beginning - where the journey is from, where it is to, on what road etc., and there's information about the available map and picture sizes. After that, one line for each image, with information about the map pixel position, the map segments affected, the co-ordinates, timestamp, speed, and heading. At the end there's a status message and a list of possible onward connections (only one in this case).
This is enough for the CGI script to create the HTML pages for this journey.
There's also a CSS mode in which the CGI will do away with the custom painted map tiles and just use CSS positioning to put the dot where it should be. This reduced the bandwidth used and enables us to select different dot images based on the heading.
The disadvantage of this "standard mode" is that many browsers visibly "clear" the page in between reloads, resulting in a sometimes rather annoying flicker. (Opera handles it perfectly flicker-free, though!)
This procedure means that the frame mode will only work when Javascript is enabled.
Also, the map display, being segmented into 5x5 individual images, relies on browser image caching. If the map "scrolls", the browser should only load the new row or column of images and "remember" that the others are loaded already. The only exception is the Java applet which caches the images on its own.
252c:Journey from North Erradale to Melvaig ae83:Journey from Inverlael to Blarnalearoch 86dc:Journey from North Erradale to Gairloch / Melvaig f207:Journey from Kerrysdale to Kinlochewe 99e6:Journey from Badcaul to Badluarach [...] -5.812468577402863:58.15879941547619:59249.58824709085:111120.0 34263:0:209740:923408:97 34188:82:209663:923329:97 34180:88:209654:923324:97 34108:284:209574:923130:97 [...] |
The journey list is really just the journey IDs and a textual designator; then there's an empty line, followed by a coordinate conversion line and then one line for every photo in the whole of the application.
The photo lines consist of two co-ordinate pairs; the first is a simple "metres from the top left corner of the coverage area", the second is the British Grid. The self-made "metre" pair is based on a primitive conversion where one degree of latitude equals 111120 metres, and one degree of longitude equals 111120 * cos (average latitude) metres. This is sufficient for the distance search performed by the search script. The search script uses the first pair when searching for a latitude/longitude pair and the second when searching for a British Grid reference, as the conversion between the two was too nasty to added to the Perl script. The fifth value on the photo line is a pointer to a journey, in this example it's the "jonurney on line 97".
The places.txt file starts out the same, but after the empty line you have something like this:
Dundonnell River::27,63 Black Water::29,131 Contin::36,83,114,130 Loch Carron::65,120 Loch Bad á Chrótha::11,15 Badachro::11,15 [...] |
This is just a list of terms found either in the names of start and end vertices of a journey or in one of the "via" tags of the matching edge; again, with pointers to journeys. The search script uses the String::Similarity module to extract those names from the list that look similar to what the user entered.