Commit 6db0c594 authored by Przemyslaw Kaminski's avatar Przemyslaw Kaminski

[Graph] work on sigmajs selector

parent 9e296c86
......@@ -4,13 +4,11 @@ module Gargantext.Components.Graph
-- , forceAtlas2Settings, ForceAtlas2Settings, ForceAtlas2OptionalSettings
-- )
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.Maybe (Maybe(..))
import Data.Nullable (Nullable)
import Data.Tuple (fst)
import Data.Tuple.Nested ((/\))
import DOM.Simple.Console (log, log2)
import DOM.Simple.Types (Element)
......@@ -72,6 +70,7 @@ graphCpt = R.hooksComponent "Graph" cpt
_ <- Sigma.addRenderer sig {
"type": "canvas"
, container: c
, additionalContexts: ["mouseSelector"]
}
pure unit
......@@ -80,6 +79,8 @@ graphCpt = R.hooksComponent "Graph" cpt
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
_ <- Sigma.bindMouseSelectorPlugin sigma
pure unit
Sigmax.setEdges sig false
Sigma.startForceAtlas2 sig props.forceAtlas2Settings
......@@ -172,6 +173,7 @@ type SigmaSettings =
, mouseEnabled :: Boolean
-- , mouseInertiaDuration :: Number
-- , mouseInertiaRatio :: Number
, mouseSelectorSize :: Number
-- , mouseWheelEnabled :: Boolean
, mouseZoomDuration :: Number
, nodeBorderColor :: String
......@@ -239,6 +241,7 @@ sigmaSettings =
, minEdgeSize: 0.5 -- in fact used in tina as edge size
, minNodeSize: 1.0
, mouseEnabled: true
, mouseSelectorSize: 10.0
, mouseZoomDuration: 150.0
, nodeBorderColor: "default" -- choices: "default" color vs. "node" color
--, nodesPowRatio : 10.8
......
......@@ -414,6 +414,6 @@ transformGraph controls graph = SigmaxTypes.Graph {nodes: newNodes, edges: newEd
_ -> edge
nodeMarked node@{ id } =
if Set.member id (fst controls.selectedNodeIds) then
node { borderColor = "#000", type = "hovered" }
node { borderColor = "#000", type = "selected" }
else
node
......@@ -25,7 +25,7 @@ import Gargantext.Components.Graph as Graph
import Gargantext.Components.GraphExplorer.Button (centerButton)
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, mouseSelectorSizeButton)
import Gargantext.Components.GraphExplorer.ToggleButton (multiSelectEnabledButton, edgesToggleButton, pauseForceAtlasButton)
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Hooks.Sigmax as Sigmax
......@@ -56,14 +56,17 @@ controlsToSigmaSettings { cursorSize: (cursorSize /\ _)} = Graph.sigmaSettings
type LocalControls =
( labelSize :: R.State Number
, mouseSelectorSize :: R.State Number
)
initialLocalControls :: R.Hooks (Record LocalControls)
initialLocalControls = do
labelSize <- R.useState' 14.0
mouseSelectorSize <- R.useState' 10.0
pure $ {
labelSize
, mouseSelectorSize
}
controls :: Record Controls -> R.Element
......@@ -153,6 +156,7 @@ controlsCpt = R.hooksComponent "GraphControls" cpt
-- save button
, RH.li {} [ nodeSearchControl { graph: props.graph
, selectedNodeIds: props.selectedNodeIds } ]
, RH.li {} [ mouseSelectorSizeButton props.sigmaRef localControls.mouseSelectorSize ]
]
]
]
......
......@@ -12,8 +12,6 @@ import Reactix as R
import Reactix.DOM.HTML as H
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
type Props = (
......
......@@ -3,6 +3,7 @@ module Gargantext.Components.GraphExplorer.SlideButton
, sizeButton
, cursorSizeButton
, labelSizeButton
, mouseSelectorSizeButton
) where
import Global (readFloat)
......@@ -48,27 +49,45 @@ sizeButtonCpt = R.hooksComponent "SizeButton" cpt
cursorSizeButton :: R.State Number -> R.Element
cursorSizeButton state =
sizeButton {
state: state
state
, caption: "Cursor Size"
, min: 1.0
, max: 4.0
, onChange: \e -> snd state $ const $ readFloat $ R2.unsafeEventValue e
, onChange: snd state <<< const <<< readFloat <<< R2.unsafeEventValue
}
labelSizeButton :: R.Ref Sigmax.Sigma -> R.State Number -> R.Element
labelSizeButton sigmaRef state =
sizeButton {
state: state
state
, caption: "Label Size"
, min: 5.0
, max: 30.0
, onChange: \e -> do
let sigma = R.readRef sigmaRef
let newValue = readFloat $ R2.unsafeEventValue e
let (value /\ setValue) = state
let (_ /\ setValue) = state
Sigmax.dependOnSigma sigma "[labelSizeButton] sigma: Nothing" $ \s -> do
Sigma.setSettings s {
defaultLabelSize: 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
import Reactix.DOM.HTML as H
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Hooks.Sigmax as Sigmax
import Gargantext.Hooks.Sigmax.Types as SigmaxTypes
type Props = (
......
module Gargantext.Hooks.Sigmax
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.Either (either)
......
......@@ -9,7 +9,7 @@ if (typeof window !== 'undefined') {
const CustomShapes = require('sigma/plugins/garg.js').init(sigma, window).customShapes;
require('sigma/src/utils/sigma.utils.js').init(sigma);
sigma.canvas.nodes.hovered = (node, context, settings) => {
sigma.canvas.nodes.selected = (node, context, settings) => {
// hack
// We need to temporarily set node.type to 'def'. This is for 2 reasons
// 1. Make it render as a normal node
......@@ -17,11 +17,96 @@ sigma.canvas.nodes.hovered = (node, context, settings) => {
// again with node.type = 'hovered')
node.type = 'def';
sigma.canvas.hovers.def(node, context, settings);
node.type = 'hovered';
node.type = 'selected';
};
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;
_container.onmousemove = function(e) { return mouseMove(e); };
_context.canvas.onclick = function(e) { return onClick(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;
_container.onmousemove = null;
}
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) => {
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);
}
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) {
try {
return right(new sigma(opts));
......@@ -45,6 +130,14 @@ function addRenderer(left, right, sigma, renderer) {
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) {
try {
sigma.killRenderer(renderer);
......@@ -91,6 +184,7 @@ exports._sigma = _sigma;
exports._graphRead = graphRead;
exports._refresh = refresh;
exports._addRenderer = addRenderer;
exports._bindMouseSelectorPlugin = bindMouseSelectorPlugin;
exports._killRenderer = killRenderer;
exports._getRendererContainer = getRendererContainer;
exports._setRendererContainer = setRendererContainer;
......
......@@ -70,6 +70,16 @@ foreign import _addRenderer
r
(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 = runEffectFn4 _killRenderer Left Right
......
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