-----------------------------------------------------------------------------
-- |
-- Module      :  Graphics.Rendering.Chart.Plot.Annotation
-- Copyright   :  (c) Tim Docker 2006, 2014
-- License     :  BSD-style (see chart/COPYRIGHT)
--
-- Show textual annotations on a chart.

{-# LANGUAGE TemplateHaskell #-}

module Graphics.Rendering.Chart.Plot.Annotation(
    PlotAnnotation(..),

    plot_annotation_hanchor,
    plot_annotation_vanchor,
    plot_annotation_angle,
    plot_annotation_style,
    plot_annotation_background,
    plot_annotation_offset,
    plot_annotation_values
) where

import Control.Lens
import Data.Default.Class
import Graphics.Rendering.Chart.Geometry
import Graphics.Rendering.Chart.Drawing
import Graphics.Rendering.Chart.Renderable
import Graphics.Rendering.Chart.Plot.Types
import Graphics.Rendering.Chart.Drawing
import Graphics.Rendering.Chart.Geometry
import Graphics.Rendering.Chart.Plot.Types

-- | Value for describing a series of text annotations
--   to be placed at arbitrary points on the graph. Annotations
--   can be rotated and styled.

data PlotAnnotation  x y = PlotAnnotation {
      forall x y. PlotAnnotation x y -> HTextAnchor
_plot_annotation_hanchor :: HTextAnchor,
      forall x y. PlotAnnotation x y -> VTextAnchor
_plot_annotation_vanchor :: VTextAnchor,
      forall x y. PlotAnnotation x y -> Double
_plot_annotation_angle   :: Double,
      -- ^ Angle, in degrees, to rotate the annotation about the anchor point.
      forall x y. PlotAnnotation x y -> FontStyle
_plot_annotation_style   :: FontStyle,
      forall x y. PlotAnnotation x y -> Rectangle
_plot_annotation_background :: Rectangle,
      -- ^ Rectangle which style determines the background of the annotation
      -- text and which '_rect_minsize' determines the additional width and
      -- height of the background area
      forall x y. PlotAnnotation x y -> Vector
_plot_annotation_offset  :: Vector,
      forall x y. PlotAnnotation x y -> [(x, y, String)]
_plot_annotation_values  :: [(x,y,String)]
}


instance ToPlot PlotAnnotation where
    toPlot :: forall x y. PlotAnnotation x y -> Plot x y
toPlot PlotAnnotation x y
p = Plot {
      _plot_render :: PointMapFn x y -> BackendProgram ()
_plot_render = forall x y.
PlotAnnotation x y -> PointMapFn x y -> BackendProgram ()
renderAnnotation PlotAnnotation x y
p,
      _plot_legend :: [(String, Rect -> BackendProgram ())]
_plot_legend = [],
      _plot_all_points :: ([x], [y])
_plot_all_points = (forall a b. (a -> b) -> [a] -> [b]
map (forall s a. s -> Getting a s a -> a
^.forall s t a b. Field1 s t a b => Lens s t a b
_1) [(x, y, String)]
vs , forall a b. (a -> b) -> [a] -> [b]
map (forall s a. s -> Getting a s a -> a
^.forall s t a b. Field2 s t a b => Lens s t a b
_2) [(x, y, String)]
vs)
    }
      where
        vs :: [(x, y, String)]
vs = forall x y. PlotAnnotation x y -> [(x, y, String)]
_plot_annotation_values PlotAnnotation x y
p


renderAnnotation :: PlotAnnotation x y -> PointMapFn x y -> BackendProgram ()
renderAnnotation :: forall x y.
PlotAnnotation x y -> PointMapFn x y -> BackendProgram ()
renderAnnotation PlotAnnotation x y
p PointMapFn x y
pMap = forall a. FontStyle -> BackendProgram a -> BackendProgram a
withFontStyle FontStyle
style forall a b. (a -> b) -> a -> b
$ do
                            forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ forall {a}.
(x, y, String) -> ProgramT ChartBackendInstr Identity (PickFn a)
drawRect [(x, y, String)]
values
                            forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (x, y, String) -> BackendProgram ()
drawOne [(x, y, String)]
values
    where hta :: HTextAnchor
hta = forall x y. PlotAnnotation x y -> HTextAnchor
_plot_annotation_hanchor PlotAnnotation x y
p
          vta :: VTextAnchor
vta = forall x y. PlotAnnotation x y -> VTextAnchor
_plot_annotation_vanchor PlotAnnotation x y
p
          values :: [(x, y, String)]
values = forall x y. PlotAnnotation x y -> [(x, y, String)]
_plot_annotation_values PlotAnnotation x y
p
          angle :: Double
angle =  forall x y. PlotAnnotation x y -> Double
_plot_annotation_angle PlotAnnotation x y
p
          style :: FontStyle
style =  forall x y. PlotAnnotation x y -> FontStyle
_plot_annotation_style PlotAnnotation x y
p
          offset :: Vector
offset = forall x y. PlotAnnotation x y -> Vector
_plot_annotation_offset PlotAnnotation x y
p
          rectangle :: Rectangle
rectangle = forall x y. PlotAnnotation x y -> Rectangle
_plot_annotation_background PlotAnnotation x y
p
          (Double
x1,Double
y1) = Rectangle -> (Double, Double)
_rect_minsize Rectangle
rectangle
          drawRect :: (x, y, String) -> ProgramT ChartBackendInstr Identity (PickFn a)
drawRect (x
x,y
y,String
s) = do
              TextSize
ts <- String -> BackendProgram TextSize
textSize String
s
              let (Double
x2,Double
y2) = (TextSize -> Double
textSizeWidth TextSize
ts, TextSize -> Double
textSizeHeight TextSize
ts)
                  Point Double
x3 Double
y3 = x -> y -> Point
point x
x y
y
                  -- position of top-left vertex of the rectangle
                  xvp :: HTextAnchor -> Double
xvp HTextAnchor
HTA_Left = Double
x3 forall a. Num a => a -> a -> a
- Double
x1 forall a. Fractional a => a -> a -> a
/ Double
2
                  xvp HTextAnchor
HTA_Centre = Double
x3 forall a. Num a => a -> a -> a
- (Double
x1 forall a. Num a => a -> a -> a
+ Double
x2) forall a. Fractional a => a -> a -> a
/ Double
2
                  xvp HTextAnchor
HTA_Right = Double
x3 forall a. Num a => a -> a -> a
- Double
x2 forall a. Num a => a -> a -> a
- Double
x1 forall a. Fractional a => a -> a -> a
/ Double
2
                  yvp :: VTextAnchor -> Double
yvp VTextAnchor
VTA_Top = Double
y3 forall a. Num a => a -> a -> a
- Double
y1 forall a. Fractional a => a -> a -> a
/ Double
2
                  yvp VTextAnchor
VTA_Centre = Double
y3 forall a. Num a => a -> a -> a
- (Double
y1 forall a. Num a => a -> a -> a
+ Double
y2) forall a. Fractional a => a -> a -> a
/ Double
2
                  yvp VTextAnchor
VTA_Bottom = Double
y3 forall a. Num a => a -> a -> a
- Double
y2 forall a. Num a => a -> a -> a
- Double
y1 forall a. Fractional a => a -> a -> a
/ Double
2
                  yvp VTextAnchor
VTA_BaseLine = Double
y3 forall a. Num a => a -> a -> a
- Double
y1 forall a. Fractional a => a -> a -> a
/ Double
2 forall a. Num a => a -> a -> a
- TextSize -> Double
textSizeAscent TextSize
ts
              forall a. Point -> Rectangle -> BackendProgram (PickFn a)
drawRectangle (Double -> Double -> Point
Point (HTextAnchor -> Double
xvp HTextAnchor
hta) (VTextAnchor -> Double
yvp VTextAnchor
vta) Point -> Vector -> Point
`pvadd` Vector
offset) Rectangle
rectangle{ _rect_minsize :: (Double, Double)
_rect_minsize = (Double
x1forall a. Num a => a -> a -> a
+Double
x2,Double
y1forall a. Num a => a -> a -> a
+Double
y2) }
          drawOne :: (x, y, String) -> BackendProgram ()
drawOne (x
x,y
y,String
s) = HTextAnchor
-> VTextAnchor -> Double -> Point -> String -> BackendProgram ()
drawTextsR HTextAnchor
hta VTextAnchor
vta Double
angle (x -> y -> Point
point x
x y
y) String
s
          point :: x -> y -> Point
point x
x y
y = PointMapFn x y
pMap (forall a. a -> Limit a
LValue x
x, forall a. a -> Limit a
LValue y
y) Point -> Vector -> Point
`pvadd` Vector
offset

instance Default (PlotAnnotation x y) where
  def :: PlotAnnotation x y
def = PlotAnnotation
    { _plot_annotation_hanchor :: HTextAnchor
_plot_annotation_hanchor = HTextAnchor
HTA_Centre
    , _plot_annotation_vanchor :: VTextAnchor
_plot_annotation_vanchor = VTextAnchor
VTA_Centre
    , _plot_annotation_angle :: Double
_plot_annotation_angle   = Double
0
    , _plot_annotation_style :: FontStyle
_plot_annotation_style   = forall a. Default a => a
def
    , _plot_annotation_background :: Rectangle
_plot_annotation_background = forall a. Default a => a
def
    , _plot_annotation_values :: [(x, y, String)]
_plot_annotation_values  = []
    , _plot_annotation_offset :: Vector
_plot_annotation_offset  = Double -> Double -> Vector
Vector Double
0 Double
0
    }

$( makeLenses ''PlotAnnotation )