packages feed

chart-svg-0.1.0: app/venn.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}

import Chart
import Control.Lens
import Data.Generics.Labels ()
import qualified Data.Map.Strict as Map
import qualified Data.Text as Text
import qualified Data.Text.Lazy as Lazy
import NumHask.Prelude
import Lucid
import Lucid.Base

xs :: Map.Map Text (Point Double)
xs =
  Map.fromList
    [ ("origin", Point 0 0), -- origin
      ("circle1", Point 0.5 (-0.5 + cos (pi / 6))), -- center of circle 1
      ("circle2", Point 0 (-0.5)), -- center of circle 2
      ("circle3", Point (-0.5) ((-0.5) + cos (pi / 6))), -- center of circle 3
      ("corner1", Point 0 ((-0.5) + 2 * cos (pi / 6))), -- corner 1
      ("corner2", Point 1 (-0.5)), -- corner 2
      ("corner3", Point (-1) (-0.5)) -- corner 3
    ]

vennps :: Text -> (Double, Double)
vennps k = let (Point x y) = xs Map.! k in (x, - y)

moveA :: Double -> Double -> Text
moveA x y = "M" <> show x <> "," <> show y

data Arc = Arc {arcXr :: Double, arcYr :: Double, arcRot :: Double, arcLargeArcFlag :: Bool, arcSweepFlag :: Bool, arcX :: Double, arcY :: Double} deriving (Eq, Show, Generic)

