Buttons.purs 10.6 KB
Newer Older
arturo's avatar
arturo committed
1 2
module Gargantext.Components.GraphExplorer.Toolbar.Buttons
  ( centerButton
arturo's avatar
arturo committed
3 4 5 6 7 8 9 10 11 12
  , cameraButton
  , edgesToggleButton
  , louvainToggleButton
  , pauseForceAtlasButton
  , resetForceAtlasButton
  , multiSelectEnabledButton
  ) where

import Prelude

arturo's avatar
arturo committed
13
import DOM.Simple.Console (log2)
14
import Data.Array as A
arturo's avatar
arturo committed
15
import Data.Either (Either(..))
arturo's avatar
arturo committed
16
import Data.Foldable (intercalate)
arturo's avatar
arturo committed
17
import Data.Formatter.DateTime as DFDT
arturo's avatar
arturo committed
18
import Data.Maybe (Maybe(..))
19
import Data.Sequence as Seq
20
import Effect (Effect)
arturo's avatar
arturo committed
21 22 23 24
import Effect.Aff (launchAff_)
import Effect.Class (liftEffect)
import Effect.Now as EN
import Gargantext.Components.Bootstrap as B
arturo's avatar
arturo committed
25
import Gargantext.Components.Bootstrap.Types (ButtonVariant(..), Variant(..))
arturo's avatar
arturo committed
26 27 28 29 30 31
import Gargantext.Components.Forest.Tree.Node.Action.Upload (uploadArbitraryData)
import Gargantext.Components.Forest.Tree.Node.Action.Upload.Types (FileFormat(..))
import Gargantext.Components.GraphExplorer.API (cloneGraph)
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Components.GraphExplorer.Utils as GEU
import Gargantext.Hooks.Sigmax as Sigmax
32
import Gargantext.Hooks.Sigmax.Camera as Camera
33
import Gargantext.Hooks.Sigmax.Graphology as Graphology
arturo's avatar
arturo committed
34 35 36 37 38 39 40 41 42 43 44
import Gargantext.Hooks.Sigmax.Sigma as Sigma
import Gargantext.Hooks.Sigmax.Types as SigmaxTypes
import Gargantext.Sessions (Session)
import Gargantext.Utils ((?))
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T

here :: R2.Here
arturo's avatar
arturo committed
45
here = R2.here "Gargantext.Components.GraphExplorer.Toolbar.Button"
arturo's avatar
arturo committed
46 47 48

------------------------------------------------------

49
type CenterButtonProps =
50
  ( forceAtlasState :: T.Box SigmaxTypes.ForceAtlasState
51 52 53 54 55 56 57 58 59
  , sigmaRef        :: R.Ref Sigmax.Sigma )

centerButton :: R2.Leaf CenterButtonProps
centerButton = R2.leaf centerButtonCpt
centerButtonCpt :: R.Component CenterButtonProps
centerButtonCpt = here.component "centerButton" cpt
  where
    cpt { forceAtlasState
        , sigmaRef } _ = do
60 61
      forceAtlasState' <- R2.useLive' forceAtlasState

62 63 64 65
      pure $ B.button
        { callback: \_ -> do
          Sigmax.dependOnSigma (R.readRef sigmaRef) "[centerButton] sigma: Nothing" $ \s ->
            Camera.updateCamera (Camera.camera s) Camera.defaultCamera
66
        , status: SigmaxTypes.forceAtlasComponentStatus forceAtlasState'
67 68 69
        , variant: OutlinedButtonVariant Secondary
        }
        [ H.text "Center" ]
arturo's avatar
arturo committed
70 71 72 73

------------------------------------------------------

type CameraButtonProps =
74 75
  ( id              :: Int
  , hyperdataGraph  :: GET.HyperdataGraph
76
  , forceAtlasState :: T.Box SigmaxTypes.ForceAtlasState
77 78 79
  , reloadForest    :: T2.ReloadS
  , session         :: Session
  , sigmaRef        :: R.Ref Sigmax.Sigma
arturo's avatar
arturo committed
80 81
  )

82 83 84 85 86 87
screenshotFilename :: Effect String
screenshotFilename = do
  nowdt <- EN.nowDateTime
  pure $ case DFDT.formatDateTime "YYYY-MM-DDTHH:mm:ss" nowdt of
    Left err -> err
    Right s -> s <> "-screenshot.png"
arturo's avatar
arturo committed
88

