From ffc0a842ae29db53dd92e276c089a6d5914c6456 Mon Sep 17 00:00:00 2001 From: stuebinm Date: Thu, 9 May 2024 01:25:16 +0200 Subject: rough initial work on space-time diagrams this does svg templating with hamlet. It might be better to use a javascript library instead (templating svgs is a little confusing tbh), but for now i'll see how far i get with this. --- lib/Server/Frontend.hs | 1 + lib/Server/Frontend/Routes.hs | 2 + lib/Server/Frontend/SpaceTime.hs | 104 +++++++++++++++++++++++++++++++++++++++ messages/de.msg | 1 + messages/en.msg | 1 + tracktrain.cabal | 1 + 6 files changed, 110 insertions(+) create mode 100644 lib/Server/Frontend/SpaceTime.hs diff --git a/lib/Server/Frontend.hs b/lib/Server/Frontend.hs index 8d744db..3beb9e0 100644 --- a/lib/Server/Frontend.hs +++ b/lib/Server/Frontend.hs @@ -6,6 +6,7 @@ import Server.Frontend.Gtfs import Server.Frontend.OnboardUnit import Server.Frontend.Routes import Server.Frontend.Tickets +import Server.Frontend.SpaceTime import Yesod import Yesod.Auth diff --git a/lib/Server/Frontend/Routes.hs b/lib/Server/Frontend/Routes.hs index 2d74338..8dceda5 100644 --- a/lib/Server/Frontend/Routes.hs +++ b/lib/Server/Frontend/Routes.hs @@ -45,6 +45,8 @@ mkYesodData "Frontend" [parseRoutes| /ticket/announce/#UUID AnnounceR POST /ticket/del-announce/#UUID DelAnnounceR GET +/spacetime SpaceTimeDiagramR GET + /token/block/#Token TokenBlock GET /gtfs/trips GtfsTripsViewR GET diff --git a/lib/Server/Frontend/SpaceTime.hs b/lib/Server/Frontend/SpaceTime.hs new file mode 100644 index 0000000..307e795 --- /dev/null +++ b/lib/Server/Frontend/SpaceTime.hs @@ -0,0 +1,104 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE QuasiQuotes #-} +{-# LANGUAGE RecordWildCards #-} + +module Server.Frontend.SpaceTime (getSpaceTimeDiagramR) where + +import Server.Frontend.Routes + +import Data.Functor ((<&>)) +import qualified Data.Map as M +import Data.Text (Text) +import qualified Data.Vector as V +import qualified GTFS +import Text.Blaze.Html (Html) +import qualified Data.Text as T +import Yesod +import Text.Read (readMaybe) +import Data.Time (getCurrentTime, UTCTime (..)) +import Persist +import Data.Function ((&), on) +import Data.List +import Data.Coerce (coerce) +import Control.Monad (when, forM) +import GHC.Float (int2Double) +import Fmt ((|+), (+|)) +import Data.Maybe (catMaybes, mapMaybe) +import GTFS (Seconds(unSeconds)) + +getSpaceTimeDiagramR :: Handler Html +getSpaceTimeDiagramR = do + + req <- getRequest + + day <- case lookup "day" (reqGetParams req) >>= (readMaybe . T.unpack) of + Just day -> pure day + Nothing -> liftIO $ getCurrentTime <&> utctDay + + tickets <- runDB $ selectList [ TicketDay ==. day ] [] >>= mapM (\ticket -> do + stops <- selectList [StopTicket ==. entityKey ticket] [] + pure (ticket, stops)) + + + -- TODO: this should be a nicer error message + when (null tickets) + notFound + + -- we take the longest trip of the day. This will lead to unreasonable results + -- if there's more than one shape (this whole route should probably take a shape id tbh) + stations <- runDB $ fmap snd tickets + & maximumBy (compare `on` length) + & fmap entityVal + & sortOn stopSequence + & mapM (\stop -> do + s <- getJust (stopStation stop) + pure (stopStation stop, s, stop)) + + let maxSequence = stopSequence ((\(_,_,stop) -> stop) (last stations)) + let scaleSequence a = int2Double a * 100 / int2Double maxSequence + + let (minY, maxY) = tickets + <&> snd + & concat + <&> (timeToPos . stopDeparture . entityVal) + & (\ys -> (minimum ys - 20, maximum ys + 20)) + + defaultLayout $ do + [whamlet| +