2022-04-17 21:04:13 +02:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
|
|
2022-04-19 23:11:06 +02:00
|
|
|
module Onomap.Svg (drawMap, renderMap) where
|
2022-04-17 21:04:13 +02:00
|
|
|
|
|
|
|
|
import qualified Data.Map as Map
|
|
|
|
|
import Data.Maybe (fromMaybe)
|
|
|
|
|
import Data.Text (Text)
|
|
|
|
|
import qualified Data.Text as Text
|
2022-10-07 02:21:34 +02:00
|
|
|
import Data.Text.Lazy (toStrict)
|
2022-04-17 21:04:13 +02:00
|
|
|
import Graphics.Svg
|
2022-10-07 02:21:34 +02:00
|
|
|
import Onomap.Types (Area (..), ByArea (..), ScaleToMaximum (..), SvgSettings (..))
|
2022-04-17 21:04:13 +02:00
|
|
|
import Text.Printf (printf)
|
|
|
|
|
|
2022-10-07 02:21:34 +02:00
|
|
|
renderMap :: SvgSettings -> [Text] -> [Area] -> [(Text, ByArea Double)] -> Text
|
|
|
|
|
renderMap settings colorPalette areas statistics = toStrict $ prettyText $ drawMap settings colorPalette areas statistics
|
2022-04-19 23:11:06 +02:00
|
|
|
|
2022-10-07 02:21:34 +02:00
|
|
|
drawMap :: SvgSettings -> [Text] -> [Area] -> [(Text, ByArea Double)] -> Element
|
|
|
|
|
drawMap settings colorPalette areas statistics =
|
|
|
|
|
doctype <> with (svg11_ content) [Version_ <<- "1.1", Width_ <<- "650", Height_ <<- Text.pack (show (900 + 20 * length statistics))]
|
2022-04-17 21:04:13 +02:00
|
|
|
where
|
2022-10-07 02:21:34 +02:00
|
|
|
theMaxima = map maximum $ map (getByArea . snd) statistics
|
|
|
|
|
globalMaximum = maximum theMaxima
|
2022-04-17 21:04:13 +02:00
|
|
|
localize = Text.replace "." "," . Text.dropWhileEnd (== '.') . Text.dropWhileEnd (== '0')
|
|
|
|
|
showRounded = Text.pack . printf "%.2f"
|
2022-10-07 02:21:34 +02:00
|
|
|
frameColor = "black"
|
2022-04-17 21:04:13 +02:00
|
|
|
areaPaths =
|
|
|
|
|
foldMap
|
|
|
|
|
( \area ->
|
2022-10-07 02:21:34 +02:00
|
|
|
path_ [Stroke_ <<- frameColor, Stroke_width_ <<- "0.3px", Fill_ <<- "none", D_ <<- path area]
|
|
|
|
|
<> foldMap
|
|
|
|
|
( \((surname, statistic), color, theMaximum) ->
|
|
|
|
|
let count = fromMaybe 0 (Map.lookup (key area) (getByArea statistic))
|
|
|
|
|
theTitle =
|
|
|
|
|
( title_
|
|
|
|
|
[]
|
|
|
|
|
( toElement $
|
|
|
|
|
mconcat
|
|
|
|
|
[ name area
|
|
|
|
|
, ": "
|
|
|
|
|
, Text.intercalate
|
|
|
|
|
", "
|
2022-10-07 02:40:52 +02:00
|
|
|
( map
|
|
|
|
|
( \(surname, statistic) ->
|
|
|
|
|
let count = fromMaybe 0 (Map.lookup (key area) (getByArea statistic))
|
|
|
|
|
in localize (showRounded count) <> " (" <> Text.toTitle surname <> ")"
|
|
|
|
|
)
|
|
|
|
|
statistics
|
|
|
|
|
)
|
2022-10-07 02:21:34 +02:00
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
in path_
|
|
|
|
|
[ D_ <<- path area
|
|
|
|
|
, Fill_ <<- color
|
|
|
|
|
, Fill_opacity_
|
|
|
|
|
<<- showRounded
|
|
|
|
|
( if count == 0
|
|
|
|
|
then 0
|
|
|
|
|
else
|
|
|
|
|
count
|
|
|
|
|
/ ( case scaleToMaximum settings of
|
|
|
|
|
Global -> globalMaximum
|
|
|
|
|
Local -> theMaximum
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
, Stroke_ <<- "none"
|
|
|
|
|
]
|
|
|
|
|
theTitle
|
2022-04-17 21:04:13 +02:00
|
|
|
)
|
2022-10-07 02:21:34 +02:00
|
|
|
(zip3 statistics (cycle colorPalette) theMaxima)
|
2022-04-17 21:04:13 +02:00
|
|
|
)
|
|
|
|
|
areas
|
|
|
|
|
content =
|
2022-10-07 02:21:34 +02:00
|
|
|
foldMap
|
|
|
|
|
( \(index, color, theMaximum) ->
|
|
|
|
|
defs_
|
|
|
|
|
[]
|
|
|
|
|
( linearGradient_
|
|
|
|
|
[ Id_ <<- "legend" <> Text.pack (show index)
|
|
|
|
|
, X1_ <<- "0"
|
|
|
|
|
, X2_ <<- case scaleToMaximum settings of
|
|
|
|
|
Global -> Text.pack (show (recip $ theMaximum / globalMaximum))
|
|
|
|
|
Local -> "1"
|
|
|
|
|
, Y1_ <<- "0"
|
|
|
|
|
, Y2_ <<- "0"
|
2022-04-17 21:04:13 +02:00
|
|
|
]
|
2022-10-07 02:21:34 +02:00
|
|
|
( stop_ [Offset_ <<- "0%", Stop_color_ <<- "white"]
|
|
|
|
|
<> stop_ [Offset_ <<- "100%", Stop_color_ <<- color]
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
(zip3 [0 ..] colorPalette theMaxima)
|
|
|
|
|
<> foldMap
|
|
|
|
|
( \(index, (name, statistic), color) ->
|
|
|
|
|
g_
|
|
|
|
|
[]
|
|
|
|
|
( rect_
|
|
|
|
|
[ X_ <<- "165"
|
|
|
|
|
, Y_ <<- Text.pack (show (880 + 20 * index))
|
|
|
|
|
, Stroke_ <<- frameColor
|
|
|
|
|
, Width_ <<- "350"
|
|
|
|
|
, Height_ <<- "10"
|
|
|
|
|
, Fill_ <<- "url(#legend" <> Text.pack (show index) <> ")"
|
|
|
|
|
]
|
|
|
|
|
<> text_
|
|
|
|
|
[ X_ <<- "155"
|
|
|
|
|
, Y_ <<- Text.pack (show (890 + 20 * index))
|
|
|
|
|
, Font_size_ <<- "18"
|
|
|
|
|
, Fill_ <<- "black"
|
|
|
|
|
, Text_anchor_ <<- "end"
|
|
|
|
|
]
|
|
|
|
|
(toElement $ Text.toTitle name)
|
|
|
|
|
<> text_
|
|
|
|
|
[ X_ <<- "525"
|
|
|
|
|
, Y_ <<- Text.pack (show (890 + 20 * index))
|
|
|
|
|
, Font_size_ <<- "18"
|
|
|
|
|
, Fill_ <<- "black"
|
|
|
|
|
]
|
|
|
|
|
(toElement $ localize $ showRounded $ maximum $ getByArea statistic)
|
|
|
|
|
)
|
2022-04-17 21:04:13 +02:00
|
|
|
)
|
2022-10-07 02:21:34 +02:00
|
|
|
(zip3 [0 ..] statistics colorPalette)
|
|
|
|
|
<> style_ [] "path { mix-blend-mode: multiply; }"
|
2022-04-17 21:04:13 +02:00
|
|
|
<> g_ [] areaPaths
|