Graph.purs 9.83 KB
Newer Older
James Laver's avatar
James Laver committed
1 2 3 4 5 6
module Gargantext.Components.Graph
  -- ( graph, graphCpt
  -- , sigmaSettings, SigmaSettings, SigmaOptionalSettings
  -- , forceAtlas2Settings, ForceAtlas2Settings, ForceAtlas2OptionalSettings
  -- )
  where
7
import Prelude (bind, const, discard, not, pure, unit, ($))
8

9
import Data.Either (Either(..))
10
import Data.Maybe (Maybe(..))
11
import Data.Nullable (Nullable)
12
import Data.Tuple.Nested ((/\))
13
import DOM.Simple.Console (log, log2)
14
import DOM.Simple.Types (Element)
15
import FFI.Simple (delay)
James Laver's avatar
James Laver committed
16 17
import Reactix as R
import Reactix.DOM.HTML as RH
18

19 20 21
import Gargantext.Hooks.Sigmax as Sigmax
import Gargantext.Hooks.Sigmax.Types as SigmaxTypes
import Gargantext.Hooks.Sigmax.Sigma as Sigma
James Laver's avatar
James Laver committed
22 23 24

type OnProps  = ()

25 26
data Stage = Init | Ready | Cleanup

James Laver's avatar
James Laver committed
27
type Props sigma forceatlas2 =
28
  ( elRef :: R.Ref (Nullable Element)
29
  , forceAtlas2Settings :: forceatlas2
30
  , graph :: SigmaxTypes.SGraph
31
  , multiSelectEnabledRef :: R.Ref Boolean
32
  , selectedNodeIds :: R.State SigmaxTypes.NodeIds
33
  , showEdges :: R.State SigmaxTypes.ShowEdgesState
34
  , sigmaRef :: R.Ref Sigmax.Sigma
35
  , sigmaSettings :: sigma
36
  , stage :: R.State Stage
37
  , transformedGraph :: SigmaxTypes.SGraph
38
  )
James Laver's avatar
James Laver committed
39 40 41 42 43

graph :: forall s fa2. Record (Props s fa2) -> R.Element
graph props = R.createElement graphCpt props []

graphCpt :: forall s fa2. R.Component (Props s fa2)
44
graphCpt = R.hooksComponent "G.C.Graph" cpt
James Laver's avatar
James Laver committed
45 46
  where
    cpt props _ = do
47
      stageHooks props
48

49 50 51 52 53 54
      -- NOTE: This div is not empty after sigma initializes.
      -- When we change state, we make it empty though.
      --pure $ RH.div { ref: props.elRef, style: {height: "95%"} } []
      pure $ case R.readNullableRef props.elRef of
        Nothing -> RH.div {} []
        Just el -> R.createPortal [] el
55

56
    stageHooks props@{multiSelectEnabledRef, selectedNodeIds, sigmaRef, stage: (Init /\ setStage)} = do
57
      R.useEffectOnce $ do
58
        let rSigma = R.readRef props.sigmaRef
59

60 61 62 63 64 65 66
        case Sigmax.readSigma rSigma of
          Nothing -> do
            eSigma <- Sigma.sigma {settings: props.sigmaSettings}
            case eSigma of
              Left err -> log2 "[graphCpt] error creating sigma" err
              Right sig -> do
                Sigmax.writeSigma rSigma $ Just sig
67

68
                Sigmax.dependOnContainer props.elRef "[graphCpt (Ready)] container not found" $ \c -> do
69 70 71
                  _ <- Sigma.addRenderer sig {
                      "type": "canvas"
                    , container: c
72
                    , additionalContexts: ["mouseSelector"]
73 74 75 76 77
                    }
                  pure unit

                Sigmax.refreshData sig $ Sigmax.sigmafy props.graph

78 79 80
                Sigmax.dependOnSigma (R.readRef sigmaRef) "[graphCpt (Ready)] no sigma" $ \sigma -> do
                  -- bind the click event only initially, when ref was empty
                  Sigmax.bindSelectedNodesClick sigma selectedNodeIds multiSelectEnabledRef
81 82
                  _ <- Sigma.bindMouseSelectorPlugin sigma
                  pure unit
83

84 85
                Sigmax.setEdges sig false
                Sigma.startForceAtlas2 sig props.forceAtlas2Settings
86

87
                pure unit
88 89
          Just sig -> do
            pure unit
90

91
        setStage $ const Ready
92

93
        delay unit $ \_ -> do
94
          log "[graphCpt] cleanup"
95 96
          pure $ pure unit

97
    stageHooks props@{showEdges: (showEdges /\ _), sigmaRef, stage: (Ready /\ setStage), transformedGraph} = do
98 99
      let tEdgesMap = SigmaxTypes.edgesGraphMap transformedGraph
      let tNodesMap = SigmaxTypes.nodesGraphMap transformedGraph
