module Graphics.Rendering.Chart.SparkLine
(
SparkLine(..)
, SparkOptions(..)
, smoothSpark
, barSpark
, sparkSize
, renderSparkLine
, sparkLineToRenderable
, sparkWidth
) where
import Control.Monad
import Data.List
import Data.Ord
import Graphics.Rendering.Chart.Geometry
import Graphics.Rendering.Chart.Drawing
import Graphics.Rendering.Chart.Renderable
import Data.Colour
import Data.Colour.Names
data SparkLine = SparkLine { sl_options :: SparkOptions
, sl_data :: [Double]
}
data SparkOptions = SparkOptions
{ so_smooth :: Bool
, so_step :: Int
, so_height :: Int
, so_limits :: (Double,Double)
, so_bgColor :: Colour Double
, so_minColor :: Colour Double
, so_maxColor :: Colour Double
, so_lastColor :: Colour Double
, so_minMarker :: Bool
, so_maxMarker :: Bool
, so_lastMarker :: Bool
} deriving (Show)
smoothSpark :: SparkOptions
smoothSpark = SparkOptions
{ so_smooth = True
, so_step = 2
, so_height = 20
, so_limits = (0,100)
, so_bgColor = white
, so_minColor = red
, so_maxColor = green
, so_lastColor = blue
, so_minMarker = True
, so_maxMarker = True
, so_lastMarker = True
}
barSpark :: SparkOptions
barSpark = smoothSpark { so_smooth=False }
sparkLineToRenderable :: SparkLine -> Renderable ()
sparkLineToRenderable sp = Renderable
{ minsize = let (w,h) = sparkSize sp in return (fromIntegral w , fromIntegral h)
, render = \_rect-> renderSparkLine sp
}
instance ToRenderable SparkLine where
toRenderable = sparkLineToRenderable
sparkWidth :: SparkLine -> Int
sparkWidth SparkLine{sl_options=opt, sl_data=ds} =
let w = 4 + (so_step opt) * (length ds 1) + extrawidth
extrawidth | so_smooth opt = 0
| otherwise = bw * length ds
bw | so_smooth opt = 0
| otherwise = 2
in w
sparkSize :: SparkLine -> (Int,Int)
sparkSize s = (sparkWidth s, so_height (sl_options s))
renderSparkLine :: SparkLine -> BackendProgram (PickFn ())
renderSparkLine SparkLine{sl_options=opt, sl_data=ds} =
let w = 4 + (so_step opt) * (length ds 1) + extrawidth
extrawidth | so_smooth opt = 0
| otherwise = bw * length ds
bw | so_smooth opt = 0
| otherwise = 2
h = so_height opt
dmin = fst (so_limits opt)
dmax = snd (so_limits opt)
coords = zipWith (\x y-> Point (fi x) y)
[1,(1+bw+so_step opt)..(1+(so_step opt+bw)*(length ds))]
[ fi h ( (ydmin) /
((dmaxdmin+1) / fi (h4)) )
| y <- ds ]
minpt = maximumBy (comparing p_y) coords
maxpt = minimumBy (comparing p_y) coords
endpt = last coords
boxpt :: Point -> Rect
boxpt (Point x y) = Rect (Point (x1)(y1)) (Point (x+1)(y+1))
fi :: (Num b, Integral a) => a -> b
fi = fromIntegral
in do
withFillStyle (solidFillStyle (opaque (so_bgColor opt))) $ do
fillPath (rectPath (Rect (Point 0 0) (Point (fi w) (fi h))))
if so_smooth opt
then do
withLineStyle (solidLine 1 (opaque grey)) $ do
p <- alignStrokePoints coords
strokePointPath p
else do
withFillStyle (solidFillStyle (opaque grey)) $ do
forM_ coords $ \ (Point x y) ->
fillPath (rectPath (Rect (Point (x1) y) (Point (x+1) (fi h))))
when (so_minMarker opt) $ do
withFillStyle (solidFillStyle (opaque (so_minColor opt))) $ do
p <- alignFillPath (rectPath (boxpt minpt))
fillPath p
when (so_maxMarker opt) $ do
withFillStyle (solidFillStyle (opaque (so_maxColor opt))) $ do
p <- alignFillPath (rectPath (boxpt maxpt))
fillPath p
when (so_lastMarker opt) $ do
withFillStyle (solidFillStyle (opaque (so_lastColor opt))) $ do
p <- alignFillPath (rectPath (boxpt endpt))
fillPath p
return nullPickFn