----------------------------------------------------------------------------- -- | -- Module : Graphics.Rendering.Chart.Legend -- Copyright : (c) Tim Docker 2006 -- License : BSD-style (see chart/COPYRIGHT) -- -- Types and functions for handling the legend(s) on a chart. A legend -- is an area on the chart used to label the plotted values. {-# OPTIONS_GHC -XTemplateHaskell #-} module Graphics.Rendering.Chart.Legend( Legend(..), LegendStyle(..), LegendOrientation(..), defaultLegendStyle, legendToRenderable, legend_label_style, legend_margin, legend_plot_size, legend_orientation ) where import qualified Graphics.Rendering.Cairo as C import Control.Monad import Data.List (nub, partition,intersperse) import Data.Accessor.Template import Graphics.Rendering.Chart.Types import Graphics.Rendering.Chart.Plot.Types import Graphics.Rendering.Chart.Renderable import Graphics.Rendering.Chart.Grid ---------------------------------------------------------------------- -- Legend data LegendStyle = LegendStyle { legend_label_style_ :: CairoFontStyle, legend_margin_ :: Double, legend_plot_size_ :: Double, legend_orientation_ :: LegendOrientation } -- | Legends can be constructed in two orientations: in rows -- (where we specify the maximum number of columns), and in -- columns (where we specify the maximum number of rows) data LegendOrientation = LORows Int | LOCols Int data Legend x y = Legend LegendStyle [(String, Rect -> CRender ())] instance ToRenderable (Legend x y) where toRenderable = setPickFn nullPickFn.legendToRenderable legendToRenderable :: Legend x y -> Renderable String legendToRenderable (Legend ls lvs) = gridToRenderable grid where grid = case legend_orientation_ ls of LORows n -> mkGrid n aboveG besideG LOCols n -> mkGrid n besideG aboveG aboveG = aboveN.(intersperse ggap1) besideG = besideN.(intersperse ggap1) mkGrid n join1 join2 = join1 [ join2 (map rf ps1) | ps1 <- groups n ps ] ps :: [(String, [Rect -> CRender ()])] ps = join_nub lvs rf (title,rfs) = besideN [gpic,ggap2,gtitle] where gpic = besideN $ intersperse ggap2 (map rp rfs) gtitle = tval $ lbl title rp rfn = tval $ Renderable { minsize = return (legend_plot_size_ ls, 0), render = \(w,h) -> do rfn (Rect (Point 0 0) (Point w h)) return (\_-> Just title) } ggap1 = tval $ spacer (legend_margin_ ls,legend_margin_ ls / 2) ggap2 = tval $ spacer1 (lbl "X") lbl s = label (legend_label_style_ ls) HTA_Left VTA_Centre s groups :: Int -> [a] -> [[a]] groups n [] = [] groups n vs = let (vs1,vs2) = splitAt n vs in vs1:groups n vs2 join_nub :: [(String, a)] -> [(String, [a])] join_nub ((x,a1):ys) = case partition ((==x) . fst) ys of (xs, rest) -> (x, a1:map snd xs) : join_nub rest join_nub [] = [] defaultLegendStyle :: LegendStyle defaultLegendStyle = LegendStyle { legend_label_style_ = defaultFontStyle, legend_margin_ = 20, legend_plot_size_ = 20, legend_orientation_ = LORows 4 } ---------------------------------------------------------------------- -- Template haskell to derive an instance of Data.Accessor.Accessor -- for each field. $( deriveAccessors ''LegendStyle )