100 101 102

      -- TODO Probably this can be optimized to re-mark selected nodes only when they changed
      R.useEffect' $ do
103
        Sigmax.dependOnSigma (R.readRef sigmaRef) "[graphCpt (Ready)] no sigma" $ \sigma -> do
104
          Sigmax.performDiff sigma transformedGraph
105 106
          Sigmax.updateEdges sigma tEdgesMap
          Sigmax.updateNodes sigma tNodesMap
107
          Sigmax.setEdges sigma (not $ SigmaxTypes.edgeStateHidden showEdges)
108 109 110

    stageHooks _ = pure unit

James Laver's avatar
James Laver committed
111 112 113 114 115 116 117 118 119 120

type SigmaSettings =
  ( animationsTime :: Number
  , autoRescale :: Boolean
  , autoResize :: Boolean
  , batchEdgesDrawing :: Boolean
  , borderSize :: Number
  -- , canvasEdgesBatchSize :: Number
  -- , clone :: Boolean
  -- , defaultEdgeColor :: String
121
  , defaultEdgeHoverColor :: String
James Laver's avatar
James Laver committed
122 123 124 125 126
  , defaultEdgeType :: String
  , defaultHoverLabelBGColor :: String
  , defaultHoverLabelColor :: String
  , defaultLabelColor :: String
  -- , defaultLabelHoverColor :: String
127
  , defaultLabelSize :: Number
James Laver's avatar
James Laver committed
128 129 130 131
  , defaultNodeBorderColor :: String
  , defaultNodeColor :: String
  -- , defaultNodeHoverColor :: String
  -- , defaultNodeType :: String
132
  , doubleClickEnabled :: Boolean
James Laver's avatar
James Laver committed
133 134 135 136 137 138 139 140 141 142
  -- , doubleClickTimeout :: Number
  -- , doubleClickZoomDuration :: Number
  -- , doubleClickZoomingRatio :: Number
  -- , doubleTapTimeout :: Number
  -- , dragTimeout :: Number
  , drawEdgeLabels :: Boolean
  , drawEdges :: Boolean
  , drawLabels :: Boolean
  , drawNodes :: Boolean
  -- , edgeColor :: String
143 144
  , edgeHoverColor :: String
  , edgeHoverExtremities :: Boolean
145
  , edgeHoverPrecision :: Number
146
  , edgeHoverSizeRatio :: Number
James Laver's avatar
James Laver committed
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
  -- , edgesPowRatio :: Number
  -- , enableCamera :: Boolean
  , enableEdgeHovering :: Boolean
  , enableHovering :: Boolean
  -- , eventsEnabled :: Boolean
  , font :: String
  , fontStyle :: String
  , hideEdgesOnMove :: Boolean
  -- , hoverFont :: String
  -- , hoverFontStyle :: String
  -- , immutable :: Boolean
  -- , labelColor :: String
  -- , labelHoverBGColor :: String
  -- , labelHoverColor :: String
  -- , labelHoverShadow :: String
  -- , labelHoverShadowColor :: String
  , labelSize :: String
  , labelSizeRatio :: Number
  , labelThreshold :: Number
  , maxEdgeSize :: Number
  , maxNodeSize :: Number
  -- , minArrowSize :: Number
  , minEdgeSize :: Number
  , minNodeSize :: Number
  , mouseEnabled :: Boolean
  -- , mouseInertiaDuration :: Number
  -- , mouseInertiaRatio :: Number
174
  , mouseSelectorSize :: Number
James Laver's avatar
James Laver committed
175 176 177 178
  -- , mouseWheelEnabled :: Boolean
  , mouseZoomDuration :: Number
  , nodeBorderColor :: String
  -- , nodeHoverColor :: String
179
  --, nodesPowRatio :: Number
James Laver's avatar
James Laver committed
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
  , rescaleIgnoreSize :: Boolean
  -- , scalingMode :: String
  -- , sideMargin :: Number
  , singleHover :: Boolean
  -- , skipErrors :: Boolean
  , touchEnabled :: Boolean
  -- , touchInertiaDuration :: Number
  -- , touchInertiaRatio :: Number
  , twBorderGreyColor     :: String
  , twEdgeDefaultOpacity  :: Number
  , twEdgeGreyColor       :: String
  , twNodeRendBorderColor :: String
  , twNodeRendBorderSize :: Number
  , twNodesGreyOpacity    :: Number
  , twSelectedColor       :: String
  , verbose :: Boolean
  -- , webglEdgesBatchSize :: Number
  -- , webglOversamplingRatio :: Number
  , zoomMax :: Number
  , zoomMin :: Number
  , zoomingRatio :: Number
  )

  -- not selected <=> (1-greyness)
  -- selected nodes <=> special label
