Commit 355d7525 authored by Alexandre Delanoë's avatar Alexandre Delanoë

Merge remote-tracking branch 'origin/219-memiescape-rc0.x' into dev-merge

parents 63d64b4d d21e6801
This diff is collapsed.
This diff is collapsed.
......@@ -1138,4 +1138,580 @@ select.form-control {
width: 100%;
}
/* fonts */
@font-face {
font-family: "Inter-Regular";
font-style: normal;
font-weight: 400;
src: url("../fonts/phylo/Inter-Regular.woff2") format("woff2"), url("../fonts/phylo/Inter-Regular.woff") format("woff");
}
@font-face {
font-family: "Inter-Bold";
font-style: normal;
font-weight: 700;
src: url("../fonts/phylo/Inter-Bold.woff2") format("woff2"), url("../fonts/phylo/Inter-Bold.woff") format("woff");
}
/* grid */
.phylo {
font-family: "Inter-Regular";
font-size: 16px;
display: grid;
grid-template-columns: repeat(15, 1fr);
grid-template-rows: 2% 7% 7% auto 1%;
grid-gap: 10px;
height: calc(100vh - 0px);
color: #0d1824;
}
/* ---- row 1 ---- */
.phylo-title {
grid-row: 1;
grid-column: 1/2;
align-items: center;
text-align: right;
margin-top: 0.5px;
}
.phylo-folder {
grid-row: 1;
grid-column: 2/16;
align-items: center;
}
/* -------------------- */
.phylo-corpus {
grid-row: 2/3;
grid-column: 1/2;
/*background : #3E75B3;*/
font-size: 14px;
display: flex;
align-items: center;
justify-content: right;
}
.phylo-phylo {
grid-row: 3/4;
grid-column: 1/2;
font-size: 14px;
display: flex;
align-items: center;
justify-content: right;
}
.phylo-corpus-info {
grid-row: 2/3;
grid-column: 2/4;
font-size: 14px;
display: flex;
flex-direction: column;
justify-content: center;
}
.phylo-phylo-info {
grid-row: 3/4;
grid-column: 2/4;
font-size: 14px;
display: flex;
flex-direction: column;
justify-content: center;
}
.phylo-how {
grid-row: 2/4;
grid-column: 1/2;
z-index: 2;
display: flex;
align-items: center;
justify-content: right;
}
.phylo-isoline {
grid-row: 2/4;
grid-column: 3/15;
/*background: rgba(223,216,200,0.25); */
}
.phylo-isoline-info {
grid-row: 2/4;
grid-column: 15/16;
padding-top: 20%;
padding-bottom: 20%;
padding-left: 15px;
}
.phylo-isoline-info .btn-group {
display: initial;
}
/* -------------------- */
.phylo-scape {
grid-row: 4;
grid-column: 1/15;
/*background: #FFCC73;*/
}
.phylo-timeline {
grid-row: 4;
grid-column: 1/2;
}
.phylo-graph {
grid-row: 4;
grid-column: 15/16;
/*background: #FFCC73;*/
}
/* classes */
/* ---------- icons ---------- */
a {
color: inherit;
cursor: pointer;
}
.how {
cursor: pointer;
position: relative;
}
.tooltip {
font-family: "Inter-Regular";
font-size: 14px;
font-style: normal;
font-weight: 400;
}
i.how span {
position: absolute;
width: 300px;
color: #FFFFFF;
background: #0d1824;
height: 30px;
line-height: 30px;
text-align: center;
visibility: hidden;
border-radius: 6px;
}
i.how span:after {
content: "";
position: absolute;
top: 50%;
right: 100%;
margin-top: -8px;
width: 0;
height: 0;
border-right: 8px solid #0d1824;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
}
i.how:hover span {
visibility: visible;
left: 100%;
top: 50%;
margin-top: -15px;
margin-left: 15px;
z-index: 999;
}
.switch > .far + .fa,
.switch:hover > .far {
display: none;
}
.switch:hover > .far + .fa {
display: inherit;
color: #0d1824;
}
/* ---------- fonts ---------- */
.font-bold {
font-family: "Inter-Bold";
text-transform: uppercase;
}
.font-small {
color: #0d1824;
font-size: 12px;
}
.header {
/*font-weight: bold;*/
/*text-transform: uppercase;*/
font-weight: 500;
cursor: pointer;
}
.header:hover {
font-weight: bold;
}
/* ---------- input ---------- */
.button {
background-color: white;
border: 1.5px solid #0d1824;
cursor: pointer;
}
.button:hover {
background-color: #0d1824;
color: white;
}
.btn-group button {
margin-top: 1px;
margin-bottom: 1px;
display: block;
width: 40px;
}
.draw {
display: none;
}
.phylo-focus {
fill: #f8381f;
color: #f8381f;
}
.reset {
visibility: hidden;
}
.label {
visibility: hidden;
}
.heading {
visibility: hidden;
}
.export {
visibility: hidden;
}
.headed {
background-color: #0d1824;
color: white;
}
.labeled {
background-color: #0d1824;
color: white;
}
.input-file {
display: inline-block;
cursor: pointer;
}
.input-file:hover {
border-bottom: 1.5px solid #0d1824;
}
.input-name {
font-style: italic;
opacity: 0.7;
font-size: 14px;
padding-left: 6px;
padding-right: 6px;
}
/* ---------- axis ---------- */
.x-axis path {
stroke: #EBE4DD;
stroke-width: 1.5px;
}
.y-axis path {
stroke: #EBE4DD;
stroke-width: 1.5px;
}
.y-highlight {
stroke: #f3be54;
stroke-width: 1.5px;
}
.x-mark {
fill: #4A5C70;
stroke-width: 1px;
stroke: #fff;
}
.x-mark-over {
fill: #f3be54;
}
.x-mark-focus {
fill: #f8381f;
}
.tick text {
font-family: "Inter-Regular";
}
.tick text:hover {
cursor: pointer;
}
.y-label {
font-size: 10px;
font-family: "Inter-Regular";
font-weight: normal;
}
.y-label-bold {
font-size: 12px;
font-family: "Inter-Bold";
font-weight: bold;
}
.y-mark-year-inner {
fill: #4A5C70;
}
.y-mark-year-inner-highlight {
fill: #f3be54;
}
.y-mark-year-outer {
fill: #fff;
stroke: #4A5C70;
stroke-width: 1px;
}
.y-mark-year-outer-highlight {
fill: #fff;
stroke: #f3be54;
stroke-width: 3px;
}
.y-mark-month {
fill: #4A5C70;
}
/* ---------- group ---------- */
.group-outer {
stroke-width: 0.8px;
stroke: #fff;
fill: #fff;
}
.group-inner {
stroke-width: 0.8px;
stroke: #0d1824;
fill: #0d1824;
/*cursor: pointer;*/
z-index: 10;
}
.group-heading {
fill: #fff;
stroke: #B5B5B5;
}
.group-focus {
stroke: #f8381f;
}
.source-focus {
stroke: #67a9cf;
}
.group-unfocus {
stroke: #A9A9A9;
}
.group-path {
cursor: pointer;
}
/* ---------- labels ---------- */
.ngrams {
visibility: hidden;
}
.term {
cursor: pointer;
}
.term:hover {
font-weight: bold;
fill: #f8381f;
}
.term-unfocus {
/*fill: #A9A9A9;*/
}
.term-focus {
/*fill: black;*/
}
.term-path {
fill: none;
stroke: #F0684D;
stroke-width: 1.5px;
}
.emerging {
/*text-decoration: underline #F0684D;*/
/*fill:#5AA350;*/
/*fill: #5AA350;*/
fill: #F8381F;
}
.decreasing {
/*text-decoration: underline #74B5FF;*/
fill: #11638F;
}
.path-focus {
fill: none;
stroke: #F0684D;
stroke-width: 1.5px;
}
.path-unfocus {
stroke: #A9A9A9;
}
.path-heading {
stroke: #B5B5B5;
}
/* ---------- phylo ---------- */
.branch-hover {
fill: #f3be54;
opacity: 0.5;
}
/* elements */
#file-path {
display: none;
}
/* axis */
.axisRight {
font-family: "Inter-Regular";
font-size: 10px;
}
/* isoline */
.peak {
stroke: white;
stroke-width: 1px;
font-family: "Inter-Regular";
font-size: 14px;
text-anchor: middle;
visibility: visible;
}
.peak-over {
font-size: 18px;
stroke-width: 2px;
cursor: pointer;
stroke: #f3be54;
z-index: 100;
}
.peak-focus {
font-size: 18px;
stroke-width: 2px;
stroke: #F0684D;
}
.peak-focus-source {
font-size: 18px;
stroke-width: 2px;
stroke: #67a9cf;
}
.peak-label {
text-align: center;
font-family: "Inter-Regular";
font-size: 14px;
font-style: normal;
font-weight: 400;
color: #FFFFFF;
border-radius: 3px;
border-style: solid;
border-width: 2px;
border-color: white;
background: #0d1824;
padding: 5px;
z-index: 10;
position: absolute;
visibility: hidden;
}
.word-cloud {
font-family: "Inter-Regular";
font-size: 12px;
}
.search {
margin-left: 10px;
visibility: hidden;
position: absolute;
z-index: 7;
font-size: 14px;
background-color: transparent;
outline: 0;
border-width: 0 0 2px;
border-color: #0d1824;
}
.search-label {
visibility: hidden;
margin-left: 5px;
}
.search:focus {
border-color: #F0684D;
}
.autocomplete {
margin-left: 10px;
visibility: hidden;
position: absolute;
z-index: 7;
font-size: 14px;
background-color: transparent;
color: silver;
z-index: 1;
border: none;
}
.loading {
visibility: hidden;
}
.phylo-name {
visibility: hidden;
text-transform: capitalize;
font-weight: bold;
}
.select-source {
margin-left: 10px;
display: none;
border: 1.5px solid #0d1824;
cursor: pointer;
outline: 0;
background: transparent;
border-image: none;
outline-offset: -2px;
outline-color: transparent;
box-shadow: none;
-webkit-appearance: none;
}
option {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 150px;
}
/*# sourceMappingURL=sass.css.map */
This diff is collapsed.
......@@ -206,6 +206,26 @@ let additions =
, repo = "https://github.com/natefaubion/purescript-convertable-options"
, version = "v1.0.0"
}
, d3 =
{ dependencies =
[ "aff"
, "aff-promise"
, "dom-simple"
, "easy-ffi"
, "effect"
, "exceptions"
, "foreign"
, "functions"
, "js-date"
, "maybe"
, "prelude"
, "psci-support"
, "tuples"
, "web-dom"
]
, repo = "https://github.com/cgenie/purescript-d3"
, version = "v0.9.1"
}
}
in upstream // overrides // additions
......
......@@ -26,6 +26,7 @@ to generate this file without the comments in this block.
, "control"
, "convertable-options"
, "css"
, "d3"
, "datetime"
, "dom-filereader"
, "dom-simple"
......
module Gargantext.Components.Nodes.Corpus.Phylo where
module Gargantext.Components.Nodes.Corpus.Phylo
( phyloLayout
) where
import Gargantext.Prelude
( pure, ($) )
-- import Gargantext.Utils.Toestand as T2
-- import Toestand as T
import Affjax as AX
import Affjax.ResponseFormat as ResponseFormat
import DOM.Simple.Console (log2)
import Data.Either (Either(..))
import Data.HTTP.Method (Method(..))
import Data.Maybe (Maybe(..))
import Effect.Aff (Aff, launchAff_)
import Effect.Class (liftEffect)
import Gargantext.Components.PhyloExplorer.JSON (PhyloJSONSet)
import Gargantext.Components.PhyloExplorer.Layout (layout)
import Gargantext.Components.PhyloExplorer.Types (PhyloDataSet, parsePhyloJSONSet)
import Gargantext.Sessions (Session)
import Gargantext.Types (NodeID)
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
import Simple.JSON as JSON
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.Nodes.Corpus.Phylo"
type Props = ( nodeId :: NodeID, session :: Session )
type Props =
( nodeId :: NodeID
, session :: Session
)
phyloLayout :: R2.Component Props
phyloLayout = R.createElement phyloLayoutCpt
phyloLayoutCpt :: R.Component Props
phyloLayoutCpt = here.component "phyloLayout" cpt where
cpt { nodeId, session } content = do
pure $ H.h1 {} [ H.text "Hello Phylo" ]
cpt _ _ = do
fetchedDataBox <- T.useBox (Nothing :: Maybe PhyloDataSet)
fetchedData <- T.useLive T.unequal fetchedDataBox
R.useEffectOnce' $ launchAff_ do
result <- fetchPhyloJSON
liftEffect $ case result of
Left err -> log2 "error" err
Right res -> T.write_ (Just res) fetchedDataBox
pure case fetchedData of
Nothing -> mempty
Just phyloDataSet -> layout { phyloDataSet } []
fetchPhyloJSON :: Aff (Either String PhyloDataSet)
fetchPhyloJSON =
let
-- @WIP remove dumb data
url = "http://localhost:5000/js/knowledge-phylomemy.json"
-- url = "http://localhost:5000/js/vaccines_countries_06_2021.json"
request = AX.defaultRequest
{ url = url
, method = Left GET
, responseFormat = ResponseFormat.string
}
in do
result <- request # AX.request
liftEffect $ case result of
Left err -> pure $ Left $ AX.printError err
Right response -> case JSON.readJSON response.body of
Left err -> pure $ Left $ show err
Right (res :: PhyloJSONSet) -> pure $ Right $ parsePhyloJSONSet res
This diff is collapsed.
module Gargantext.Components.PhyloExplorer.Draw
( drawPhylo
, highlightSource
, unhide
, setGlobalDependencies, setGlobalD3Reference
) where
import Gargantext.Prelude
import DOM.Simple (Document, Window, querySelectorAll)
import Data.Either (Either(..))
import Data.Foldable (for_)
import Data.FoldableWithIndex (forWithIndex_)
import Data.Maybe (Maybe(..), maybe)
import Effect (Effect)
import Effect.Uncurried (EffectFn1, EffectFn7, runEffectFn1, runEffectFn7)
import FFI.Simple (applyTo, getProperty, (..), (.=), (.?))
import Gargantext.Components.PhyloExplorer.Types (AncestorLink, Branch, BranchLink, GlobalTerm(..), Group(..), Link, Period, PhyloDataSet(..))
import Graphics.D3.Base (D3, D3Eff)
import Graphics.D3.Selection as D3S
import Graphics.D3.Util (ffi)
foreign import _drawPhylo :: EffectFn7
(Array Branch)
(Array Period)
(Array Group)
(Array Link)
(Array AncestorLink)
(Array BranchLink)
(Array Number)
(Unit)
drawPhylo ::
Array Branch
-> Array Period
-> Array Group
-> Array Link
-> Array AncestorLink
-> Array BranchLink
-> Array Number
-> Effect Unit
drawPhylo = runEffectFn7 _drawPhylo
foreign import _drawWordCloud :: forall a. EffectFn1 (Array a) Unit
drawWordCloud :: forall a. Array a -> Effect Unit
drawWordCloud = runEffectFn1 _drawWordCloud
-----------------------------------------------------------
orDie :: forall err a. Maybe a -> err -> Either err a
orDie (Just a) _ = Right a
orDie Nothing err = Left err
-- @XXX: FFI.Simple `(...)` throws error (JavaScript issue)
-- need to decompose computation
--
-- (?) chained prototype property issue?
applyTo_ :: forall src arg res. src -> String -> Array arg -> res
applyTo_ src name args =
let fn = getProperty name src
in applyTo fn src args
infixl 4 applyTo_ as ~~
-- @WIP: DOM.Simple lack of "ClassList" module
addClass :: forall el. el -> Array String -> Effect Unit
addClass el args = pure $ (el .. "classList") ~~ "add" $ args
removeClass :: forall el. el -> Array String -> Effect Unit
removeClass el args = pure $ (el .. "classList") ~~ "remove" $ args
-- @WIP: "Graphics.D3.Selection" lack of "filter" function
-- @WIP: "Graphics.D3.Selection" lack of "nodes" function
selectionFilter :: forall d. String -> D3S.Selection d -> D3Eff (D3S.Selection D3S.Void)
selectionFilter = ffi ["query", "selection", ""] "selection.filter(query)"
selectionNodes :: forall d el. D3S.Selection d -> D3Eff (Array el)
selectionNodes = ffi ["selection", ""] "selection.nodes()"
-----------------------------------------------------------
setGlobalDependencies :: Window -> PhyloDataSet -> Effect Unit
setGlobalDependencies w (PhyloDataSet o)
= do
_ <- pure $ (w .= "freq") {}
_ <- pure $ (w .= "nbBranches") o.nbBranches
_ <- pure $ (w .= "nbDocs") o.nbDocs
_ <- pure $ (w .= "nbFoundations") o.nbFoundations
_ <- pure $ (w .= "nbGroups") o.nbGroups
_ <- pure $ (w .= "nbPeriods") o.nbPeriods
_ <- pure $ (w .= "nbTerms") o.nbTerms
_ <- pure $ (w .= "sources") o.sources
_ <- pure $ (w .= "terms") []
_ <- pure $ (w .= "timeScale") o.timeScale
_ <- pure $ (w .= "weighted") o.weighted
(freq :: Array Int) <- pure $ w .. "freq"
(terms :: Array GlobalTerm) <- pure $ w .. "terms"
for_ o.groups \(Group g) -> do
let
f = g.foundation
l = g.label
forWithIndex_ f \idx val ->
let
idx' = show idx
val' = show val
in
-- For each entries in group.foundation array,
-- increment consequently the global window.keys array
case (freq .? val') of
Nothing -> pure $ (freq .= val') 0
Just v -> pure $ (freq .= val') (v +1)
*>
-- For each entries in group.foundation array,
-- if the global window.terms does not have it in property,
-- append an item to the global window.terms
case (terms .? val') of
Just _ -> pure unit
Nothing -> void <<< pure $ (terms .= val') $ GlobalTerm
{ label: l .. idx'
, fdt : val'
}
-- Use FFI native `Array.flat` method (not mutating its caller in this
-- context)
void do
new <- pure $ (terms ~~ "flat") []
pure $ (w .= "terms") new
-- @XXX: prevent PureScript from not injecting D3
setGlobalD3Reference :: Window -> D3 -> Effect Unit
setGlobalD3Reference window d3 = void $ pure $ (window .= "d3") d3
-----------------------------------------------------------
unhide :: Document -> String -> Effect Unit
unhide d s = do
setText s `toElements` "#phyloName"
turnVisible `toElements` "#phyloName"
turnVisible `toElements` ".reset"
turnVisible `toElements` ".label"
turnVisible `toElements` ".heading"
turnVisible `toElements` ".export"
where
toElements fn query = querySelectorAll d query >>= flip for_ fn
turnVisible el = do
style <- pure $ (el .. "style")
pure $ (style .= "visibility") "visible"
setText name el = pure $ (el .= "innerHTML") name
-----------------------------------------------------------
highlightSource :: Window -> String -> Effect Unit
highlightSource window value =
let
hasHighlight = maybe false identity (window .? "highlighted")
hasLdView = maybe false identity (window .? "ldView")
in do
groups <- D3S.rootSelectAll ".group-inner"
if hasHighlight
then
selectionFilter ".source-focus" groups
>>= selectionNodes
>>= flip for_ (flip addClass [ "group-unfocus" ])
else
pure unit
-- unselected all the groups
_ <- selectionNodes groups
>>= flip for_ (flip removeClass [ "source-focus" ])
if hasLdView
then
selectionNodes groups
>>= flip for_ (fill "#f5eee6")
else
selectionNodes groups
>>= flip for_ (fill "#fff")
_ <- D3S.rootSelectAll ".peak"
>>= D3S.classed "peak-focus-source" false
-- select the relevant ones
if (value == "unselect")
then
pure unit
else do
arr <- selectionFilter (".source-" <> value) groups
>>= selectionNodes
drawWordCloud arr
for_ arr selectNodeGroup
where
fill :: forall el. String -> el -> Effect Unit
fill hex el = do
style <- pure $ (el .. "style")
pure $ (style .= "fill") hex
selectNodeGroup :: forall el. el -> Effect Unit
selectNodeGroup el = do
removeClass el [ "group-unfocus" ]
addClass el [ "source-focus" ]
fill "#a6bddb" el
bid <- pure $ (el ~~ "getAttribute") [ "bId" ]
void $
D3S.rootSelect ("#peak-" <> bid)
>>= D3S.classed "peak-focus-source" true
module Gargantext.Components.PhyloExplorer.JSON where
import Gargantext.Prelude
import Data.Generic.Rep (class Generic)
import Data.Generic.Rep as GR
import Data.Maybe (Maybe)
import Data.Show.Generic (genericShow)
import Gargantext.Utils.SimpleJSON (untaggedSumRep)
import Simple.JSON as JSON
type GraphData =
( bb :: String
, color :: String
, fontsize :: String
, label :: String
, labelloc :: String
, lheight :: String
, lp :: String
, lwidth :: String
, name :: String
, nodesep :: String
, overlap :: String
, phyloBranches :: String
, phyloDocs :: String
, phyloFoundations :: String
, phyloGroups :: String
, phyloPeriods :: String
, phyloSources :: String
, phyloTerms :: String
, phyloTimeScale :: String
, rank :: String
, ranksep :: String
, ratio :: String
, splines :: String
, style :: String
)
--------------------------------------------------
newtype PhyloJSONSet = PhyloJSONSet
{ _subgraph_cnt :: Int
, directed :: Boolean
, edges :: Array RawEdge
, objects :: Array RawObject
, strict :: Boolean
| GraphData
}
derive instance Generic PhyloJSONSet _
derive instance Eq PhyloJSONSet
instance Show PhyloJSONSet where show = genericShow
derive newtype instance JSON.ReadForeign PhyloJSONSet
--------------------------------------------------
type NodeData =
( height :: String
, label :: String
, name :: String
, nodeType :: String
, pos :: String
, shape :: String
, width :: String
)
data RawObject
= GroupToNode
{ _gvid :: Int
, bId :: String
, branchId :: String
, fontname :: String
, foundation :: String
, frequence :: String
, from :: String
, lbl :: String
, penwidth :: String
, role :: String
, seaLvl :: String
, source :: String
, strFrom :: Maybe String
, strTo :: Maybe String
, support :: String
, to :: String
, weight :: String
| NodeData
}
| BranchToNode
{ _gvid :: Int
, age :: String
, bId :: String
, birth :: String
, branchId :: String
, branch_x :: String
, branch_y :: String
, fillcolor :: String
, fontname :: String
, fontsize :: String
, size :: String
, style :: String
| NodeData
}
| PeriodToNode
{ _gvid :: Int
, fontsize :: String
, from :: String
, strFrom :: Maybe String
, strTo :: Maybe String
, to :: String
| NodeData
}
| Layer
{ _gvid :: Int
, nodes :: Array Int
| GraphData
}
derive instance Generic RawObject _
derive instance Eq RawObject
instance Show RawObject where show = genericShow
instance JSON.ReadForeign RawObject where
readImpl f = GR.to <$> untaggedSumRep f
--------------------------------------------------
type EdgeData =
( color :: String
, head :: Int
, pos :: String
, tail :: Int
, width :: String
)
data RawEdge
= GroupToAncestor
{ _gvid :: Int
, arrowhead :: String
, edgeType :: String
, lbl :: String
, penwidth :: String
, style :: String
| EdgeData
}
| GroupToGroup
{ _gvid :: Int
, constraint :: String
, edgeType :: String
, lbl :: String
, penwidth :: String
| EdgeData
}
| BranchToGroup
{ _gvid :: Int
, arrowhead :: String
, edgeType :: String
| EdgeData
}
| BranchToBranch
{ _gvid :: Int
, arrowhead :: String
, style :: String
| EdgeData
}
| PeriodToPeriod
{ _gvid :: Int
| EdgeData
}
derive instance Generic RawEdge _
derive instance Eq RawEdge
instance Show RawEdge where show = genericShow
instance JSON.ReadForeign RawEdge where
readImpl f = GR.to <$> untaggedSumRep f
module Gargantext.Components.PhyloExplorer.Layout
( layout
) where
import Gargantext.Prelude
import DOM.Simple (document, window)
import Data.Array as Array
import Gargantext.Components.PhyloExplorer.Draw (drawPhylo, highlightSource, setGlobalD3Reference, setGlobalDependencies, unhide)
import Gargantext.Components.PhyloExplorer.Types (PhyloDataSet(..))
import Gargantext.Utils (nbsp)
import Gargantext.Utils.Reactix as R2
import Graphics.D3.Base (d3)
import Reactix as R
import Reactix.DOM.HTML as H
here :: R2.Here
here = R2.here "Gargantext.Components.PhyloExplorer"
type Props =
( phyloDataSet :: PhyloDataSet
)
layout :: R2.Component Props
layout = R.createElement layoutCpt
layoutCpt :: R.Component Props
layoutCpt = here.component "layout" cpt where
cpt { phyloDataSet: (PhyloDataSet o)
} _ = do
-- States
R.useEffectOnce' $ do
unhide document o.name
setGlobalD3Reference window d3
setGlobalDependencies window (PhyloDataSet o)
drawPhylo
o.branches
o.periods
o.groups
o.links
o.ancestorLinks
o.branchLinks
o.bb
-- Render
pure $
H.div
{ className: "phylo" }
[
-- <!-- row 1 -->
H.div
{ className: "phylo-title font-bold" }
[ H.text "Mèmiescape" ]
,
H.div
{ className: "phylo-folder" }
[
-- <!-- title bar (static mode) -->
H.label
{ id: "phyloName"
, className: "phylo-name"
}
[]
,
-- <!-- folder bar -->
-- H.label
-- { id: "file-label"
-- , for: "file-path"
-- , className: "input-file"
-- }
-- [ H.text "load a phylomemy →" ]
-- ,
-- H.input
-- { id: "file-path"
-- , type: "file"
-- , maxLength: "10"
-- }
-- ,
-- H.label
-- { id: "file-name"
-- , className: "input-name"
-- }
-- []
-- ,
-- H.button
-- { id: "draw"
-- , className: "button draw"
-- }
-- [ H.text "draw" ]
-- ,
-- <!-- source selector -->
R2.select
{ id: "checkSource"
, className: "select-source"
, defaultValue: ""
, on: { change: \e -> highlightSource window e.target.value }
} $
[
H.option
{ disabled: true
, value: ""
}
[ H.text "select a source ↴" ]
,
H.option
{ value: "unselect" }
[ H.text "unselect source ✕" ]
]
<>
flip Array.mapWithIndex o.sources
( \idx val ->
H.option
{ value: idx }
[ H.text val ]
)
,
-- <!-- search bar -->
H.label
{ id: "search-label"
, className: "search-label"
}
[ H.text "find a term →" ]
,
H.input
{ id: "search-box"
, type: "text"
, className: "search"
}
,
H.input
{ id: "search-autocomplete"
, text: "text"
, className: "autocomplete"
, disabled: true
, value: ""
}
]
,
-- <!-- row 2 & 3 -->
phyloCorpus {} []
,
phyloCorpusInfo
{ nbDocs : o.nbDocs
, nbFoundations : o.nbFoundations
, nbPeriods : o.nbPeriods
}
[]
,
phyloHow {} []
,
phyloPhylo {} []
,
phyloPhyloInfo
{ nbTerms : o.nbTerms
, nbGroups : o.nbGroups
, nbBranches : o.nbBranches
}
[]
,
H.div
{ id: "phyloIsoLine"
, className: "phylo-isoline"
}
[]
,
H.div
{ id: "phyloIsolineInfo"
, className: "phylo-isoline-info"
}
[
H.div
{ className: "btn-group" }
[
H.button
{ id: "reset"
, className: "button reset"
}
[
H.i
{ className: "fa fa-arrows-alt" }
[]
]
,
H.button
{ id: "label"
, className: "button label"
}
[
H.i
{ className: "fa fa-dot-circle-o" }
[]
]
,
H.button
{ id: "heading"
, className: "button heading"
}
[
H.i
{ className: "fa fa-sort-alpha-asc" }
[]
]
,
H.button
{ id: "export"
, className: "button export"
}
[
H.i
{ className: "fas fa-camera" }
[]
]
]
]
,
-- <!-- row 4 -->
H.div
{ id: "phyloScape"
, className: "phylo-scape"
}
[]
,
H.div
{ id: "phyloTimeline"
, className: "phylo-timeline"
}
[]
,
H.div
{ id: "phyloGraph"
, className: "phylo-graph"
}
[]
]
--------------------------------------------------------
phyloCorpus :: R2.Component ()
phyloCorpus = R.createElement phyloCorpusCpt
phyloCorpusCpt :: R.Component ()
phyloCorpusCpt = here.component "phyloCorpus" cpt where
cpt _ _ = do
-- Render
pure $
H.div
{ id: "phyloCorpus"
, className: "phylo-corpus"
}
[ H.text "corpus" ]
---------------------------------------------------------
phyloHow :: R2.Component ()
phyloHow = R.createElement phyloHowCpt
phyloHowCpt :: R.Component ()
phyloHowCpt = here.component "phyloHow" cpt where
cpt _ _ = do
-- Render
pure $
H.div
{ id: "phyloHow"
, className: "phylo-how"
}
[
H.a
{ id: "phyloSearch"
, href: "http://maps.gargantext.org/phylo/knowledge_visualization/memiescape/documentation.html"
, target: "_blank"
}
[
H.div
{ className: "switch" }
[
H.i
{ className: "far fa-question-circle how" }
[]
,
H.i
{ className: "fa fa-question-circle how" }
[
H.span
{ className: "tooltip" }
[ H.text "click to see how the phylomemy was built" ]
]
]
]
]
---------------------------------------------------------
phyloPhylo :: R2.Component ()
phyloPhylo = R.createElement phyloPhyloCpt
phyloPhyloCpt :: R.Component ()
phyloPhyloCpt = here.component "phyloPhylo" cpt where
cpt _ _ = do
-- Render
pure $
H.div
{ id: "phyloPhylo"
, className: "phylo-phylo"
}
[ H.text "phylomemy" ]
---------------------------------------------------------
type PhyloCorpusInfoProps =
( nbDocs :: Int
, nbFoundations :: Int
, nbPeriods :: Int
)
phyloCorpusInfo :: R2.Component PhyloCorpusInfoProps
phyloCorpusInfo = R.createElement phyloCorpusInfoCpt
phyloCorpusInfoCpt :: R.Component PhyloCorpusInfoProps
phyloCorpusInfoCpt = here.component "phyloCorpusInfo" cpt where
cpt props _ = do
-- Render
pure $
H.div
{ id: "phyloCorpusInfo"
, className: "phylo-corpus-info"
}
[
H.span
{}
[
H.b {} [ H.text $ show props.nbDocs ]
, H.text $ nbsp 1 <> "docs"
]
,
H.span
{}
[
H.b {} [ H.text $ show props.nbFoundations ]
, H.text $ nbsp 1 <> "foundations"
]
,
H.span
{}
[
H.b {} [ H.text $ show props.nbPeriods ]
, H.text $ nbsp 1 <> "periods"
]
]
---------------------------------------------------------
type PhyloPhyloInfoProps =
( nbTerms :: Int
, nbGroups :: Int
, nbBranches :: Int
)
phyloPhyloInfo :: R2.Component PhyloPhyloInfoProps
phyloPhyloInfo = R.createElement phyloPhyloInfoCpt
phyloPhyloInfoCpt :: R.Component PhyloPhyloInfoProps
phyloPhyloInfoCpt = here.component "phyloPhyloInfo" cpt where
cpt props _ = do
-- Render
pure $
H.div
{ id: "phyloPhyloInfo"
, className: "phylo-phylo-info"
}
[
H.span
{}
[
H.b
{ id: "phyloTerms" }
[ H.text $ show props.nbTerms ]
, H.text $ nbsp 1 <> "terms"
]
,
H.span
{}
[
H.b
{ id: "phyloGroups" }
[ H.text $ show props.nbGroups ]
, H.text $ nbsp 1 <> "groups"
]
,
H.span
{}
[
H.b
{ id: "phyloBranches" }
[ H.text $ show props.nbBranches ]
, H.text $ nbsp 1 <> "branches"
]
]
'use strict';
/**
* @name yearToDate
* @param {string} year
* @returns {Date}
*/
function yearToDate(year) {
var d = new Date();
d.setYear(parseInt(year));
d.setMonth(0);
d.setDate(1);
return d;
}
/**
* @name stringToDate
* @param {string} str
* @returns {Date}
*/
function stringToDate(str) {
var arr = (str.replace('"','')).split('-');
var d = new Date();
d.setYear(parseInt(arr[0]));
d.setMonth(parseInt(arr[1]));
d.setMonth(d.getMonth() - 1);
d.setDate(parseInt(arr[2]));
return d;
}
/**
* @name utcStringToDate
* @param {string} str
* @returns {Date}
*/
function utcStringToDate(str) {
var arr = ((str.replace('"','')).replace(' UTC','')).split(/[\s-:]+/);
var d = new Date();
d.setYear(parseInt(arr[0]));
d.setMonth(parseInt(arr[1]));
d.setDate(parseInt(arr[2]));
d.setHours(parseInt(arr[3]), parseInt(arr[4]), parseInt(arr[5]))
return d;
}
exports.yearToDate = yearToDate;
exports.stringToDate = stringToDate;
exports.utcStringToDate = utcStringToDate;
This diff is collapsed.
......@@ -39,7 +39,7 @@ instance ( GenericTaggedSumRep a
) => GenericTaggedSumRep (GR.Constructor name a) where
genericTaggedSumRep f = do
-- r :: { "type" :: String } <- JSON.read' f
-- if r."type" == name
-- if r."type" == name
-- then withExcept (map $ ErrorAtProperty name) $ GR.Constructor <$> genericTaggedSumRep r
-- else fail $ ForeignError $ "Wrong type tag " <> r."type" <> " where " <> name <> " was expected."
r :: FO.Object Foreign <- JSON.read' f
......@@ -60,5 +60,28 @@ instance ( JSON.ReadForeign a
-----------------------------------------------------------
-- | Applying Generics-Rep to decoding untagged JSON values
-- |
-- | https://purescript-simple-json.readthedocs.io/en/latest/generics-rep.html
class UntaggedSumRep rep where
untaggedSumRep :: Foreign -> Foreign.F rep
instance untaggedSumRepSum ::
( UntaggedSumRep a
, UntaggedSumRep b
) => UntaggedSumRep (GR.Sum a b) where
untaggedSumRep f
= GR.Inl <$> untaggedSumRep f
<|> GR.Inr <$> untaggedSumRep f
instance untaggedSumRepConstructor ::
( UntaggedSumRep a
) => UntaggedSumRep (GR.Constructor name a) where
untaggedSumRep f = GR.Constructor <$> untaggedSumRep f
instance untaggedSumRepArgument ::
( JSON.ReadForeign a
) => UntaggedSumRep (GR.Argument a) where
untaggedSumRep f = GR.Argument <$> JSON.readImpl f
/* fonts */
@font-face {
font-family: 'Inter-Regular';
font-style: normal;
font-weight: 400;
src: url("../fonts/phylo/Inter-Regular.woff2") format("woff2"),
url("../fonts/phylo/Inter-Regular.woff") format("woff");
}
@font-face {
font-family: 'Inter-Bold';
font-style: normal;
font-weight: 700;
src: url("../fonts/phylo/Inter-Bold.woff2") format("woff2"),
url("../fonts/phylo/Inter-Bold.woff") format("woff");
}
/* grid */
.phylo {
font-family: "Inter-Regular";
font-size: 16px;
display: grid;
grid-template-columns: repeat(15, 1fr);
grid-template-rows: 2% 7% 7% auto 1%;
grid-gap: 10px;
height: 100vh;
color: #0d1824;
}
/* ---- row 1 ---- */
.phylo-title {
grid-row: 1;
grid-column: 1 / 2;
align-items: center;
text-align: right;
margin-top: 0.5px;
}
.phylo-folder {
grid-row: 1;
grid-column: 2 / 16;
align-items: center;
}
/* -------------------- */
.phylo-corpus {
grid-row: 2 / 3;
grid-column: 1 / 2;
/*background : #3E75B3;*/
font-size: 14px;
display: flex;
align-items: center;
justify-content: right;
}
.phylo-phylo {
grid-row: 3 / 4;
grid-column: 1 / 2;
font-size: 14px;
display: flex;
align-items: center;
justify-content: right;
}
.phylo-corpus-info {
grid-row: 2 / 3;
grid-column: 2 / 4;
font-size: 14px;
display: flex;
flex-direction: column;
justify-content: center;
}
.phylo-phylo-info {
grid-row: 3 / 4;
grid-column: 2 / 4;
font-size: 14px;
display: flex;
flex-direction: column;
justify-content: center;
}
.phylo-how {
grid-row: 2 / 4;
grid-column: 1 / 2;
z-index: 2;
display: flex;
align-items: center;
justify-content: right;
}
.phylo-isoline {
grid-row: 2 / 4;
grid-column: 3 / 15;
/*background: rgba(223,216,200,0.25); */
}
.phylo-isoline-info {
grid-row: 2 / 4;
grid-column: 15 / 16;
padding-top: 20%;
padding-bottom: 20%;
padding-left: 15px;
.btn-group {
display: initial;
}
}
/* -------------------- */
.phylo-scape {
grid-row: 4;
grid-column: 1 / 15;
/*background: #FFCC73;*/
}
.phylo-timeline {
grid-row: 4;
grid-column: 1 / 2;
}
.phylo-graph {
grid-row: 4;
grid-column: 15 / 16;
/*background: #FFCC73;*/
}
/* classes */
/* ---------- icons ---------- */
a {
color: inherit;
cursor: pointer;
}
.how {
cursor: pointer;
position: relative;
}
.tooltip {
font-family: "Inter-Regular";
font-size: 14px;
font-style: normal;
font-weight: 400;
}
i.how span {
position: absolute;
width:300px;
color: #FFFFFF;
background: #0d1824;
height: 30px;
line-height: 30px;
text-align: center;
visibility: hidden;
border-radius: 6px;
}
i.how span:after {
content: '';
position: absolute;
top: 50%;
right: 100%;
margin-top: -8px;
width: 0; height: 0;
border-right: 8px solid #0d1824;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
}
i.how:hover span {
visibility: visible;
left: 100%;
top: 50%;
margin-top: -15px;
margin-left: 15px;
z-index: 999;
}
.switch > .far + .fa,
.switch:hover > .far {
display: none;
}
.switch:hover > .far + .fa {
display: inherit;
color: #0d1824;
}
/* ---------- fonts ---------- */
.font-bold {
font-family: "Inter-Bold";
text-transform: uppercase;
}
.font-small {
color: #0d1824;
font-size: 12px;
}
.header {
/*font-weight: bold;*/
/*text-transform: uppercase;*/
font-weight: 500;
cursor: pointer;
}
.header:hover {
font-weight: bold;
}
/* ---------- input ---------- */
.button {
background-color: white;
border: 1.5px solid #0d1824;
cursor: pointer;
}
.button:hover {
background-color: #0d1824;
color: white;
}
.btn-group button{
margin-top: 1px;
margin-bottom: 1px;
display: block;
width: 40px;
}
.draw {
display: none;
}
.phylo-focus {
fill: #f8381f;
color: #f8381f;
}
.reset {
visibility: hidden;
}
.label {
visibility: hidden;
}
.heading {
visibility: hidden;
}
.export {
visibility: hidden;
}
.headed {
background-color: #0d1824;
color: white;
}
.labeled {
background-color: #0d1824;
color: white;
}
.input-file {
display: inline-block;
cursor: pointer;
}
.input-file:hover {
border-bottom: 1.5px solid #0d1824;
}
.input-name {
font-style: italic;
opacity: 0.7;
font-size: 14px;
padding-left: 6px;
padding-right: 6px;
}
/* ---------- axis ---------- */
.x-axis path {
stroke: #EBE4DD;
stroke-width: 1.5px;
}
.y-axis path {
stroke: #EBE4DD;
stroke-width: 1.5px;
}
.y-highlight {
stroke: #f3be54;
stroke-width: 1.5px;
}
.x-mark {
fill: #4A5C70;
stroke-width: 1px;
stroke: #fff;
}
.x-mark-over {
fill: #f3be54;
}
.x-mark-focus {
fill: #f8381f;
}
.tick text {
font-family: "Inter-Regular";
}
.tick text:hover {
cursor: pointer;
}
.y-label {
font-size: 10px;
font-family: "Inter-Regular";
font-weight: normal;
}
.y-label-bold {
font-size: 12px;
font-family: "Inter-Bold";
font-weight: bold;
}
.y-mark-year-inner {
fill: #4A5C70;
}
.y-mark-year-inner-highlight {
fill: #f3be54;
}
.y-mark-year-outer {
fill: #fff;
stroke: #4A5C70;
stroke-width: 1px;
}
.y-mark-year-outer-highlight {
fill: #fff;
stroke: #f3be54;
stroke-width: 3px;
}
.y-mark-month {
fill: #4A5C70;
}
/* ---------- group ---------- */
.group-outer {
stroke-width: 0.8px;
stroke: #fff;
fill: #fff;
}
.group-inner {
stroke-width: 0.8px;
stroke: #0d1824;
fill: #0d1824;
/*cursor: pointer;*/
z-index: 10;
}
.group-heading {
fill: #fff;
stroke: #B5B5B5;
}
.group-focus {
stroke: #f8381f;
}
.source-focus {
stroke: #67a9cf;
}
.group-unfocus {
stroke: #A9A9A9;
}
.group-path {
cursor: pointer;
}
/* ---------- labels ---------- */
.ngrams {
visibility: hidden;
}
.term {
cursor: pointer;
}
.term:hover {
font-weight: bold;
fill: #f8381f;
}
// .term-unfocus {
// fill: #A9A9A9;
// }
// .term-focus {
// fill: black;
// }
.term-path {
fill: none;
stroke: #F0684D;
stroke-width: 1.5px;
}
.emerging {
/*text-decoration: underline #F0684D;*/
/*fill:#5AA350;*/
/*fill: #5AA350;*/
fill: #F8381F;
}
.decreasing {
/*text-decoration: underline #74B5FF;*/
fill: #11638F;
}
.path-focus {
fill: none;
stroke: #F0684D;
stroke-width: 1.5px;
}
.path-unfocus {
stroke: #A9A9A9;
}
.path-heading {
stroke: #B5B5B5;
}
/* ---------- phylo ---------- */
.branch-hover {
fill: #f3be54;
opacity: 0.5;
}
/* elements */
#file-path {
display: none;
}
/* axis */
.axisRight {
font-family: "Inter-Regular";
font-size: 10px;
}
/* isoline */
.peak {
stroke: white;
stroke-width: 1px;
font-family: "Inter-Regular";
font-size: 14px;
text-anchor: middle;
visibility: visible;
}
.peak-over {
font-size: 18px;
stroke-width: 2px;
cursor: pointer;
stroke: #f3be54;
z-index: 100;
}
.peak-focus {
font-size: 18px;
stroke-width: 2px;
stroke: #F0684D;
}
.peak-focus-source {
font-size: 18px;
stroke-width: 2px;
stroke: #67a9cf;
}
.peak-label {
text-align: center;
font-family: "Inter-Regular";
font-size: 14px;
font-style: normal;
font-weight: 400;
color: #FFFFFF;
border-radius: 3px;
border-style: solid;
border-width: 2px;
border-color: white;
background: #0d1824;
padding: 5px;
z-index: 10;
position: absolute;
visibility: hidden;
}
.word-cloud {
font-family: "Inter-Regular";
font-size: 12px;
}
.search {
margin-left: 10px;
visibility: hidden;
position: absolute;
z-index: 7;
font-size: 14px;
background-color: transparent;
outline: 0;
border-width: 0 0 2px;
border-color: #0d1824
}
.search-label {
visibility: hidden;
margin-left: 5px;
}
.search:focus {
border-color: #F0684D
}
.autocomplete {
margin-left: 10px;
visibility: hidden;
position: absolute;
z-index: 7;
font-size: 14px;
background-color: transparent;
color: silver;
z-index: 1;
border: none;
}
.loading {
visibility: hidden;
}
.phylo-name {
visibility:hidden;
text-transform: capitalize;
font-weight: bold;
}
.select-source {
margin-left: 10px;
display: none;
border: 1.5px solid #0d1824;
cursor: pointer;
outline: 0;
background: transparent;
border-image: none;
outline-offset: -2px;
outline-color: transparent;
box-shadow: none;
-webkit-appearance: none;
}
option {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 150px;
}
......@@ -8,3 +8,4 @@
@use "_range_slider.sass"
@use "_annotation.sass"
@use "_folder_view.sass"
@use "_phylo.scss"
This diff is collapsed.
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