Commit 4b40520a authored by Romain Loth's avatar Romain Loth

restabilize facets and legends details

better facet-options modal dialog layout + better conditional fill values in form + spacing in titling metric + no need to hard-code dynamic attrs options in html since they were added to TW.Facets in commit c4a93fb1 + sigmaListeners needed to create forms *after* dynamic attrs first scan
parent b276cb07
......@@ -661,15 +661,22 @@
<select id="choose-attr" name="choose-attr"
class="custom-select form-control">
<option selected value="0"></option>
<option value="auto-size" data-opttype="auto">Auto size</option>
<option value="auto-degree" data-opttype="auto">Auto degree</option>
<option value="auto-indegree" data-opttype="auto">Auto in degree</option>
<option value="auto-outdegree" data-opttype="auto">Auto out degree</option>
<!-- filled by fillAttrsInForm(.) -->
</select>
</div>
</div>
<div class="question">
<div class="input-group">
<label for="attr-translation" class="smlabel input-group-addon">Legend</label>
<input id="attr-translation" name="attr-translation" maxlength="70"
type="text" class="form-control autocomp" placeholder="A label for this attribute"
>
</div>
<p class="legend">Will be displayed in the color menu and legends box.</p>
</div>
<div class="question">
<div class="input-group">
<label for="attr-col" class="smlabel input-group-addon">Coloring function</label>
......@@ -684,31 +691,6 @@
</div>
</div>
<!-- this titling functionality is like a head -n inside each class -->
<div class="question conditional-q" id="choose-titling-div">
<p class="legend">Please choose a size/weight metric used to rank the "title-candidates" inside each cluster.</p>
<div class="input-group">
<label for="attr-titling-metric" class="smlabel input-group-addon">Titling metric</label>
<select id="attr-titling-metric" name="attr-titling-metric"
class="custom-select form-control">
<option value="auto-size" data-opttype="auto">Auto size</option>
<option value="auto-degree" data-opttype="auto">Auto degree</option>
<option value="auto-indegree" data-opttype="auto">Auto in degree</option>
<option value="auto-outdegree" data-opttype="auto">Auto out degree</option>
<!-- other attrs filled by fillAttrsInForm(., 'num') -->
</select>
</div>
<div class="input-group" style="margin-top:.5em;">
<label for="attr-titling-n" class="smlabel input-group-addon">Number of terms</label>
<input id="attr-titling-n" name="attr-titling-n" maxlength="2"
type="text" class="form-control autocomp" placeholder="number of node labels to pick as title (1-10)"
onchange="let castint = parseInt(this.value) ; if (castint != this.value || castint < 1) {this.value = 1} else if(castint > 10) {this.value = 10}"
>
</div>
</div>
<div class="question">
<div class="input-group">
<label for="attr-binmode" class="smlabel input-group-addon">Binning Mode</label>
......@@ -733,12 +715,25 @@
<p class="legend">Please input an integer value between 2 and 24.</p>
</div>
<div class="question input-group">
<label for="attr-translation" class="smlabel input-group-addon"> Title </label>
<input id="attr-translation" name="attr-translation" maxlength="70"
type="text" class="form-control autocomp" placeholder="a text for the color menu"
>
</div>
<!-- this titling functionality is like a head -n inside each class -->
<div class="question conditional-q" id="choose-titling-div">
<p class="legend">Please choose a size/weight metric used to rank the "title-candidates" inside each cluster.</p>
<div class="input-group">
<label for="attr-titling-metric" class="smlabel input-group-addon">Titling metric</label>
<select id="attr-titling-metric" name="attr-titling-metric"
class="custom-select form-control">
<!-- other attrs filled by fillAttrsInForm(., 'num') -->
</select>
</div>
<div class="input-group" style="margin-top:.5em;">
<label for="attr-titling-n" class="smlabel input-group-addon">Number of terms</label>
<input id="attr-titling-n" name="attr-titling-n" maxlength="2"
type="text" class="form-control autocomp" placeholder="number of node labels to pick as title (1-10)"
onchange="let castint = parseInt(this.value) ; if (castint != this.value || castint < 1) {this.value = 1} else if(castint > 10) {this.value = 10}"
>
</div>
</div>
</form>
......
......@@ -67,10 +67,10 @@ TW.conf = (function(TW){
TWConf.defaultFacetOptions = {
// attr title coloring fun nbins binning strategy label in menus
'auto-size' : {'col': "gradient", 'n': 6, 'binmode': 'samerange' },
'auto-degree' : {'col': "heatmap", 'n': 7, 'binmode': 'samepop' },
'auto-indegree' : {'col': "heatmap", 'n': 7, 'binmode': 'samepop' },
'auto-outdegree' : {'col': "heatmap", 'n': 7, 'binmode': 'samepop' },
'auto-size' : {'col': "gradient", 'n': 6, 'binmode': 'samerange', 'legend': 'Auto Size' },
'auto-degree' : {'col': "heatmap", 'n': 7, 'binmode': 'samepop', 'legend': 'Auto Degree'},
'auto-indegree' : {'col': "heatmap", 'n': 7, 'binmode': 'samepop', 'legend': 'Auto InDegree'},
'auto-outdegree' : {'col': "heatmap", 'n': 7, 'binmode': 'samepop', 'legend': 'Auto OutDegree'},
'cluster_index' : {'col': "cluster" , 'binmode': 'off' },
'clust_louvain' : {'col': "cluster" , 'binmode': 'off',
'legend':'Louvain clustering' },
......
......@@ -879,6 +879,7 @@ var TinaWebJS = function ( sigmacanvas ) {
// to init local, instance-related listeners (need to run at new sigma instance)
// args: @partialGraph = a sigma instance
// accessed globals: TW.Facets
this.initSigmaListeners = function(partialGraph, initialActivetypes, initialActivereltypes, optionalRelDocsConf) {
// console.log("initSigmaListeners TW.categories / types array / reltypeskeys array: ", TW.categories, initialActivetypes, initialActivereltypes)
......
......@@ -50,8 +50,7 @@ function updateDynamicFacets(optionalFilter) {
let autoFacets = facetsBinning(autoVals)
// merge them into clusters
for (var icat in TW.categories) {
let nodecat = TW.categories[icat]
for (var nodecat in TW.catDict) {
for (var autoAttr in TW.sigmaAttributes) {
for (var facet in autoFacets[nodecat]) {
TW.Facets[nodecat][facet] = autoFacets[nodecat][facet]
......@@ -382,7 +381,7 @@ function set_ClustersLegend ( daclass, groupedByTicks ) {
}
// replacing the cluster numbers by those k best titles in the legend
preparedLabel = "["+titles.map(function(x){return x.key}).join('/')+"...]" + ` (${nMatchedNodes})`
preparedLabel = "["+titles.map(function(x){return x.key}).join(' / ')+"...]" + ` (${nMatchedNodes})`
// console.log("finding title perf", performance.now() - t0, titles)
}
......@@ -1001,29 +1000,42 @@ function activateModules() {
// cf. doc/developer_manual.md autodiagnose remark)
function fillAttrsInForm(menuId, optionalAttTypeConstraint) {
var actypes = getActivetypesNames()
for (let tid in actypes) {
let ty = actypes[tid]
let elChooser = document.getElementById(menuId)
// remove any previous fromFacets options from possible previous graphs
let autoOptions = document.getElementById(menuId).querySelectorAll('option[data-opttype=fromFacets]')
for (var i = 0 ; i <= autoOptions.length - 1 ; i++) {
elChooser.removeChild(autoOptions[i])
}
// 1- remove any previous fromFacets options from possible previous graphs
let autoOptions = document.getElementById(menuId).querySelectorAll('option[data-opttype=fromFacets]')
for (var i = 0 ; i <= autoOptions.length - 1 ; i++) {
elChooser.removeChild(autoOptions[i])
}
// each facet family or clustering type was already prepared
for (let att in TW.Facets[ty]) {
// 2- ls | uniq all options (no matter what active type they belong too)
let uniqOptions = {}
for (let tid in actypes) {
let ty = actypes[tid]
for (var att in TW.Facets[ty]) {
if (!optionalAttTypeConstraint
|| ( TW.Facets[ty][att].meta.dataType
&& TW.Facets[ty][att].meta.dataType == optionalAttTypeConstraint)) {
let opt = document.createElement('option')
opt.value = att
opt.innerText = att
opt.dataset.opttype = "fromFacets"
elChooser.appendChild(opt)
}
uniqOptions[att] = true
}
}
}
// 3- write to DOM
let elChooser = document.getElementById(menuId)
for (var att in uniqOptions) {
// <option> creation
// -------------------
// each facet family or clustering type was already prepared
let opt = document.createElement('option')
opt.value = att
opt.innerText = att
if (att in TW.sigmaAttributes) {
opt.dataset.opttype = "auto"
}
else {
opt.dataset.opttype = "fromFacets"
}
elChooser.appendChild(opt)
}
}
......@@ -1046,44 +1058,42 @@ function conditiOpen(subQId, mainQId, mainQOkValues) {
// attr-col change has complex consequences
function colChangedHandler() {
// for titling subquestion open
conditiOpen('choose-titling-div', 'attr-col',['cluster'])
// for the implication [cluster => binmode off]
// for the implication [cluster => grey freeze binmode off but keep it shown,
// other => reactivate ]
// (no sense to ordinally bin clusters)
let elColQ = document.getElementById('attr-col')
let elBinmodeQ = document.getElementById('attr-binmode')
if (elColQ.value == 'cluster') {
elBinmodeQ.value = "off"
elBinmodeQ.disabled = true
document.getElementById("attr-nbins-div").style.display = 'none'
elBinmodeQ.style.backgroundColor = "#777"
}
else {
elBinmodeQ.disabled = false
elBinmodeQ.style.backgroundColor = ""
}
// for titling subquestion show
conditiOpen('choose-titling-div', 'attr-col',['cluster'])
// for nbins subquestion show
conditiOpen('attr-nbins-div', 'attr-binmode',['samepop', 'samerange'])
}
function showAttrConf() {
let attrTitle = this.value
let settings = TW.facetOptions[attrTitle]
if (settings) {
document.getElementById('attr-col').value = settings.col || 'gradient'
document.getElementById('attr-binmode').value = settings.binmode || 'off'
document.getElementById('attr-translation').value = settings.legend || attrTitle
if(settings.n) {
document.getElementById('attr-nbins-div').style.display = 'block'
document.getElementById('attr-nbins').value = settings.n || 5
}
if(settings.col == 'cluster') {
document.getElementById('choose-titling-div').style.display = 'block'
document.getElementById('attr-titling-metric').value = settings.titlingMetric || ''
document.getElementById('attr-titling-n').value = settings.titlingNTerms || 1
// no sense to ordinally bin clusters
document.getElementById('attr-binmode').value = "off"
document.getElementById('attr-binmode').disabled = true
}
}
let settings = TW.facetOptions[attrTitle] || {}
document.getElementById('attr-translation').value = settings.legend || attrTitle
document.getElementById('attr-col').value = settings.col || 'gradient'
document.getElementById('attr-binmode').value = settings.binmode || 'off'
document.getElementById('attr-nbins').value = settings.n || TW.conf.legendsBins || 5
document.getElementById('attr-titling-metric').value = settings.titlingMetric || 'auto-size'
document.getElementById('attr-titling-n').value = settings.titlingNTerms || 2
// make the binmode and titling details adapt to choosen settings.col
colChangedHandler()
}
......
......@@ -518,7 +518,13 @@ function mainStartGraph(inFormat, inData, twInstance) {
// NB : camera positions are fix if the node is fixed => they only depend on layout
// renderer position depend on viewpoint/zoom (like ~ html absolute positions of the node in the div)
// now that we have a sigma instance let's adapt the environment and bind our click handlers to it
// prepare the colors/clusters menu until next changeType/changeLevel
// (and update TW.Facets)
updateDynamicFacets()
changeGraphAppearanceByFacets()
// now that we have a sigma instance and TW.Facets
// let's adapt the environment and bind our click handlers to it
twInstance.initSigmaListeners(
TW.partialGraph,
initialActivetypes, // to init node sliders and .class gui elements
......@@ -578,10 +584,6 @@ function mainStartGraph(inFormat, inData, twInstance) {
// will run fa2 if enough nodes and TW.conf.fa2Enabled == true
sigma_utils.smartForceAtlas()
// prepare the colors/clusters menu until next changeType/changeLevel
updateDynamicFacets()
changeGraphAppearanceByFacets()
}
}
......
......@@ -66,7 +66,11 @@ TW.conf = (function(TW){
// (values overridden by data/myproject/project_conf.json "facets" if present)
TWConf.defaultFacetOptions = {
// attr title
// attr title coloring fun nbins binning strategy label in menus
'auto-size' : {'col': "gradient", 'n': 6, 'binmode': 'samerange', 'legend': 'Auto Size' },
'auto-degree' : {'col': "heatmap", 'n': 7, 'binmode': 'samepop', 'legend': 'Auto Degree'},
'auto-indegree' : {'col': "heatmap", 'n': 7, 'binmode': 'samepop', 'legend': 'Auto InDegree'},
'auto-outdegree' : {'col': "heatmap", 'n': 7, 'binmode': 'samepop', 'legend': 'Auto OutDegree'},
'cluster_index' : {'col': "cluster" , 'binmode': 'off' },
'clust_louvain' : {'col': "cluster" , 'binmode': 'off',
'legend':'Louvain clustering' },
......@@ -178,7 +182,7 @@ TW.conf = (function(TW){
TWConf.histogramStartThreshold = 10 ; // for daily histo module
// (from how many docs are significant)
TWConf.maxPastStates = 5 ; // number of TW.states to remember (~CTRL-Z)
TWConf.maxPastStates = 15 ; // number of TW.states to remember (~CTRL-Z)
// Layout options
......
......@@ -66,7 +66,11 @@ TW.conf = (function(TW){
// (values overridden by data/myproject/project_conf.json "facets" if present)
TWConf.defaultFacetOptions = {
// attr title
// attr title coloring fun nbins binning strategy label in menus
'auto-size' : {'col': "gradient", 'n': 6, 'binmode': 'samerange', 'legend': 'Auto Size' },
'auto-degree' : {'col': "heatmap", 'n': 7, 'binmode': 'samepop', 'legend': 'Auto Degree'},
'auto-indegree' : {'col': "heatmap", 'n': 7, 'binmode': 'samepop', 'legend': 'Auto InDegree'},
'auto-outdegree' : {'col': "heatmap", 'n': 7, 'binmode': 'samepop', 'legend': 'Auto OutDegree'},
'cluster_index' : {'col': "cluster" , 'binmode': 'off' },
'clust_louvain' : {'col': "cluster" , 'binmode': 'off',
'legend':'Louvain clustering' },
......@@ -165,7 +169,7 @@ TW.conf = (function(TW){
// TW.geomap = false;
// TW.twittertimeline = false;
TWConf.maxPastStates = 5 ; // number of TW.states to remember (~CTRL-Z)
TWConf.maxPastStates = 15 ; // number of TW.states to remember (~CTRL-Z)
// Layout options
......
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