sigmaSettings :: {|SigmaSettings}
sigmaSettings =
207
  { animationsTime: 30000.0
James Laver's avatar
James Laver committed
208 209
  , autoRescale: true
  , autoResize: true
James Laver's avatar
James Laver committed
210
  , batchEdgesDrawing: true
211
  , borderSize: 1.0                   -- for ex, bigger border when hover
212
  , defaultEdgeHoverColor: "#f00"
James Laver's avatar
James Laver committed
213 214 215 216
  , defaultEdgeType: "curve"          -- 'curve' or 'line' (curve iff ourRendering)
  , defaultHoverLabelBGColor: "#fff"
  , defaultHoverLabelColor: "#000"
  , defaultLabelColor: "#000"         -- labels text color
217
  , defaultLabelSize: 8.0                -- (old tina: showLabelsIfZoom)
218 219
  , defaultNodeBorderColor : "#000"   -- <- if nodeBorderColor = 'default'
  , defaultNodeColor: "#FFF"
220
  , doubleClickEnabled: false -- indicates whether or not the graph can be zoomed on double-click
James Laver's avatar
James Laver committed
221 222 223 224
  , drawEdgeLabels: true
  , drawEdges: true
  , drawLabels: true
  , drawNodes: true
225
  , enableEdgeHovering: false
226 227
  , edgeHoverExtremities: true
  , edgeHoverColor: "edge"
228
  , edgeHoverPrecision: 2.0
229
  , edgeHoverSizeRatio: 2.0
James Laver's avatar
James Laver committed
230
  , enableHovering: true
231
  , font: "arial"                -- font params
James Laver's avatar
James Laver committed
232 233
  , fontStyle: "bold"
  , hideEdgesOnMove: true
234
  , labelSize : "proportional" -- alt : proportional
235
  , labelSizeRatio: 2.0               -- label size in ratio of node size
236
  , labelThreshold: 7.0               -- min node cam size to start showing label
237
  , maxEdgeSize: 1.0
238
  , maxNodeSize: 8.0
239
  , minEdgeSize: 0.5              -- in fact used in tina as edge size
240
  , minNodeSize: 1.0
James Laver's avatar
James Laver committed
241
  , mouseEnabled: true
242
  , mouseSelectorSize: 15.0
James Laver's avatar
James Laver committed
243
  , mouseZoomDuration: 150.0
244 245 246 247 248 249 250 251 252 253 254 255
  , nodeBorderColor: "default"           -- choices: "default" color vs. "node" color
  --, nodesPowRatio : 10.8
  , rescaleIgnoreSize : false
  , singleHover : true
  , touchEnabled : true
  , twBorderGreyColor : "rgba(100, 100, 100, 0.9)"
  , twEdgeDefaultOpacity : 0.4       -- initial opacity added to src/tgt colors
  , twEdgeGreyColor : "rgba(100, 100, 100, 0.25)"
  , twNodeRendBorderColor : "#FFF"
  , twNodeRendBorderSize : 2.5          -- node borders (only iff ourRendering)
  , twNodesGreyOpacity : 5.5           -- smaller value: more grey
  , twSelectedColor : "node"     -- "node" for a label bg like the node color, "default" for white background
James Laver's avatar
James Laver committed
256 257 258
  , verbose : true
  , zoomMax: 1.7
  , zoomMin: 0.0
259
  , zoomingRatio: 1.7
James Laver's avatar
James Laver committed
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
  }
  
type ForceAtlas2Settings =
  ( adjustSizes :: Boolean
  , barnesHutOptimize :: Boolean
  -- , barnesHutTheta :: Number
  , edgeWeightInfluence :: Number
  -- , fixedY  :: Boolean
  , gravity :: Number
  , iterationsPerRender :: Number
  , linLogMode :: Boolean
  , outboundAttractionDistribution :: Boolean
  , scalingRatio :: Number
  , skipHidden :: Boolean
  , slowDown :: Number
  , startingIterations :: Number
  , strongGravityMode :: Boolean
  -- , timeout :: Number
  -- , worker :: Boolean
  )

forceAtlas2Settings :: {|ForceAtlas2Settings}
forceAtlas2Settings =
283
  { adjustSizes : true
James Laver's avatar
James Laver committed
284
  , barnesHutOptimize   : true
285
  , edgeWeightInfluence : 1.0
James Laver's avatar
James Laver committed
286 287
    -- fixedY : false
  , gravity : 1.0
288
  , iterationsPerRender : 10.0
289
  , linLogMode : false  -- false
James Laver's avatar
James Laver committed
290
  , outboundAttractionDistribution: false
291
  , scalingRatio : 10.0
James Laver's avatar
James Laver committed
292
  , skipHidden: false
293 294
  , slowDown : 1.0
  , startingIterations : 10.0
James Laver's avatar
James Laver committed
295 296
  , strongGravityMode : false
  }