Commit b9137508 authored by Przemyslaw Kaminski's avatar Przemyslaw Kaminski

[Graph] range slider works, very crude

parent 66dc5e27
.range-slider {
position: relative;
}
.range-slider .scale {
position: absolute;
background-color: #555;
}
.range-slider .knob {
position: absolute;
cursor: pointer;
}
/*# sourceMappingURL=range-slider.css.map */
......@@ -7,3 +7,4 @@
.knob
position: absolute
cursor: pointer
......@@ -21,15 +21,17 @@ import Reactix as R
import Reactix.DOM.HTML as RH
import Gargantext.Components.Graph as Graph
import Gargantext.Components.GraphExplorer.SlideButton (cursorSizeButton, labelSizeButton, nodeSizeButton)
import Gargantext.Components.GraphExplorer.RangeControl (nodeSizeControl)
import Gargantext.Components.GraphExplorer.SlideButton (cursorSizeButton, labelSizeButton)
import Gargantext.Components.GraphExplorer.ToggleButton (edgesToggleButton)
import Gargantext.Utils.Range as Range
import Gargantext.Utils.Reactix as R2
type Controls =
( cursorSize :: R.State Number
, labelSize :: R.State Number
, nodeSize :: R.State Number
, nodeSize :: R.State Range.NumberRange
, multiNodeSelect :: R.Ref Boolean
, showControls :: R.State Boolean
, showEdges :: R.State Boolean
......@@ -40,16 +42,16 @@ type Controls =
controlsToSigmaSettings :: Record Controls -> Record Graph.SigmaSettings
controlsToSigmaSettings { cursorSize: (cursorSize /\ _)
, labelSize: (labelSize /\ _)
, nodeSize: (nodeSize /\ _)
, nodeSize: (Range.Closed { min: nodeSizeMin, max: nodeSizeMax } /\ _)
, showEdges: (showEdges /\ _)} = Graph.sigmaSettings {
drawEdges = showEdges
, drawEdgeLabels = showEdges
, hideEdgesOnMove = not showEdges
, labelMaxSize = labelSize
, maxEdgeSize = if showEdges then 1.0 else 0.0
, maxNodeSize = nodeSize
, maxNodeSize = nodeSizeMax
, minEdgeSize = if showEdges then 1.0 else 0.0
, minNodeSize = nodeSize
, minNodeSize = nodeSizeMin
}
controls :: Record Controls -> R.Element
......@@ -74,7 +76,7 @@ controlsCpt = R.hooksComponent "GraphControls" cpt
-- search topics
, RH.li {} [ cursorSizeButton props.cursorSize ] -- cursor size: 0-100
, RH.li {} [ labelSizeButton props.labelSize ] -- labels size: 1-4
, RH.li {} [ nodeSizeButton props.nodeSize ] -- node size : 5-15
, RH.li {} [ nodeSizeControl props.nodeSize ] -- node size : 5-15
-- edge size : ??
-- zoom: 0 -100 - calculate ratio
-- toggle multi node selection
......@@ -88,7 +90,7 @@ useGraphControls :: R.Hooks (Record Controls)
useGraphControls = do
cursorSize <- R.useState' 10.0
labelSize <- R.useState' 3.0
nodeSize <- R.useState' 5.0
nodeSize <- R.useState' $ Range.Closed { min: 5.0, max: 5.0 }
multiNodeSelect <- R.useRef false
showControls <- R.useState' false
showEdges <- R.useState' true
......@@ -114,7 +116,7 @@ getCursorSize { cursorSize: ( size /\ _ ) } = size
getLabelSize :: Record Controls -> Number
getLabelSize { labelSize: ( size /\ _ ) } = size
getNodeSize :: Record Controls -> Number
getNodeSize :: Record Controls -> Range.NumberRange
getNodeSize { nodeSize: ( size /\ _ ) } = size
getMultiNodeSelect :: Record Controls -> Boolean
......@@ -138,7 +140,7 @@ setCursorSize { cursorSize: ( _ /\ setSize ) } v = setSize $ const v
setLabelSize :: Record Controls -> Number -> Effect Unit
setLabelSize { labelSize: ( _ /\ setSize) } v = setSize $ const v
setNodeSize :: Record Controls -> Number -> Effect Unit
setNodeSize :: Record Controls -> Range.NumberRange -> Effect Unit
setNodeSize { nodeSize: ( _ /\ setSize ) } v = setSize $ const v
setMultiNodeSelect :: Record Controls -> Boolean -> Effect Unit
......
......@@ -3,7 +3,6 @@ module Gargantext.Components.GraphExplorer.SlideButton
, sizeButton
, cursorSizeButton
, labelSizeButton
, nodeSizeButton
) where
import Global (readFloat)
......@@ -43,7 +42,3 @@ cursorSizeButton state =
labelSizeButton :: R.State Number -> R.Element
labelSizeButton state =
sizeButton { state: state, caption: "Label Size", min: 1.0, max: 4.0 }
nodeSizeButton :: R.State Number -> R.Element
nodeSizeButton state =
sizeButton { state: state, caption: "Node Size", min: 5.0, max: 15.0 }
......@@ -14,7 +14,6 @@ import Thermite (PerformAction, Spec)
import Gargantext.Components.Login.Types (TreeId)
import Gargantext.Components.Graph as Graph
import Gargantext.Utils.Range as Range
newtype Node = Node
{ id_ :: String
......
......@@ -54,6 +54,7 @@ rangeSliderCpt = R.hooksComponent "RangeSlider" cpt
cpt props _ = do
R.useEffect' $ do
liftEffect $ log2 "Props: " props
-- scale bar
scaleElem <- R.useRef null -- dom ref
scalePos <- R2.usePositionRef scaleElem
......@@ -71,6 +72,7 @@ rangeSliderCpt = R.hooksComponent "RangeSlider" cpt
dragKnob /\ setDragKnob <- R.useState' $ (Nothing :: Maybe Knob)
-- the bounding box within which the mouse can drag
dragScale <- R.useRef $ Nothing
-- the handler functions for trapping mouse events, so they can be removed
mouseMoveHandler <- (R.useRef $ Nothing) :: R.Hooks (R.Ref (Maybe (EL.Callback Event.MouseEvent)))
mouseUpHandler <- (R.useRef $ Nothing) :: R.Hooks (R.Ref (Maybe (EL.Callback Event.MouseEvent)))
......@@ -78,24 +80,48 @@ rangeSliderCpt = R.hooksComponent "RangeSlider" cpt
do log "RangeSlider: Destroying event handlers"
destroyEventHandler "mousemove" mouseMoveHandler
destroyEventHandler "mouseup" mouseUpHandler
R2.useLayoutEffect1' dragKnob $ \_ -> do
case dragKnob of
Just knob -> do
let drag = (getDragScale knob scalePos lowPos highPos) :: Maybe Range.NumberRange
R.setRef dragScale drag
let onMouseMove = EL.callback $ \(event :: Event.MouseEvent) ->
case reproject drag scalePos value (R2.domMousePosition event) of
Just val -> setKnob knob setValue value val
let onMouseMove = EL.callback $ \(event :: Event.MouseEvent) -> do
-- log2 "drag" drag
-- log2 "scale" scalePos
-- -- log2 "value" value
-- let (R2.Point mousePos) = R2.domMousePosition event
-- log2 "mouse position" mousePos
-- let scale = rectRange <$> R.readRef scalePos
-- case scale of
-- Just scale_ ->
-- case drag of
-- Just drag_ -> do
-- let normal = Range.normalise scale_ (Range.clamp drag_ mousePos.x)
-- log2 "normal" normal
-- log2 "project normal" $ Range.projectNormal props.bounds normal
-- _ -> log "drag is Nothing"
-- _ -> log "scale is Nothing"
case reproject drag scalePos props.bounds (R2.domMousePosition event) of
Just val -> do
log2 "reproject val" val
setKnob knob setValue value val
Nothing -> destroy unit
let onMouseUp = EL.callback $ \(_event :: Event.MouseEvent) -> destroy unit
let onMouseUp = EL.callback $ \(_event :: Event.MouseEvent) -> do
setDragKnob $ const Nothing
destroy unit
log "RangeSlider: Creating event handlers"
log2 "Clamp: " $ Range.clamp props.bounds value'.min
EL.addEventListener document "mousemove" onMouseMove
EL.addEventListener document "mouseup" onMouseUp
R.setRef mouseMoveHandler $ Just onMouseMove
R.setRef mouseUpHandler $ Just onMouseUp
Nothing -> destroy unit
pure $ H.div { className, aria }
[ renderScale scaleElem props value'
, renderKnob lowElem value'.min ("Minimum value:" <> show value'.min) MinKnob setDragKnob
, renderKnob highElem value'.max ("Maximum value:" <> show value'.max) MaxKnob setDragKnob
, renderKnob lowElem value'.min props.bounds ("Minimum value:" <> show value'.min) MinKnob setDragKnob
, renderKnob highElem value'.max props.bounds ("Maximum value:" <> show value'.max) MaxKnob setDragKnob
]
className = "range-slider"
aria = { label: "Range Slider Control. Expresses filtering data by a minimum and maximum value range through two slider knobs. Knobs can be adjusted with the arrow keys." }
......@@ -129,20 +155,23 @@ getDragScale knob scalePos lowPos highPos = do
max MaxKnob scale _ = scale.right
renderScale ref {width,height} {min, max} =
H.div { ref, className, width, height, aria } []
H.div { ref, className, width, height, aria, style } []
where
className = "scale"
aria = { label: "Scale running from " <> show min <> " to " <> show max }
style = { width: "100%", height: "3px" }
renderKnob ref val label knob set =
H.div { ref, tabIndex, className, aria, onMouseDown } [ H.text (show val) ]
renderKnob ref val bounds label knob set =
H.div { ref, tabIndex, className, aria, onMouseDown, style } [ H.text (show val) ]
where
tabIndex = 0
className = "knob"
aria = { label }
aria = { label: label <> ", perc: " <> show percOffset }
onMouseDown = mkEffectFn1 $ \_ -> set $ const $ Just knob
percOffset = Range.normalise bounds val
style = { left: (show $ 100.0 * percOffset) <> "%" }
-- todo round to nearest epsilon
-- TODO round to nearest epsilon
reproject :: Maybe Range.NumberRange -> R.Ref (Maybe DOMRect) -> Range.NumberRange -> R2.Point -> Maybe Number
reproject drag scale value (R2.Point mousePos) = do
drag_ <- drag
......
......@@ -28,8 +28,8 @@ endConfig = endConfig' V10
endConfig' :: ApiVersion -> EndConfig
endConfig' v = { front : frontRelative
--, back : backLocal v
, back: backDev v
, back : backLocal v
--, back: backDev v
, static : staticRelative
}
-- , back : backDemo v }
......
......@@ -4,5 +4,4 @@ import Prelude
import Math as Math
roundToMultiple :: Number -> Number -> Number
roundToMultiple num eps = eps * Math.round (num / eps)
roundToMultiple eps num = eps * Math.round (num / eps)
......@@ -19,21 +19,21 @@ instance closedRange :: Ord t => Range (Closed t) t where
type NumberRange = Closed Number
range :: Closed Number -> Number
range :: NumberRange -> Number
range (Closed r) = r.max - r.min
-- | Clamps the value to within the range and returns a normalised
-- | (0-1) float indication progress along the range
normalise :: Closed Number -> Number -> Number
normalise r v = clamp r v / range r
normalise :: NumberRange -> Number -> Number
normalise r@(Closed {min}) v = (clamp r v - min) / range r
-- | Given a normal (0-1) float representing progress along a range,
-- | project it onto the range
projectNormal :: Closed Number -> Number -> Number
projectNormal r v = clamp closedProbability v * range r
projectNormal :: NumberRange -> Number -> Number
projectNormal r@(Closed {min}) v = (clamp closedProbability v * range r) + min
-- | A closed range between 0 and 1
closedProbability :: Closed Number
closedProbability :: NumberRange
closedProbability = Closed { min: 0.0, max: 1.0 }
-- | Updates the minimum value in a closed range
......
......@@ -5091,10 +5091,10 @@ public-encrypt@^4.0.0:
randombytes "^2.0.1"
safe-buffer "^5.1.2"
pulp@^12.4.0:
version "12.4.2"
resolved "https://registry.yarnpkg.com/pulp/-/pulp-12.4.2.tgz#0d8221005da08bd4507a56c8b0e6c8b0996e10e7"
integrity sha512-hU2vADQCh/PJBtVX5rTpSyhHbOopYUZ5QLlgoz0ZBFHjgGY1I9dPBqH5FW5uag9Q1Ewz8OeWHtLDmRtY6w7UlQ==
pulp@^13.0.0:
version "13.0.0"
resolved "https://registry.yarnpkg.com/pulp/-/pulp-13.0.0.tgz#ed7f4dd0e0ae20a79d4ac3621e387b4ebae4bf18"
integrity sha512-wjjAVuN1Shx6783NvTd8aPwWZ1pE94+isiWtdAJhedvbLqJuwe8p5CSNul9FS0WvBz7ejdrW0vc6wLDLsKX7Yw==
dependencies:
browserify "^16.2.3"
browserify-incremental "^3.1.1"
......@@ -5105,7 +5105,6 @@ pulp@^12.4.0:
node-static "^0.7.11"
read "^1.0.7"
sorcery "^0.10.0"
string-stream "0.0.7"
temp "^0.9.0"
through "^2.3.8"
tree-kill "^1.2.1"
......@@ -6058,11 +6057,6 @@ stream-splicer@^2.0.0:
inherits "^2.0.1"
readable-stream "^2.0.2"
string-stream@0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/string-stream/-/string-stream-0.0.7.tgz#cfcde82799fa62f303429aaa79336ee8834332fe"
integrity sha1-z83oJ5n6YvMDQpqqeTNu6INDMv4=
string-width@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
......
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