{-# LANGUAGE OverloadedStrings, DeriveGeneric #-} {-| Module : Lucid.Leaflet Description : LeafletJS bindings Copyright : (c) Tom Nielsen, Marco Zocca, 2019 License : GPL-3 Maintainer : ocramz fripost org Stability : experimental Portability : POSIX Bindings to the LeafletJS map API. See https://leafletjs.com/ for usage details -} module Lucid.Leaflet ( -- * CDN declarations leafletCDN, leafletCssCDN, -- * Utilities leafletMap, osmTileLayer, -- * Types LMap(..), LMapElement(..), TileLayerProperties(..) ) where import qualified Data.Aeson as Aeson import qualified Data.ByteString.Lazy as BSL import Lucid import qualified Data.Text as T import qualified Data.Text.Encoding as T import Lucid.PreEscaped import Data.Monoid import GHC.Generics -- | Statement for embedding the LeafletJS javascript blob. leafletCDN :: Monad m => HtmlT m () leafletCDN = scriptSrc "https://unpkg.com/leaflet@1.2.0/dist/leaflet.js" data LMap = LMap T.Text | SetView (Double, Double) Double LMap deriving (Eq, Show) data LMapElement = TileLayer T.Text TileLayerProperties | Marker (Double, Double) | BindPopup T.Text LMapElement deriving (Eq, Show) newtype TileLayerProperties = TileLayerProperties { attribution :: T.Text } deriving (Eq, Show, Generic) instance Aeson.ToJSON TileLayerProperties mapElementToJS :: LMapElement -> T.Text mapElementToJS e' = "\n" <> f e' <> ".addTo(lmap);" where tshow = T.pack . show f (Marker (x, y)) = "L.marker(["<> tshow x<>", "<> tshow y<>"])" f (BindPopup t e) = f e <> ".bindPopup('"<>t<>"')" f (TileLayer url ps) = "L.tileLayer('"<>url<>"',"<>g ps<>")" g = T.decodeUtf8 . BSL.toStrict . Aeson.encode -- | OpenStreetMap tile layer osmTileLayer :: LMapElement osmTileLayer = TileLayer "http://{s}.tile.osm.org/{z}/{x}/{y}.png" $ TileLayerProperties "© OpenStreetMap contributors" -- | Statement for embedding the LeafletJS CSS stylesheet. leafletCssCDN :: Monad m => HtmlT m () leafletCssCDN = link_ [rel_ "stylesheet", href_ "https://unpkg.com/leaflet@1.2.0/dist/leaflet.css"] -- | @\@ section that declares a LeafletJS map leafletMap :: Monad m => LMap -> [LMapElement] -> HtmlT m () leafletMap mp elms = script_ $ writeMap mp <> writeElems elms where writeMap m = "\nvar lmap = " <> writeMap' m <> ";" writeMap' (LMap e) = "L.map('"<>e<>"')" writeMap' (SetView (x,y) z m) = writeMap' m <> ".setView(["<> tshow x<>", "<> tshow y<>"], "<> tshow z<>")" writeElems = T.unlines . map mapElementToJS tshow = T.pack . show