gps2htmlReport (empty) → 0.1
raw patch · 9 files changed
+516/−0 lines, 9 filesdep +Chartdep +basedep +cairosetup-changed
Dependencies added: Chart, base, cairo, colour, data-accessor, directory, filepath, gd, gps, html, process, random, time, xsd
Files
- Data/GPS/Gps2HtmlReport/HTMLGenerator.hs +84/−0
- Data/GPS/Gps2HtmlReport/JourneyCharts.hs +114/−0
- Data/GPS/Gps2HtmlReport/JourneyStats.hs +107/−0
- Data/GPS/Gps2HtmlReport/Main.hs +41/−0
- Data/GPS/Gps2HtmlReport/OsmChart.hs +40/−0
- LICENSE +30/−0
- README.md +74/−0
- Setup.hs +2/−0
- gps2htmlReport.cabal +24/−0
+ Data/GPS/Gps2HtmlReport/HTMLGenerator.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE ScopedTypeVariables #-}++-- | The `HTMLGenerator' module generates the HTML content for the index.html generated+module Data.GPS.Gps2HtmlReport.HTMLGenerator where++import Text.Html+import Data.GPS hiding (src,link,href)+import Text.Printf+import Data.Maybe++import Data.GPS.Gps2HtmlReport.JourneyStats++-- | Takes all the WayPoints and generates the HTML file+generateHtmlPage :: [WptType] -> Html+generateHtmlPage points = + let header1 = h1 $ stringToHtml "Journey Statistics"+ header2 = h1 $ stringToHtml "Charts of the Journey"+ header3 = h1 $ stringToHtml "OpenStreetMap Chart"+ title = thetitle $ stringToHtml "GPX Track Report"+ theStyle = style (stringToHtml cssContent) ! [thetype "text/css"]+ theHeader = header $ concatHtml [title,theStyle]+ mainArea = thediv (concatHtml [header1,statsTable points,br,header2,chartTable,header3,osmImg]) -- ! [identifier "main"]+ theBody = body mainArea+ in concatHtml [theHeader,theBody,pgFooter]++-- | The OpenStreetMap image area+osmImg :: Html+osmImg = center $ image ! [src "osm.png"]++-- | Takes all the WayPoints and calculates the journey statistics+statsTable :: [WptType] -> Html+statsTable points = + let tblHeader1 = th $ stringToHtml "Journey Details"+ tblHeader2 = th $ stringToHtml "Elevation"+ tblHeader3 = th $ stringToHtml "Speed"+ distTravelled = printf "%.2f" $ journeyDistance points+ maybeMaxElePt = findPoint points (head points) ele (>)+ maybeMinElePt = findPoint points (head points) ele (<)+ maxElevation = printf "%.1f" (if isJust maybeMaxElePt then snd $ fromJust maybeMaxElePt else 0.0)+ minElevation = printf "%.1f" (if isJust maybeMinElePt then snd $ fromJust maybeMinElePt else 0.0)+ meanEle = printf "%.1f" $ meanElevation points+ journeyMins = show $ round (journeyTime points) `div` 60+ journeySecs = show $ round (journeyTime points) `rem` 60+ mxSpd = printf "%.1f" $ maxSpeed points+ meanSpd = printf "%.1f" $ meanJourneySpeed points+ maybeDateOfJourney = dateOfJourney points+ journeyDate = (if isJust maybeDateOfJourney then show $ fromJust maybeDateOfJourney else "") + li1c1 = li $ stringToHtml ("Journey Date: "++ journeyDate)+ li2c1 = li $ stringToHtml ("Distance Travelled: "++ distTravelled++"m")+ li3c1 = li $ stringToHtml ("Journey Time: "++journeyMins++"m "++journeySecs++"s")+ li1c2 = li $ stringToHtml ("Maximum Elevation: "++ maxElevation++"m")+ li2c2 = li $ stringToHtml ("Minimum Elevation: "++minElevation++"m")+ li3c2 = li $ stringToHtml ("Mean Elevation: "++ meanEle++"m")+ li1c3 = li $ stringToHtml ("Maximum speed: "++ mxSpd++"m/s")+ li2c3 = li $ stringToHtml ("Mean speed: "++meanSpd++"m/s")+ col1 = td (concatHtml [li1c1,li2c1,li3c1]) ! [valign "top"]+ col2 = td (concatHtml [li1c2,li2c2,li3c2]) ! [valign "top"]+ col3 = td (concatHtml [li1c3,li2c3]) ! [valign "top"]+ row1 = tr $ concatHtml [tblHeader1,tblHeader2,tblHeader3]+ row2 = tr $ concatHtml [col1,col2,col3]+ tbl = table (concatHtml [row1,row2]) -- ! [cellspacing 10]+ in center tbl+ +-- | The CSS style text to format the rendering of the HTML page. It would be good to replace with Haskell HTML combinator library functions+cssContent = "h1 {font-size: 22px;color: #335577;font-weight: bold; margin-top: 20px;margin-left: 70px;font-family: New Century Schoolbook, serif;} div { width: 900px; margin-top: 50px; margin:0 auto;} table {border-spacing: 20px 0px;} footer {text-align:right; background-color:#EEEEEE; width:900px; margin:0 auto; margin-top: 30px}"++-- | The area holding the Cairo charts+chartTable = + let img1 = image ! [src "chart1.png"]+ img2 = image ! [src "chart2.png"]+ cell1 = td img1+ cell2 = td img2+ row1 = tr $ concatHtml [cell1,cell2]+ tbl = table row1+ in center tbl++-- | The footer+pgFooter = + let projectLink = anchor (stringToHtml "gps2htmlReport") ! [href "https://github.com/robstewart57/Gps2HtmlReport"]+ infoStr = stringToHtml "Report generated by "+ in footer (concatHtml [infoStr,projectLink]) ! [identifier "main"]++-- | This appears to be missing from the `html' package+footer = tag "FOOTER"
+ Data/GPS/Gps2HtmlReport/JourneyCharts.hs view
@@ -0,0 +1,114 @@+-- | This module uses the JourneyStats module to generate+-- the statistics about the journey WayPoints, then+-- uses the Cairo bindings to generate the charts+module Data.GPS.Gps2HtmlReport.JourneyCharts where++import Data.GPS+import Data.Maybe+import Graphics.Rendering.Chart+import Data.Accessor+import Data.Colour+import Data.Colour.Names++import Data.GPS.Gps2HtmlReport.JourneyStats++data OutputType = Window | PNG | PS | PDF | SVG++chooseLineWidth Window = 1.0+chooseLineWidth PNG = 1.0+chooseLineWidth PDF = 0.25+chooseLineWidth PS = 0.25+chooseLineWidth SVG = 0.25++-- | Generates the Cairo chart showing speed and elevation over time+speedAndElevationOverTimeChart :: [WptType] -> OutputType -> Renderable ()+speedAndElevationOverTimeChart points otype = toRenderable layout+ where+ layout = layout1_title ^="Speed, Average Speed & Elevation"+ $ layout1_title_style ^= defaultFontStyle { font_size_ = 12.0 }+ $ layout1_background ^= solidFillStyle (opaque white)+ $ layout1_right_axis ^= defaultLayoutAxis { laxis_title_ = "Elevation (metres)", laxis_override_ = axisGridHide }+ $ layout1_left_axis ^: laxis_title ^= "Speed (metres)"+ $ layout1_plots ^= [ Right (toPlot elevationArea),+ Left (toPlot speedLine),+ Left (toPlot avrSpeedLine) + ]+ $ setLayout1Foreground fg+ defaultLayout1++ lineStyle c = line_width ^= 1 * chooseLineWidth otype+ $ line_color ^= c+ $ defaultPlotLines ^. plot_lines_style++ theSpeeds = [(theTime,spd) | (theTime,spd) <- speedAtPoints points]++ speedLine = plot_lines_style ^= lineStyle (opaque blue)+ $ plot_lines_values ^= [[ (theTime,speed) | (theTime,speed) <- theSpeeds]]+ $ plot_lines_title ^= "Speed"+ $ defaultPlotLines++ avrSpeedLine = plot_lines_style ^= lineStyle (red `withOpacity` 0.5)+ $ plot_lines_values ^= [[ (theTime,speed) | (theTime,speed) <- avrSpeedOverTime theSpeeds 0.0 0.0 []]]+ $ plot_lines_title ^= "Avr Speed"+ $ defaultPlotLines ++ elevationArea = plot_fillbetween_style ^= solidFillStyle (green `withOpacity` 0.1)+ $ plot_fillbetween_values ^= [ (theTime,(0,elevation)) | (theTime,elevation) <- ptsElevation points]+ $ plot_fillbetween_title ^= "Elevation"+ $ defaultPlotFillBetween++ fg = opaque black+++-- | Generates the Cairo chart showing accumulative distance and elevation over time, with spots showing maximum and minimum elevation points+accumDistanceAndElevationChart :: [WptType] -> OutputType -> Renderable ()+accumDistanceAndElevationChart points otype = toRenderable layout+ where+ layout = layout1_title ^="Accumulative Distance & Elevation"+ $ layout1_title_style ^= defaultFontStyle { font_size_ = 12.0 }+ $ layout1_background ^= solidFillStyle (opaque white)+ $ layout1_right_axis ^= defaultLayoutAxis { laxis_title_ = "Distance (metres)", laxis_override_ = axisGridHide }+ $ layout1_left_axis ^: laxis_title ^= "Elevation (metres)"+ $ layout1_plots ^= [ Right (toPlot accumDistanceArea),+ Left (toPlot elevationLine),+ Left (toPlot spots)+ ]+ $ setLayout1Foreground fg+ defaultLayout1++ lineStyle c = line_width ^= 1 * chooseLineWidth otype+ $ line_color ^= c+ $ defaultPlotLines ^. plot_lines_style++ elevationLine = plot_lines_style ^= lineStyle (opaque black)+ $ plot_lines_values ^= [[ (theTime,elevation) | (theTime,elevation) <- ptsElevation points]]+ $ plot_lines_title ^= "Elevation"+ $ defaultPlotLines ++ accumDistanceArea = plot_fillbetween_style ^= solidFillStyle (red `withOpacity` 0.2)+ $ plot_fillbetween_values ^= [ (theTime,(0,accumDist)) | (theTime,accumDist) <- accumDistance points 0.0]+ $ plot_fillbetween_title ^= "Distance"+ $ defaultPlotFillBetween++ spotMaxPoint = let point = findPoint points (head points) ele (>)+ in (if isJust point then Just (fst $ fromJust point, snd $ fromJust point, 5 :: Double) else Nothing)++ spotMinPoint = let point = findPoint points (head points) ele (<)+ in (if isJust point then Just (fst $ fromJust point, snd $ fromJust point, 5 :: Double) else Nothing)++ spots = area_spots_title ^= "Altitude"+ $ area_spots_max_radius ^= 5+ $ area_spots_values ^= (if isJust spotMinPoint && isJust spotMaxPoint then [fromJust spotMinPoint,fromJust spotMaxPoint] else [])+ $ defaultAreaSpots++ fg = opaque black++renderToPng :: (t, OutputType -> Renderable a) -> FilePath -> IO (PickFn a)+renderToPng (_,ir) = renderableToPNGFile (ir Window) 384 288++chart1 :: [WptType] -> (String, OutputType -> Renderable ())+chart1 points = ("speedAndElevationOverTimeChart", speedAndElevationOverTimeChart points)++chart2 :: [WptType] -> (String, OutputType -> Renderable ())+chart2 points = ("accumDistanceAndElevationChart", accumDistanceAndElevationChart points)+
+ Data/GPS/Gps2HtmlReport/JourneyStats.hs view
@@ -0,0 +1,107 @@+-- | This module provides the JourneyCharts and HTMLGenerator +-- modules with statistics for the charts, and the journey statistics+module Data.GPS.Gps2HtmlReport.JourneyStats where++import Data.GPS hiding (speed)+import Data.Maybe+import Data.Time.LocalTime+import Data.Time.Clock+import Data.Time.Calendar+import Text.XML.XSD.DateTime++-- | Takes all WayPoints, and creates a list of tuples containing (TimeStamp,Elevation)+ptsElevation :: [WptType] -> [(LocalTime,Double)]+ptsElevation = map (\point -> (utcToLocalTime dfltTZ (Text.XML.XSD.DateTime.toUTCTime (fromJust $ time point)) , fromJust $ ele point))++-- | Takes all WayPoints, and creates a list of tuples containing (TimeStamp,AvrSpeedAtThisPoint)+avrSpeedOverTime :: [(LocalTime,Speed)] -> Double -> Double -> [(LocalTime,Speed)] -> [(LocalTime,Speed)]+avrSpeedOverTime [] _ _ _ = []+avrSpeedOverTime [spd] totalSpeed numPoints iteratedAvr = iteratedAvr ++ [(fst spd, (snd spd + totalSpeed) / (numPoints+1))]+avrSpeedOverTime (spd:spds) totalSpeed numPoints iteratedAvr = avrSpeedOverTime [spd] totalSpeed numPoints iteratedAvr ++ avrSpeedOverTime spds (snd spd + totalSpeed) (numPoints+1) iteratedAvr++-- | Takes all WayPoints, and creates a list of tuples containing (TimeStamp,SpeedAtThisPoint) +speedAtPoints :: [WptType] -> [(LocalTime,Speed)]+speedAtPoints [] = []+speedAtPoints (point:points) = (lclTime $ fromJust (time point),0.0) : speedAtPoints' point points++speedAtPoints' :: WptType -> [WptType] -> [(LocalTime, Speed)]+speedAtPoints' _ [] = []+speedAtPoints' prev [x]+ | isJust (time x) = [(lclTime $ fromJust (time x), fromJust $ speed prev x)]+ | otherwise = []+speedAtPoints' prev (x:xs)+ | isJust (time x) = (lclTime $ fromJust (time x), fromJust $ speed prev x) : speedAtPoints' x xs+ | otherwise = [] ++ speedAtPoints' x xs++-- | Takes all WayPoints, and creates a list of tuples containing (TimeStamp,JourneyDistanceAtPoint)+accumDistance :: [WptType] -> Double -> [(LocalTime,Distance)]+accumDistance [] _ = []+accumDistance [x] _ = [(lclTime $ fromJust (time x),0.0)]+accumDistance (x:xs) acc = + let dist = distance x (head xs) + in (lclTime $ fromJust (time x), dist + acc ) : accumDistance (tail xs) (dist + acc)++-- | Takes all WayPoints, an element in wptType, and an Eq function, returning a single WayPoint+findPoint :: [WptType] -> WptType -> (WptType -> Maybe Double) -> (Double -> Double -> Bool) -> Maybe (LocalTime,Double)+findPoint [] _ _ _ = Nothing+findPoint (point:points) currSelected wayPointElement equalityF+ | equalityF (fromJust $ wayPointElement point) (fromJust $ wayPointElement currSelected) = findPoint points point wayPointElement equalityF+ | otherwise = if null points+ then Just (lclTime (fromJust $ time currSelected), fromJust $ ele currSelected)+ else findPoint points currSelected wayPointElement equalityF++-- | Calculates the total journey distance+journeyDistance :: (Lat a, Lon a) => [a] -> Distance+journeyDistance [] = 0.0+journeyDistance [_] = 0.0+journeyDistance (point:points) = distance point (head points) + journeyDistance points++-- | Calculates the average speed of the journey+meanJourneySpeed :: (Lat a, Lon a) => [a] -> Distance+meanJourneySpeed points = journeyDistance points / fromIntegral (length points)++-- | Calculates the maximum speed+maxSpeed :: [WptType] -> Speed+maxSpeed points =+ let speedTuple = speedAtPoints points+ speedList = map snd speedTuple+ maxSpeed = foldr max 0.0 speedList+ in maxSpeed++-- | Calculates the average elevation throughout the journey+meanElevation :: Ele a => [a] -> Double+meanElevation points = + let elevationVals = map (fromJust . ele) points+ totalElevation = foldr (+) 0.0 elevationVals+ theMean = totalElevation / fromIntegral (length points)+ in theMean++-- | Calculates the total journey time+journeyTime :: Time a => [a] -> NominalDiffTime+journeyTime [] = fromInteger 0+journeyTime [_] = fromInteger 0+journeyTime (point:points) = + let startTime = toUTCTime (fromJust (time point))+ endTime = toUTCTime (fromJust (time $ last points))+ in diffUTCTime endTime startTime++-- | Extracts the date of the journey (from the first WayPoint)+dateOfJourney :: Time a => [a] -> Maybe Day+dateOfJourney [] = Nothing+dateOfJourney (point:_) = Just $ utctDay $ toUTCTime $ fromJust (time point)++lclTime :: DateTime -> LocalTime+lclTime dteTime = utcToLocalTime dfltTZ (Text.XML.XSD.DateTime.toUTCTime dteTime)++dfltTZ :: TimeZone+dfltTZ = TimeZone {timeZoneMinutes=0,timeZoneSummerOnly=False,timeZoneName="GMT"}++-- | Overides the `speed' function in the `gps' package+speed :: (Lat loc, Lon loc, Time loc) => loc -> loc -> Maybe Speed+speed a b = + case (getUTCTime b, getUTCTime a) of+ (Just x, Just y) -> Just $ distance a b / realToFrac (diffUTCTime x y) + _ -> Nothing++getUTCTime :: (Lat a, Lon a, Time a) => a -> Maybe UTCTime+getUTCTime = fmap toUTCTime . time
+ Data/GPS/Gps2HtmlReport/Main.hs view
@@ -0,0 +1,41 @@+module Main where++import Data.GPS+import System.FilePath+import System.Directory+import Text.Html++import Data.GPS.Gps2HtmlReport.OsmChart+import Data.GPS.Gps2HtmlReport.HTMLGenerator+import Data.GPS.Gps2HtmlReport.JourneyCharts++-- | Reads the current directory for all .gpx files, then maps to `generateReport' for each one+main :: IO [()]+main = do+ curDir <- getCurrentDirectory+ allFiles <- getDirectoryContents curDir+ let allFilesSplit = map splitExtension allFiles+ let gpxFiles = filter (\(_,b) -> b==".gpx") allFilesSplit+ putStr ("Processing "++show (length gpxFiles)++" file(s)...\n")+ mapM (\(a,b) -> generateReport (curDir++"/"++a) (a++b)) gpxFiles++-- | Creates empty directory for each web report+createEmptyDir :: FilePath -> IO ()+createEmptyDir dir = do+ exists <- doesDirectoryExist dir+ (if exists then removeDirectoryRecursive dir >> createDirectory dir else createDirectory dir)++-- | Generates the HTML report for each .gpx file+generateReport :: FilePath -> FilePath -> IO ()+generateReport webDir gpxFile = do+ points <- readGPX gpxFile+ case length points of+ 0 -> putStr "Unable to parse GPX file. Skipping..."+ otherwise -> do+ createEmptyDir webDir+ renderToPng (chart1 points) (webDir++"/chart1.png")+ renderToPng (chart2 points) (webDir++"/chart2.png")+ writeFile (webDir++"/index.html") $ renderHtml $ generateHtmlPage points+ createOsmMap webDir gpxFile+ putStr $ "Processing '"++gpxFile++"' complete. Report saved in: "++webDir++"/index.html\n"+ return ()
+ Data/GPS/Gps2HtmlReport/OsmChart.hs view
@@ -0,0 +1,40 @@+-- {-# LANGUAGE ScopedTypeVariables #-}++-- | This module utilizes the perl gpx2png program+-- to download the OSM tiles, and the GraphicsMagick bindings+-- to resize the OSM image if necessary+module Data.GPS.Gps2HtmlReport.OsmChart where++import System.FilePath+import System.Directory+import System.Process+import Graphics.GD+import Control.Monad++-- | If the generated OSM image has a greater width than 800 pixels, it is scaled to have a width of 800 pixels.+fitToWidth :: FilePath -> IO ()+fitToWidth imgPath = do+ img <- loadPngFile imgPath+ dimensions <- imageSize img+ let width = fst dimensions+ when (width > 800) $ resizeImg imgPath img dimensions++-- | Uses the GraphicsMagick bindings the resize the image+resizeImg :: FilePath -> Image -> (Int,Int) -> IO () +resizeImg imgPath img dimensions = do+ let resizeRatio = fromIntegral (fst dimensions) / 800.0+ height = round (fromIntegral (snd dimensions) / resizeRatio)+ resizedImg <- resizeImage 800 height img+ savePngFile imgPath resizedImg+ +-- | Calls the perl `gpx2png' utility to download the relevant OSM tiles+createOsmMap :: String -> String -> IO [()]+createOsmMap webDir gpxFile = do+ (_,_,_,pid) <- createProcess (shell ("perl gpx2png/gpx2png.pl -q -o "++webDir++"/osm.png "++ gpxFile))+ waitForProcess pid+ fitToWidth $ webDir++"/osm.png"+ curDir <- getCurrentDirectory+ allFiles <- getDirectoryContents curDir+ let allFilesSplit = map splitExtension allFiles+ let tmpPngFiles = filter (\(_,b) -> b==".png") allFilesSplit+ mapM (\(a,b) -> removeFile (a++b) ) tmpPngFiles
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Robert Stewart 2011++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of the author nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,74 @@+GPS 2 HTML Report+================++This is a utility written in Haskell, to generate HTML reports from GPS track files.++Included in the report:++* Details of the journey... journey time, distance travelled etc..+* Diagrams charting speed, elevation, accumulated distance etc..+* OpenStreetMap diagram highlighting the GPS track++An example can be seen [HERE](http://www.macs.hw.ac.uk/~rs46/gps2htmlreport/3/index.html).++The Haddock documentation pages can be found [here](http://www.macs.hw.ac.uk/~rs46/gps2htmlreport/doc/).++Installation+------------+It is assumed that you have the Haskell Platform installed.++Just run these commands to configure and install the `gps2HtmlReport' utility, run these commands:++```+cabal configure+cabal install+```++This Haskell program also makes use of the bindings to **GraphcsMagick** and **Cairo**, and so the necessary system packages need to be installed, via a *nix package manager.++On an RPM-based package manager, run this command as root:++```+yum install GraphicsMagick cairo+```++Prerequisites+-------------+First of all, you need to have your GPS date in a GPX file. There are many gpx exporters available. I use my Android phone to take GPX tracks, with a great application, [OSMTracker](https://code.google.com/p/osmtracker-android/). This application allows you to export your GPS tracks to GPX.++Usage+-----+The program will search for all files ending in ".gpx", and for each one, generate a HTML report.++```+$ cd $location_of_gpx_files+$ ls+1.gpx 2.gpx 3.gpx+$ gps2HtmlReport+Processing 3 file(s)...+Processing '1.gpx' complete. Report saved in: /home/foo/gps_tracks/1/index.html+Processing '2.gpx' complete. Report saved in: /home/foo/gps_tracks/2/index.html+Processing '3.gpx' complete. Report saved in: /home/foo/gps_tracks/3/index.html+```++Notes+-----+This project requires testing!++If you are able to use the utility to generate HTML reports, then I'd like to hear suggestions for improvements. If you are **unable** to run it, then I **really** want to hear from you. What the problem is; How far did you get; or better still, send me the .gpx file.++I'd also like to know what is required to make this utility work on non-Linux systems. This has been tested on a Fedora Linux machine. Does it work on Mac OSX? Windows? What needs doing to run it on other Linux distro's?++Either way, get in touch!++To Do+-----++* It would be great to port the perl `gpx2png' utility to Haskell, eliminating this dependency.+* This Haskell program currently makes use of elevation, latitude and longitude. There are many other attributes possibly available in WptType. Ideas for what to do with these attributes [here](http://hackage.haskell.org/packages/archive/GPX/0.4.8/doc/html/Data-Geo-GPX-WptType.html#t:WptType) most welcome.++Credits+-------+Thanks goes to the developers of the [gpx2png project](http://wiki.openstreetmap.org/wiki/Gpx2png), which is used to generate the OpenStreetMap image.++In addition, thanks to [Thomas DuBuisson](http://www.haskellers.com/user/TomMD), for implementing the `gps' package and contributing it to Hackage.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ gps2htmlReport.cabal view
@@ -0,0 +1,24 @@+Name: gps2htmlReport+Version: 0.1+Cabal-Version: >=1.2+Description: Generate a HTML summary report of GPS tracks+synopsis: GPS to HTML Summary Report+License: BSD3+License-file: LICENSE+Author: Rob Stewart <robstewart57@googlemail.com>+Maintainer: Rob Stewart <robstewart57@googlemail.com>+Homepage: https://github.com/robstewart57/Gps2HtmlReport+bug-reports: https://github.com/robstewart57/Gps2HtmlReport+Build-Type: Simple+stability: alpha+category: Data+extra-source-files: README.md+tested-with: GHC ==7.0.2++Executable gps2htmlReport+ Main-is: Data/GPS/Gps2HtmlReport/Main.hs++library+ Build-Depends: base >= 4 && < 5, html, gps, time, cairo, Chart, random, data-accessor, colour, xsd, filepath, directory, process, gd+ Extensions: ScopedTypeVariables+ Exposed-Modules: Data.GPS.Gps2HtmlReport.HTMLGenerator, Data.GPS.Gps2HtmlReport.JourneyStats, Data.GPS.Gps2HtmlReport.JourneyCharts, Data.GPS.Gps2HtmlReport.OsmChart