Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
purescript-gargantext
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Grégoire Locqueville
purescript-gargantext
Commits
81465f81
Commit
81465f81
authored
Dec 09, 2019
by
Nicolas Pouillard
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dev' of
https://gitlab.iscpif.fr/gargantext/purescript-gargantext
into dev
parents
3f3389ec
a411ad1d
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
127 additions
and
46 deletions
+127
-46
Graph.purs
src/Gargantext/Components/Graph.purs
+8
-7
GraphExplorer.purs
src/Gargantext/Components/GraphExplorer.purs
+62
-24
Controls.purs
src/Gargantext/Components/GraphExplorer/Controls.purs
+22
-6
RangeControl.purs
src/Gargantext/Components/GraphExplorer/RangeControl.purs
+9
-9
Sigmax.purs
src/Gargantext/Hooks/Sigmax.purs
+25
-0
Types.purs
src/Gargantext/Hooks/Sigmax/Types.purs
+1
-0
No files found.
src/Gargantext/Components/Graph.purs
View file @
81465f81
...
...
@@ -32,9 +32,10 @@ type Props sigma forceatlas2 =
, graph :: Graph
, selectedEdgeIds :: R.State SigmaxTypes.SelectedEdgeIds
, selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds
, sigmaSettings :: sigma
, sigmaRef :: R.Ref Sigmax.Sigma
, sigmaSettings :: sigma
, stage :: R.State Stage
, transformedGraph :: Graph
)
graph :: forall s fa2. Record (Props s fa2) -> R.Element
...
...
@@ -91,14 +92,14 @@ graphCpt = R.hooksComponent "Graph" cpt
pure $ pure unit
stageHooks props@{stage: (Ready /\ setStage)} = do
let
edgesMap = SigmaxTypes.edgesGraphMap props.g
raph
let
nodesMap = SigmaxTypes.nodesGraphMap props.g
raph
let
tEdgesMap = SigmaxTypes.edgesGraphMap props.transformedG
raph
let
tNodesMap = SigmaxTypes.nodesGraphMap props.transformedG
raph
-- TODO Probably this can be optimized to re-mark selected nodes only when they changed
R.useEffect' $ do
Sigmax.dependOnSigma (R.readRef props.sigmaRef) "[graphCpt] no sigma" $ \sigma -> do
Sigmax.
markSelectedEdges sigma (fst props.selectedEdgeIds) e
dgesMap
Sigmax.
markSelectedNodes sigma (fst props.selectedNodeIds) n
odesMap
Sigmax.
updateEdges sigma tE
dgesMap
Sigmax.
updateNodes sigma tN
odesMap
stageHooks _ = pure unit
...
...
@@ -228,9 +229,9 @@ sigmaSettings =
, labelSizeRatio: 2.0 -- label size in ratio of node size
, labelThreshold: 5.0 -- min node cam size to start showing label
, maxEdgeSize: 1.0
, maxNodeSize:
7
.0
, maxNodeSize:
8
.0
, minEdgeSize: 0.5 -- in fact used in tina as edge size
, minNodeSize:
0.1
, minNodeSize:
1.0
, mouseEnabled: true
, mouseZoomDuration: 150.0
, nodeBorderColor: "default" -- choices: "default" color vs. "node" color
...
...
src/Gargantext/Components/GraphExplorer.purs
View file @
81465f81
...
...
@@ -20,7 +20,6 @@ import Reactix.DOM.HTML as RH
import Math (log)
import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Hooks.Sigmax (Sigma)
import Gargantext.Hooks.Sigmax as Sigmax
import Gargantext.Hooks.Sigmax.Types as SigmaxTypes
import Gargantext.Components.GraphExplorer.Controls as Controls
...
...
@@ -33,6 +32,7 @@ import Gargantext.Ends (Frontends)
import Gargantext.Routes (SessionRoute(NodeAPI), AppRoute)
import Gargantext.Sessions (Session, Sessions, get)
import Gargantext.Types (NodeType(Graph))
import Gargantext.Utils.Range as Range
import Gargantext.Utils.Reactix as R2
type GraphId = Int
...
...
@@ -78,8 +78,6 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt
dataRef <- R.useRef graph
graphRef <- R.useRef null
controls <- Controls.useGraphControls
selectedNodeIds <- R.useState' $ Set.empty
selectedEdgeIds <- R.useState' $ Set.empty
R.useEffect' $ do
case Tuple (R.readRef dataRef) graph of
...
...
@@ -89,16 +87,10 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt
let rSigma = R.readRef controls.sigmaRef
Sigmax.cleanupSigma rSigma "explorerCpt"
R.setRef dataRef graph
snd
selectedNod
eIds $ const Set.empty
snd
selectedEdg
eIds $ const Set.empty
snd
controls.selectedEdg
eIds $ const Set.empty
snd
controls.selectedNod
eIds $ const Set.empty
snd controls.graphStage $ const Graph.Init
R.useEffect' $ do
if fst controls.showSidePanel == GET.InitialClosed && (not Set.isEmpty $ fst selectedNodeIds) then
snd controls.showSidePanel $ \_ -> GET.Opened
else
pure unit
pure $
RH.div
{ id: "graph-explorer" }
...
...
@@ -113,8 +105,20 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt
, row [ Controls.controls controls ]
, 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
, mGraph graphRef controls.sigmaRef {graphId, graph, graphStage: controls.graphStage, selectedNodeIds, selectedEdgeIds}
, mSidebar graph mMetaData {frontends, session, selectedNodeIds, showSidePanel: fst controls.showSidePanel}
, mGraph { controls
, elRef: graphRef
, graphId
, graph
, graphStage: controls.graphStage
, selectedEdgeIds: controls.selectedEdgeIds
, selectedNodeIds: controls.selectedNodeIds
, sigmaRef: controls.sigmaRef
}
, mSidebar graph mMetaData { frontends
, session
, selectedNodeIds: controls.selectedNodeIds
, showSidePanel: fst controls.showSidePanel
}
]
, row [
]
...
...
@@ -146,16 +150,18 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt
RH.div {className: "col-md-2", style: {paddingTop: "60px"}}
[forest {sessions, route, frontends, showLogin}]
mGraph ::
R.Ref (Nullable Element)
-> R.Ref Sigma
-> {
graphId :: GraphId
mGraph ::
{ controls :: Record Controls.Controls
, 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}
, selectedEdgeIds :: R.State SigmaxTypes.SelectedEdgeIds
, sigmaRef :: R.Ref Sigmax.Sigma
}
-> R.Element
mGraph
_ _
{graph: Nothing} = RH.div {} []
mGraph
graphRef sigmaRef r@{graph: Just graph} = graphView graphRef sigmaRef
$ r { graph = graph }
mGraph {graph: Nothing} = RH.div {} []
mGraph
r@{graph: Just graph} = graphView
$ r { graph = graph }
mSidebar :: Maybe Graph.Graph
-> Maybe GET.MetaData
...
...
@@ -176,29 +182,36 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt
}
type GraphProps = (
graphId :: GraphId
controls :: Record Controls.Controls
, elRef :: R.Ref (Nullable Element)
, graphId :: GraphId
, graph :: Graph.Graph
, graphStage :: R.State Graph.Stage
, selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds
, selectedEdgeIds :: R.State SigmaxTypes.SelectedEdgeIds
, sigmaRef :: R.Ref Sigmax.Sigma
)
graphView :: R
.Ref (Nullable Element) -> R.Ref Sigma -> R
ecord GraphProps -> R.Element
graphView :: Record GraphProps -> R.Element
--graphView sigmaRef props = R.createElement (R.memo el memoCmp) props []
graphView
elRef sigmaRef
props = R.createElement el props []
graphView props = R.createElement el props []
where
--memoCmp props1 props2 = props1.graphId == props2.graphId
el = R.hooksComponent "GraphView" cpt
cpt {graphId, graph, selectedEdgeIds, selectedNodeIds} _children = do
cpt {controls, elRef, graphId, graph, selectedEdgeIds, selectedNodeIds, sigmaRef} _children = do
-- TODO Cache this?
let transformedGraph = transformGraph controls graph
pure $ Graph.graph {
elRef
, forceAtlas2Settings: Graph.forceAtlas2Settings
, graph
, selectedEdgeIds
, selectedNodeIds
, sigmaRef
, sigmaSettings: Graph.sigmaSettings
, sigmaRef: sigmaRef
, stage: props.graphStage
, transformedGraph
}
convert :: GET.GraphData -> Tuple (Maybe GET.MetaData) Graph.Graph
...
...
@@ -209,6 +222,7 @@ convert (GET.GraphData r) = Tuple r.metaData $ SigmaxTypes.Graph {nodes, edges}
Seq.singleton
{ id : n.id_
, size : log (toNumber n.size + 1.0)
, hidden : false
, label : n.label
, x : n.x -- cos (toNumber i)
, y : n.y -- sin (toNumber i)
...
...
@@ -357,3 +371,27 @@ defaultPalette = ["#5fa571","#ab9ba2","#da876d","#bdd3ff"
getNodes :: Session -> GraphId -> Aff GET.GraphData
getNodes session graphId = get session $ NodeAPI Graph (Just graphId) ""
transformGraph :: Record Controls.Controls -> Graph.Graph -> Graph.Graph
transformGraph controls graph@(SigmaxTypes.Graph {nodes, edges}) = SigmaxTypes.Graph {nodes: newNodes, edges: newEdges}
where
graphEdgesMap = SigmaxTypes.edgesGraphMap graph
graphNodesMap = SigmaxTypes.nodesGraphMap graph
newNodes = nodeSizes <$> nodeMarked <$> nodes
newEdges = edgeMarked <$> edges
nodeSizes node@{ size } =
if Range.within (fst controls.nodeSize) size then
node
else
node { hidden = true }
edgeMarked edge@{ id } =
if Set.member id (fst controls.selectedEdgeIds) then
edge { color = "#ff0000" }
else
edge
nodeMarked node@{ id } =
if Set.member id (fst controls.selectedNodeIds) then
node { color = "#ff0000" }
else
node
src/Gargantext/Components/GraphExplorer/Controls.purs
View file @
81465f81
...
...
@@ -11,7 +11,8 @@ module Gargantext.Components.GraphExplorer.Controls
) where
import Data.Maybe (Maybe(..))
import Data.Tuple (fst)
import Data.Set as Set
import Data.Tuple (fst, snd)
import Data.Tuple.Nested ((/\), get1)
import Effect (Effect)
import Effect.Timer (setTimeout)
...
...
@@ -26,6 +27,7 @@ import Gargantext.Components.GraphExplorer.SlideButton (cursorSizeButton, labelS
import Gargantext.Components.GraphExplorer.ToggleButton (edgesToggleButton, pauseForceAtlasButton)
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Hooks.Sigmax as Sigmax
import Gargantext.Hooks.Sigmax.Types as SigmaxTypes
import Gargantext.Utils.Range as Range
import Gargantext.Utils.Reactix as R2
...
...
@@ -33,6 +35,9 @@ type Controls =
( cursorSize :: R.State Number
, graphStage :: R.State Graph.Stage
, multiNodeSelect :: R.Ref Boolean
, nodeSize :: R.State Range.NumberRange
, selectedEdgeIds :: R.State (Set.Set String)
, selectedNodeIds :: R.State (Set.Set String)
, showControls :: R.State Boolean
, showSidePanel :: R.State GET.SidePanelState
, showTree :: R.State Boolean
...
...
@@ -45,7 +50,6 @@ controlsToSigmaSettings { cursorSize: (cursorSize /\ _)} = Graph.sigmaSettings
type LocalControls =
( edgeSize :: R.State Range.NumberRange
, labelSize :: R.State Number
, nodeSize :: R.State Range.NumberRange
, pauseForceAtlas :: R.State Boolean
, showEdges :: R.State Boolean
)
...
...
@@ -54,14 +58,14 @@ initialLocalControls :: R.Hooks (Record LocalControls)
initialLocalControls = do
edgeSize <- R.useState' $ Range.Closed { min: 0.5, max: 1.0 }
labelSize <- R.useState' 14.0
nodeSize <- R.useState' $ Range.Closed { min: 5
.0, max: 10.0 }
--nodeSize <- R.useState' $ Range.Closed { min: 0
.0, max: 10.0 }
pauseForceAtlas <- R.useState' true
showEdges <- R.useState' true
pure $ {
edgeSize
, labelSize
, nodeSize
--
, nodeSize
, pauseForceAtlas
, showEdges
}
...
...
@@ -86,6 +90,12 @@ controlsCpt = R.hooksComponent "GraphControls" cpt
R.useEffect' $ Sigmax.handleForceAtlas2Pause props.sigmaRef localControls.pauseForceAtlas (get1 localControls.showEdges) mFAPauseRef
R.useEffect' $ do
if fst props.showSidePanel == GET.InitialClosed && (not Set.isEmpty $ fst props.selectedNodeIds) then
snd props.showSidePanel $ \_ -> GET.Opened
else
pure unit
R.useEffectOnce' $ do
timeoutId <- setTimeout 2000 $ do
let (toggled /\ setToggled) = localControls.pauseForceAtlas
...
...
@@ -114,7 +124,7 @@ controlsCpt = R.hooksComponent "GraphControls" cpt
-- search topics
, RH.li {} [ cursorSizeButton props.cursorSize ] -- cursor size: 0-100
, RH.li {} [ labelSizeButton props.sigmaRef localControls.labelSize ] -- labels size: 1-4
, RH.li {} [ nodeSizeControl props.
sigmaRef localControls.nodeSize ] -- node size : 5-15
, RH.li {} [ nodeSizeControl props.
nodeSize ]
-- zoom: 0 -100 - calculate ratio
-- toggle multi node selection
-- save button
...
...
@@ -127,15 +137,21 @@ useGraphControls = do
cursorSize <- R.useState' 10.0
graphStage <- R.useState' Graph.Init
multiNodeSelect <- R.useRef false
nodeSize <- R.useState' $ Range.Closed { min: 0.0, max: 10.0 }
showTree <- R.useState' false
selectedNodeIds <- R.useState' $ Set.empty
selectedEdgeIds <- R.useState' $ Set.empty
showControls <- R.useState' false
showSidePanel <- R.useState' GET.InitialClosed
showTree <- R.useState' false
sigma <- Sigmax.initSigma
sigmaRef <- R.useRef sigma
pure { cursorSize
, graphStage
, multiNodeSelect
, nodeSize
, selectedEdgeIds
, selectedNodeIds
, showControls
, showSidePanel
, showTree
...
...
src/Gargantext/Components/GraphExplorer/RangeControl.purs
View file @
81465f81
...
...
@@ -55,24 +55,24 @@ edgeSizeControl sigmaRef (state /\ setState) =
}
}
nodeSizeControl :: R.
Ref Sigmax.Sigma -> R.
State Range.NumberRange -> R.Element
nodeSizeControl
sigmaRef
(state /\ setState) =
nodeSizeControl :: R.State Range.NumberRange -> R.Element
nodeSizeControl (state /\ setState) =
rangeControl {
caption: "Node Size"
, sliderProps: {
bounds: Range.Closed { min:
5
.0, max: 15.0 }
bounds: Range.Closed { min:
0
.0, max: 15.0 }
, initialValue: state
, epsilon: 0.1
, step: 1.0
, width: 10.0
, height: 5.0
, onChange: \range@(Range.Closed {min, max}) -> do
let sigma = R.readRef sigmaRef
Sigmax.dependOnSigma sigma "[nodeSizeControl] sigma: Nothing" $ \s -> do
Sigma.setSettings s {
minNodeSize: min
, maxNodeSize: max
}
--
let sigma = R.readRef sigmaRef
--
Sigmax.dependOnSigma sigma "[nodeSizeControl] sigma: Nothing" $ \s -> do
--
Sigma.setSettings s {
--
minNodeSize: min
--
, maxNodeSize: max
--
}
setState $ const range
}
}
src/Gargantext/Hooks/Sigmax.purs
View file @
81465f81
...
...
@@ -184,6 +184,31 @@ markSelectedNodes sigma selectedNodeIds graphNodes = do
Sigma.refresh sigma
updateEdges :: Sigma.Sigma -> EdgesMap -> Effect Unit
updateEdges sigma edgesMap = do
Sigma.forEachEdge sigma \e -> do
let mTEdge = Map.lookup e.id edgesMap
case mTEdge of
Nothing -> error $ "Edge id " <> e.id <> " not found in edgesMap"
(Just tEdge@{color: tColor}) -> do
_ <- pure $ (e .= "color") tColor
pure unit
Sigma.refresh sigma
updateNodes :: Sigma.Sigma -> NodesMap -> Effect Unit
updateNodes sigma nodesMap = do
Sigma.forEachNode sigma \n -> do
let mTNode = Map.lookup n.id nodesMap
case mTNode of
Nothing -> error $ "Node id " <> n.id <> " not found in nodesMap"
(Just tNode@{color: tColor, hidden: tHidden}) -> do
_ <- pure $ (n .= "color") tColor
_ <- pure $ (n .= "hidden") tHidden
pure unit
Sigma.refresh sigma
bindSelectedNodesClick :: R.Ref Sigma -> R.State SelectedNodeIds -> Effect Unit
bindSelectedNodesClick sigmaRef (_ /\ setSelectedNodeIds) =
dependOnSigma (R.readRef sigmaRef) "[graphCpt] no sigma" $ \sigma -> do
...
...
src/Gargantext/Hooks/Sigmax/Types.purs
View file @
81465f81
...
...
@@ -21,6 +21,7 @@ type Renderer = { "type" :: String, container :: Element }
type Node =
( id :: String
, label :: String
, hidden :: Boolean
, x :: Number
, y :: Number
, size :: Number
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment