Commit 2fa0f2d8 authored by Przemyslaw Kaminski's avatar Przemyslaw Kaminski

[sigma] mouse clicking works now

Hover still doesn't though.
parent faf6c03f
...@@ -227,7 +227,7 @@ loadPage { session, nodeId, listId, query, params: {limit, offset, orderBy } } = ...@@ -227,7 +227,7 @@ loadPage { session, nodeId, listId, query, params: {limit, offset, orderBy } } =
case eSearchResult of case eSearchResult of
Left err -> pure $ Left err Left err -> pure $ Left err
Right (SearchResult {result}) -> do Right (SearchResult {result}) -> do
liftEffect $ here.log2 "[loadPage] result" result --liftEffect $ here.log2 "[loadPage] result" result
-- $ SearchQuery {query: concat query, expected: SearchDoc} -- $ SearchQuery {query: concat query, expected: SearchDoc}
pure $ Right $ case result of pure $ Right $ case result of
SearchResultDoc {docs} -> Docs {docs: doc2view <$> Seq.fromFoldable docs} SearchResultDoc {docs} -> Docs {docs: doc2view <$> Seq.fromFoldable docs}
......
...@@ -292,6 +292,7 @@ convert (GET.GraphData r) = Tuple r.metaData $ SigmaxT.Graph {nodes, edges} ...@@ -292,6 +292,7 @@ convert (GET.GraphData r) = Tuple r.metaData $ SigmaxT.Graph {nodes, edges}
, equilateral: { numPoints: 3 } , equilateral: { numPoints: 3 }
, gargType , gargType
, hidden : false , hidden : false
, highlighted: false
, id : n.id_ , id : n.id_
, label : n.label , label : n.label
, size : DN.log (toNumber n.size + 1.0) , size : DN.log (toNumber n.size + 1.0)
...@@ -406,9 +407,9 @@ transformGraph graph { edgeConfluence' ...@@ -406,9 +407,9 @@ transformGraph graph { edgeConfluence'
nodeMarked :: Record SigmaxT.Node -> Record SigmaxT.Node nodeMarked :: Record SigmaxT.Node -> Record SigmaxT.Node
nodeMarked node@{ id } = nodeMarked node@{ id } =
if Set.member id selectedNodeIds' then if Set.member id selectedNodeIds' then
node { borderColor = "#000", type = "selected" } node { borderColor = "#000", highlighted = true, type = "selected" }
else else
node node { highlighted = false }
nodeHideSize :: Record SigmaxT.Node -> Record SigmaxT.Node nodeHideSize :: Record SigmaxT.Node -> Record SigmaxT.Node
nodeHideSize node@{ size } = nodeHideSize node@{ size } =
......
...@@ -59,12 +59,13 @@ drawGraphCpt = R.memo' $ here.component "graph" cpt where ...@@ -59,12 +59,13 @@ drawGraphCpt = R.memo' $ here.component "graph" cpt where
boxes <- AppStore.use boxes <- AppStore.use
{ showEdges { showEdges
, graphStage
, graph , graph
, startForceAtlas , graphStage
, selectedNodeIds
, multiSelectEnabled
, hyperdataGraph , hyperdataGraph
, mouseSelectorSize
, multiSelectEnabled
, selectedNodeIds
, startForceAtlas
} <- GraphStore.use } <- GraphStore.use
showEdges' <- R2.useLive' showEdges showEdges' <- R2.useLive' showEdges
...@@ -125,6 +126,7 @@ drawGraphCpt = R.memo' $ here.component "graph" cpt where ...@@ -125,6 +126,7 @@ drawGraphCpt = R.memo' $ here.component "graph" cpt where
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 multiSelectEnabled Sigmax.bindSelectedNodesClick sigma selectedNodeIds multiSelectEnabled
Sigmax.bindShiftWheel sigma mouseSelectorSize
_ <- Sigma.bindMouseSelectorPlugin sigma _ <- Sigma.bindMouseSelectorPlugin sigma
pure unit pure unit
......
...@@ -80,8 +80,8 @@ docListWrapperCpt = here.component "wrapper" cpt where ...@@ -80,8 +80,8 @@ docListWrapperCpt = here.component "wrapper" cpt where
-- | Hooks -- | Hooks
-- | -- |
R.useEffect1' selectedNodeIds' $ R.useEffect1' selectedNodeIds' $ do
T.write_ (selectedNodeIds' # toSearchQuery >>> Just) query T.write_ (Just $ toSearchQuery selectedNodeIds') query
-- | Render -- | Render
-- | -- |
......
...@@ -85,7 +85,7 @@ mouseSelectorSizeButton :: R.Ref Sigmax.Sigma -> T.Box Number -> R.Element ...@@ -85,7 +85,7 @@ mouseSelectorSizeButton :: R.Ref Sigmax.Sigma -> T.Box Number -> R.Element
mouseSelectorSizeButton sigmaRef state = mouseSelectorSizeButton sigmaRef state =
sizeButton { sizeButton {
state state
, caption: "Selector size" , caption: "Selector size (Shift + wheel)"
, min: 1.0 , min: 1.0
, max: 50.0 , max: 50.0
, onChange: \e -> do , onChange: \e -> do
...@@ -98,7 +98,5 @@ mouseSelectorSizeButton sigmaRef state = ...@@ -98,7 +98,5 @@ mouseSelectorSizeButton sigmaRef state =
Sigma.setSettings s { Sigma.setSettings s {
mouseSelectorSize: newValue mouseSelectorSize: newValue
} }
here.log "[mouseSelectorSizeButton] write start"
T.write_ newValue state T.write_ newValue state
here.log "[mouseSelectorSizeButton] write stop"
} }
...@@ -24,7 +24,8 @@ import Gargantext.Hooks.Sigmax.Sigma as Sigma ...@@ -24,7 +24,8 @@ import Gargantext.Hooks.Sigmax.Sigma as Sigma
import Gargantext.Hooks.Sigmax.Types as ST import Gargantext.Hooks.Sigmax.Types as ST
import Gargantext.Utils.Console as C import Gargantext.Utils.Console as C
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
import Prelude (Unit, bind, discard, flip, map, not, pure, unit, ($), (&&), (*>), (<<<), (<>), (>>=)) import Gargantext.Utils.Set as GSet
import Prelude (Unit, bind, discard, flip, map, not, pure, unit, ($), (&&), (*>), (<<<), (<>), (>>=), (+), (>), negate)
import Reactix as R import Reactix as R
import Toestand as T import Toestand as T
...@@ -184,20 +185,15 @@ updateNodes sigma nodesMap = do ...@@ -184,20 +185,15 @@ updateNodes sigma nodesMap = do
-- | Toggles item visibility in the selected set -- | Toggles item visibility in the selected set
-- Basically: add items that are NOT in `selected` and remove items
-- that are in `selected`.
multiSelectUpdate :: ST.NodeIds -> ST.NodeIds -> ST.NodeIds multiSelectUpdate :: ST.NodeIds -> ST.NodeIds -> ST.NodeIds
multiSelectUpdate new selected = foldl fld selected new multiSelectUpdate new selected = foldl GSet.toggle selected new
where
fld selectedAcc item =
if Set.member item selectedAcc then
Set.delete item selectedAcc
else
Set.insert item selectedAcc
bindSelectedNodesClick :: Sigma.Sigma -> T.Box ST.NodeIds -> T.Box Boolean -> Effect Unit bindSelectedNodesClick :: Sigma.Sigma -> T.Box ST.NodeIds -> T.Box Boolean -> Effect Unit
bindSelectedNodesClick sigma selectedNodeIds multiSelectEnabled = bindSelectedNodesClick sigma selectedNodeIds multiSelectEnabled =
Sigma.bindClickNodes sigma $ \nodeIds' -> do Sigma.bindClickNodes sigma $ \nodeIds' -> do
console.log2 "[bindSelectedNodesClick] nodeIds'" nodeIds'
let nodeIds = Set.fromFoldable nodeIds' let nodeIds = Set.fromFoldable nodeIds'
multiSelectEnabled' <- T.read multiSelectEnabled multiSelectEnabled' <- T.read multiSelectEnabled
if multiSelectEnabled' then if multiSelectEnabled' then
...@@ -205,15 +201,16 @@ bindSelectedNodesClick sigma selectedNodeIds multiSelectEnabled = ...@@ -205,15 +201,16 @@ bindSelectedNodesClick sigma selectedNodeIds multiSelectEnabled =
else else
T.write_ nodeIds selectedNodeIds T.write_ nodeIds selectedNodeIds
bindSelectedEdgesClick :: R.Ref Sigma -> R.State ST.EdgeIds -> Effect Unit bindShiftWheel :: Sigma.Sigma -> T.Box Number -> Effect Unit
bindSelectedEdgesClick sigmaRef (_ /\ setEdgeIds) = bindShiftWheel sigma mouseSelectorSize =
dependOnSigma (R.readRef sigmaRef) "[graphCpt] no sigma" $ \sigma -> do Sigma.bindShiftWheel sigma $ \delta -> do
Sigma.bindClickEdge sigma $ \edge -> do let step = if delta > 0.0 then 5.0 else -5.0
setEdgeIds \eids -> val <- T.read mouseSelectorSize
if Set.member edge.id eids then let newVal = val + step
Set.delete edge.id eids Sigma.setSettings sigma {
else mouseSelectorSize: newVal
Set.insert edge.id eids }
T.write_ newVal mouseSelectorSize
selectorWithSize :: Sigma.Sigma -> Int -> Effect Unit selectorWithSize :: Sigma.Sigma -> Int -> Effect Unit
selectorWithSize _ _ = do selectorWithSize _ _ = do
...@@ -224,10 +221,10 @@ performDiff sigma g = do ...@@ -224,10 +221,10 @@ performDiff sigma g = do
-- if (Seq.null addEdges) && (Seq.null addNodes) && (Set.isEmpty removeEdges) && (Set.isEmpty removeNodes) then -- if (Seq.null addEdges) && (Seq.null addNodes) && (Set.isEmpty removeEdges) && (Set.isEmpty removeNodes) then
-- pure unit -- pure unit
-- else do -- else do
console.log2 "[performDiff] addNodes" addNodes -- console.log2 "[performDiff] addNodes" addNodes
console.log2 "[performDiff] addEdges" $ A.fromFoldable addEdges -- console.log2 "[performDiff] addEdges" $ A.fromFoldable addEdges
console.log2 "[performDiff] removeNodes" removeNodes -- console.log2 "[performDiff] removeNodes" removeNodes
console.log2 "[performDiff] removeEdges" removeEdges -- console.log2 "[performDiff] removeEdges" removeEdges
traverse_ (Graphology.addNode sigmaGraph) addNodes traverse_ (Graphology.addNode sigmaGraph) addNodes
traverse_ (Graphology.addEdge sigmaGraph) addEdges traverse_ (Graphology.addEdge sigmaGraph) addEdges
traverse_ (Graphology.removeEdge sigmaGraph) removeEdges traverse_ (Graphology.removeEdge sigmaGraph) removeEdges
......
...@@ -63,73 +63,55 @@ let sigmaMouseSelector = function(sigma, options) { ...@@ -63,73 +63,55 @@ let sigmaMouseSelector = function(sigma, options) {
const distance = (x1, y1, x2, y2) => Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); const distance = (x1, y1, x2, y2) => Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
let mouseSelector = () => { let mouseSelector = () => {
let _self = this; const _self = this;
let _offset = null;
const _s = sigma; const _s = sigma;
//const _renderer = renderer;
const captor = sigma.mouseCaptor; const captor = sigma.mouseCaptor;
const _container = captor.container; const _container = captor.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;
const _context = _container.getContext('2d'); const _context = _container.getContext('2d');
// These are used to prevent using the 'click' event when in fact this was a drag
let _clickPositionX = null; const unbindAll = () => {
let _clickPositionY = null; // TODO Maybe not needed if sigma is killed and we did bind to
let _isValidClick = false; // mouse captor instead of the canvas?
_container.onmousemove = (e) => { return mouseMove(e); }; // _container.onclick = null;
_container.onclick = (e) => { return onClick(e); }; // _container.onmousemove = null;
//_context.canvas.onclick = function(e) { return onClick(e); }; // _container.onmousedown = null;
_container.onmousedown = (e) => { return onMouseDown(e); } // _container.onmouseup = null;
_container.onmouseup = (e) => { return onMouseUp(e); }
captor.on('click', (e) => { return onClick(e); });
// The mouseSelector canvas will pass its events down to the "mouse" canvas.
//_context.canvas.style.pointerEvents = 'none';
sigma.on('kill', () => _self.unbindAll());
this.unbindAll = () => {
// console.log('[sigmaMouseSelector] unbinding');
_container.onclick = null;
//_context.canvas.onmousemove = null;
_container.onmousemove = null;
_container.onmousedown = null;
_container.onmouseup = null;
} }
const onMouseDown = (e) => { const bindAll = () => {
_clickPositionX = e.clientX; captor.on('mousemove', mouseMove);
_clickPositionY = e.clientY; captor.on('click', onClick);
captor.on('wheel', onWheel);
sigma.on('kill', () => unbindAll());
} }
const onMouseUp = (e) => { const onWheel = (e) => {
// Prevent triggering click when in fact this was a drag const shiftPressed = e.original.shiftKey;
if ((_clickPositionX != e.clientX) || (_clickPositionY != e.clientY)) { // zoom in has e.delta > 0 (around 0.44)
_clickPositionX = null; // zoom out has e.delta < 0 (around -0.44)
_clickPositionY = null; if(shiftPressed) {
_isValidClick = false; // TODO Fix this so that the canvas is not zoomed.
} else { console.log('[onWheel] e', e);
_isValidClick = true; e.original.preventDefault();
e.original.stopPropagation();
sigma.emit('shiftWheel', {
delta: e.delta
});
} }
} }
// Responsible for rendering the selector properly
const mouseMove = (e) => { const mouseMove = (e) => {
const size = sigma.settings['mouseSelectorSize'] || 3; const size = sigma.settings['mouseSelectorSize'] || 3;
//const x = e.clientX + document.body.scrollLeft - _offset.left - size/2;
//const y = e.clientY + document.body.scrollTop - _offset.top - size/2;
const x = e.layerX;
const y = e.layerY;
_context.clearRect(0, 0, _context.canvas.width, _context.canvas.height); _context.clearRect(0, 0, _context.canvas.width, _context.canvas.height);
_context.fillStyle = 'rgba(91, 192, 222, 0.7)'; _context.fillStyle = 'rgba(91, 192, 222, 0.7)';
_context.beginPath(); _context.beginPath();
_context.arc( _context.arc(
x, e.x,
y, e.y,
size, size,
0, 0,
Math.PI * 2, Math.PI * 2,
...@@ -140,61 +122,33 @@ let sigmaMouseSelector = function(sigma, options) { ...@@ -140,61 +122,33 @@ let sigmaMouseSelector = function(sigma, options) {
} }
const onClick = (e) => { const onClick = (e) => {
// TODO For some reason this event is sent again, with
// _clickPositionX/Y empty
if(!_isValidClick || !_clickPositionX || !_clickPositionY) {
return;
}
const size = sigma.settings['mouseSelectorSize'] || 3; const size = sigma.settings['mouseSelectorSize'] || 3;
//const x = e.data.clientX + document.body.scrollLeft - _offset.left - size/2;
//const y = e.data.clientY + document.body.scrollTop - _offset.top - size/2;
//const prefix = _renderer.options.prefix;
//console.log('[sigmaMouseSelector] clicked', e, x, y, size);
let nodeIds = []; let nodeIds = [];
for(let nodeId in sigma.nodeDataCache) { for(let nodeId in sigma.nodeDataCache) {
let data = sigma.nodeDataCache[nodeId]; let data = sigma.nodeDataCache[nodeId];
let position = sigma.framedGraphToViewport(data); let position = sigma.framedGraphToViewport(data);
// TODO Either distance or node is clicked directly
if(distance(e.x, e.y, position.x, position.y) <= size) { if(distance(e.x, e.y, position.x, position.y) <= size) {
nodeIds.push(nodeId); nodeIds.push(nodeId);
} }
} }
/* // handle node click when our selector doesn't cover it's center
sigma.graph.forEachNode((node, attrs) => { // (e.g. large nodes)
if(distance(x, y, attrs.x, attrs.y) <= size) { const nodeAtPosition = sigma.getNodeAtPosition(e);
nodes.push(node); if((nodeAtPosition && (nodeIds.indexOf(nodeAtPosition) == -1))) {
nodeIds.push(nodeAtPosition);
} }
});
*/
//console.log('[sigmaMouseSelector] nodes', nodes);
// nodes.forEach((n) => {
// sigma.emit('clickNode', { node: n });
// })
sigma.emit('clickNodes', { sigma.emit('clickNodes', {
nodeIds: nodeIds nodeIds: nodeIds
//captor: e.data //captor: e.data
}) })
_clickPositionX = null; _clickPositionX = null;
_clickPositionY = null; _clickPositionY = null;
}
const calculateOffset = (element) => { return false;
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')
};
};
// Container resize event listener bindAll();
// @TODO: debounce?
const onContainerResize = (entries) => {
_offset = calculateOffset(_container);
};
const _resizeObserver = new ResizeObserver( onContainerResize );
_resizeObserver.observe(_container);
} }
mouseSelector(); mouseSelector();
...@@ -209,9 +163,8 @@ let sigmaMouseSelector = function(sigma, options) { ...@@ -209,9 +163,8 @@ let sigmaMouseSelector = function(sigma, options) {
function _sigma(left, right, el, opts) { function _sigma(left, right, el, opts) {
try { try {
let graph = new Graph(); let graph = new Graph();
console.log('initializing sigma with el', el);
console.log('initializing sigma with opts', opts);
let s = new sigma(graph, el, opts); let s = new sigma(graph, el, opts);
console.log('initializing sigma with el', el, 'opts', 'sigma', s);
sigmaMouseSelector(s); sigmaMouseSelector(s);
return right(s); return right(s);
} catch(e) { } catch(e) {
......
...@@ -137,6 +137,14 @@ bindClickNodes s f = on_ s "clickNodes" $ \e -> do ...@@ -137,6 +137,14 @@ bindClickNodes s f = on_ s "clickNodes" $ \e -> do
unbindClickNodes :: Sigma -> Effect Unit unbindClickNodes :: Sigma -> Effect Unit
unbindClickNodes s = unbind_ s "clickNodes" unbindClickNodes s = unbind_ s "clickNodes"
-- | Shift + mousewheel changes selector size
bindShiftWheel :: Sigma -> (Number -> Effect Unit) -> Effect Unit
bindShiftWheel s f = on_ s "shiftWheel" $ \e -> do
let delta = e .. "delta" :: Number
f delta
unbindShiftWheel :: Sigma -> Effect Unit
unbindShiftWheel s = unbind_ s "shiftWheel"
-- | Bind a `overNode` event. -- | Bind a `overNode` event.
bindOverNode :: Sigma -> (Record Types.Node -> Effect Unit) -> Effect Unit bindOverNode :: Sigma -> (Record Types.Node -> Effect Unit) -> Effect Unit
bindOverNode s f = bindNodeEvent s "overNode" f bindOverNode s f = bindNodeEvent s "overNode" f
......
...@@ -40,6 +40,7 @@ type Node = ( ...@@ -40,6 +40,7 @@ type Node = (
, equilateral :: { numPoints :: Int } , equilateral :: { numPoints :: Int }
, gargType :: GT.Mode , gargType :: GT.Mode
, hidden :: Boolean , hidden :: Boolean
, highlighted :: Boolean
, id :: NodeId , id :: NodeId
, label :: String , label :: String
, size :: Number , size :: Number
......
module Gargantext.Utils.Set where
import Data.Ord (class Ord)
import Data.Set as Set
-- | If `a` is in Set, remove it, otherwise add it
toggle :: forall a. Ord a => Set.Set a -> a -> Set.Set a
toggle s x = if Set.member x s then Set.delete x s else Set.insert x s
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