-- | 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 ( renderToPng, -- :: (t, OutputType -> Renderable a) -> FilePath -> IO (PickFn a) chart1, -- :: [WptType] -> (String, OutputType -> Renderable ()) chart2 -- :: [WptType] -> (String, OutputType -> Renderable ()) )where import Data.GPS import Data.Maybe import Graphics.Rendering.Chart import Data.Accessor import Data.Colour import Data.Colour.Names import Data.Time.LocalTime import Data.GPS.Gps2HtmlReport.JourneyStats (ptsElevation,avrSpeedOverTime,accumDistance,findPoint) 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 = [(utcToLocalTime utc theTime,spd) | (theTime,spd) <- avgSpeeds 10 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)