Commit 9b8fde6e authored by Alexandre Delanoë's avatar Alexandre Delanoë

Merge branch 'dev-warnings-cleanup' into dev

parents 73386281 57f6fa5c
...@@ -79,18 +79,6 @@ li#rename #rename-a { ...@@ -79,18 +79,6 @@ li#rename #rename-a {
width: 1300px; width: 1300px;
} }
#search-popup-tooltip {
position: absolute;
left: 300px;
top: -300px;
background-color: white;
z-index: 1000;
}
#search-popup-tooltip:hover {
border: none;
text-decoration: none;
}
#create-node-tooltip { #create-node-tooltip {
position: absolute; position: absolute;
left: 96px; left: 96px;
...@@ -216,6 +204,11 @@ li:hover a#rename-leaf { ...@@ -216,6 +204,11 @@ li:hover a#rename-leaf {
justify-content: center; justify-content: center;
} }
.flex-center {
display: flex;
justify-content: space-between;
}
a:focus, a:hover { a:focus, a:hover {
cursor: pointer; cursor: pointer;
} }
......
.range { .range {
width: 400px; width: 400px;
/* some space for the right knob */
padding-right: 30px;
} }
.range .range-slider { .range .range-slider {
position: relative; position: relative;
......
.range .range
width: 400px width: 400px
/* some space for the right knob */
padding-right: 30px
.range-slider .range-slider
position: relative position: relative
......
...@@ -4,7 +4,9 @@ module Gargantext.Components.Graph ...@@ -4,7 +4,9 @@ module Gargantext.Components.Graph
-- , forceAtlas2Settings, ForceAtlas2Settings, ForceAtlas2OptionalSettings -- , forceAtlas2Settings, ForceAtlas2Settings, ForceAtlas2OptionalSettings
-- ) -- )
where where
import Prelude (bind, const, discard, pure, ($), unit) import Prelude (bind, const, discard, pure, ($), unit, map)
import Data.Array as A
import Data.Either (Either(..)) import Data.Either (Either(..))
import Data.Maybe (Maybe(..)) import Data.Maybe (Maybe(..))
import Data.Nullable (Nullable) import Data.Nullable (Nullable)
...@@ -22,20 +24,18 @@ import Gargantext.Hooks.Sigmax.Sigma as Sigma ...@@ -22,20 +24,18 @@ import Gargantext.Hooks.Sigmax.Sigma as Sigma
type OnProps = () type OnProps = ()
type Graph = SigmaxTypes.Graph SigmaxTypes.Node SigmaxTypes.Edge
data Stage = Init | Ready | Cleanup data Stage = Init | Ready | Cleanup
type Props sigma forceatlas2 = type Props sigma forceatlas2 =
( elRef :: R.Ref (Nullable Element) ( elRef :: R.Ref (Nullable Element)
, forceAtlas2Settings :: forceatlas2 , forceAtlas2Settings :: forceatlas2
, graph :: Graph , graph :: SigmaxTypes.SGraph
, selectedEdgeIds :: R.State SigmaxTypes.SelectedEdgeIds , multiSelectEnabledRef :: R.Ref Boolean
, selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds , selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds
, sigmaRef :: R.Ref Sigmax.Sigma , sigmaRef :: R.Ref Sigmax.Sigma
, sigmaSettings :: sigma , sigmaSettings :: sigma
, stage :: R.State Stage , stage :: R.State Stage
, transformedGraph :: Graph , transformedGraph :: SigmaxTypes.SGraph
) )
graph :: forall s fa2. Record (Props s fa2) -> R.Element graph :: forall s fa2. Record (Props s fa2) -> R.Element
...@@ -54,9 +54,8 @@ graphCpt = R.hooksComponent "Graph" cpt ...@@ -54,9 +54,8 @@ graphCpt = R.hooksComponent "Graph" cpt
Nothing -> RH.div {} [] Nothing -> RH.div {} []
Just el -> R.createPortal [] el Just el -> R.createPortal [] el
stageHooks props@{stage: (Init /\ setStage)} = do stageHooks props@{multiSelectEnabledRef, selectedNodeIds, sigmaRef, stage: (Init /\ setStage)} = do
R.useEffectOnce $ do R.useEffectOnce $ do
log "[graphCpt] effect once"
let rSigma = R.readRef props.sigmaRef let rSigma = R.readRef props.sigmaRef
case Sigmax.readSigma rSigma of case Sigmax.readSigma rSigma of
...@@ -67,7 +66,7 @@ graphCpt = R.hooksComponent "Graph" cpt ...@@ -67,7 +66,7 @@ graphCpt = R.hooksComponent "Graph" cpt
Right sig -> do Right sig -> do
Sigmax.writeSigma rSigma $ Just sig Sigmax.writeSigma rSigma $ Just sig
Sigmax.dependOnContainer props.elRef "[graphCpt] container not found" $ \c -> do Sigmax.dependOnContainer props.elRef "[graphCpt (Ready)] container not found" $ \c -> do
_ <- Sigma.addRenderer sig { _ <- Sigma.addRenderer sig {
"type": "canvas" "type": "canvas"
, container: c , container: c
...@@ -76,28 +75,28 @@ graphCpt = R.hooksComponent "Graph" cpt ...@@ -76,28 +75,28 @@ graphCpt = R.hooksComponent "Graph" cpt
Sigmax.refreshData sig $ Sigmax.sigmafy props.graph Sigmax.refreshData sig $ Sigmax.sigmafy props.graph
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
Sigmax.setEdges sig false Sigmax.setEdges sig false
Sigma.startForceAtlas2 sig props.forceAtlas2Settings Sigma.startForceAtlas2 sig props.forceAtlas2Settings
-- bind the click event only initially, when ref was empty
Sigmax.bindSelectedNodesClick props.sigmaRef props.selectedNodeIds
Sigmax.bindSelectedEdgesClick props.sigmaRef props.selectedEdgeIds
Just sig -> do Just sig -> do
pure unit pure unit
setStage $ const $ Ready setStage $ const Ready
delay unit $ \_ -> do delay unit $ \_ -> do
log "[graphCpt] cleanup" log "[graphCpt] cleanup"
pure $ pure unit pure $ pure unit
stageHooks props@{stage: (Ready /\ setStage)} = do stageHooks props@{sigmaRef, stage: (Ready /\ setStage), transformedGraph} = do
let tEdgesMap = SigmaxTypes.edgesGraphMap props.transformedGraph let tEdgesMap = SigmaxTypes.edgesGraphMap transformedGraph
let tNodesMap = SigmaxTypes.nodesGraphMap props.transformedGraph let tNodesMap = SigmaxTypes.nodesGraphMap transformedGraph
-- TODO Probably this can be optimized to re-mark selected nodes only when they changed -- TODO Probably this can be optimized to re-mark selected nodes only when they changed
R.useEffect' $ do R.useEffect' $ do
Sigmax.dependOnSigma (R.readRef props.sigmaRef) "[graphCpt] no sigma" $ \sigma -> do Sigmax.dependOnSigma (R.readRef sigmaRef) "[graphCpt (Ready)] no sigma" $ \sigma -> do
Sigmax.updateEdges sigma tEdgesMap Sigmax.updateEdges sigma tEdgesMap
Sigmax.updateNodes sigma tNodesMap Sigmax.updateNodes sigma tNodesMap
......
...@@ -6,18 +6,18 @@ import Data.FoldableWithIndex (foldMapWithIndex) ...@@ -6,18 +6,18 @@ import Data.FoldableWithIndex (foldMapWithIndex)
import Data.Foldable (foldMap) import Data.Foldable (foldMap)
import Data.Int (toNumber) import Data.Int (toNumber)
import Data.Map as Map import Data.Map as Map
import Data.Maybe (Maybe(..)) import Data.Maybe (Maybe(..), fromJust)
import Data.Nullable (null, Nullable) import Data.Nullable (null, Nullable)
import Data.Sequence as Seq import Data.Sequence as Seq
import Data.Set as Set import Data.Set as Set
import Data.Tuple (fst, snd, Tuple(..)) import Data.Tuple (fst, snd, Tuple(..))
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
-- import DOM.Simple.Console (log2)
import DOM.Simple.Types (Element) import DOM.Simple.Types (Element)
import Effect.Aff (Aff) import Effect.Aff (Aff)
import Math (log)
import Partial.Unsafe (unsafePartial)
import Reactix as R import Reactix as R
import Reactix.DOM.HTML as RH import Reactix.DOM.HTML as RH
import Math (log)
import Gargantext.Hooks.Loader (useLoader) import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Hooks.Sigmax as Sigmax import Gargantext.Hooks.Sigmax as Sigmax
...@@ -47,7 +47,7 @@ type LayoutProps = ...@@ -47,7 +47,7 @@ type LayoutProps =
) )
type Props = ( type Props = (
graph :: Maybe Graph.Graph graph :: SigmaxTypes.SGraph
, mMetaData :: Maybe GET.MetaData , mMetaData :: Maybe GET.MetaData
| LayoutProps | LayoutProps
) )
...@@ -64,7 +64,7 @@ explorerLayoutCpt = R.hooksComponent "G.C.GraphExplorer.explorerLayout" cpt ...@@ -64,7 +64,7 @@ explorerLayoutCpt = R.hooksComponent "G.C.GraphExplorer.explorerLayout" cpt
where where
handler loaded = handler loaded =
explorer { graphId, mCurrentRoute, mMetaData explorer { graphId, mCurrentRoute, mMetaData
, session, sessions, graph: Just graph, frontends, showLogin} , session, sessions, graph, frontends, showLogin}
where (Tuple mMetaData graph) = convert loaded where (Tuple mMetaData graph) = convert loaded
-------------------------------------------------------------- --------------------------------------------------------------
...@@ -77,19 +77,19 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt ...@@ -77,19 +77,19 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt
cpt {frontends, graph, graphId, mCurrentRoute, mMetaData, session, sessions, showLogin} _ = do cpt {frontends, graph, graphId, mCurrentRoute, mMetaData, session, sessions, showLogin} _ = do
dataRef <- R.useRef graph dataRef <- R.useRef graph
graphRef <- R.useRef null graphRef <- R.useRef null
controls <- Controls.useGraphControls controls <- Controls.useGraphControls graph
multiSelectEnabledRef <- R.useRef $ fst controls.multiSelectEnabled
R.useEffect' $ do R.useEffect' $ do
case Tuple (R.readRef dataRef) graph of let readData = R.readRef dataRef
Tuple Nothing Nothing -> pure unit if SigmaxTypes.eqGraph readData graph then
Tuple (Just g1) (Just g2) | SigmaxTypes.eqGraph g1 g2 -> pure unit pure unit
_ -> do else do
let rSigma = R.readRef controls.sigmaRef let rSigma = R.readRef controls.sigmaRef
Sigmax.cleanupSigma rSigma "explorerCpt" Sigmax.cleanupSigma rSigma "explorerCpt"
R.setRef dataRef graph R.setRef dataRef graph
snd controls.selectedEdgeIds $ const Set.empty snd controls.selectedNodeIds $ const Set.empty
snd controls.selectedNodeIds $ const Set.empty snd controls.graphStage $ const Graph.Init
snd controls.graphStage $ const Graph.Init
pure $ pure $
RH.div RH.div
...@@ -105,15 +105,12 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt ...@@ -105,15 +105,12 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt
, row [ Controls.controls controls ] , row [ Controls.controls controls ]
, row [ tree (fst controls.showTree) {sessions, mCurrentRoute, frontends} (snd showLogin) , row [ tree (fst controls.showTree) {sessions, mCurrentRoute, frontends} (snd showLogin)
, RH.div { ref: graphRef, id: "graph-view", className: graphClassName controls, style: {height: "95%"} } [] -- graph container , RH.div { ref: graphRef, id: "graph-view", className: graphClassName controls, style: {height: "95%"} } [] -- graph container
, mGraph { controls , graphView { controls
, elRef: graphRef , elRef: graphRef
, graphId , graphId
, graph , graph
, graphStage: controls.graphStage , multiSelectEnabledRef
, selectedEdgeIds: controls.selectedEdgeIds }
, selectedNodeIds: controls.selectedNodeIds
, sigmaRef: controls.sigmaRef
}
, mSidebar graph mMetaData { frontends , mSidebar graph mMetaData { frontends
, session , session
, selectedNodeIds: controls.selectedNodeIds , selectedNodeIds: controls.selectedNodeIds
...@@ -150,29 +147,15 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt ...@@ -150,29 +147,15 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt
RH.div {className: "col-md-2", style: {paddingTop: "60px"}} RH.div {className: "col-md-2", style: {paddingTop: "60px"}}
[forest {sessions, route, frontends, showLogin}] [forest {sessions, route, frontends, showLogin}]
mGraph :: { controls :: Record Controls.Controls mSidebar :: SigmaxTypes.SGraph
, elRef :: R.Ref (Nullable Element)
, graphId :: GraphId
, graph :: Maybe Graph.Graph
, graphStage :: R.State Graph.Stage
, selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds
, selectedEdgeIds :: R.State SigmaxTypes.SelectedEdgeIds
, sigmaRef :: R.Ref Sigmax.Sigma
}
-> R.Element
mGraph {graph: Nothing} = RH.div {} []
mGraph r@{graph: Just graph} = graphView $ r { graph = graph }
mSidebar :: Maybe Graph.Graph
-> Maybe GET.MetaData -> Maybe GET.MetaData
-> { frontends :: Frontends -> { frontends :: Frontends
, showSidePanel :: GET.SidePanelState , showSidePanel :: GET.SidePanelState
, selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds , selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds
, session :: Session } , session :: Session }
-> R.Element -> R.Element
mSidebar Nothing _ _ = RH.div {} []
mSidebar _ Nothing _ = RH.div {} [] mSidebar _ Nothing _ = RH.div {} []
mSidebar (Just graph) (Just metaData) {frontends, session, selectedNodeIds, showSidePanel} = mSidebar graph (Just metaData) {frontends, session, selectedNodeIds, showSidePanel} =
Sidebar.sidebar { frontends Sidebar.sidebar { frontends
, graph , graph
, metaData , metaData
...@@ -185,36 +168,37 @@ type GraphProps = ( ...@@ -185,36 +168,37 @@ type GraphProps = (
controls :: Record Controls.Controls controls :: Record Controls.Controls
, elRef :: R.Ref (Nullable Element) , elRef :: R.Ref (Nullable Element)
, graphId :: GraphId , graphId :: GraphId
, graph :: Graph.Graph , graph :: SigmaxTypes.SGraph
, graphStage :: R.State Graph.Stage , multiSelectEnabledRef :: R.Ref Boolean
, selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds
, selectedEdgeIds :: R.State SigmaxTypes.SelectedEdgeIds
, sigmaRef :: R.Ref Sigmax.Sigma
) )
graphView :: Record GraphProps -> R.Element graphView :: Record GraphProps -> R.Element
--graphView sigmaRef props = R.createElement (R.memo el memoCmp) props [] --graphView sigmaRef props = R.createElement (R.memo el memoCmp) props []
graphView props = R.createElement el props [] graphView props = R.createElement graphViewCpt props []
graphViewCpt :: R.Component GraphProps
graphViewCpt = R.hooksComponent "GraphView" cpt
where where
--memoCmp props1 props2 = props1.graphId == props2.graphId cpt {controls, elRef, graphId, graph, multiSelectEnabledRef} _children = do
el = R.hooksComponent "GraphView" cpt
cpt {controls, elRef, graphId, graph, selectedEdgeIds, selectedNodeIds, sigmaRef} _children = do
-- TODO Cache this? -- TODO Cache this?
let transformedGraph = transformGraph controls graph let transformedGraph = transformGraph controls graph
R.useEffect1' (fst controls.multiSelectEnabled) $ do
R.setRef multiSelectEnabledRef $ fst controls.multiSelectEnabled
pure $ Graph.graph { pure $ Graph.graph {
elRef elRef
, forceAtlas2Settings: Graph.forceAtlas2Settings , forceAtlas2Settings: Graph.forceAtlas2Settings
, graph , graph
, selectedEdgeIds , multiSelectEnabledRef
, selectedNodeIds , selectedNodeIds: controls.selectedNodeIds
, sigmaRef , sigmaRef: controls.sigmaRef
, sigmaSettings: Graph.sigmaSettings , sigmaSettings: Graph.sigmaSettings
, stage: props.graphStage , stage: controls.graphStage
, transformedGraph , transformedGraph
} }
convert :: GET.GraphData -> Tuple (Maybe GET.MetaData) Graph.Graph convert :: GET.GraphData -> Tuple (Maybe GET.MetaData) SigmaxTypes.SGraph
convert (GET.GraphData r) = Tuple r.metaData $ SigmaxTypes.Graph {nodes, edges} convert (GET.GraphData r) = Tuple r.metaData $ SigmaxTypes.Graph {nodes, edges}
where where
nodes = foldMapWithIndex nodeFn r.nodes nodes = foldMapWithIndex nodeFn r.nodes
...@@ -232,7 +216,14 @@ convert (GET.GraphData r) = Tuple r.metaData $ SigmaxTypes.Graph {nodes, edges} ...@@ -232,7 +216,14 @@ convert (GET.GraphData r) = Tuple r.metaData $ SigmaxTypes.Graph {nodes, edges}
cDef (GET.Cluster {clustDefault}) = clustDefault cDef (GET.Cluster {clustDefault}) = clustDefault
nodesMap = SigmaxTypes.nodesMap nodes nodesMap = SigmaxTypes.nodesMap nodes
edges = foldMap edgeFn r.edges edges = foldMap edgeFn r.edges
edgeFn (GET.Edge e) = Seq.singleton {id : e.id_, color, size: 1.0, source : e.source, target : e.target} edgeFn (GET.Edge e) = Seq.singleton { id : e.id_
, color
, confluence : e.confluence
, hidden : false
, size: 1.0
, source : e.source
, target : e.target
, weight : e.weight }
where where
color = case Map.lookup e.source nodesMap of color = case Map.lookup e.source nodesMap of
Nothing -> "#000000" Nothing -> "#000000"
...@@ -373,23 +364,47 @@ getNodes :: Session -> GraphId -> Aff GET.GraphData ...@@ -373,23 +364,47 @@ getNodes :: Session -> GraphId -> Aff GET.GraphData
getNodes session graphId = get session $ NodeAPI Graph (Just graphId) "" getNodes session graphId = get session $ NodeAPI Graph (Just graphId) ""
transformGraph :: Record Controls.Controls -> Graph.Graph -> Graph.Graph transformGraph :: Record Controls.Controls -> SigmaxTypes.SGraph -> SigmaxTypes.SGraph
transformGraph controls graph@(SigmaxTypes.Graph {nodes, edges}) = SigmaxTypes.Graph {nodes: newNodes, edges: newEdges} transformGraph controls graph = SigmaxTypes.Graph {nodes: newNodes, edges: newEdges}
where where
edges = SigmaxTypes.graphEdges graph
nodes = SigmaxTypes.graphNodes graph
graphEdgesMap = SigmaxTypes.edgesGraphMap graph graphEdgesMap = SigmaxTypes.edgesGraphMap graph
graphNodesMap = SigmaxTypes.nodesGraphMap graph graphNodesMap = SigmaxTypes.nodesGraphMap graph
newNodes = nodeSizes <$> nodeMarked <$> nodes selectedEdgeIds =
newEdges = edgeMarked <$> edges Set.fromFoldable
nodeSizes node@{ size } = $ Seq.map _.id
$ Seq.filter (\e -> Set.member e.source (fst controls.selectedNodeIds)) edges
hasSelection = not $ Set.isEmpty (fst controls.selectedNodeIds)
newNodes = nodeSizeFilter <$> nodeMarked <$> nodes
newEdges = edgeConfluenceFilter <$> edgeWeightFilter <$> edgeMarked <$> edges
nodeSizeFilter node@{ size } =
if Range.within (fst controls.nodeSize) size then if Range.within (fst controls.nodeSize) size then
node node
else else
node { hidden = true } node { hidden = true }
edgeMarked edge@{ id } =
if Set.member id (fst controls.selectedEdgeIds) then edgeConfluenceFilter edge@{ confluence } =
edge { color = "#ff0000" } if Range.within (fst controls.edgeConfluence) confluence then
edge
else else
edge { hidden = true }
edgeWeightFilter edge@{ weight } =
if Range.within (fst controls.edgeWeight) weight then
edge edge
else
edge { hidden = true }
edgeMarked edge@{ id } = do
let isSelected = Set.member id selectedEdgeIds
let sourceNode = Map.lookup edge.source graphNodesMap
case Tuple hasSelection isSelected of
Tuple false true -> edge { color = "#ff0000" }
Tuple true true -> edge { color = (unsafePartial $ fromJust sourceNode).color }
Tuple true false -> edge { color = "#dddddd" }
_ -> edge
nodeMarked node@{ id } = nodeMarked node@{ id } =
if Set.member id (fst controls.selectedNodeIds) then if Set.member id (fst controls.selectedNodeIds) then
node { color = "#ff0000" } node { color = "#ff0000" }
......
...@@ -7,10 +7,11 @@ module Gargantext.Components.GraphExplorer.Controls ...@@ -7,10 +7,11 @@ module Gargantext.Components.GraphExplorer.Controls
, getShowTree, setShowTree , getShowTree, setShowTree
, getShowControls, setShowControls , getShowControls, setShowControls
, getCursorSize, setCursorSize , getCursorSize, setCursorSize
, getMultiNodeSelect, setMultiNodeSelect
) where ) where
import Data.Maybe (Maybe(..)) import Data.Array as A
import Data.Maybe (Maybe(..), maybe)
import Data.Sequence as Seq
import Data.Set as Set import Data.Set as Set
import Data.Tuple (fst, snd) import Data.Tuple (fst, snd)
import Data.Tuple.Nested ((/\), get1) import Data.Tuple.Nested ((/\), get1)
...@@ -22,9 +23,10 @@ import Reactix.DOM.HTML as RH ...@@ -22,9 +23,10 @@ import Reactix.DOM.HTML as RH
import Gargantext.Components.Graph as Graph import Gargantext.Components.Graph as Graph
import Gargantext.Components.GraphExplorer.Button (centerButton) import Gargantext.Components.GraphExplorer.Button (centerButton)
import Gargantext.Components.GraphExplorer.RangeControl (edgeSizeControl, nodeSizeControl) import Gargantext.Components.GraphExplorer.RangeControl (edgeConfluenceControl, edgeWeightControl, nodeSizeControl)
import Gargantext.Components.GraphExplorer.Search (nodeSearchControl)
import Gargantext.Components.GraphExplorer.SlideButton (cursorSizeButton, labelSizeButton) import Gargantext.Components.GraphExplorer.SlideButton (cursorSizeButton, labelSizeButton)
import Gargantext.Components.GraphExplorer.ToggleButton (edgesToggleButton, pauseForceAtlasButton) import Gargantext.Components.GraphExplorer.ToggleButton (multiSelectEnabledButton, edgesToggleButton, pauseForceAtlasButton)
import Gargantext.Components.GraphExplorer.Types as GET import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Hooks.Sigmax as Sigmax import Gargantext.Hooks.Sigmax as Sigmax
import Gargantext.Hooks.Sigmax.Types as SigmaxTypes import Gargantext.Hooks.Sigmax.Types as SigmaxTypes
...@@ -33,11 +35,13 @@ import Gargantext.Utils.Reactix as R2 ...@@ -33,11 +35,13 @@ import Gargantext.Utils.Reactix as R2
type Controls = type Controls =
( cursorSize :: R.State Number ( cursorSize :: R.State Number
, edgeConfluence :: R.State Range.NumberRange
, edgeWeight :: R.State Range.NumberRange
, graph :: SigmaxTypes.SGraph
, graphStage :: R.State Graph.Stage , graphStage :: R.State Graph.Stage
, multiNodeSelect :: R.Ref Boolean , multiSelectEnabled :: R.State Boolean
, nodeSize :: R.State Range.NumberRange , nodeSize :: R.State Range.NumberRange
, selectedEdgeIds :: R.State (Set.Set String) , selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds
, selectedNodeIds :: R.State (Set.Set String)
, showControls :: R.State Boolean , showControls :: R.State Boolean
, showSidePanel :: R.State GET.SidePanelState , showSidePanel :: R.State GET.SidePanelState
, showTree :: R.State Boolean , showTree :: R.State Boolean
...@@ -48,23 +52,21 @@ controlsToSigmaSettings :: Record Controls -> Record Graph.SigmaSettings ...@@ -48,23 +52,21 @@ controlsToSigmaSettings :: Record Controls -> Record Graph.SigmaSettings
controlsToSigmaSettings { cursorSize: (cursorSize /\ _)} = Graph.sigmaSettings controlsToSigmaSettings { cursorSize: (cursorSize /\ _)} = Graph.sigmaSettings
type LocalControls = type LocalControls =
( edgeSize :: R.State Range.NumberRange ( labelSize :: R.State Number
, labelSize :: R.State Number
, pauseForceAtlas :: R.State Boolean , pauseForceAtlas :: R.State Boolean
, showEdges :: R.State Boolean , showEdges :: R.State Boolean
) )
initialLocalControls :: R.Hooks (Record LocalControls) initialLocalControls :: R.Hooks (Record LocalControls)
initialLocalControls = do initialLocalControls = do
edgeSize <- R.useState' $ Range.Closed { min: 0.5, max: 1.0 }
labelSize <- R.useState' 14.0 labelSize <- R.useState' 14.0
--nodeSize <- R.useState' $ Range.Closed { min: 0.0, max: 10.0 } --nodeSize <- R.useState' $ Range.Closed { min: 0.0, max: 10.0 }
pauseForceAtlas <- R.useState' true pauseForceAtlas <- R.useState' true
search <- R.useState' ""
showEdges <- R.useState' true showEdges <- R.useState' true
pure $ { pure $ {
edgeSize labelSize
, labelSize
--, nodeSize --, nodeSize
, pauseForceAtlas , pauseForceAtlas
, showEdges , showEdges
...@@ -107,6 +109,11 @@ controlsCpt = R.hooksComponent "GraphControls" cpt ...@@ -107,6 +109,11 @@ controlsCpt = R.hooksComponent "GraphControls" cpt
R.setRef mFAPauseRef $ Just timeoutId R.setRef mFAPauseRef $ Just timeoutId
pure unit pure unit
let nodesSorted = A.sortWith (_.size) $ Seq.toUnfoldable $ SigmaxTypes.graphNodes props.graph
let nodeSizeMin = maybe 0.0 _.size $ A.head nodesSorted
let nodeSizeMax = maybe 100.0 _.size $ A.last nodesSorted
let nodeSizeRange = Range.Closed { min: nodeSizeMin, max: nodeSizeMax }
pure $ case getShowControls props of pure $ case getShowControls props of
false -> RH.div {} [] false -> RH.div {} []
true -> RH.div { className: "col-md-12", style: { paddingBottom: "10px" } } true -> RH.div { className: "col-md-12", style: { paddingBottom: "10px" } }
...@@ -116,7 +123,8 @@ controlsCpt = R.hooksComponent "GraphControls" cpt ...@@ -116,7 +123,8 @@ controlsCpt = R.hooksComponent "GraphControls" cpt
RH.li {} [ centerButton props.sigmaRef ] RH.li {} [ centerButton props.sigmaRef ]
, RH.li {} [ pauseForceAtlasButton props.sigmaRef localControls.pauseForceAtlas ] -- spatialization (pause ForceAtlas2) , RH.li {} [ pauseForceAtlasButton props.sigmaRef localControls.pauseForceAtlas ] -- spatialization (pause ForceAtlas2)
, RH.li {} [ edgesToggleButton props.sigmaRef localControls.showEdges ] , RH.li {} [ edgesToggleButton props.sigmaRef localControls.showEdges ]
, RH.li {} [ edgeSizeControl props.sigmaRef localControls.edgeSize ] -- edge size : 0-3 , RH.li {} [ edgeConfluenceControl props.sigmaRef props.edgeConfluence ]
, RH.li {} [ edgeWeightControl props.sigmaRef props.edgeWeight ]
-- change level -- change level
-- file upload -- file upload
-- run demo -- run demo
...@@ -124,33 +132,40 @@ controlsCpt = R.hooksComponent "GraphControls" cpt ...@@ -124,33 +132,40 @@ controlsCpt = R.hooksComponent "GraphControls" cpt
-- search topics -- search topics
, RH.li {} [ cursorSizeButton props.cursorSize ] -- cursor size: 0-100 , RH.li {} [ cursorSizeButton props.cursorSize ] -- cursor size: 0-100
, RH.li {} [ labelSizeButton props.sigmaRef localControls.labelSize ] -- labels size: 1-4 , RH.li {} [ labelSizeButton props.sigmaRef localControls.labelSize ] -- labels size: 1-4
, RH.li {} [ nodeSizeControl props.nodeSize ] , RH.li {} [ nodeSizeControl nodeSizeRange props.nodeSize ]
-- zoom: 0 -100 - calculate ratio -- zoom: 0 -100 - calculate ratio
-- toggle multi node selection , RH.li {} [ multiSelectEnabledButton props.multiSelectEnabled ] -- toggle multi node selection
-- save button -- save button
, RH.li {} [ nodeSearchControl { selectedNodeIds: props.selectedNodeIds } ]
] ]
] ]
] ]
useGraphControls :: R.Hooks (Record Controls) useGraphControls :: SigmaxTypes.SGraph -> R.Hooks (Record Controls)
useGraphControls = do useGraphControls graph = do
let edges = SigmaxTypes.graphEdges graph
let nodes = SigmaxTypes.graphNodes graph
cursorSize <- R.useState' 10.0 cursorSize <- R.useState' 10.0
edgeConfluence <- R.useState' $ Range.Closed { min: 0.0, max: 1.0 }
edgeWeight <- R.useState' $ Range.Closed { min: 0.0, max: 1.0 }
graphStage <- R.useState' Graph.Init graphStage <- R.useState' Graph.Init
multiNodeSelect <- R.useRef false multiSelectEnabled <- R.useState' false
nodeSize <- R.useState' $ Range.Closed { min: 0.0, max: 10.0 } nodeSize <- R.useState' $ Range.Closed { min: 0.0, max: 100.0 }
showTree <- R.useState' false showTree <- R.useState' false
selectedNodeIds <- R.useState' $ Set.empty selectedNodeIds <- R.useState' $ Set.empty
selectedEdgeIds <- R.useState' $ Set.empty
showControls <- R.useState' false showControls <- R.useState' false
showSidePanel <- R.useState' GET.InitialClosed showSidePanel <- R.useState' GET.InitialClosed
sigma <- Sigmax.initSigma sigma <- Sigmax.initSigma
sigmaRef <- R.useRef sigma sigmaRef <- R.useRef sigma
pure { cursorSize pure { cursorSize
, edgeConfluence
, edgeWeight
, graph
, graphStage , graphStage
, multiNodeSelect , multiSelectEnabled
, nodeSize , nodeSize
, selectedEdgeIds
, selectedNodeIds , selectedNodeIds
, showControls , showControls
, showSidePanel , showSidePanel
...@@ -167,9 +182,6 @@ getShowTree { showTree: ( should /\ _ ) } = should ...@@ -167,9 +182,6 @@ getShowTree { showTree: ( should /\ _ ) } = should
getCursorSize :: Record Controls -> Number getCursorSize :: Record Controls -> Number
getCursorSize { cursorSize: ( size /\ _ ) } = size getCursorSize { cursorSize: ( size /\ _ ) } = size
getMultiNodeSelect :: Record Controls -> Boolean
getMultiNodeSelect { multiNodeSelect } = R.readRef multiNodeSelect
setShowControls :: Record Controls -> Boolean -> Effect Unit setShowControls :: Record Controls -> Boolean -> Effect Unit
setShowControls { showControls: ( _ /\ set ) } v = set $ const v setShowControls { showControls: ( _ /\ set ) } v = set $ const v
...@@ -178,6 +190,3 @@ setShowTree { showTree: ( _ /\ set ) } v = set $ not <<< const v ...@@ -178,6 +190,3 @@ setShowTree { showTree: ( _ /\ set ) } v = set $ not <<< const v
setCursorSize :: Record Controls -> Number -> Effect Unit setCursorSize :: Record Controls -> Number -> Effect Unit
setCursorSize { cursorSize: ( _ /\ setSize ) } v = setSize $ const v setCursorSize { cursorSize: ( _ /\ setSize ) } v = setSize $ const v
setMultiNodeSelect :: Record Controls -> Boolean -> Effect Unit
setMultiNodeSelect { multiNodeSelect } = R.setRef multiNodeSelect
module Gargantext.Components.GraphExplorer.RangeControl module Gargantext.Components.GraphExplorer.RangeControl
( Props ( Props
, rangeControl , rangeControl
, edgeSizeControl , edgeConfluenceControl
, edgeWeightControl
, nodeSizeControl , nodeSizeControl
) where ) where
...@@ -33,34 +34,50 @@ rangeControlCpt = R.hooksComponent "RangeButton" cpt ...@@ -33,34 +34,50 @@ rangeControlCpt = R.hooksComponent "RangeButton" cpt
, RS.rangeSlider sliderProps , RS.rangeSlider sliderProps
] ]
edgeSizeControl :: R.Ref Sigmax.Sigma -> R.State Range.NumberRange -> R.Element edgeConfluenceControl :: R.Ref Sigmax.Sigma -> R.State Range.NumberRange -> R.Element
edgeSizeControl sigmaRef (state /\ setState) = edgeConfluenceControl sigmaRef (state /\ setState) =
rangeControl { rangeControl {
caption: "Edge Size" caption: "Edge Confluence Weight"
, sliderProps: {
bounds: Range.Closed { min: 0.0, max: 1.0 }
, initialValue: state
, epsilon: 0.01
, step: 1.0
, width: 10.0
, height: 5.0
, onChange: setState <<< const
}
}
edgeWeightControl :: R.Ref Sigmax.Sigma -> R.State Range.NumberRange -> R.Element
edgeWeightControl sigmaRef (state /\ setState) =
rangeControl {
caption: "Edge Weight"
, sliderProps: { , sliderProps: {
bounds: Range.Closed { min: 0.0, max: 3.0 } bounds: Range.Closed { min: 0.0, max: 3.0 }
, initialValue: state , initialValue: state
, epsilon: 0.1 , epsilon: 0.01
, step: 1.0 , step: 1.0
, width: 10.0 , width: 10.0
, height: 5.0 , height: 5.0
, onChange: \range@(Range.Closed {min, max}) -> do , onChange: setState <<< const
let sigma = R.readRef sigmaRef -- , onChange: \range@(Range.Closed {min, max}) -> do
Sigmax.dependOnSigma sigma "[edgeSizeControl] sigma: Nothing" $ \s -> do -- let sigma = R.readRef sigmaRef
Sigma.setSettings s { -- Sigmax.dependOnSigma sigma "[edgeWeightControl] sigma: Nothing" $ \s -> do
minEdgeSize: min -- Sigma.setSettings s {
, maxEdgeSize: max -- minEdgeSize: min
} -- , maxEdgeSize: max
setState $ const range -- }
-- setState $ const range
} }
} }
nodeSizeControl :: R.State Range.NumberRange -> R.Element nodeSizeControl :: Range.NumberRange -> R.State Range.NumberRange -> R.Element
nodeSizeControl (state /\ setState) = nodeSizeControl (Range.Closed { min: rangeMin, max: rangeMax }) (state /\ setState) =
rangeControl { rangeControl {
caption: "Node Size" caption: "Node Size"
, sliderProps: { , sliderProps: {
bounds: Range.Closed { min: 0.0, max: 15.0 } bounds: Range.Closed { min: rangeMin, max: rangeMax }
, initialValue: state , initialValue: state
, epsilon: 0.1 , epsilon: 0.1
, step: 1.0 , step: 1.0
......
module Gargantext.Components.GraphExplorer.Search
( Props
, nodeSearchControl
) where
import Global (readFloat)
import Prelude
import Data.Set as Set
import Data.Tuple (snd)
import Data.Tuple.Nested ((/\))
import DOM.Simple.Console (log2)
import Effect (Effect)
import FFI.Simple ((..))
import Reactix as R
import Reactix.DOM.HTML as H
import Gargantext.Hooks.Sigmax as Sigmax
import Gargantext.Hooks.Sigmax.Sigma as Sigma
import Gargantext.Hooks.Sigmax.Types as SigmaxTypes
import Gargantext.Utils.Reactix as R2
type Props = (
selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds
)
nodeSearchControl :: Record Props -> R.Element
nodeSearchControl props = R.createElement sizeButtonCpt props []
sizeButtonCpt :: R.Component Props
sizeButtonCpt = R.hooksComponent "NodeSearchControl" cpt
where
cpt {selectedNodeIds} _ = do
(search /\ setSearch) <- R.useState' ""
pure $
H.div { className: "form-group" }
[ H.div { className: "input-group" }
[ H.input { type: "text"
, className: "form-control"
, defaultValue: search
, on: { input: \e -> setSearch $ const $ e .. "target" .. "value" }
}
, H.div { className: "btn input-group-addon"
, on: { click: \_ -> log2 "[sizeButtonCpt] search" search }
}
[ H.span { className: "fa fa-search" } [] ]
]
]
-- TODO Wherefrom do I get graph nodes?
-- How to implement filtering here? I want to set selectedNodeIds based on graph data.
...@@ -14,7 +14,6 @@ import Reactix.DOM.HTML as RH ...@@ -14,7 +14,6 @@ import Reactix.DOM.HTML as RH
import Gargantext.Data.Array (catMaybes) import Gargantext.Data.Array (catMaybes)
import Gargantext.Components.RandomText (words) import Gargantext.Components.RandomText (words)
import Gargantext.Components.Nodes.Corpus.Graph.Tabs as GT import Gargantext.Components.Nodes.Corpus.Graph.Tabs as GT
import Gargantext.Components.Graph as Graph
import Gargantext.Components.GraphExplorer.Types as GET import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Ends (Frontends) import Gargantext.Ends (Frontends)
import Gargantext.Hooks.Sigmax.Types as SigmaxTypes import Gargantext.Hooks.Sigmax.Types as SigmaxTypes
...@@ -22,7 +21,7 @@ import Gargantext.Sessions (Session) ...@@ -22,7 +21,7 @@ import Gargantext.Sessions (Session)
type Props = type Props =
( frontends :: Frontends ( frontends :: Frontends
, graph :: Graph.Graph , graph :: SigmaxTypes.SGraph
, metaData :: GET.MetaData , metaData :: GET.MetaData
, selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds , selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds
, session :: Session , session :: Session
......
module Gargantext.Components.GraphExplorer.ToggleButton module Gargantext.Components.GraphExplorer.ToggleButton
( Props, toggleButton, toggleButtonCpt ( Props
, toggleButton
, toggleButtonCpt
, multiSelectEnabledButton
, controlsToggleButton , controlsToggleButton
, edgesToggleButton , edgesToggleButton
, sidebarToggleButton , sidebarToggleButton
...@@ -66,6 +69,15 @@ edgesToggleButton sigmaRef state = ...@@ -66,6 +69,15 @@ edgesToggleButton sigmaRef state =
setToggled not setToggled not
} }
multiSelectEnabledButton :: R.State Boolean -> R.Element
multiSelectEnabledButton state =
toggleButton {
state: state
, onMessage: "Single-node"
, offMessage: "Multi-node"
, onClick: \_ -> snd state not
}
pauseForceAtlasButton :: R.Ref Sigmax.Sigma -> R.State Boolean -> R.Element pauseForceAtlasButton :: R.Ref Sigmax.Sigma -> R.State Boolean -> R.Element
pauseForceAtlasButton sigmaRef state = pauseForceAtlasButton sigmaRef state =
toggleButton { toggleButton {
......
...@@ -88,7 +88,7 @@ type State = ( ...@@ -88,7 +88,7 @@ type State = (
--, showSidePanel :: R.State Boolean --, showSidePanel :: R.State Boolean
--, showControls :: R.State Boolean --, showControls :: R.State Boolean
--, showTree :: R.State Boolean --, showTree :: R.State Boolean
--, sigmaGraphData :: R.State (Maybe Graph.Graph) --, sigmaGraphData :: R.State (Maybe SigmaxTypes.SGraph)
--, sigmaSettings :: R.State ({|Graph.SigmaSettings}) --, sigmaSettings :: R.State ({|Graph.SigmaSettings})
--treeId :: R.State (Maybe TreeId) --treeId :: R.State (Maybe TreeId)
) )
......
module Gargantext.Hooks.Sigmax module Gargantext.Hooks.Sigmax
where where
import Prelude (Unit, bind, discard, flip, pure, unit, ($), (*>), (<<<), (<>), (>>=), (||), not, const, map)
import Data.Array as A import Data.Array as A
import Data.Either (either) import Data.Either (either)
import Data.Foldable (sequence_) import Data.Foldable (sequence_, foldl)
import Data.Map as Map import Data.Map as Map
import Data.Maybe (Maybe(..)) import Data.Maybe (Maybe(..))
import Data.Nullable (Nullable) import Data.Nullable (Nullable)
...@@ -20,9 +22,8 @@ import Effect.Class.Console (error) ...@@ -20,9 +22,8 @@ import Effect.Class.Console (error)
import Effect.Timer (TimeoutId, clearTimeout) import Effect.Timer (TimeoutId, clearTimeout)
import FFI.Simple ((.=)) import FFI.Simple ((.=))
import Gargantext.Hooks.Sigmax.Sigma as Sigma import Gargantext.Hooks.Sigmax.Sigma as Sigma
import Gargantext.Hooks.Sigmax.Types (Graph(..), EdgesMap, NodesMap, SelectedNodeIds, SelectedEdgeIds) import Gargantext.Hooks.Sigmax.Types (Graph(..), SGraph, EdgesMap, NodesMap, SelectedNodeIds, SelectedEdgeIds, graphEdges)
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
import Prelude (Unit, bind, discard, flip, pure, unit, ($), (*>), (<<<), (<>), (>>=), not)
import Reactix as R import Reactix as R
type Sigma = type Sigma =
...@@ -190,8 +191,9 @@ updateEdges sigma edgesMap = do ...@@ -190,8 +191,9 @@ updateEdges sigma edgesMap = do
let mTEdge = Map.lookup e.id edgesMap let mTEdge = Map.lookup e.id edgesMap
case mTEdge of case mTEdge of
Nothing -> error $ "Edge id " <> e.id <> " not found in edgesMap" Nothing -> error $ "Edge id " <> e.id <> " not found in edgesMap"
(Just tEdge@{color: tColor}) -> do (Just {color: tColor, hidden: tHidden}) -> do
_ <- pure $ (e .= "color") tColor _ <- pure $ (e .= "color") tColor
_ <- pure $ (e .= "hidden") tHidden
pure unit pure unit
Sigma.refresh sigma Sigma.refresh sigma
...@@ -202,28 +204,38 @@ updateNodes sigma nodesMap = do ...@@ -202,28 +204,38 @@ updateNodes sigma nodesMap = do
let mTNode = Map.lookup n.id nodesMap let mTNode = Map.lookup n.id nodesMap
case mTNode of case mTNode of
Nothing -> error $ "Node id " <> n.id <> " not found in nodesMap" Nothing -> error $ "Node id " <> n.id <> " not found in nodesMap"
(Just tNode@{color: tColor, hidden: tHidden}) -> do (Just {color: tColor, hidden: tHidden}) -> do
_ <- pure $ (n .= "color") tColor _ <- pure $ (n .= "color") tColor
_ <- pure $ (n .= "hidden") tHidden _ <- pure $ (n .= "hidden") tHidden
pure unit pure unit
Sigma.refresh sigma Sigma.refresh sigma
bindSelectedNodesClick :: R.Ref Sigma -> R.State SelectedNodeIds -> Effect Unit -- | Toggles item visibility in the selected set
bindSelectedNodesClick sigmaRef (_ /\ setSelectedNodeIds) = multiSelectUpdate :: SelectedNodeIds -> SelectedNodeIds -> SelectedNodeIds
dependOnSigma (R.readRef sigmaRef) "[graphCpt] no sigma" $ \sigma -> do multiSelectUpdate new selected = foldl fld selected new
Sigma.bindClickNode sigma $ \node -> do where
setSelectedNodeIds \nids -> fld selectedAcc item =
if Set.member node.id nids then if Set.member item selectedAcc then
Set.delete node.id nids Set.delete item selectedAcc
else else
Set.insert node.id nids Set.insert item selectedAcc
bindSelectedNodesClick :: Sigma.Sigma -> R.State SelectedNodeIds -> R.Ref Boolean -> Effect Unit
bindSelectedNodesClick sigma (_ /\ setSelectedNodeIds) multiSelectEnabledRef =
Sigma.bindClickNodes sigma $ \nodes -> do
let multiSelectEnabled = R.readRef multiSelectEnabledRef
let nodeIds = Set.fromFoldable $ map _.id nodes
if multiSelectEnabled then
setSelectedNodeIds $ multiSelectUpdate nodeIds
else
setSelectedNodeIds $ const nodeIds
bindSelectedEdgesClick :: R.Ref Sigma -> R.State SelectedEdgeIds -> Effect Unit bindSelectedEdgesClick :: R.Ref Sigma -> R.State SelectedEdgeIds -> Effect Unit
bindSelectedEdgesClick sigmaRef (_ /\ setSelectedEdgeIds) = bindSelectedEdgesClick sigmaRef (_ /\ setSelectedEdgeIds) =
dependOnSigma (R.readRef sigmaRef) "[graphCpt] no sigma" $ \sigma -> do dependOnSigma (R.readRef sigmaRef) "[graphCpt] no sigma" $ \sigma -> do
Sigma.bindClickEdge sigma $ \edge -> do Sigma.bindClickEdge sigma $ \edge -> do
log2 "[bindClickEdge] edge" edge
setSelectedEdgeIds \eids -> setSelectedEdgeIds \eids ->
if Set.member edge.id eids then if Set.member edge.id eids then
Set.delete edge.id eids Set.delete edge.id eids
......
...@@ -142,6 +142,14 @@ bindClickNode s f = bind_ s "clickNode" $ \e -> do ...@@ -142,6 +142,14 @@ bindClickNode s f = bind_ s "clickNode" $ \e -> do
unbindClickNode :: Sigma -> Effect Unit unbindClickNode :: Sigma -> Effect Unit
unbindClickNode s = unbind_ s "clickNode" unbindClickNode s = unbind_ s "clickNode"
bindClickNodes :: Sigma -> (Array (Record Types.Node) -> Effect Unit) -> Effect Unit
bindClickNodes s f = bind_ s "clickNodes" $ \e -> do
let nodes = e .. "data" .. "node" :: Array (Record Types.Node)
f nodes
unbindClickNodes :: Sigma -> Effect Unit
unbindClickNodes s = unbind_ s "clickNodes"
bindOverNode :: Sigma -> (Record Types.Node -> Effect Unit) -> Effect Unit bindOverNode :: Sigma -> (Record Types.Node -> Effect Unit) -> Effect Unit
bindOverNode s f = bind_ s "overNode" $ \e -> do bindOverNode s f = bind_ s "overNode" $ \e -> do
let node = e .. "data" .. "node" :: Record Types.Node let node = e .. "data" .. "node" :: Record Types.Node
......
module Gargantext.Hooks.Sigmax.Types where module Gargantext.Hooks.Sigmax.Types where
import Prelude (map, ($), (&&), (==)) import Prelude (map, ($), (&&), (==), class Ord, Ordering, compare)
import Data.Map as Map import Data.Map as Map
import Data.Sequence (Seq) import Data.Sequence (Seq)
import Data.Set as Set import Data.Set as Set
...@@ -30,27 +30,36 @@ type Node = ...@@ -30,27 +30,36 @@ type Node =
type Edge = type Edge =
( id :: String ( id :: String
, color :: String , color :: String
, confluence :: Number
, hidden :: Boolean
, size :: Number , size :: Number
, source :: String , source :: String
, target :: String ) , target :: String
, weight :: Number )
type SelectedNodeIds = Set.Set String type SelectedNodeIds = Set.Set String
type SelectedEdgeIds = Set.Set String type SelectedEdgeIds = Set.Set String
type EdgesMap = Map.Map String (Record Edge) type EdgesMap = Map.Map String (Record Edge)
type NodesMap = Map.Map String (Record Node) type NodesMap = Map.Map String (Record Node)
type SGraph = Graph Node Edge
graphEdges :: SGraph -> Seq (Record Edge)
graphEdges (Graph {edges}) = edges
graphNodes :: SGraph -> Seq (Record Node)
graphNodes (Graph {nodes}) = nodes
edgesGraphMap :: Graph Node Edge -> EdgesMap edgesGraphMap :: Graph Node Edge -> EdgesMap
edgesGraphMap graph = do edgesGraphMap graph =
let (Graph {edges}) = graph Map.fromFoldable $ map (\e -> Tuple e.id e) $ graphEdges graph
Map.fromFoldable $ map (\e -> Tuple e.id e) edges
nodesMap :: Seq (Record Node) -> NodesMap nodesMap :: Seq (Record Node) -> NodesMap
nodesMap nodes = Map.fromFoldable $ map (\n -> Tuple n.id n) nodes nodesMap nodes = Map.fromFoldable $ map (\n -> Tuple n.id n) nodes
nodesGraphMap :: Graph Node Edge -> NodesMap nodesGraphMap :: Graph Node Edge -> NodesMap
nodesGraphMap graph = do nodesGraphMap graph =
let (Graph {nodes}) = graph nodesMap $ graphNodes graph
nodesMap nodes
eqGraph :: (Graph Node Edge) -> (Graph Node Edge) -> Boolean eqGraph :: (Graph Node Edge) -> (Graph Node Edge) -> Boolean
eqGraph (Graph {nodes: n1, edges: e1}) (Graph {nodes: n2, edges: e2}) = (n1 == n2) && (e1 == e2) eqGraph (Graph {nodes: n1, edges: e1}) (Graph {nodes: n2, edges: e2}) = (n1 == n2) && (e1 == e2)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment