Commit c73f90ca authored by Alexandre Delanoë's avatar Alexandre Delanoë

Merge branch 'dev-sigmajs-selector' into dev

parents f3fdb94b 2ed26a3c
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
position: absolute; position: absolute;
max-height: 600px; max-height: 600px;
overflow-y: scroll; overflow-y: scroll;
top: 150px; top: 170px;
z-index: 1; z-index: 1;
} }
#graph-explorer #graph-view { #graph-explorer #graph-view {
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
position: absolute; position: absolute;
max-height: 600px; max-height: 600px;
overflow-y: scroll; overflow-y: scroll;
top: 150px; top: 170px;
z-index: 1; z-index: 1;
left: 70%; left: 70%;
border: 1px white solid; border: 1px white solid;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
position: absolute position: absolute
max-height: 600px max-height: 600px
overflow-y: scroll overflow-y: scroll
top: 150px top: 170px
z-index: 1 z-index: 1
#graph-explorer #graph-explorer
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
"prop-types": "15.6.2", "prop-types": "15.6.2",
"react": "^16.10", "react": "^16.10",
"react-dom": "^16.10", "react-dom": "^16.10",
"sigma": "git://github.com/jjl/sigma.js#garg" "sigma": "git://github.com/poorscript/sigma.js#garg"
}, },
"eslintConfig": { "eslintConfig": {
"extends": "react-app" "extends": "react-app"
......
...@@ -81,9 +81,8 @@ appCpt = R.hooksComponent "G.C.App.app" cpt where ...@@ -81,9 +81,8 @@ appCpt = R.hooksComponent "G.C.App.app" cpt where
forestLayout :: Frontends -> Sessions -> AppRoute -> R2.Setter Boolean -> R.Element -> R.Element forestLayout :: Frontends -> Sessions -> AppRoute -> R2.Setter Boolean -> R.Element -> R.Element
forestLayout frontends sessions route showLogin child = forestLayout frontends sessions route showLogin child =
R.fragment [ topBar {}, row main, footer {} ] R.fragment [ topBar {}, R2.row [main], footer {} ]
where where
row child' = H.div {className: "row"} [child']
main = main =
R.fragment R.fragment
[ H.div {className: "col-md-2", style: {paddingTop: "60px"}} [ H.div {className: "col-md-2", style: {paddingTop: "60px"}}
......
...@@ -254,7 +254,7 @@ docViewCpt = R.hooksComponent "G.C.DocsTable.docView" cpt where ...@@ -254,7 +254,7 @@ docViewCpt = R.hooksComponent "G.C.DocsTable.docView" cpt where
, layout: { frontends, session, nodeId, tabType, listId , layout: { frontends, session, nodeId, tabType, listId
, corpusId, totalRecords, chart, showSearch } } _ = do , corpusId, totalRecords, chart, showSearch } } _ = do
pure $ H.div {className: "container1"} pure $ H.div {className: "container1"}
[ H.div {className: "row"} [ R2.row
[ chart [ chart
, if showSearch then searchBar query else H.div {} [] , if showSearch then searchBar query else H.div {} []
, H.div {className: "col-md-12"} , H.div {className: "col-md-12"}
......
...@@ -28,6 +28,7 @@ import Gargantext.Sessions (Session, sessionId, post, deleteWithBody) ...@@ -28,6 +28,7 @@ import Gargantext.Sessions (Session, sessionId, post, deleteWithBody)
import Gargantext.Types (NodeType(..), OrderBy(..), NodePath(..)) import Gargantext.Types (NodeType(..), OrderBy(..), NodePath(..))
import Gargantext.Utils (toggleSet, zeroPad) import Gargantext.Utils (toggleSet, zeroPad)
import Gargantext.Utils.DecodeMaybe ((.|)) import Gargantext.Utils.DecodeMaybe ((.|))
import Gargantext.Utils.Reactix as R2
------------------------------------------------------------------------ ------------------------------------------------------------------------
type NodeID = Int type NodeID = Int
...@@ -191,7 +192,7 @@ docViewCpt = R.hooksComponent "G.C.FacetsTable.DocView" cpt ...@@ -191,7 +192,7 @@ docViewCpt = R.hooksComponent "G.C.FacetsTable.DocView" cpt
snd path $ const ipp snd path $ const ipp
pure $ H.div { className: "container1" } pure $ H.div { className: "container1" }
[ H.div { className: "row" } [ R2.row
[ chart [ chart
, H.div { className: "col-md-12" } , H.div { className: "col-md-12" }
[ pageLayout { deletions, frontends, totalRecords, container, session, path } ] [ pageLayout { deletions, frontends, totalRecords, container, session, path } ]
...@@ -241,7 +242,7 @@ docViewGraphCpt = R.hooksComponent "FacetsDocViewGraph" cpt ...@@ -241,7 +242,7 @@ docViewGraphCpt = R.hooksComponent "FacetsDocViewGraph" cpt
, H.p {} [ H.text "" ] , H.p {} [ H.text "" ]
, H.br {} , H.br {}
, H.div { className: "container-fluid" } , H.div { className: "container-fluid" }
[ H.div { className: "row" } [ R2.row
[ chart [ chart
, H.div { className: "col-md-12" } , H.div { className: "col-md-12" }
[ pageLayout { frontends, totalRecords, deletions, container, session, path } [ pageLayout { frontends, totalRecords, deletions, container, session, path }
......
...@@ -224,7 +224,7 @@ nodePopupView d p mPop@(Just NodePopup /\ setPopupOpen) = R.createElement el p [ ...@@ -224,7 +224,7 @@ nodePopupView d p mPop@(Just NodePopup /\ setPopupOpen) = R.createElement el p [
panelHeading renameBoxOpen@(open /\ _) = panelHeading renameBoxOpen@(open /\ _) =
H.div {className: "panel-heading"} H.div {className: "panel-heading"}
[ H.div {className: "row" } [ R2.row
[ H.div {className: "col-md-8"} [ H.div {className: "col-md-8"}
[ renameBox d {id, name, nodeType} renameBoxOpen ] [ renameBox d {id, name, nodeType} renameBoxOpen ]
......
...@@ -4,13 +4,11 @@ module Gargantext.Components.Graph ...@@ -4,13 +4,11 @@ module Gargantext.Components.Graph
-- , forceAtlas2Settings, ForceAtlas2Settings, ForceAtlas2OptionalSettings -- , forceAtlas2Settings, ForceAtlas2Settings, ForceAtlas2OptionalSettings
-- ) -- )
where where
import Prelude (bind, const, discard, pure, ($), unit, map, not, show) import Prelude (bind, const, discard, not, pure, unit, ($))
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)
import Data.Tuple (fst)
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
import DOM.Simple.Console (log, log2) import DOM.Simple.Console (log, log2)
import DOM.Simple.Types (Element) import DOM.Simple.Types (Element)
...@@ -32,7 +30,6 @@ type Props sigma forceatlas2 = ...@@ -32,7 +30,6 @@ type Props sigma forceatlas2 =
, graph :: SigmaxTypes.SGraph , graph :: SigmaxTypes.SGraph
, multiSelectEnabledRef :: R.Ref Boolean , multiSelectEnabledRef :: R.Ref Boolean
, selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds , selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds
, selectorSize :: R.State Int
, showEdges :: R.State SigmaxTypes.ShowEdgesState , showEdges :: R.State SigmaxTypes.ShowEdgesState
, sigmaRef :: R.Ref Sigmax.Sigma , sigmaRef :: R.Ref Sigmax.Sigma
, sigmaSettings :: sigma , sigmaSettings :: sigma
...@@ -72,6 +69,7 @@ graphCpt = R.hooksComponent "Graph" cpt ...@@ -72,6 +69,7 @@ graphCpt = R.hooksComponent "Graph" cpt
_ <- Sigma.addRenderer sig { _ <- Sigma.addRenderer sig {
"type": "canvas" "type": "canvas"
, container: c , container: c
, additionalContexts: ["mouseSelector"]
} }
pure unit pure unit
...@@ -80,6 +78,8 @@ graphCpt = R.hooksComponent "Graph" cpt ...@@ -80,6 +78,8 @@ graphCpt = R.hooksComponent "Graph" cpt
Sigmax.dependOnSigma (R.readRef sigmaRef) "[graphCpt (Ready)] no sigma" $ \sigma -> do Sigmax.dependOnSigma (R.readRef sigmaRef) "[graphCpt (Ready)] no sigma" $ \sigma -> do
-- bind the click event only initially, when ref was empty -- bind the click event only initially, when ref was empty
Sigmax.bindSelectedNodesClick sigma selectedNodeIds multiSelectEnabledRef Sigmax.bindSelectedNodesClick sigma selectedNodeIds multiSelectEnabledRef
_ <- Sigma.bindMouseSelectorPlugin sigma
pure unit
Sigmax.setEdges sig false Sigmax.setEdges sig false
Sigma.startForceAtlas2 sig props.forceAtlas2Settings Sigma.startForceAtlas2 sig props.forceAtlas2Settings
...@@ -103,10 +103,6 @@ graphCpt = R.hooksComponent "Graph" cpt ...@@ -103,10 +103,6 @@ graphCpt = R.hooksComponent "Graph" cpt
Sigmax.updateNodes sigma tNodesMap Sigmax.updateNodes sigma tNodesMap
Sigmax.setEdges sigma (not $ SigmaxTypes.edgeStateHidden showEdges) Sigmax.setEdges sigma (not $ SigmaxTypes.edgeStateHidden showEdges)
-- R.useEffect1' (fst props.selectorSize) $ do
-- Sigmax.dependOnSigma (R.readRef sigmaRef) "[graphCpt (Ready)] no sigma" $ \sigma -> do
-- Sigmax.selectorWithSize sigma $ fst props.selectorSize
stageHooks _ = pure unit stageHooks _ = pure unit
...@@ -172,6 +168,7 @@ type SigmaSettings = ...@@ -172,6 +168,7 @@ type SigmaSettings =
, mouseEnabled :: Boolean , mouseEnabled :: Boolean
-- , mouseInertiaDuration :: Number -- , mouseInertiaDuration :: Number
-- , mouseInertiaRatio :: Number -- , mouseInertiaRatio :: Number
, mouseSelectorSize :: Number
-- , mouseWheelEnabled :: Boolean -- , mouseWheelEnabled :: Boolean
, mouseZoomDuration :: Number , mouseZoomDuration :: Number
, nodeBorderColor :: String , nodeBorderColor :: String
...@@ -239,6 +236,7 @@ sigmaSettings = ...@@ -239,6 +236,7 @@ sigmaSettings =
, minEdgeSize: 0.5 -- in fact used in tina as edge size , minEdgeSize: 0.5 -- in fact used in tina as edge size
, minNodeSize: 1.0 , minNodeSize: 1.0
, mouseEnabled: true , mouseEnabled: true
, mouseSelectorSize: 15.0
, mouseZoomDuration: 150.0 , mouseZoomDuration: 150.0
, nodeBorderColor: "default" -- choices: "default" color vs. "node" color , nodeBorderColor: "default" -- choices: "default" color vs. "node" color
--, nodesPowRatio : 10.8 --, nodesPowRatio : 10.8
......
...@@ -98,7 +98,7 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt ...@@ -98,7 +98,7 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt
pure $ pure $
RH.div RH.div
{ id: "graph-explorer" } { id: "graph-explorer" }
[ row [ R2.row
[ outer [ outer
[ inner [ inner
[ row1 [ row1
...@@ -107,7 +107,8 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt ...@@ -107,7 +107,8 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt
, col [ pullRight [ Toggle.sidebarToggleButton controls.showSidePanel ] ] , col [ pullRight [ Toggle.sidebarToggleButton controls.showSidePanel ] ]
] ]
, rowControls [ Controls.controls controls ] , rowControls [ Controls.controls controls ]
, row [ tree (fst controls.showTree) {sessions, mCurrentRoute, frontends} (snd showLogin) , R2.row [
tree (fst controls.showTree) {sessions, mCurrentRoute, frontends} (snd showLogin)
, RH.div { ref: graphRef, id: "graph-view", className: "col-md-12" } [] -- graph container , RH.div { ref: graphRef, id: "graph-view", className: "col-md-12" } [] -- graph container
, graphView { controls , graphView { controls
, elRef: graphRef , elRef: graphRef
...@@ -130,7 +131,6 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt ...@@ -130,7 +131,6 @@ explorerCpt = R.hooksComponent "G.C.GraphExplorer.explorer" cpt
outer = RH.div { className: "col-md-12" } outer = RH.div { className: "col-md-12" }
inner = RH.div { className: "container-fluid", style: { paddingTop: "90px" } } inner = RH.div { className: "container-fluid", style: { paddingTop: "90px" } }
row1 = RH.div { className: "row", style: { paddingBottom: "10px", marginTop: "-24px" } } row1 = RH.div { className: "row", style: { paddingBottom: "10px", marginTop: "-24px" } }
row = RH.div { className: "row" }
rowControls = RH.div { className: "row controls" } rowControls = RH.div { className: "row controls" }
col = RH.div { className: "col-md-4" } col = RH.div { className: "col-md-4" }
pullLeft = RH.div { className: "pull-left" } pullLeft = RH.div { className: "pull-left" }
...@@ -189,7 +189,6 @@ graphViewCpt = R.hooksComponent "GraphView" cpt ...@@ -189,7 +189,6 @@ graphViewCpt = R.hooksComponent "GraphView" cpt
, graph , graph
, multiSelectEnabledRef , multiSelectEnabledRef
, selectedNodeIds: controls.selectedNodeIds , selectedNodeIds: controls.selectedNodeIds
, selectorSize: controls.selectorSize
, showEdges: controls.showEdges , showEdges: controls.showEdges
, sigmaRef: controls.sigmaRef , sigmaRef: controls.sigmaRef
, sigmaSettings: Graph.sigmaSettings , sigmaSettings: Graph.sigmaSettings
...@@ -201,7 +200,7 @@ convert :: GET.GraphData -> Tuple (Maybe GET.MetaData) SigmaxTypes.SGraph ...@@ -201,7 +200,7 @@ 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
nodeFn i (GET.Node n) = nodeFn _i (GET.Node n) =
Seq.singleton Seq.singleton
{ borderColor: color { borderColor: color
, color : color , color : color
...@@ -224,12 +223,14 @@ convert (GET.GraphData r) = Tuple r.metaData $ SigmaxTypes.Graph {nodes, edges} ...@@ -224,12 +223,14 @@ convert (GET.GraphData r) = Tuple r.metaData $ SigmaxTypes.Graph {nodes, edges}
, hidden : false , hidden : false
, size: 1.0 , size: 1.0
, source : e.source , source : e.source
, sourceNode
, target : e.target , target : e.target
, targetNode
, weight : e.weight } , weight : e.weight }
where where
color = case Map.lookup e.source nodesMap of sourceNode = unsafePartial $ fromJust $ Map.lookup e.source nodesMap
Nothing -> "#000000" targetNode = unsafePartial $ fromJust $ Map.lookup e.target nodesMap
Just node -> node.color color = sourceNode.color
defaultPalette :: Array String defaultPalette :: Array String
defaultPalette = ["#5fa571","#ab9ba2","#da876d","#bdd3ff" defaultPalette = ["#5fa571","#ab9ba2","#da876d","#bdd3ff"
...@@ -371,16 +372,14 @@ transformGraph controls graph = SigmaxTypes.Graph {nodes: newNodes, edges: newEd ...@@ -371,16 +372,14 @@ transformGraph controls graph = SigmaxTypes.Graph {nodes: newNodes, edges: newEd
where where
edges = SigmaxTypes.graphEdges graph edges = SigmaxTypes.graphEdges graph
nodes = SigmaxTypes.graphNodes graph nodes = SigmaxTypes.graphNodes graph
graphEdgesMap = SigmaxTypes.edgesGraphMap graph
graphNodesMap = SigmaxTypes.nodesGraphMap graph
selectedEdgeIds = selectedEdgeIds =
Set.fromFoldable Set.fromFoldable
$ Seq.map _.id $ Seq.map _.id
$ Seq.filter (\e -> Set.member e.source (fst controls.selectedNodeIds)) edges $ SigmaxTypes.neighbouringEdges graph (fst controls.selectedNodeIds)
hasSelection = not $ Set.isEmpty (fst controls.selectedNodeIds) hasSelection = not $ Set.isEmpty (fst controls.selectedNodeIds)
newNodes = nodeSizeFilter <$> nodeMarked <$> nodes newNodes = Seq.map (nodeSizeFilter <<< nodeMarked) nodes
newEdges = edgeConfluenceFilter <$> edgeWeightFilter <$> edgeShowFilter <$> edgeMarked <$> edges newEdges = Seq.map (edgeConfluenceFilter <<< edgeWeightFilter <<< edgeShowFilter <<< edgeMarked) edges
nodeSizeFilter node@{ size } = nodeSizeFilter node@{ size } =
if Range.within (fst controls.nodeSize) size then if Range.within (fst controls.nodeSize) size then
...@@ -404,16 +403,15 @@ transformGraph controls graph = SigmaxTypes.Graph {nodes: newNodes, edges: newEd ...@@ -404,16 +403,15 @@ transformGraph controls graph = SigmaxTypes.Graph {nodes: newNodes, edges: newEd
else else
edge { hidden = true } edge { hidden = true }
edgeMarked edge@{ id } = do edgeMarked edge@{ id, sourceNode } = do
let isSelected = Set.member id selectedEdgeIds let isSelected = Set.member id selectedEdgeIds
let sourceNode = Map.lookup edge.source graphNodesMap
case Tuple hasSelection isSelected of case Tuple hasSelection isSelected of
Tuple false true -> edge { color = "#ff0000" } Tuple false true -> edge { color = "#ff0000" }
Tuple true true -> edge { color = (unsafePartial $ fromJust sourceNode).color } Tuple true true -> edge { color = sourceNode.color }
Tuple true false -> edge { color = "#dddddd" } Tuple true false -> edge { color = "rgba(221, 221, 221, 0.5)" }
_ -> edge _ -> edge
nodeMarked node@{ id } = nodeMarked node@{ id } =
if Set.member id (fst controls.selectedNodeIds) then if Set.member id (fst controls.selectedNodeIds) then
node { borderColor = "#000", type = "hovered" } node { borderColor = "#000", type = "selected" }
else else
node node
module Gargantext.Components.GraphExplorer.Controls module Gargantext.Components.GraphExplorer.Controls
( Controls ( Controls
, controlsToSigmaSettings
, useGraphControls , useGraphControls
, controls , controls
, controlsCpt , controlsCpt
, getShowTree, setShowTree , getShowTree, setShowTree
, getShowControls, setShowControls , getShowControls, setShowControls
, getCursorSize, setCursorSize
) where ) where
import Data.Array as A import Data.Array as A
...@@ -25,7 +23,7 @@ import Gargantext.Components.Graph as Graph ...@@ -25,7 +23,7 @@ import Gargantext.Components.Graph as Graph
import Gargantext.Components.GraphExplorer.Button (centerButton) import Gargantext.Components.GraphExplorer.Button (centerButton)
import Gargantext.Components.GraphExplorer.RangeControl (edgeConfluenceControl, edgeWeightControl, nodeSizeControl) import Gargantext.Components.GraphExplorer.RangeControl (edgeConfluenceControl, edgeWeightControl, nodeSizeControl)
import Gargantext.Components.GraphExplorer.Search (nodeSearchControl) import Gargantext.Components.GraphExplorer.Search (nodeSearchControl)
import Gargantext.Components.GraphExplorer.SlideButton (cursorSizeButton, labelSizeButton) import Gargantext.Components.GraphExplorer.SlideButton (labelSizeButton, mouseSelectorSizeButton)
import Gargantext.Components.GraphExplorer.ToggleButton (multiSelectEnabledButton, 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
...@@ -34,8 +32,7 @@ import Gargantext.Utils.Range as Range ...@@ -34,8 +32,7 @@ import Gargantext.Utils.Range as Range
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
type Controls = type Controls =
( cursorSize :: R.State Number ( edgeConfluence :: R.State Range.NumberRange
, edgeConfluence :: R.State Range.NumberRange
, edgeWeight :: R.State Range.NumberRange , edgeWeight :: R.State Range.NumberRange
, forceAtlasState :: R.State SigmaxTypes.ForceAtlasState , forceAtlasState :: R.State SigmaxTypes.ForceAtlasState
, graph :: SigmaxTypes.SGraph , graph :: SigmaxTypes.SGraph
...@@ -43,7 +40,6 @@ type Controls = ...@@ -43,7 +40,6 @@ type Controls =
, multiSelectEnabled :: R.State Boolean , multiSelectEnabled :: R.State Boolean
, nodeSize :: R.State Range.NumberRange , nodeSize :: R.State Range.NumberRange
, selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds , selectedNodeIds :: R.State SigmaxTypes.SelectedNodeIds
, selectorSize :: R.State Int
, showControls :: R.State Boolean , showControls :: R.State Boolean
, showEdges :: R.State SigmaxTypes.ShowEdgesState , showEdges :: R.State SigmaxTypes.ShowEdgesState
, showSidePanel :: R.State GET.SidePanelState , showSidePanel :: R.State GET.SidePanelState
...@@ -51,19 +47,19 @@ type Controls = ...@@ -51,19 +47,19 @@ type Controls =
, sigmaRef :: R.Ref Sigmax.Sigma , sigmaRef :: R.Ref Sigmax.Sigma
) )
controlsToSigmaSettings :: Record Controls -> Record Graph.SigmaSettings
controlsToSigmaSettings { cursorSize: (cursorSize /\ _)} = Graph.sigmaSettings
type LocalControls = type LocalControls =
( labelSize :: R.State Number ( labelSize :: R.State Number
, mouseSelectorSize :: R.State Number
) )
initialLocalControls :: R.Hooks (Record LocalControls) initialLocalControls :: R.Hooks (Record LocalControls)
initialLocalControls = do initialLocalControls = do
labelSize <- R.useState' 14.0 labelSize <- R.useState' 14.0
mouseSelectorSize <- R.useState' 15.0
pure $ { pure $ {
labelSize labelSize
, mouseSelectorSize
} }
controls :: Record Controls -> R.Element controls :: Record Controls -> R.Element
...@@ -145,7 +141,6 @@ controlsCpt = R.hooksComponent "GraphControls" cpt ...@@ -145,7 +141,6 @@ controlsCpt = R.hooksComponent "GraphControls" cpt
-- run demo -- run demo
-- search button -- search button
-- search topics -- search topics
, 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 nodeSizeRange props.nodeSize ] , RH.li {} [ nodeSizeControl nodeSizeRange props.nodeSize ]
-- zoom: 0 -100 - calculate ratio -- zoom: 0 -100 - calculate ratio
...@@ -153,13 +148,13 @@ controlsCpt = R.hooksComponent "GraphControls" cpt ...@@ -153,13 +148,13 @@ controlsCpt = R.hooksComponent "GraphControls" cpt
-- save button -- save button
, RH.li {} [ nodeSearchControl { graph: props.graph , RH.li {} [ nodeSearchControl { graph: props.graph
, selectedNodeIds: props.selectedNodeIds } ] , selectedNodeIds: props.selectedNodeIds } ]
, RH.li {} [ mouseSelectorSizeButton props.sigmaRef localControls.mouseSelectorSize ]
] ]
] ]
] ]
useGraphControls :: SigmaxTypes.SGraph -> R.Hooks (Record Controls) useGraphControls :: SigmaxTypes.SGraph -> R.Hooks (Record Controls)
useGraphControls graph = do useGraphControls graph = do
cursorSize <- R.useState' 10.0
edgeConfluence <- R.useState' $ Range.Closed { min: 0.0, max: 1.0 } edgeConfluence <- R.useState' $ Range.Closed { min: 0.0, max: 1.0 }
edgeWeight <- R.useState' $ Range.Closed { min: 0.0, max: 1.0 } edgeWeight <- R.useState' $ Range.Closed { min: 0.0, max: 1.0 }
forceAtlasState <- R.useState' SigmaxTypes.InitialRunning forceAtlasState <- R.useState' SigmaxTypes.InitialRunning
...@@ -168,15 +163,13 @@ useGraphControls graph = do ...@@ -168,15 +163,13 @@ useGraphControls graph = do
nodeSize <- R.useState' $ Range.Closed { min: 0.0, max: 100.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
selectorSize <- R.useState' 5
showControls <- R.useState' false showControls <- R.useState' false
showEdges <- R.useState' SigmaxTypes.EShow showEdges <- R.useState' SigmaxTypes.EShow
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 { edgeConfluence
, edgeConfluence
, edgeWeight , edgeWeight
, forceAtlasState , forceAtlasState
, graph , graph
...@@ -184,7 +177,6 @@ useGraphControls graph = do ...@@ -184,7 +177,6 @@ useGraphControls graph = do
, multiSelectEnabled , multiSelectEnabled
, nodeSize , nodeSize
, selectedNodeIds , selectedNodeIds
, selectorSize
, showControls , showControls
, showEdges , showEdges
, showSidePanel , showSidePanel
...@@ -198,14 +190,8 @@ getShowControls { showControls: ( should /\ _ ) } = should ...@@ -198,14 +190,8 @@ getShowControls { showControls: ( should /\ _ ) } = should
getShowTree :: Record Controls -> Boolean getShowTree :: Record Controls -> Boolean
getShowTree { showTree: ( should /\ _ ) } = should getShowTree { showTree: ( should /\ _ ) } = should
getCursorSize :: Record Controls -> Number
getCursorSize { cursorSize: ( size /\ _ ) } = size
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
setShowTree :: Record Controls -> Boolean -> Effect Unit setShowTree :: Record Controls -> Boolean -> Effect Unit
setShowTree { showTree: ( _ /\ set ) } v = set $ not <<< const v setShowTree { showTree: ( _ /\ set ) } v = set $ not <<< const v
setCursorSize :: Record Controls -> Number -> Effect Unit
setCursorSize { cursorSize: ( _ /\ setSize ) } v = setSize $ const v
...@@ -12,8 +12,6 @@ import Reactix as R ...@@ -12,8 +12,6 @@ import Reactix as R
import Reactix.DOM.HTML as H import Reactix.DOM.HTML as H
import Gargantext.Components.RangeSlider as RS import Gargantext.Components.RangeSlider as RS
import Gargantext.Hooks.Sigmax as Sigmax
import Gargantext.Hooks.Sigmax.Sigma as Sigma
import Gargantext.Utils.Range as Range import Gargantext.Utils.Range as Range
type Props = ( type Props = (
......
...@@ -4,20 +4,29 @@ module Gargantext.Components.GraphExplorer.Sidebar ...@@ -4,20 +4,29 @@ module Gargantext.Components.GraphExplorer.Sidebar
import Prelude import Prelude
import Data.Array (head) import Data.Array (head)
import Data.Int (fromString)
import Data.Map as Map import Data.Map as Map
import Data.Maybe (Maybe(..)) import Data.Maybe (Maybe(..))
import Data.Sequence as Seq
import Data.Set as Set import Data.Set as Set
import Data.Traversable (traverse_)
import Data.Tuple.Nested((/\)) import Data.Tuple.Nested((/\))
import DOM.Simple.Console (log2)
import Effect (Effect)
import Effect.Aff (Aff, launchAff_)
import Reactix as R import Reactix as R
import Reactix.DOM.HTML as RH import Reactix.DOM.HTML as RH
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.GraphExplorer.Types as GET import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Data.Array (mapMaybe)
import Gargantext.Ends (Frontends) import Gargantext.Ends (Frontends)
import Gargantext.Hooks.Sigmax.Types as SigmaxTypes import Gargantext.Hooks.Sigmax.Types as SigmaxTypes
import Gargantext.Sessions (Session) import Gargantext.Routes (SessionRoute(NodeAPI))
import Gargantext.Sessions (Session, delete)
import Gargantext.Types (NodeType(..))
import Gargantext.Utils.Reactix as R2
type Props = type Props =
( frontends :: Frontends ( frontends :: Frontends
...@@ -44,20 +53,35 @@ sidebarCpt = R.hooksComponent "Sidebar" cpt ...@@ -44,20 +53,35 @@ sidebarCpt = R.hooksComponent "Sidebar" cpt
pure $ pure $
RH.div { id: "sp-container", className: "col-md-3" } RH.div { id: "sp-container", className: "col-md-3" }
[ RH.div {} [ RH.div {}
[ RH.div { className: "row" } [ R2.row
[ RH.div { className: "col-md-12" } [ R2.col12
[ RH.ul { id: "myTab", className: "nav nav-tabs", role: "tablist"} [ RH.ul { id: "myTab", className: "nav nav-tabs", role: "tablist"}
[ RH.li { className: "nav-item" } [ RH.div { className: "tab-content" }
[ RH.div { className: "", role: "tabpanel" }
(Seq.toUnfoldable $ (Seq.map (badge props.selectedNodeIds) (badges props.graph props.selectedNodeIds)))
]
, RH.div { className: "tab-content" }
[
RH.button { className: "btn btn-danger"
, on: { click: onClickRemove props.session props.selectedNodeIds }}
[ RH.text "Remove" ]
]
, RH.li { className: "nav-item" }
[ RH.a { id: "home-tab" [ RH.a { id: "home-tab"
, className: "nav-link active" , className: "nav-link active"
, data: {toggle: "tab"} , data: {toggle: "tab"}
, href: "#home" , href: "#home"
, role: "tab" , role: "tab"
, aria: {controls: "home", selected: "true"}} , aria: {controls: "home", selected: "true"}
[ RH.text "Selected nodes" ] ] ] }
[ RH.text "Neighbours" ]
]
]
, RH.div { className: "tab-content", id: "myTabContent" } , RH.div { className: "tab-content", id: "myTabContent" }
[ RH.div { className: "", id: "home", role: "tabpanel" } [ RH.div { className: "", id: "home", role: "tabpanel" }
(badge <$> badges props.selectedNodeIds nodesMap) ] ] (Seq.toUnfoldable $ (Seq.map (badge props.selectedNodeIds) (neighbourBadges props.graph props.selectedNodeIds)))
]
]
{-, RH.div { className: "col-md-12", id: "horizontal-checkbox" } {-, RH.div { className: "col-md-12", id: "horizontal-checkbox" }
[ RH.ul {} [ RH.ul {}
[ checkbox "Pubs" [ checkbox "Pubs"
...@@ -74,8 +98,13 @@ sidebarCpt = R.hooksComponent "Sidebar" cpt ...@@ -74,8 +98,13 @@ sidebarCpt = R.hooksComponent "Sidebar" cpt
] ]
] ]
] ]
badge text = badge (_ /\ setSelectedNodeIds) {id, label} =
RH.a { className: "badge badge-light" } [ RH.text text ] RH.a { className: "badge badge-light"
, on: { click: onClick }
} [ RH.text label ]
where
onClick e = do
setSelectedNodeIds $ const $ Set.singleton id
checkbox text = checkbox text =
RH.li {} RH.li {}
[ RH.span {} [ RH.text text ] [ RH.span {} [ RH.text text ]
...@@ -83,10 +112,24 @@ sidebarCpt = R.hooksComponent "Sidebar" cpt ...@@ -83,10 +112,24 @@ sidebarCpt = R.hooksComponent "Sidebar" cpt
, className: "checkbox" , className: "checkbox"
, checked: true , checked: true
, title: "Mark as completed" } ] , title: "Mark as completed" } ]
badges (selectedNodeIds /\ _) nodesMap = map (\n -> n.label) badges :: SigmaxTypes.SGraph -> R.State SigmaxTypes.SelectedNodeIds -> Seq.Seq (Record SigmaxTypes.Node)
$ catMaybes badges graph (selectedNodeIds /\ _) = SigmaxTypes.nodesById graph selectedNodeIds
$ map (\n -> Map.lookup n nodesMap) neighbourBadges :: SigmaxTypes.SGraph -> R.State SigmaxTypes.SelectedNodeIds -> Seq.Seq (Record SigmaxTypes.Node)
$ Set.toUnfoldable selectedNodeIds neighbourBadges graph (selectedNodeIds /\ _) = SigmaxTypes.neighbours graph selectedNodes
where
selectedNodes = SigmaxTypes.nodesById graph selectedNodeIds
onClickRemove session (selectedNodeIds /\ _) e = do
log2 "[onClickRemove] selectedNodeIds" selectedNodeIds
let nodeIds = mapMaybe fromString $ Set.toUnfoldable selectedNodeIds
deleteNodes session nodeIds
deleteNodes :: Session -> Array Int -> Effect Unit
deleteNodes session nodeIds = do
traverse_ (launchAff_ <<< deleteNode session) nodeIds
deleteNode :: Session -> Int -> Aff Int
deleteNode session nodeId = delete session $ NodeAPI Node (Just nodeId) ""
query _ _ _ _ (selectedNodeIds /\ _) | Set.isEmpty selectedNodeIds = RH.div {} [] query _ _ _ _ (selectedNodeIds /\ _) | Set.isEmpty selectedNodeIds = RH.div {} []
query frontends (GET.MetaData metaData) session nodesMap (selectedNodeIds /\ _) = query frontends (GET.MetaData metaData) session nodesMap (selectedNodeIds /\ _) =
......
module Gargantext.Components.GraphExplorer.SlideButton module Gargantext.Components.GraphExplorer.SlideButton
( Props ( Props
, sizeButton , sizeButton
, cursorSizeButton
, labelSizeButton , labelSizeButton
, mouseSelectorSizeButton
) where ) where
import Global (readFloat) import Global (readFloat)
import Prelude import Prelude
import Data.Tuple (snd)
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
import Effect (Effect) import Effect (Effect)
import Reactix as R import Reactix as R
...@@ -45,30 +44,38 @@ sizeButtonCpt = R.hooksComponent "SizeButton" cpt ...@@ -45,30 +44,38 @@ sizeButtonCpt = R.hooksComponent "SizeButton" cpt
} }
] ]
cursorSizeButton :: R.State Number -> R.Element
cursorSizeButton state =
sizeButton {
state: state
, caption: "Cursor Size"
, min: 1.0
, max: 4.0
, onChange: \e -> snd state $ const $ readFloat $ R2.unsafeEventValue e
}
labelSizeButton :: R.Ref Sigmax.Sigma -> R.State Number -> R.Element labelSizeButton :: R.Ref Sigmax.Sigma -> R.State Number -> R.Element
labelSizeButton sigmaRef state = labelSizeButton sigmaRef state =
sizeButton { sizeButton {
state: state state
, caption: "Label Size" , caption: "Label Size"
, min: 5.0 , min: 5.0
, max: 30.0 , max: 30.0
, onChange: \e -> do , onChange: \e -> do
let sigma = R.readRef sigmaRef let sigma = R.readRef sigmaRef
let newValue = readFloat $ R2.unsafeEventValue e let newValue = readFloat $ R2.unsafeEventValue e
let (value /\ setValue) = state let (_ /\ setValue) = state
Sigmax.dependOnSigma sigma "[labelSizeButton] sigma: Nothing" $ \s -> do Sigmax.dependOnSigma sigma "[labelSizeButton] sigma: Nothing" $ \s -> do
Sigma.setSettings s { Sigma.setSettings s {
defaultLabelSize: newValue defaultLabelSize: newValue
} }
setValue $ const newValue setValue $ const newValue
} }
mouseSelectorSizeButton :: R.Ref Sigmax.Sigma -> R.State Number -> R.Element
mouseSelectorSizeButton sigmaRef state =
sizeButton {
state
, caption: "Selector Size"
, min: 1.0
, max: 50.0
, onChange: \e -> do
let sigma = R.readRef sigmaRef
let (_ /\ setValue) = state
let newValue = readFloat $ R2.unsafeEventValue e
Sigmax.dependOnSigma sigma "[mouseSelectorSizeButton] sigma: Nothing" $ \s -> do
Sigma.setSettings s {
mouseSelectorSize: newValue
}
setValue $ const newValue
}
...@@ -19,7 +19,6 @@ import Reactix as R ...@@ -19,7 +19,6 @@ import Reactix as R
import Reactix.DOM.HTML as H import Reactix.DOM.HTML as H
import Gargantext.Components.GraphExplorer.Types as GET import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Hooks.Sigmax as Sigmax
import Gargantext.Hooks.Sigmax.Types as SigmaxTypes import Gargantext.Hooks.Sigmax.Types as SigmaxTypes
type Props = ( type Props = (
......
...@@ -79,7 +79,6 @@ instance showSelectedNode :: Show SelectedNode where ...@@ -79,7 +79,6 @@ instance showSelectedNode :: Show SelectedNode where
type State = ( type State = (
-- corpusId :: R.State Int -- corpusId :: R.State Int
--, cursorSize :: R.State Number
--, filePath :: R.State String --, filePath :: R.State String
--, graphData :: R.State GraphData --, graphData :: R.State GraphData
--, legendData :: R.State (Array Legend) --, legendData :: R.State (Array Legend)
......
...@@ -157,7 +157,7 @@ formCpt = R.hooksComponent "G.C.Login.form" cpt where ...@@ -157,7 +157,7 @@ formCpt = R.hooksComponent "G.C.Login.form" cpt where
error <- R.useState' "" error <- R.useState' ""
username <- R.useState' "" username <- R.useState' ""
password <- R.useState' "" password <- R.useState' ""
pure $ H.div {className: "row"} pure $ R2.row
[ cardGroup [ cardGroup
[ card [ card
[ cardBlock [ cardBlock
......
...@@ -149,14 +149,14 @@ tableContainer { path: {searchQuery, termListFilter, termSizeFilter} /\ setPath ...@@ -149,14 +149,14 @@ tableContainer { path: {searchQuery, termListFilter, termSizeFilter} /\ setPath
} props = } props =
H.div {className: "container-fluid"} H.div {className: "container-fluid"}
[ H.div {className: "jumbotron1"} [ H.div {className: "jumbotron1"}
[ H.div {className: "row"} [ R2.row
[ H.div {className: "panel panel-default"} [ H.div {className: "panel panel-default"}
[ H.div {className: "panel-heading"} [ H.div {className: "panel-heading"}
[ H.h2 {className: "panel-title", style: {textAlign : "center"}} [ H.h2 {className: "panel-title", style: {textAlign : "center"}}
[ H.span {className: "glyphicon glyphicon-hand-down"} [] [ H.span {className: "glyphicon glyphicon-hand-down"} []
, H.text "Extracted Terms" , H.text "Extracted Terms"
] ]
, H.div {className: "row"} , R2.row
[ H.div {className: "col-md-3", style: {marginTop: "6px"}} [ H.div {className: "col-md-3", style: {marginTop: "6px"}}
[ H.input { className: "form-control" [ H.input { className: "form-control"
, name: "search" , name: "search"
......
...@@ -90,12 +90,12 @@ tableHeaderLayoutCpt = R.hooksComponent "G.C.Table.tableHeaderLayout" cpt ...@@ -90,12 +90,12 @@ tableHeaderLayoutCpt = R.hooksComponent "G.C.Table.tableHeaderLayout" cpt
where where
cpt {title, desc, query, date, user} _ = cpt {title, desc, query, date, user} _ =
pure $ R.fragment pure $ R.fragment
[ H.div {className: "row"} [ R2.row
[ H.div {className: "col-md-3"} [ H.h3 {} [H.text title] ] [ H.div {className: "col-md-3"} [ H.h3 {} [H.text title] ]
, H.div {className: "col-md-9"} , H.div {className: "col-md-9"}
[ H.hr {style: {height: "2px", backgroundColor: "black"}} ] [ H.hr {style: {height: "2px", backgroundColor: "black"}} ]
] ]
, H.div {className: "row"} , R2.row
[ H.div {className: "jumbotron1", style: {padding: "12px 0px 20px 12px"}} [ H.div {className: "jumbotron1", style: {padding: "12px 0px 20px 12px"}}
[ H.div {className: "col-md-8 content"} [ H.div {className: "col-md-8 content"}
[ H.p {} [ H.p {}
...@@ -158,7 +158,7 @@ tableCpt = R.hooksComponent "G.C.Table.table" cpt ...@@ -158,7 +158,7 @@ tableCpt = R.hooksComponent "G.C.Table.table" cpt
defaultContainer :: {title :: String} -> Record TableContainerProps -> R.Element defaultContainer :: {title :: String} -> Record TableContainerProps -> R.Element
defaultContainer {title} props = R.fragment defaultContainer {title} props = R.fragment
[ H.div {className: "row"} [ R2.row
[ H.div {className: "col-md-4"} [ props.pageSizeDescription ] [ H.div {className: "col-md-4"} [ props.pageSizeDescription ]
, H.div {className: "col-md-4"} [ props.paginationLinks ] , H.div {className: "col-md-4"} [ props.paginationLinks ]
, H.div {className: "col-md-4"} [ props.pageSizeControl ] , H.div {className: "col-md-4"} [ props.pageSizeControl ]
......
...@@ -3,7 +3,7 @@ module Gargantext.Data.Array ...@@ -3,7 +3,7 @@ module Gargantext.Data.Array
import Data.Array as DA import Data.Array as DA
import Data.Maybe import Data.Maybe
import Data.Sequence as DS import Data.Sequence as Seq
import Data.Tuple (Tuple(..)) import Data.Tuple (Tuple(..))
import Prelude (bind, flip, identity, (<<<)) import Prelude (bind, flip, identity, (<<<))
...@@ -16,9 +16,9 @@ splitEvery n xs = ...@@ -16,9 +16,9 @@ splitEvery n xs =
in DA.cons h (splitEvery n t) in DA.cons h (splitEvery n t)
splitAt :: forall a. Int -> Array a -> Tuple (Array a) (Array a) splitAt :: forall a. Int -> Array a -> Tuple (Array a) (Array a)
splitAt n ls = Tuple (DS.toUnfoldable x) (DS.toUnfoldable xs) splitAt n ls = Tuple (Seq.toUnfoldable x) (Seq.toUnfoldable xs)
where where
Tuple x xs = DS.splitAt n (DS.fromFoldable ls) Tuple x xs = Seq.splitAt n (Seq.fromFoldable ls)
---------------------------------------------------------------------- ----------------------------------------------------------------------
-- | Array with Maybe tools -- | Array with Maybe tools
...@@ -36,4 +36,15 @@ concatMap = flip bind ...@@ -36,4 +36,15 @@ concatMap = flip bind
singleton :: forall a. a -> Array a singleton :: forall a. a -> Array a
singleton a = [a] singleton a = [a]
----------------------------------------------------------------------
-- | Seq with Maybe tools
seqMapMaybe :: forall a b. (a -> Maybe b) -> Seq.Seq a -> Seq.Seq b
seqMapMaybe f = seqConcatMap (maybe Seq.empty Seq.singleton <<< f)
seqCatMaybes :: forall a. Seq.Seq (Maybe a) -> Seq.Seq a
seqCatMaybes = seqMapMaybe identity
----------------------------------------------------------------------
-- | Seq misc tools
seqConcatMap :: forall a b. (a -> Seq.Seq b) -> Seq.Seq a -> Seq.Seq b
seqConcatMap = flip bind
module Gargantext.Hooks.Sigmax module Gargantext.Hooks.Sigmax
where where
import Prelude (Unit, bind, discard, flip, pure, unit, ($), (*>), (<<<), (<>), (>>=), (||), not, const, map) 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)
......
...@@ -9,7 +9,7 @@ if (typeof window !== 'undefined') { ...@@ -9,7 +9,7 @@ if (typeof window !== 'undefined') {
const CustomShapes = require('sigma/plugins/garg.js').init(sigma, window).customShapes; const CustomShapes = require('sigma/plugins/garg.js').init(sigma, window).customShapes;
require('sigma/src/utils/sigma.utils.js').init(sigma); require('sigma/src/utils/sigma.utils.js').init(sigma);
sigma.canvas.nodes.hovered = (node, context, settings) => { sigma.canvas.nodes.selected = (node, context, settings) => {
// hack // hack
// We need to temporarily set node.type to 'def'. This is for 2 reasons // We need to temporarily set node.type to 'def'. This is for 2 reasons
// 1. Make it render as a normal node // 1. Make it render as a normal node
...@@ -17,11 +17,129 @@ sigma.canvas.nodes.hovered = (node, context, settings) => { ...@@ -17,11 +17,129 @@ sigma.canvas.nodes.hovered = (node, context, settings) => {
// again with node.type = 'hovered') // again with node.type = 'hovered')
node.type = 'def'; node.type = 'def';
sigma.canvas.hovers.def(node, context, settings); sigma.canvas.hovers.def(node, context, settings);
node.type = 'hovered'; node.type = 'selected';
}; };
CustomShapes.init(); CustomShapes.init();
let sigmaMouseSelector = (sigma, options) => {
sigma.plugins = sigma.plugins || {};
sigma.plugins.mouseSelector = (s, renderer) => {
var _self = this;
var _offset = null;
const _s = s;
const _renderer = renderer;
const _container = _renderer.container;
//renderer.initDOM('canvas', 'mouseSelector');
// A hack to force resize to be called (there is a width/height equality
// check which can't be escaped in any other way).
//renderer.resize(renderer.width - 1, renderer.height - 1);
//renderer.resize(renderer.width + 1, renderer.height + 1);
const _context = _renderer.contexts.mouseSelector;
// These are used to prevent using the 'click' event when in fact this was a drag
let _clickPositionX = null;
let _clickPositionY = null;
let _isValidClick = false;
_container.onmousemove = function(e) { return mouseMove(e); };
_context.canvas.onclick = function(e) { return onClick(e); };
_container.onmousedown = function(e) { return onMouseDown(e); }
_container.onmouseup = function(e) { return onMouseUp(e); }
s.bind('click', function(e) { return onClick(e); })
// The mouseSelector canvas will pass its events down to the "mouse" canvas.
_context.canvas.style.pointerEvents = 'none';
s.bind('kill', () => _self.unbindAll());
this.unbindAll = () => {
console.log('[sigmaMouseSelector] unbinding');
_container.onclick = null;
_context.canvas.onmousemove = null;
_container.onmousedown = null;
_container.onmouseup = null;
}
const onMouseDown = (e) => {
_clickPositionX = e.clientX;
_clickPositionY = e.clientY;
}
const onMouseUp = (e) => {
// Prevent triggering click when in fact this was a drag
if ((_clickPositionX != e.clientX) || (_clickPositionY != e.clientY)) {
_clickPositionX = null;
_clickPositionY = null;
_isValidClick = false;
} else {
_isValidClick = true;
}
}
const mouseMove = (e) => {
const size = _s.settings('mouseSelectorSize') || 3;
const x = e.clientX - _offset.left - size/2;
const y = e.clientY - _offset.top - size/2;
_context.clearRect(0, 0, _context.canvas.width, _context.canvas.height);
_context.fillStyle = 'rgba(91, 192, 222, 0.7)';
_context.beginPath();
_context.arc(
x,
y,
size,
0,
Math.PI * 2,
true
);
_context.closePath();
_context.fill();
}
const onClick = (e) => {
if(!_isValidClick) {
return;
}
const size = _s.settings('mouseSelectorSize') || 3;
const x = e.data.clientX - _offset.left - size/2;
const y = e.data.clientY - _offset.top - size/2;
const prefix = _renderer.options.prefix;
//console.log('[sigmaMouseSelector] clicked', e, x, y, size);
let nodes = [];
_s.graph.nodes().forEach((node) => {
const nodeX = node[prefix + 'x'];
const nodeY = node[prefix + 'y'];
if(sigma.utils.getDistance(x, y, nodeX, nodeY) <= size) {
nodes.push(node);
}
});
//console.log('[sigmaMouseSelector] nodes', nodes);
_renderer.dispatchEvent('clickNodes', {
node: nodes,
captor: e.data
})
_clickPositionX = null;
_clickPositionY = null;
}
const calculateOffset = (element) => {
var style = window.getComputedStyle(element);
var getCssProperty = function(prop) {
return parseInt(style.getPropertyValue(prop).replace('px', '')) || 0;
};
return {
left: element.getBoundingClientRect().left + getCssProperty('padding-left'),
top: element.getBoundingClientRect().top + getCssProperty('padding-top')
};
};
_offset = calculateOffset(renderer.container);
}
}
sigmaMouseSelector(sigma);
function _sigma(left, right, opts) { function _sigma(left, right, opts) {
try { try {
return right(new sigma(opts)); return right(new sigma(opts));
...@@ -45,6 +163,14 @@ function addRenderer(left, right, sigma, renderer) { ...@@ -45,6 +163,14 @@ function addRenderer(left, right, sigma, renderer) {
return left(e); return left(e);
} }
} }
function bindMouseSelectorPlugin(left, right, sig) {
try {
return right(sigma.plugins.mouseSelector(sig, sig.renderers[0]));
} catch(e) {
console.log('[bindMouseSelectorPlugin] error', e);
return left(e);
}
}
function killRenderer(left, right, sigma, renderer) { function killRenderer(left, right, sigma, renderer) {
try { try {
sigma.killRenderer(renderer); sigma.killRenderer(renderer);
...@@ -91,6 +217,7 @@ exports._sigma = _sigma; ...@@ -91,6 +217,7 @@ exports._sigma = _sigma;
exports._graphRead = graphRead; exports._graphRead = graphRead;
exports._refresh = refresh; exports._refresh = refresh;
exports._addRenderer = addRenderer; exports._addRenderer = addRenderer;
exports._bindMouseSelectorPlugin = bindMouseSelectorPlugin;
exports._killRenderer = killRenderer; exports._killRenderer = killRenderer;
exports._getRendererContainer = getRendererContainer; exports._getRendererContainer = getRendererContainer;
exports._setRendererContainer = setRendererContainer; exports._setRendererContainer = setRendererContainer;
......
...@@ -70,6 +70,16 @@ foreign import _addRenderer ...@@ -70,6 +70,16 @@ foreign import _addRenderer
r r
(Either err Unit) (Either err Unit)
bindMouseSelectorPlugin :: forall err. Sigma -> Effect (Either err Unit)
bindMouseSelectorPlugin = runEffectFn3 _bindMouseSelectorPlugin Left Right
foreign import _bindMouseSelectorPlugin
:: forall a b err.
EffectFn3 (a -> Either a b)
(b -> Either a b)
Sigma
(Either err Unit)
killRenderer :: forall r err. Sigma -> r -> Effect (Either err Unit) killRenderer :: forall r err. Sigma -> r -> Effect (Either err Unit)
killRenderer = runEffectFn4 _killRenderer Left Right killRenderer = runEffectFn4 _killRenderer Left Right
......
...@@ -15,69 +15,3 @@ exports.pauseForceAtlas2 = function() { ...@@ -15,69 +15,3 @@ exports.pauseForceAtlas2 = function() {
} }
} }
}; };
var trackMouse = function(cursorSize, e) {
if(!e.shiftKey) {
var partialGraph = window.sigmaGargInstance;
// new sigma.js 2D mouse context
var ctx = partialGraph.renderers[0].contexts.mouse;
ctx.globalCompositeOperation = "source-over";
// clear zone each time to prevent repeated frame artifacts
ctx.clearRect(50, 50,
partialGraph.renderers[0].container.offsetWidth,
partialGraph.renderers[0].container.offsetHeight);
// classic mousemove event or other similar non-sigma events
var coord = window.sigma.utils.mouseCoords(e)
var x = (coord.x + coord.clientX) / 2 // ; // sigma.utils.getX(e);
var y = (coord.y + coord.clientY) /2 // ; // sigma.utils.getY(e);
console.log('trackMouse', coord);
// optional: make more labels appear on circle hover (/!\ costly /!\ esp. on large graphs)
// if (partialGraph.conf.moreLabelsUnderArea) {
// // convert screen => mouse => cam
// var mouseCoords = (50,50); // sigma.utils.mouseCoords(e)
// var camCoords = partialGraph.cam.cameraPosition(mouseCoords.x, mouseCoords.y)
//
// var exactNodeset = circleGetAreaNodes(camCoords.x,camCoords.y)
// // console.log("nodes under circle:", exactNodeset)
//
// // we'll use labelThreshold / 3 as the "boosted" cam:size threshold
// var pfx = partialGraph.cam.readPrefix
// var toRedraw = []
// for (var k in exactNodeset) {
// var n = partialGraph.graph.nodes(exactNodeset[k])
// if(!n.hidden && n[pfx+'size'] > (partialGraph.customSettings.labelThreshold / 3)) {
// toRedraw.push(n)
// }
// }
// redrawNodesInHoverLayer(toRedraw, "hovers")
// }
// draw the circle itself
ctx.strokeStyle = '#000';
ctx.lineWidth = 1;
ctx.fillStyle = "#71C3FF";
ctx.globalAlpha = 0.5;
ctx.beginPath();
ctx.arc(x, y, cursorSize, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.globalAlpha = 1
}
};
exports.sigmaOnMouseMove = function(props) {
return function(e) {
return function() {
if(typeof(window.sigmaGargInstance) !== "undefined") {
if(props.cursorSize > 0) trackMouse(props.cursorSize, e);
}
};
};
};
...@@ -6,7 +6,6 @@ import Data.Nullable (Nullable) ...@@ -6,7 +6,6 @@ import Data.Nullable (Nullable)
import Effect (Effect) import Effect (Effect)
import Effect.Uncurried (EffectFn1, runEffectFn1) import Effect.Uncurried (EffectFn1, runEffectFn1)
import React (ReactRef, SyntheticEventHandler) import React (ReactRef, SyntheticEventHandler)
import React.SyntheticEvent (SyntheticMouseEvent)
import Record.Unsafe (unsafeGet) import Record.Unsafe (unsafeGet)
import Unsafe.Coerce (unsafeCoerce) import Unsafe.Coerce (unsafeCoerce)
import Gargantext.Types (class Optional) import Gargantext.Types (class Optional)
...@@ -92,7 +91,6 @@ foreign import data CameraInstance' :: # Type ...@@ -92,7 +91,6 @@ foreign import data CameraInstance' :: # Type
type SigmaInstance = { | SigmaInstance' } type SigmaInstance = { | SigmaInstance' }
type CameraInstance = { | CameraInstance' } type CameraInstance = { | CameraInstance' }
foreign import sigmaOnMouseMove :: {cursorSize :: Number} -> SyntheticMouseEvent -> Effect Unit
cameras :: SigmaInstance -> Array CameraInstance cameras :: SigmaInstance -> Array CameraInstance
cameras = unsafeGet "cameras" cameras = unsafeGet "cameras"
......
module Gargantext.Hooks.Sigmax.Types where module Gargantext.Hooks.Sigmax.Types where
import Prelude (map, ($), (&&), (==), class Eq, class Ord, class Show, Ordering, compare) import DOM.Simple.Types (Element)
import Data.Generic.Rep (class Generic) import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Eq (genericEq) import Data.Generic.Rep.Eq (genericEq)
import Data.Generic.Rep.Show (genericShow) import Data.Generic.Rep.Show (genericShow)
import Data.Map as Map import Data.Map as Map
import Data.Sequence (Seq) import Data.Sequence as Seq
import Data.Set as Set import Data.Set as Set
import Data.Tuple (Tuple(..)) import Data.Tuple (Tuple(..))
import DOM.Simple.Types (Element) import Prelude (map, ($), (&&), (||), (==), class Eq, class Ord, class Show, Ordering, compare)
newtype Graph n e = Graph { nodes :: Seq {|n}, edges :: Seq {|e} } newtype Graph n e = Graph { nodes :: Seq.Seq {|n}, edges :: Seq.Seq {|e} }
--derive instance eqGraph :: Eq Graph --derive instance eqGraph :: Eq Graph
...@@ -40,7 +40,9 @@ type Edge = ...@@ -40,7 +40,9 @@ type Edge =
, hidden :: Boolean , hidden :: Boolean
, size :: Number , size :: Number
, source :: String , source :: String
, sourceNode :: Record Node
, target :: String , target :: String
, targetNode :: Record Node
, weight :: Number ) , weight :: Number )
type SelectedNodeIds = Set.Set String type SelectedNodeIds = Set.Set String
...@@ -50,24 +52,43 @@ type NodesMap = Map.Map String (Record Node) ...@@ -50,24 +52,43 @@ type NodesMap = Map.Map String (Record Node)
type SGraph = Graph Node Edge type SGraph = Graph Node Edge
graphEdges :: SGraph -> Seq (Record Edge) graphEdges :: SGraph -> Seq.Seq (Record Edge)
graphEdges (Graph {edges}) = edges graphEdges (Graph {edges}) = edges
graphNodes :: SGraph -> Seq (Record Node) graphNodes :: SGraph -> Seq.Seq (Record Node)
graphNodes (Graph {nodes}) = nodes graphNodes (Graph {nodes}) = nodes
edgesGraphMap :: Graph Node Edge -> EdgesMap edgesGraphMap :: SGraph -> EdgesMap
edgesGraphMap graph = edgesGraphMap graph =
Map.fromFoldable $ map (\e -> Tuple e.id e) $ graphEdges graph Map.fromFoldable $ map (\e -> Tuple e.id e) $ graphEdges graph
nodesMap :: Seq (Record Node) -> NodesMap edgesById :: SGraph -> SelectedEdgeIds -> Seq.Seq (Record Edge)
edgesById g edgeIds = Seq.filter (\e -> Set.member e.id edgeIds) $ graphEdges g
nodesMap :: Seq.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 :: SGraph -> NodesMap
nodesGraphMap graph = nodesGraphMap graph =
nodesMap $ graphNodes graph nodesMap $ graphNodes graph
eqGraph :: (Graph Node Edge) -> (Graph Node Edge) -> Boolean nodesById :: SGraph -> SelectedNodeIds -> Seq.Seq (Record Node)
nodesById g nodeIds = Seq.filter (\n -> Set.member n.id nodeIds) $ graphNodes g
neighbours :: SGraph -> Seq.Seq (Record Node) -> Seq.Seq (Record Node)
neighbours g nodes = Seq.fromFoldable $ Set.unions [Set.fromFoldable nodes, sources, targets]
where
nodeIds = Set.fromFoldable $ Seq.map _.id nodes
selectedEdges = neighbouringEdges g nodeIds
sources = Set.fromFoldable $ nodesById g $ Set.fromFoldable $ Seq.map _.source selectedEdges
targets = Set.fromFoldable $ nodesById g $ Set.fromFoldable $ Seq.map _.target selectedEdges
neighbouringEdges :: SGraph -> SelectedNodeIds -> Seq.Seq (Record Edge)
neighbouringEdges g nodeIds = Seq.filter condition $ graphEdges g
where
condition {source, target} = (Set.member source nodeIds) || (Set.member target nodeIds)
eqGraph :: SGraph -> SGraph -> 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)
......
...@@ -226,3 +226,9 @@ dataTransferFileBlob e = unsafePartial $ do ...@@ -226,3 +226,9 @@ dataTransferFileBlob e = unsafePartial $ do
blur :: DOM.Element -> Effect Unit blur :: DOM.Element -> Effect Unit
blur el = el ... "blur" $ [] blur el = el ... "blur" $ []
row :: Array R.Element -> R.Element
row children = H.div { className: "row" } children
col12 :: Array R.Element -> R.Element
col12 children = H.div { className: "col-md-12" } children
...@@ -5798,9 +5798,9 @@ shelljs@^0.8.2: ...@@ -5798,9 +5798,9 @@ shelljs@^0.8.2:
interpret "^1.0.0" interpret "^1.0.0"
rechoir "^0.6.2" rechoir "^0.6.2"
"sigma@git://github.com/jjl/sigma.js#garg": "sigma@git://github.com/poorscript/sigma.js#garg":
version "1.2.1" version "1.2.1"
resolved "git://github.com/jjl/sigma.js#64a0e1ccd48550387ad4a56292dcbaef3258c929" resolved "git://github.com/poorscript/sigma.js#2ad537301ac0b12cae9a687fc1cb444dbe971c7c"
signal-exit@^3.0.0, signal-exit@^3.0.2: signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.2" version "3.0.2"
......
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