chart-svg-0.1.0: src/Chart/Render.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_GHC -Wall #-}
module Chart.Render
( scaleCharts,
getAspect,
getViewbox,
getSize,
renderToSvg,
renderChartsWith,
renderCharts,
renderCharts_,
writeChartsWith,
writeCharts,
writeCharts_,
renderHudChart,
renderHudOptionsChart,
writeHudOptionsChart,
svg2_,
cssCrisp,
)
where
import Chart.Types
import Control.Lens hiding (transform)
import Data.Generics.Labels ()
import qualified Data.Text.Lazy as Lazy
import Lucid
import qualified Lucid.Base as Lucid
import Lucid.Base
import NumHask.Prelude
import NumHask.Space hiding (Element)
-- | scale chart data, projecting to the supplied Rect, and expanding the resultant Rect for chart style if necessary.
--
-- Note that this modifies the underlying chart data.
-- FIXME: do a divide to make an exact fit
scaleCharts ::
Rect Double ->
[Chart Double] ->
(Rect Double, [Chart Double])
scaleCharts cs r = (defRect $ styleBoxes cs', cs')
where
cs' = projectSpots cs r
getAspect :: SvgAspect -> [Chart Double] -> Double
getAspect (ManualAspect a) _ = a
getAspect ChartAspect cs = toAspect . defRect $ styleBoxes cs
getSize :: SvgOptions -> [Chart Double] -> Point Double
getSize o cs = case view #svgAspect o of
ManualAspect a -> (view #svgHeight o *) <$> Point a 1
ChartAspect -> (\(Rect x z y w) -> Point (view #svgHeight o * (z - x)) (view #svgHeight o * (w - y))) . defRect $ styleBoxes cs
getViewbox :: SvgOptions -> [Chart Double] -> Rect Double
getViewbox o cs =
bool asp (defRect $ styleBoxes cs) (NoScaleCharts == view #scaleCharts' o)
where
asp =
case view #svgAspect o of
ManualAspect a -> Rect (a * (-0.5)) (a * 0.5) (-0.5) 0.5
ChartAspect -> defRect $ styleBoxes cs
-- * rendering
-- | @svg@ element + svg 2 attributes
svg2_ :: Term [Attribute] (s -> t) => s -> t
svg2_ m =
svg_
[ Lucid.makeAttribute "xmlns" "http://www.w3.org/2000/svg",
Lucid.makeAttribute "xmlns:xlink" "http://www.w3.org/1999/xlink"
]
m
renderToSvg :: CssOptions -> Point Double -> Rect Double -> [Chart Double] -> Html ()
renderToSvg csso (Point w' h') (Rect x z y w) cs =
with
( svg2_
( bool id (cssCrisp <>) (csso == UseCssCrisp) $
chartDefs cs <> mconcat (svg <$> cs)
)
)
[ width_ (show w'),
height_ (show h'),
makeAttribute "viewBox" (show x <> " " <> show (- w) <> " " <> show (z - x) <> " " <> show (w - y))
]
cssCrisp :: Html ()
cssCrisp = style_ [type_ "text/css"] ("{ shape-rendering: 'crispEdges'; }" :: Text)
-- | render Charts with the supplied css options, size and viewbox.
renderCharts_ :: CssOptions -> Point Double -> Rect Double -> [Chart Double] -> Text
renderCharts_ csso p r cs =
Lazy.toStrict $ renderText (renderToSvg csso p r cs)
-- | render Charts with the supplied options.
renderChartsWith :: SvgOptions -> [Chart Double] -> Text
renderChartsWith so cs =
Lazy.toStrict $ renderText (renderToSvg (so ^. #useCssCrisp) (getSize so cs'') r' cs'')
where
r' = r & maybe id padRect (so ^. #outerPad)
cs'' =
cs'
& maybe id (\x -> frameChart x (fromMaybe 0 (so ^. #innerPad))) (so ^. #chartFrame)
(r, cs') =
bool
(getViewbox so cs, cs)
(scaleCharts (getViewbox so cs) cs)
(ScaleCharts == so ^. #scaleCharts')
-- | render charts with the default options.
renderCharts :: [Chart Double] -> Text
renderCharts = renderChartsWith defaultSvgOptions
writeChartsWith :: FilePath -> SvgOptions -> [Chart Double] -> IO ()
writeChartsWith fp so cs = writeFile fp (renderChartsWith so cs)
writeCharts :: FilePath -> [Chart Double] -> IO ()
writeCharts fp cs = writeFile fp (renderCharts cs)
-- | write Charts to a file with the supplied css options, size and viewbox.
writeCharts_ :: FilePath -> CssOptions -> Point Double -> Rect Double -> [Chart Double] -> IO ()
writeCharts_ fp csso p r cs =
writeFile fp (renderCharts_ csso p r cs)
-- * rendering huds and charts
-- | Render some huds and charts.
renderHudChart :: SvgOptions -> [Hud Double] -> [Chart Double] -> Text
renderHudChart so hs cs = renderChartsWith so (runHud (getViewbox so cs) hs cs)
-- | Render a chart using the supplied svg and hud config.
renderHudOptionsChart :: SvgOptions -> HudOptions -> [Hud Double] -> [Chart Double] -> Text
renderHudOptionsChart so hc hs cs = renderHudChart so (hs <> hs') (cs <> cs')
where
(hs', cs') = makeHud (defRect $ styleBoxes cs) hc
writeHudOptionsChart :: FilePath -> SvgOptions -> HudOptions -> [Hud Double] -> [Chart Double] -> IO ()
writeHudOptionsChart fp so hc hs cs =
writeFile fp (renderHudOptionsChart so hc hs cs)