89 90 91 92 93 94
cameraButton :: R2.Leaf CameraButtonProps
cameraButton = R2.leaf cameraButtonCpt
cameraButtonCpt :: R.Component CameraButtonProps
cameraButtonCpt = here.component "cameraButton" cpt
  where
    cpt { id
95 96
        , forceAtlasState
        , hyperdataGraph: GET.HyperdataGraph { graph: GET.GraphData graphData' }
97 98 99
        , reloadForest
        , session
        , sigmaRef } _ = do
100 101
      forceAtlasState' <- R2.useLive' forceAtlasState

102 103 104
      pure $ B.button
        { callback: \_ -> do
             filename <- screenshotFilename
105
             Sigmax.dependOnSigma (R.readRef sigmaRef) "[cameraButton] sigma: Nothing" $ \s -> do
106 107 108 109
               screen <- Sigma.takeScreenshot s
               let graph = Sigma.graph s
                   edges = Graphology.edges graph
                   nodes = Graphology.nodes graph
110 111
                   graphData = GET.GraphData $ graphData' { edges = A.fromFoldable $ Seq.map GEU.stEdgeToGET edges
                                                          , nodes = A.fromFoldable $ GEU.normalizeNodes $ Seq.map GEU.stNodeToGET nodes }
112 113 114 115 116 117 118 119 120 121 122 123
               let camera = Camera.toCamera $ Camera.camera s
               let hyperdataGraph' = GET.HyperdataGraph { graph: graphData, mCamera: Just camera }
               launchAff_ $ do
                 eClonedGraphId <- cloneGraph { id, hyperdataGraph: hyperdataGraph', session }
                 case eClonedGraphId of
                   Left err -> liftEffect $ log2 "[cameraButton] RESTError" err
                   Right clonedGraphId -> do
                     eRet <- uploadArbitraryData session clonedGraphId Plain (Just filename) screen
                     case eRet of
                       Left err -> liftEffect $ log2 "[cameraButton] RESTError" err
                       Right _ret -> do
                         liftEffect $ T2.reload reloadForest
124
        , status: SigmaxTypes.forceAtlasComponentStatus forceAtlasState'
125 126
        , variant: OutlinedButtonVariant Secondary
        } [ H.text "Screenshot" ]
arturo's avatar
arturo committed
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

------------------------------------------------------

type EdgesButtonProps =
  ( state       :: T.Box SigmaxTypes.ShowEdgesState
  , stateAtlas  :: T.Box SigmaxTypes.ForceAtlasState
  )

edgesToggleButton :: R2.Leaf EdgesButtonProps
edgesToggleButton = R2.leaf edgesToggleButtonCpt
edgesToggleButtonCpt :: R.Component EdgesButtonProps
edgesToggleButtonCpt = here.component "edgesToggleButton" cpt
  where
    cpt { state, stateAtlas } _ = do
      -- States
      state'      <- R2.useLive' state
      stateAtlas' <- R2.useLive' stateAtlas

      -- Render
      pure $
        B.button
148 149 150 151
        { -- TODO: Move this to Graph.purs to the R.useEffect handler which renders nodes/edges
          callback: \_ -> T.modify_ SigmaxTypes.toggleShowEdgesState state
        , status: SigmaxTypes.forceAtlasComponentStatus stateAtlas'
        , variant: state' == SigmaxTypes.EShow ?
arturo's avatar
arturo committed
152 153 154 155 156 157 158 159
            ButtonVariant Secondary $
            OutlinedButtonVariant Secondary
        }
        [ H.text "Edges" ]

------------------------------------------------------

type LouvainToggleButtonProps =
160 161
  ( forceAtlasState :: T.Box SigmaxTypes.ForceAtlasState
  , state           :: T.Box Boolean
arturo's avatar
arturo committed
162 163 164 165 166 167 168
  )

louvainToggleButton :: R2.Leaf LouvainToggleButtonProps
louvainToggleButton = R2.leaf louvainToggleButtonCpt
louvainToggleButtonCpt :: R.Component LouvainToggleButtonProps
louvainToggleButtonCpt = here.component "louvainToggleButton" cpt
  where
169
    cpt { forceAtlasState, state } _ = do
arturo's avatar
arturo committed
170
      state' <- R2.useLive' state
171
      forceAtlasState' <- R2.useLive' forceAtlasState
arturo's avatar
arturo committed
172 173 174

      pure $
        B.button
175 176 177
        { callback: \_ -> T.modify_ (not) state
        , status: SigmaxTypes.forceAtlasComponentStatus forceAtlasState'
        , variant: state' ?
arturo's avatar
arturo committed
178 179 180 181 182 183 184 185 186 187 188 189 190 191
            ButtonVariant Secondary $
            OutlinedButtonVariant Secondary
        }
        [ H.text "Louvain" ]

--------------------------------------------------------------

type ForceAtlasProps =
  ( state :: T.Box SigmaxTypes.ForceAtlasState
  )

pauseForceAtlasButton :: R2.Leaf ForceAtlasProps
pauseForceAtlasButton = R2.leaf pauseForceAtlasButtonCpt
pauseForceAtlasButtonCpt :: R.Component ForceAtlasProps
192
pauseForceAtlasButtonCpt = here.component "pauseForceAtlasButtonButton" cpt
arturo's avatar
arturo committed
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
  where
    cpt { state } _ = do
      -- States
      state' <- R2.useLive' state

      -- Computed
      let
        cls SigmaxTypes.InitialRunning  = "on-running-animation active"
        cls SigmaxTypes.Running         = "on-running-animation active"
        cls _                           = ""

        vrt SigmaxTypes.InitialRunning  = ButtonVariant Secondary
        vrt SigmaxTypes.Running         = ButtonVariant Secondary
        vrt _                           = OutlinedButtonVariant Secondary

        icn SigmaxTypes.InitialRunning  = "pause"
        icn SigmaxTypes.InitialStopped  = "play"
        icn SigmaxTypes.Running         = "pause"
        icn SigmaxTypes.Paused          = "play"
        icn SigmaxTypes.Killed          = "play"

      -- Render
      pure $

        B.button
        { variant: vrt state'
arturo's avatar
arturo committed
219 220 221 222
        , className: intercalate " "
            [ cls state'
            , "toolbar-atlas-button"
            ]
arturo's avatar
arturo committed
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
        , callback: \_ -> T.modify_ SigmaxTypes.toggleForceAtlasState state
        }
        [
          B.icon
          { name: icn state'}
        ]

--------------------------------------------------------

type ResetForceAtlasProps =
  ( forceAtlasState :: T.Box SigmaxTypes.ForceAtlasState
  , sigmaRef        :: R.Ref Sigmax.Sigma
  )

resetForceAtlasButton :: R2.Leaf ResetForceAtlasProps
resetForceAtlasButton = R2.leaf resetForceAtlasButtonCpt
resetForceAtlasButtonCpt :: R.Component ResetForceAtlasProps
resetForceAtlasButtonCpt = here.component "resetForceAtlasToggleButton" cpt
  where
    cpt { forceAtlasState, sigmaRef } _ = do
      pure $ H.button { className: "btn btn-outline-secondary"
                      , on: { click: onClick forceAtlasState sigmaRef }
                      } [ R2.small {} [ H.text "Reset Force Atlas" ] ]

    onClick forceAtlasState sigmaRef _ = do
      -- TODO Sigma.killForceAtlas2 sigma
      -- startForceAtlas2 sigma
250
      Sigmax.dependOnSigma (R.readRef sigmaRef) "[resetForceAtlasButton] no sigma" $ \_sigma -> do
251 252 253
        -- TODO Use fa2Ref instead of sigmaRef
        --Sigma.killForceAtlas2 sigma
        --Sigma.refreshForceAtlas sigma Graph.forceAtlas2Settings
arturo's avatar
arturo committed
254 255 256 257 258
        T.write_ SigmaxTypes.Killed forceAtlasState

------------------------------------------------------------------

type MultiSelectEnabledButtonProps =
259 260
  ( forceAtlasState :: T.Box SigmaxTypes.ForceAtlasState
  , state           :: T.Box Boolean
arturo's avatar
arturo committed
261 262 263 264 265 266 267
  )

multiSelectEnabledButton :: R2.Leaf MultiSelectEnabledButtonProps
multiSelectEnabledButton = R2.leaf multiSelectEnabledButtonCpt
multiSelectEnabledButtonCpt :: R.Component MultiSelectEnabledButtonProps
multiSelectEnabledButtonCpt = here.component "multiSelectEnabledButton" cpt
  where
268
    cpt { forceAtlasState, state } _ = do
arturo's avatar
arturo committed
269
      state' <- R2.useLive' state
270
      forceAtlasState' <- R2.useLive' forceAtlasState
arturo's avatar
arturo committed
271 272 273

      pure $
        H.div
arturo's avatar
arturo committed
274 275 276 277
        { className: intercalate " "
            [ "btn-group"
            , "align-items-center"
            ]
arturo's avatar
arturo committed
278 279 280 281
        , role: "group"
        }
        [
          B.button
282 283 284
          { callback: \_ -> T.write_ false state
          , status: SigmaxTypes.forceAtlasComponentStatus forceAtlasState'
          , variant: state' ?
arturo's avatar
arturo committed
285 286 287
              OutlinedButtonVariant Secondary $
              ButtonVariant Secondary
          }
arturo's avatar
arturo committed
288
          [ H.text "Single" ]
arturo's avatar
arturo committed
289 290
        ,
          B.button
291 292 293
          { callback: \_ -> T.write_ true state
          , status: SigmaxTypes.forceAtlasComponentStatus forceAtlasState'
          , variant: state' ?
arturo's avatar
arturo committed
294 295 296
              ButtonVariant Secondary $
              OutlinedButtonVariant Secondary
          }
arturo's avatar
arturo committed
297
          [ H.text "Multiple" ]
arturo's avatar
arturo committed
298
        ]