arcA_ :: Arc -> Text
arcA_ a = show (view #arcXr a) <> " " <> show (view #arcYr a) <> " " <> show (view #arcRot a) <> " " <> bool "0" "1" (view #arcLargeArcFlag a) <> " " <> bool "0" "1" (view #arcSweepFlag a) <> " " <> show (view #arcX a) <> "," <> show (view #arcY a)

arcA :: [Arc] -> Text
arcA as = "A" <> Text.intercalate " " (arcA_ <$> as)

outerseg1 :: Text
outerseg1 =
  Text.intercalate
    " "
    [ uncurry moveA (vennps "corner1"),
      arcA
        [ uncurry (Arc 0.5 0.5 0 True True) (vennps "corner2"),
          uncurry (Arc 1 1 0 False False) (vennps "circle1"),
          uncurry (Arc 1 1 0 False False) (vennps "corner1")
        ],
      "Z"
    ]

outerseg2 :: Text
outerseg2 =
  Text.intercalate
    " "
    [ uncurry moveA (vennps "corner3"),
      arcA
        [ uncurry (Arc 0.5 0.5 0 True False) (vennps "corner2"),
          uncurry (Arc 1 1 0 False True) (vennps "circle2"),
          uncurry (Arc 1 1 0 False True) (vennps "corner3")
        ],
      "Z"
    ]

outerseg3 :: Text
outerseg3 =
  Text.intercalate
    " "
    [ uncurry moveA (vennps "corner3"),
      arcA
        [ uncurry (Arc 0.5 0.5 0 True True) (vennps "corner1"),
          uncurry (Arc 1 1 0 False False) (vennps "circle3"),
          uncurry (Arc 1 1 0 False False) (vennps "corner3")
        ],
      "Z"
    ]

innerseg :: Text
innerseg =
  Text.intercalate
    " "
    [ uncurry moveA (vennps "circle1"),
      arcA
        [ uncurry (Arc 1 1 0 False True) (vennps "circle2"),
          uncurry (Arc 1 1 0 False True) (vennps "circle3"),
          uncurry (Arc 1 1 0 False True) (vennps "circle1")
        ],
      "Z"
    ]

midseg1 :: Text
midseg1 =
  Text.intercalate
    " "
    [ uncurry moveA (vennps "corner1"),
      arcA
        [ uncurry (Arc 1 1 0 False True) (vennps "circle1"),
          uncurry (Arc 1 1 0 False False) (vennps "circle3"),
          uncurry (Arc 1 1 0 False True) (vennps "corner1")
        ],
      "Z"
    ]

midseg2 :: Text
midseg2 =
  Text.intercalate
    " "
    [ uncurry moveA (vennps "circle1"),
      arcA
        [ uncurry (Arc 1 1 0 False True) (vennps "corner2"),
          uncurry (Arc 1 1 0 False True) (vennps "circle2"),
          uncurry (Arc 1 1 0 False False) (vennps "circle1")
        ],
      "Z"
    ]

midseg3 :: Text
midseg3 =
  Text.intercalate
    " "
    [ uncurry moveA (vennps "circle2"),
      arcA
        [ uncurry (Arc 1 1 0 False True) (vennps "corner3"),
          uncurry (Arc 1 1 0 False True) (vennps "circle3"),
          uncurry (Arc 1 1 0 False False) (vennps "circle2")
        ],
      "Z"
    ]

vennGlyphs :: [Text]
vennGlyphs = [outerseg1, outerseg2, outerseg3, midseg1, midseg2, midseg3, innerseg]

seg :: Text -> Colour -> GlyphStyle
seg p c = defaultGlyphStyle & set #shape (PathGlyph p) & set #color c & set #borderColor white & set #borderSize 0.06

venns :: [Chart Double]
venns = zipWith (\p c -> Chart (GlyphA $ seg p c) [SpotPoint (Point 0.0 0.0)]) vennGlyphs palette1

phrases :: [Chart Double]
phrases = phraseChart <$> mainPhrases

data Phrase
  = Phrase
      { phraseText :: Text,
        phrasePosition :: Point Double,
        phraseSize :: Double,
        phraseRotation :: Double,
        phraseColor :: Colour,
        phraseTag :: Text,
        phraseLevel :: Int
      }
  deriving (Eq, Show, Generic)

phraseChart :: Phrase -> Chart Double
phraseChart p = Chart (TextA a [view #phraseText p]) [SpotPoint (view #phrasePosition p)]
  where
    a =
      defaultTextStyle
        & set #size (view #phraseSize p)
        & set #rotation (Just $ view #phraseRotation p)
        & set #color (view #phraseColor p)

mainPhrases :: [Phrase]
mainPhrases =
  [ Phrase "Composable" (Point 0.9 0.7) 0.16 60 c "composable" 1,
    Phrase "Functional" (Point 0 (-1)) 0.16 0 c "functional" 1,
    Phrase "Open" (Point (-1) 0.55) 0.16 (-60) c "open" 1,
    Phrase "Accurate" (Point 0.6 (-0.4)) 0.16 0 c "accurate" 1,
    Phrase "Dynamic" (Point (-0.6) (-0.4)) 0.16 0 c "dynamic" 1,
    Phrase "Modern" (Point 0 0.7) 0.16 0 c "modern" 1,
    Phrase "chart-svg" (Point 0 0) 0.2 0 c "chart-svg" 1
  ]
  where
    c = black

renderToSvgt :: CssOptions -> Point Double -> Rect Double -> [Chart Double] -> [(TextStyle, Text)] -> Html ()
renderToSvgt csso (Point w' h') (Rect x z y w) cs tts =
  with
  (svg2_ (bool id (cssCrisp <>) (csso == UseCssCrisp) $
          chartDefs cs <>
          mconcat (zipWith svgt cs tts)))
  [width_ (show w'),
   height_ (show h'),
   makeAttribute "viewBox" (show x <> " " <> show (- w) <> " " <> show (z - x) <> " " <> show (w - y))]

writeVennWords :: IO ()
writeVennWords =
  writeFile "other/venn2.svg" $ Lazy.toStrict $ renderText $
  renderToSvgt NoCssOptions (Point 300 300) (Rect (-2) 2 (-2) 2)
  (phrases <> venns <> [Chart BlankA [SpotRect (Rect (-2.0) 2.0 (-2.0) 2.0)]]) $
  (defaultTextStyle & set #color colorText,) <$>
  (replicate 7 "" <> (phraseText <$> mainPhrases) <> [""])

writeVenn :: [Colour] -> IO ()
writeVenn cs = writeChartsWith "other/venn.svg" (defaultSvgOptions & set #scaleCharts' NoScaleCharts & set #svgAspect ChartAspect & set #svgHeight 100) ([phraseChart (Phrase "λ" (Point 0 (-0.2)) 0.8 0 (Colour 0.1 0 0.2 1) "chart-svg" 1)] <> zipWith (\p c -> Chart (GlyphA $ seg p c) [SpotPoint (Point 0.0 0.0)]) [outerseg1, outerseg2, outerseg3, midseg1, midseg2, midseg3] cs <> [Chart BlankA [SpotRect (Rect (-1.5) 1.5 (-1.5) 1.5)]])

main :: IO ()
main = do
  writeVennWords
  writeVenn palette1