waterfall-cad-svg-0.8.0.0: src/Waterfall/SVG/ToSVG/LineStyle.hs
{-|
Module: Waterfall.SVG.ToSVG.LineStyle
Specify how the `Waterfall.Path2D`s in a `Waterfall.Diagram.Diagram` are displayed when it's converted to SVG (see `Waterfall.SVG.ToSVG.diagramToSvgWithLineStyle`).
`DiagramStyle` values can be constructed from the @lineWith*@ and @diagramWith*@ functions and can be combined monoidally (with `<>`), e.g.
@
thickVisibleThinHiddenLines =
diagramWithVisibleLine
( lineWithColour (Colour 0 0 0)
<> lineWithOpacity 1.0
<> lineWithWidth 3.0
)
<> diagramWithHiddenLine
( lineWithColour (Colour 0.3 0.3 1.0)
<> lineWithOpacity 0.2
<> lineWithWidth 0.5
)
@
Properties that are not set fall back to the values in `defaultDiagramStyle`
-}
{-# LANGUAGE DeriveGeneric, DerivingVia, InstanceSigs #-}
module Waterfall.SVG.ToSVG.LineStyle
( DiagramStyle
, LineStyle
, defaultDiagramStyle
-- * Constructors
, lineWithColour
, lineWithOpacity
, lineWithWidth
, diagramWithVisibleLine
, diagramWithHiddenLine
-- * Optics
, lineColour
, lineOpacity
, lineWidth
, diagramVisibleLine
, diagramHiddenLine
) where
import qualified Waterfall
import GHC.Generics (Generic, Generically (..))
import Control.DeepSeq (NFData)
import Data.Monoid (Last (..), Endo (..))
import Data.Maybe (catMaybes)
import Data.List (intersperse)
import Control.Lens (Lens', lens)
-- | How the lines in a diagram should appear
--
-- `DiagramStyle` values can be constructed from the @diagramWith*@ functions and can be combined monoidally (with `<>`).
data DiagramStyle = DiagramStyle
{ _visibleLine :: LineStyle
, _hiddenLine :: LineStyle
} deriving (Eq, Ord, Generic)
deriving (Semigroup, Monoid) via (Generically DiagramStyle)
instance NFData DiagramStyle
instance Show DiagramStyle where
showsPrec :: Int -> DiagramStyle -> ShowS
showsPrec d p =
let showTerm name term =
showString name
. showChar ' '
. showsPrec 11 term
showVisible = showTerm "diagramWithVisibleLine" (_visibleLine p)
showHidden = showTerm "diagramWithHiddenLine" (_hiddenLine p)
in case (_visibleLine p == mempty, _hiddenLine p == mempty) of
(True, True) -> showString "mempty"
(True, False) -> showParen (d > 10) showHidden
(False, True) -> showParen (d > 10) showVisible
(False, False) ->
showParen (d > 6)
( showVisible
. showString " <> "
. showHidden
)
-- | How a particular set of lines (visible or hidden) should appear
--
-- `LineStyle` values can be constructed from the @lineWith*@ functions and can be combined monoidally (with `<>`).
data LineStyle = LineStyle
{ _lineColour :: Last Waterfall.Colour
, _lineOpacity :: Last Double
, _lineWidth :: Last Double
} deriving (Eq, Ord, Generic)
deriving (Semigroup, Monoid) via (Generically LineStyle)
instance NFData LineStyle
instance Show LineStyle where
showsPrec :: Int -> LineStyle -> ShowS
showsPrec d p =
let term name field =
let fv v =
showString name
. showChar ' '
. showsPrec 11 v
in fv <$> getLast (field p)
terms = catMaybes
[ term "lineWithColour" _lineColour
, term "lineWithOpacity" _lineOpacity
, term "lineWithWidth" _lineWidth
]
in case terms of
[] -> showString "mempty"
_ -> showParen (d > 6) . appEndo
. foldMap Endo
. intersperse (showString " <> ")
$ terms
-- | Create a `LineStyle` with a given `Waterfall.Colour`
lineWithColour :: Waterfall.Colour -> LineStyle
lineWithColour c = mempty {_lineColour = Last . Just $ c}
-- | The `Waterfall.Colour` used to draw a set of lines
--
-- Used to set the @stroke@ CSS property
lineColour :: Lens' LineStyle (Maybe Waterfall.Colour)
lineColour = lens
(getLast . _lineColour)
(\ls c -> ls {_lineColour = Last c})
-- | Create a `LineStyle` with a given opacity
--
-- Opacity is in the range [0, 1]
lineWithOpacity :: Double -> LineStyle
lineWithOpacity opacity = mempty {_lineOpacity = Last . Just $ opacity}
-- | The opacity used to draw a set of lines
--
-- Used to set the @stroke-opacity@ CSS property
lineOpacity :: Lens' LineStyle (Maybe Double)
lineOpacity = lens
(getLast . _lineOpacity)
(\ls c -> ls {_lineOpacity = Last c})
-- | Create a `LineStyle` with a given width
--
-- Width is in SVG user units
lineWithWidth :: Double -> LineStyle
lineWithWidth width = mempty {_lineWidth= Last . Just $ width}
-- | The width used to draw a set of lines
--
-- Used to set the @stroke-width@ CSS property
lineWidth :: Lens' LineStyle (Maybe Double)
lineWidth = lens
(getLast . _lineWidth)
(\ls c -> ls {_lineWidth = Last c})
-- | Create a `DiagramStyle` specifying how to draw visible lines
diagramWithVisibleLine :: LineStyle -> DiagramStyle
diagramWithVisibleLine lineStyle = mempty {_visibleLine = lineStyle}
-- | The visible line style for a `DiagramStyle`
diagramVisibleLine :: Lens' DiagramStyle LineStyle
diagramVisibleLine = lens _visibleLine (\ds ls -> ds {_visibleLine = ls})
-- | Create a `DiagramStyle` specifying how to draw hidden lines
diagramWithHiddenLine :: LineStyle -> DiagramStyle
diagramWithHiddenLine lineStyle = mempty {_hiddenLine = lineStyle}
-- | The hidden line style for a `DiagramStyle`
diagramHiddenLine :: Lens' DiagramStyle LineStyle
diagramHiddenLine = lens _hiddenLine (\ds ls -> ds {_hiddenLine = ls})
-- | Fallback values used for a property of a `DiagramStyle` which is unset
--
-- @
-- defaultDiagramStyle /= mempty
-- @
defaultDiagramStyle :: DiagramStyle
defaultDiagramStyle = DiagramStyle
{ _visibleLine = LineStyle
{ _lineColour = Last . Just $ Waterfall.Colour 0 0 0
, _lineOpacity = Last . Just $ 1
, _lineWidth = Last . Just $ 1
}
, _hiddenLine = LineStyle
{ _lineColour = Last . Just $ Waterfall.Colour 0 0 0
, _lineOpacity = Last . Just $ 0.4
, _lineWidth = Last . Just $ 1
}
}