{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE Strict #-}

{- |
Module      : Granite.Render.Svg
Copyright   : (c) 2025
License     : MIT
Maintainer  : mschavinda@gmail.com

SVG backend.
-}
module Granite.Render.Svg (
    renderScene,
    renderSceneResponsive,
    attr,
    svgDoc,
    svgDocWith,
    svgRect,
    svgCircle,
    svgLine,
    svgPolyline,
    svgPath,
    svgText,
) where

import Data.Text (Text)
import Data.Text qualified as T

import Granite.Color (colorHex)
import Granite.Internal.Util (escXml, showD)
import Granite.Render.Scene (
    Mark (..),
    Point (..),
    Rect (..),
    Scene (..),
    Style (..),
    TextAnchor (..),
    TextStyle (..),
 )

attr :: Text -> Text -> Text
attr :: Text -> Text -> Text
attr Text
k Text
v = Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
k Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"=\"" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
v Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\""

svgDoc :: Double -> Double -> Text -> Text
svgDoc :: Double -> Double -> Text -> Text
svgDoc = Bool -> Double -> Double -> Text -> Text
svgDocWith Bool
False

svgDocWith :: Bool -> Double -> Double -> Text -> Text
svgDocWith :: Bool -> Double -> Double -> Text -> Text
svgDocWith Bool
responsive Double
w Double
h Text
content =
    Text
"<svg xmlns=\"http://www.w3.org/2000/svg\""
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"viewBox" (Text
"0 0 " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Double -> Text
showD Double
w Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Double -> Text
showD Double
h)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
sizing
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"font-family" Text
"system-ui, -apple-system, sans-serif"
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
">\n"
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"<rect width=\"100%\" height=\"100%\" fill=\"white\"/>\n"
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
content
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"</svg>\n"
  where
    sizing :: Text
sizing
        | Bool
responsive =
            Text -> Text -> Text
attr Text
"preserveAspectRatio" Text
"xMidYMid meet"
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"width" Text
"100%"
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"style" Text
"height:auto"
        | Bool
otherwise =
            Text -> Text -> Text
attr Text
"width" (Double -> Text
showD Double
w) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"height" (Double -> Text
showD Double
h)

svgRect :: Double -> Double -> Double -> Double -> Text -> Text -> Text
svgRect :: Double -> Double -> Double -> Double -> Text -> Text -> Text
svgRect Double
x Double
y Double
w Double
h Text
fill Text
extra =
    Text
"<rect"
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"x" (Double -> Text
showD Double
x)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"y" (Double -> Text
showD Double
y)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"width" (Double -> Text
showD Double
w)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"height" (Double -> Text
showD Double
h)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"fill" Text
fill
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
extra
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/>\n"

svgCircle :: Double -> Double -> Double -> Text -> Text
svgCircle :: Double -> Double -> Double -> Text -> Text
svgCircle Double
cx Double
cy Double
r Text
fill =
    Text
"<circle"
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"cx" (Double -> Text
showD Double
cx)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"cy" (Double -> Text
showD Double
cy)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"r" (Double -> Text
showD Double
r)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"fill" Text
fill
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/>\n"

svgLine :: Double -> Double -> Double -> Double -> Text -> Double -> Text
svgLine :: Double -> Double -> Double -> Double -> Text -> Double -> Text
svgLine Double
x1 Double
y1 Double
x2 Double
y2 Text
stroke Double
strokeW =
    Text
"<line"
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"x1" (Double -> Text
showD Double
x1)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"y1" (Double -> Text
showD Double
y1)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"x2" (Double -> Text
showD Double
x2)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"y2" (Double -> Text
showD Double
y2)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"stroke" Text
stroke
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"stroke-width" (Double -> Text
showD Double
strokeW)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/>\n"

svgPolyline :: [(Double, Double)] -> Text -> Double -> Text
svgPolyline :: [(Double, Double)] -> Text -> Double -> Text
svgPolyline [(Double, Double)]
pts Text
stroke Double
strokeW =
    Text
"<polyline"
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"points" (Text -> [Text] -> Text
T.intercalate Text
" " [Double -> Text
showD Double
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"," Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Double -> Text
showD Double
y | (Double
x, Double
y) <- [(Double, Double)]
pts])
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"fill" Text
"none"
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"stroke" Text
stroke
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"stroke-width" (Double -> Text
showD Double
strokeW)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"stroke-linejoin" Text
"round"
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"stroke-linecap" Text
"round"
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/>\n"

-- | Simple text element (legacy callers); no rotation or tooltip.
svgText :: Double -> Double -> Text -> Text -> Double -> Text -> Text
svgText :: Double -> Double -> Text -> Text -> Double -> Text -> Text
svgText Double
x Double
y Text
anchor Text
fill Double
size = Double
-> Double
-> Text
-> Text
-> Double
-> Double
-> Maybe Text
-> Text
-> Text
svgTextRT Double
x Double
y Text
anchor Text
fill Double
size Double
0 Maybe Text
forall a. Maybe a
Nothing

{- | Text element with optional rotation (degrees about @(x,y)@) and an
optional @\<title\>@ tooltip (the untruncated label). @rot = 0@ and
@title = Nothing@ produce byte-identical output to 'svgText'.
-}
svgTextRT ::
    Double ->
    Double ->
    Text ->
    Text ->
    Double ->
    Double ->
    Maybe Text ->
    Text ->
    Text
svgTextRT :: Double
-> Double
-> Text
-> Text
-> Double
-> Double
-> Maybe Text
-> Text
-> Text
svgTextRT Double
x Double
y Text
anchor Text
fill Double
size Double
rot Maybe Text
mTitle Text
content =
    Text
"<text"
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"x" (Double -> Text
showD Double
x)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"y" (Double -> Text
showD Double
y)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"text-anchor" Text
anchor
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"fill" Text
fill
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"font-size" (Double -> Text
showD Double
size)
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
rotAttr
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
">"
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
titleEl
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
escXml Text
content
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"</text>\n"
  where
    rotAttr :: Text
rotAttr
        | Double
rot Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== Double
0 = Text
""
        | Bool
otherwise =
            Text -> Text -> Text
attr
                Text
"transform"
                (Text
"rotate(" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Double -> Text
showD Double
rot Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Double -> Text
showD Double
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Double -> Text
showD Double
y Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
")")
    titleEl :: Text
titleEl = case Maybe Text
mTitle of
        Maybe Text
Nothing -> Text
""
        Just Text
t -> Text
"<title>" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
escXml Text
t Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"</title>"

svgPath :: Text -> Text -> Text -> Text
svgPath :: Text -> Text -> Text -> Text
svgPath Text
d Text
fill Text
extra =
    Text
"<path"
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"d" Text
d
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"fill" Text
fill
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
extra
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/>\n"

renderScene :: Scene -> Text
renderScene :: Scene -> Text
renderScene Scene
scene =
    Double -> Double -> Text -> Text
svgDoc (Scene -> Double
sceneWidth Scene
scene) (Scene -> Double
sceneHeight Scene
scene) (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$
        [Text] -> Text
T.concat ((Mark -> Text) -> [Mark] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map Mark -> Text
renderMark (Scene -> [Mark]
sceneMarks Scene
scene))

renderSceneResponsive :: Scene -> Text
renderSceneResponsive :: Scene -> Text
renderSceneResponsive Scene
scene =
    Bool -> Double -> Double -> Text -> Text
svgDocWith Bool
True (Scene -> Double
sceneWidth Scene
scene) (Scene -> Double
sceneHeight Scene
scene) (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$
        [Text] -> Text
T.concat ((Mark -> Text) -> [Mark] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map Mark -> Text
renderMark (Scene -> [Mark]
sceneMarks Scene
scene))

renderMark :: Mark -> Text
renderMark :: Mark -> Text
renderMark Mark
m = case Mark
m of
    MRect (Rect Double
x Double
y Double
w Double
h) Style
sty ->
        let fill :: Text
fill = Text -> (Color -> Text) -> Maybe Color -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"none" Color -> Text
colorHex (Style -> Maybe Color
styleFill Style
sty)
            extras :: Text
extras =
                Style -> Text
strokeAttrs Style
sty
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Style -> Text
opacityAttr Style
sty
         in Double -> Double -> Double -> Double -> Text -> Text -> Text
svgRect Double
x Double
y Double
w Double
h Text
fill Text
extras
    MCircle (Point Double
x Double
y) Double
r Style
sty ->
        let fill :: Text
fill = Text -> (Color -> Text) -> Maybe Color -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"none" Color -> Text
colorHex (Style -> Maybe Color
styleFill Style
sty)
         in Text
"<circle"
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"cx" (Double -> Text
showD Double
x)
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"cy" (Double -> Text
showD Double
y)
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"r" (Double -> Text
showD Double
r)
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"fill" Text
fill
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Style -> Text
strokeAttrs Style
sty
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Style -> Text
opacityAttr Style
sty
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/>\n"
    MText (Point Double
x Double
y) Text
txt TextStyle
ts ->
        Double
-> Double
-> Text
-> Text
-> Double
-> Double
-> Maybe Text
-> Text
-> Text
svgTextRT
            Double
x
            Double
y
            (TextAnchor -> Text
anchorText (TextStyle -> TextAnchor
textAnchor TextStyle
ts))
            (Color -> Text
colorHex (TextStyle -> Color
textFill TextStyle
ts))
            (TextStyle -> Double
textSize TextStyle
ts)
            (TextStyle -> Double
textRotate TextStyle
ts)
            (TextStyle -> Maybe Text
textTitle TextStyle
ts)
            Text
txt
    MPolyline [Point]
pts Style
sty ->
        let stroke :: Text
stroke = Text -> (Color -> Text) -> Maybe Color -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"#000000" Color -> Text
colorHex (Style -> Maybe Color
styleStroke Style
sty)
            pairs :: [(Double, Double)]
pairs = [(Double
px, Double
py) | Point Double
px Double
py <- [Point]
pts]
         in [(Double, Double)] -> Text -> Double -> Text
svgPolyline [(Double, Double)]
pairs Text
stroke (Style -> Double
styleStrokeWidth Style
sty)
    MPolygon [Point]
pts Style
sty ->
        let fill :: Text
fill = Text -> (Color -> Text) -> Maybe Color -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"none" Color -> Text
colorHex (Style -> Maybe Color
styleFill Style
sty)
            pairs :: [(Double, Double)]
pairs = [(Double
px, Double
py) | Point Double
px Double
py <- [Point]
pts]
            ptsStr :: Text
ptsStr = Text -> [Text] -> Text
T.intercalate Text
" " [Double -> Text
showD Double
px Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"," Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Double -> Text
showD Double
py | (Double
px, Double
py) <- [(Double, Double)]
pairs]
         in Text
"<polygon"
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"points" Text
ptsStr
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"fill" Text
fill
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Style -> Text
strokeAttrs Style
sty
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Style -> Text
opacityAttr Style
sty
                Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/>\n"
    MAxisLine (Point Double
x1 Double
y1) (Point Double
x2 Double
y2) Style
sty ->
        let stroke :: Text
stroke = Text -> (Color -> Text) -> Maybe Color -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"#000000" Color -> Text
colorHex (Style -> Maybe Color
styleStroke Style
sty)
         in Double -> Double -> Double -> Double -> Text -> Double -> Text
svgLine Double
x1 Double
y1 Double
x2 Double
y2 Text
stroke (Style -> Double
styleStrokeWidth Style
sty)
    MPath Text
d Style
sty ->
        let fill :: Text
fill = Text -> (Color -> Text) -> Maybe Color -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"none" Color -> Text
colorHex (Style -> Maybe Color
styleFill Style
sty)
         in Text -> Text -> Text -> Text
svgPath Text
d Text
fill (Style -> Text
strokeAttrs Style
sty)
    MArc (Point Double
cx Double
cy) Double
r Double
a0 Double
a1 Style
sty ->
        let x0 :: Double
x0 = Double
cx Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
r Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double -> Double
forall a. Floating a => a -> a
cos Double
a0
            y0 :: Double
y0 = Double
cy Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
r Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double -> Double
forall a. Floating a => a -> a
sin Double
a0
            x1 :: Double
x1 = Double
cx Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
r Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double -> Double
forall a. Floating a => a -> a
cos Double
a1
            y1 :: Double
y1 = Double
cy Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
r Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double -> Double
forall a. Floating a => a -> a
sin Double
a1
            largeArc :: Text
largeArc = if Double
a1 Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
a0 Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
forall a. Floating a => a
pi then Text
"1" else Text
"0"
            d :: Text
d =
                Text
"M "
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Double -> Text
showD Double
cx
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" "
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Double -> Text
showD Double
cy
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" L "
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Double -> Text
showD Double
x0
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" "
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Double -> Text
showD Double
y0
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" A "
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Double -> Text
showD Double
r
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" "
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Double -> Text
showD Double
r
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" 0 "
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
largeArc
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" 0 "
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Double -> Text
showD Double
x1
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" "
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Double -> Text
showD Double
y1
                    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" Z"
            fill :: Text
fill = Text -> (Color -> Text) -> Maybe Color -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"none" Color -> Text
colorHex (Style -> Maybe Color
styleFill Style
sty)
         in Text -> Text -> Text -> Text
svgPath Text
d Text
fill (Style -> Text
strokeAttrs Style
sty)
    MGroup [Mark]
ms ->
        Text
"<g>" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Text] -> Text
T.concat ((Mark -> Text) -> [Mark] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map Mark -> Text
renderMark [Mark]
ms) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"</g>\n"

anchorText :: TextAnchor -> Text
anchorText :: TextAnchor -> Text
anchorText TextAnchor
AnchorStart = Text
"start"
anchorText TextAnchor
AnchorMiddle = Text
"middle"
anchorText TextAnchor
AnchorEnd = Text
"end"

strokeAttrs :: Style -> Text
strokeAttrs :: Style -> Text
strokeAttrs Style
sty =
    case Style -> Maybe Color
styleStroke Style
sty of
        Maybe Color
Nothing -> Text
""
        Just Color
c ->
            Text -> Text -> Text
attr Text
"stroke" (Color -> Text
colorHex Color
c) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
attr Text
"stroke-width" (Double -> Text
showD (Style -> Double
styleStrokeWidth Style
sty))

opacityAttr :: Style -> Text
opacityAttr :: Style -> Text
opacityAttr Style
sty
    | Style -> Double
styleFillOpacity Style
sty Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< Double
1 = Text -> Text -> Text
attr Text
"fill-opacity" (Double -> Text
showD (Style -> Double
styleFillOpacity Style
sty))
    | Bool
otherwise = Text
""