Disclaimer - please do not use any of the maps on this site as your sole guidance in the field. Although the routes are mapped directly from actual walked .gpx data, the accuracy of the visual presentation is not exactly state of art. My maps are designed to easily transfer onto Ordnance Survey (OS) Explorer maps.
Why?
After the umpteenth time of planing a walk with all the expectation of new and undiscovered country, then arriving, having deja vu and realising 'oh, I've walked here before' and then remembering the brief road section on the map was in fact a nightmare - how could I have forgotten that? I must write that down somewhere.
What?
I decided early on that I didn't want to present my maps as any kind of 'mobile app' alternative to using printed maps and compass (and grudgingly, a GPS). This also allowed me not to get tied down to having to present accountable accuracy.
I also noticed the lack of any appealing walking resources on the web (maybe I didn't look hard enough). Once I wanted to find a walk in the New Forrest - but only came across lengthy, wordy Blogs and Council websites which kind of 'cheapened' the notion, and trying to read them whilst cozying up to my ipod was impossible (one reason I wanted to make my maps fully responsive). Maybe, If I could convey a tiny fraction of the spirit and freedom walking brings to me, I would happy.
An early epiphany and data gathering
Why draw a map when your feet have already done the job? My maps start off as recorded Tracks in a Garmin etrex10 - using Distance as the recording method. After downloading to Garmin's BaseCamp app the track is exported to the GPX version 1.1 format. Then the first of many fudges, to get all the points more equally spaced out (even though we set Distance as the recording method) upload .gpx to www.gpsies.com - the equal spacing should help when applying animation to the route. Now correct the buggy elevation readings using gpsvisualizer.com. After those two fixes we have to reinstate the <bounds>
tag from the original Garmin export, this contains important max & min Latitude & Longitude info which is used to calculate the routes 'shape' width and height. Now its time for the real bodge job...my maps Content Management System (CMS).
Data coaxed into compliance
- The CMS has to achieve:
- To be able to import, convert into a usable form and allow manipulation of .gpx file data.
- To allow icons and labels to be placed on map, and to associate notes and photos to points along the route.
- To be able to package and save the constructed virtual 'walk' into a MySQL database.
- To able to read in and update a previously saved virtual 'walk'.
The .gpx file format follows a simple .xml file structure which basically contains a large list of <trkpt>
tags, with each having 'lat' and 'lon' properties (Latitude and Longitude). To allow the walk route to be drawn on a 2D plane (your screen) we need to convert these lat and lon numbers into x and y values. Each <trkpt>
Latitude and Longitude properties are expressed in decimal degrees using the WGS 84 datum. After loading the .gpx file into the CMS I use a 'simple Mercator projection function' to convert degrees to cartesian coordinates (see here).
To allow the route to be displayed on a variety of screen sizes I convert all track points from cartesian units into a scalable, percent based unit. Both the Longitude (which will become the x-axis) and the Latitude (the y-axis) are converted to a 0-100% scale. The most Westerly point of walk route being 0% on the x-axis, with the most Eastley being 100%. The most Northerly being 0%, the most Southernly being 100% on the y-axis. Each walk route has a width to height ratio index - worked out using the max/min Lat & Lon values found in the <bounds>
tag. I can then use this method to fit the route into a set amount of pixels. Say we need to display route within 300px. A point stored as 90%x 12%y would convert to (300/100 * 90)px, (((300*ratio)/100)*12)px.
After some trials I abandoned full zoom functionality - its a luxury! and on mobiles is more of a hindrance - and settled on 3 zoom levels. The basic level would show the complete route (see above), the second and third would show a portion with the current position centred on screen (this meant I needed animation). The third zoom level would show route as close as possible to a OS Map, allowing user to easily transfer route onto a printed map.
Segmented Lines
Did the decision to limit zoom to 3 levels lead to the idea of having set points along route - or was it the idea to convey the spirit of walking - the idea of motion, or progression. Or was it the need to fit everything into 1 screen, so user wouldn't have to keep scrolling down then going back up to map? anyway a concept of segmenting the route came into being.
All the x and y points for the route are loaded into arrays. Segments are just the index values which 'point' to the points. A points array might look like:
The first segment might be made up of the points from 0 to 100. So we store this segment as:
Then for 2nd segment the start would be:
The map is a line made up of drawing from point to point, there are no bezier curves. For a 15K walk my gps records around 1000 points. This is far to many when drawing to 300px wide mobile screen. This meant that each zoom level would have to have its own points array. The CMS allows me to specify how many points there are on each zoom level (some walks have only 20 points for level 1). I store all the original points in the MySQL database and use a rationalisation process to get fewer points. The original points array is only used in the CMS, the online map page only loads in the 3 level zoom arrays. Again I had to use a percentage unit when storing the segment pointers, if you only have 20 points for zoom level 1 and the segments are from 0-5,6-12,13-16,17-20 when you zoom out to level 2 which has 200 points the segments will now be 0-50, 51-120,121-130,131-160,161-200!
Segment segue
As I wanted users to transfer my walks onto OS Explorer maps at least 1 level should at least resemble them a bit. It felt natural to do this at the max zoom level. This meant I would have to further segment the already segmented sections and allow styling of the final individual drawn lines, so some could be public footpaths then change to a road, then to a bridleway. To give users more clues to match up route with the printed maps I had to include bits which had not been walked. Say a footpath ends at a road, then you turn right onto the road, walk for a bit then turn off left onto another footpath - the maps looks odd if you don't include a bit of the road BEFORE the footpath meets it and AFTER you leave it - bits that I didn't walk so were not recorded!
I called this process adding Spurs. This is done by creating a new point after the line ends by projecting the vector of the two previous points, or if adding a spur before - projecting the vector of the two proceeding points backwards. This can produce erratic results, depending on how the two points vector lines up. This does highlight a big floor in the concept of working from walked data, sometimes a point won't be recorded at the start or end of a section you want to segment. A work around is to 'fudge' the recorded data in Basecamp, adding points at particular points - but then you also have to manually input elevation data for that point.
Icons, Labels and Grid Lines
To add more OS similarity I added icons based on OS designs. Along with the Labels (text) the icons origin point have to be allowed to be altered (top left, top centre, top right, bottom right, bottom centre, bottom left and centre) this is to anchor it into place on different zoom levels. The grid lines and references shown on both zoom level 2 and 3 also help in locating the walk on your map - unless you cut up your maps, my only grudge with OS maps is that the grid line references are never shown on the portion of map I'm currently walking! These, along with the distance walked, is inputed manually into the CMS.
Output
The process of displaying all the map data onto a webpage is achieved by drawing into a HTML <canvas>
tag, using Javascript. I was a bit disappointed on my first trials of drawing lines using the canvas api - the lines were blurred on my MacBook so had to overscan, drawing into a double size <canvas>
then fitting it into a correct sized <div>
which I suppose is a bit overkill.
The animation was a pain. Unfortunately I can't remember, or find the site in my browsers history, that supplied the javascript easing code but its not its fault the animation is a bit jerky. This is due to the to the nature of drawing a line dot to dot, so to speak.
UX: Labelling vs Discovery
Having over worked this project, being able to step back and try and view the maps as a user first landing from search results would, is tough - on my ego for one thing. Should everything be labelled, 'Click here to Zoom In' , 'Tap here to view photos', 'Click here to move route forward' etc, or could we hold back a bit and let human intuition play apart - I'm a great believer in letting people make they own discoveries, if they never find the photos so what? if they never hit the the route forward button and never see the animation or the complete walk? (well, that does kind of hurt). But for me, the far more important thing is that self discovery leads to some personalisation being invested in the site.
Conclusions and what I would do if I were you
Why not just use Google Maps and their API or Open Street Maps? would have been a lot quicker and may also have turned out to more useful - and may have helped in Google rankings. This was a 'conceptual' decision made at the start of project - made by my irrational part of brain - and by the time my rational side kicked in it was too late and had to go along with the ride.
One thing I would change is using a Canvas to draw the map into. I would advise looking into .svg which has nice trick on being able to animate the drawing of a line, without having to draw from point to point - which produces far smoother effects and you can use CSS for the easing and its completely responsive and pin sharp. Adding bezier curves would also produce much nicer results but a .gpx to .svg convertor seems like a big enough project on its own, unless someone out there has already done it - I do not want to do the search.