Commit f6cec553 authored by Romain Loth's avatar Romain Loth

finish main vars repackaging + fix old bugs

renamed to TW.states and TW.gui + fixed old sliders caching bug + fixed node normalization in parsing
parent a6eb472f
......@@ -31,7 +31,7 @@ This will still evolve but the main steps for any graph initialization messily u
- prepares TW.Clusters: bins and facet index (node attr vals => nodes)
4. [`main.js`] mainStartGraph() function runs all the rest
1. precomputes display properties (grey color, etc.)
2. calls [`sigmaUtils`] where the function `FillGraph()` was a central point for filtering and preparing properties but now with 2 and 3 it just copies the nodes and edges to a new structure that groups them together
2. calls [`sigmaUtils`] where the function `FillGraph()` was a central point for filtering and preparing properties but now with 2 and 3 it just creates a filtered copy of the nodes and edges of the current active types to a new structure that groups them together (POSSIBLE remove this extra step)
3. back in [`main.js`], finally all sigma settings (user + defaults) are merged and we initialize the sigma instance (`new sigma` etc.)
4. finally a call to [`TinawebJS`] initializes the action listeners and this phase should crucially initialize items that need the sigma instance (because they may depend the displayed categories, the number of displayed nodes, etc)
......
......@@ -210,7 +210,7 @@ function SomeEffect( ValueclassCode ) {
// TW.partialGraph.graph.nodes(ID).customAttrs.forceLabel = true;
// }
// TW.selectionActive=true;
// TW.gui.selectionActive=true;
TW.partialGraph.refresh()
}
......@@ -507,7 +507,7 @@ function RenderTweet( tweet) {
//FOR UNI-PARTITE
// function selectionUni(currentNode){
// console.log("\tin selectionUni:"+currentNode.id);
// if(TW.checkBox==false && TW.circleSize==0) {
// if(TW.gui.checkBox==false && TW.gui.circleSize==0) {
// highlightSelectedNodes(false);
// opossites = [];
// selections = [];
......@@ -684,7 +684,7 @@ function circleTrackMouse(e) {
// }
// }
ctx.arc(x, y, TW.circleSize, 0, Math.PI * 2, true);
ctx.arc(x, y, TW.gui.circleSize, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
ctx.stroke();
......@@ -695,7 +695,7 @@ function circleTrackMouse(e) {
// exact subset of nodes under circle
function circleGetAreaNodes(camX0, camY0) {
var cursor_ray = TW.circleSize * TW.cam.ratio // converting TW.circleSize to cam units
var cursor_ray = TW.gui.circleSize * TW.cam.ratio // converting TW.gui.circleSize to cam units
// prepare an approximate neighborhood
var slightlyLargerNodeset = circleLocalSubset(
......
......@@ -68,6 +68,11 @@ TW.conf = (function(TW){
TWConf.nodeClusAtt = "modularity_class"
// to normalize node sizes: (NB not very useful because tina normalizes them at display)
TWConf.desirableNodeSizeMin=1;
TWConf.desirableNodeSizeMax=12;
// =============
// TINA BEHAVIOR
// =============
......@@ -216,9 +221,9 @@ TW.conf = (function(TW){
// show verbose console logs...
logFetchers: false, // ...about ajax/fetching of graph data
logParsers: false, // ...about parsing said data
logFacets: true, // ...about parsing node attribute:value facets
logFacets: false, // ...about parsing node attribute:value facets
logSettings: false, // ...about settings at Tina and Sigma init time
logSelections: true
logSelections: false
}
......
......@@ -89,7 +89,7 @@ function SelectionEngine() {
coincd.push(results[i].id)
}
var targeted = this.SelectorEngine( {
addvalue:TW.checkBox,
addvalue:TW.gui.checkBox,
prevsels:selections,
currsels:coincd
} )
......@@ -170,7 +170,7 @@ function SelectionEngine() {
var sameSideNeighbors = {}
var oppositeSideNeighbors = {}
// TW.partialGraph.states.slice(-1)[0] is the present graph state
// TW.states.slice(-1)[0] is the present graph state
// eg
// {categories: ["someNodeCat"]
// categoriesDict: {"someNodeCat":0} // where val 0 or 1 is type sem or soc
......@@ -284,7 +284,7 @@ function SelectionEngine() {
console.error("NaN selection key error")
}
TW.partialGraph.states.slice(-1)[0].selections = the_new_sels;
TW.states.slice(-1)[0].selections = the_new_sels;
TW.setState( { sels: the_new_sels} )
// alert("MultipleSelection2=======\nthe_new_sels:" + JSON.stringify(the_new_sels))
......@@ -337,7 +337,7 @@ function SelectionEngine() {
}
// global flag
TW.selectionActive = true
TW.gui.selectionActive = true
TW.partialGraph.render();
......@@ -591,7 +591,7 @@ var TinaWebJS = function ( sigmacanvas ) {
setTimeout(
function (){
targeted = selInst.SelectorEngine( {
addvalue:TW.checkBox,
addvalue:TW.gui.checkBox,
clicktype:"double",
prevsels:selections,
currsels:coincidences
......@@ -599,12 +599,12 @@ var TinaWebJS = function ( sigmacanvas ) {
// tricky stuff for simulating a multiple selection D:
// ... to be improved in the future ...
var prev_cursor_size = TW.circleSize;
var prev_cursor_size = TW.gui.circleSize;
if(targeted.length>0) {
TW.circleSize = (TW.circleSize==0)? 1 : TW.circleSize;
TW.gui.circleSize = (TW.gui.circleSize==0)? 1 : TW.gui.circleSize;
cancelSelection(false);
this.selInst.MultipleSelection2({nodes:targeted});
TW.circleSize = prev_cursor_size;
TW.gui.circleSize = prev_cursor_size;
}
$("input#searchinput").val("");
......@@ -638,7 +638,7 @@ var TinaWebJS = function ( sigmacanvas ) {
setTimeout(
function() {
targeted = selInst.SelectorEngine( {
addvalue:TW.checkBox,
addvalue:TW.gui.checkBox,
clicktype:"double",
prevsels:selections,
currsels:[exfnd.id]
......@@ -808,10 +808,10 @@ var TinaWebJS = function ( sigmacanvas ) {
step: 1,
min:TW.conf.circleSizeMin,
max:TW.conf.circleSizeMax,
value:TW.circleSize,
value:TW.gui.circleSize,
onchange:function(value){
// console.log("en cursorsize: "+value);
TW.circleSize=value;
TW.gui.circleSize=value;
}
});
......@@ -872,10 +872,10 @@ var TinaWebJS = function ( sigmacanvas ) {
// general listener: shift key in the window <=> add to selection
$(document).on('keyup keydown', function(e){
// changes the global boolean ("add node to selection" status) if keydown and SHIFT
TW.checkBox = TW.manuallyChecked || e.shiftKey
TW.gui.checkBox = TW.gui.manuallyChecked || e.shiftKey
// show it in the real TW.checkBox too
$('#checkboxdiv').prop("checked", TW.manuallyChecked || e.shiftKey)
// show it in the real TW.gui.checkBox too
$('#checkboxdiv').prop("checked", TW.gui.manuallyChecked || e.shiftKey)
} );
} // finish envListeners
......@@ -894,7 +894,7 @@ var TinaWebJS = function ( sigmacanvas ) {
// cases:
// 'click' - simple click, early event
// used for area (with global: TW.circleSize)
// used for area (with global: TW.gui.circleSize)
// 'clickNode'- simple click, second event if one node
// POSS easy in new sigma.js:
......@@ -908,7 +908,7 @@ var TinaWebJS = function ( sigmacanvas ) {
// console.log("sigma click event e", e)
// case with a selector circle cursor handled here
if (TW.circleSize > 0) {
if (TW.gui.circleSize > 0) {
// actual click position, but in graph coords
var x = e.data.x
var y = e.data.y
......@@ -916,19 +916,19 @@ var TinaWebJS = function ( sigmacanvas ) {
// convert
var camCoords = TW.cam.cameraPosition(x,y)
// retrieve area nodes, using indexed quadtree and global TW.circleSize
// retrieve area nodes, using indexed quadtree and global TW.gui.circleSize
var circleNodes = circleGetAreaNodes(
camCoords.x,
camCoords.y
)
// 1) clear previous while keeping its list (useful iff 'Add' TW.checkBox)
// 1) clear previous while keeping its list (useful iff 'Add' TW.gui.checkBox)
var previousSelection = selections
cancelSelection(false)
// 2) show selection + do all related effects
var targeted = selInst.SelectorEngine( {
addvalue:TW.checkBox,
addvalue:TW.gui.checkBox,
currsels:circleNodes,
prevsels:previousSelection
} )
......@@ -950,9 +950,9 @@ var TinaWebJS = function ( sigmacanvas ) {
var previousSelection = selections
cancelSelection(false, {norender:true}); // no need to render before MS2
if (TW.circleSize == 0) {
if (TW.gui.circleSize == 0) {
var targeted = selInst.SelectorEngine( {
addvalue:TW.checkBox,
addvalue:TW.gui.checkBox,
currsels:[theNodeId],
prevsels:previousSelection
} )
......@@ -972,7 +972,7 @@ var TinaWebJS = function ( sigmacanvas ) {
if (! e.data.captor.isDragging
&& Object.keys(selections).length
&& ! TW.circleSize) {
&& ! TW.gui.circleSize) {
// we clear selections and all its effects
cancelSelection(false);
......@@ -1003,7 +1003,7 @@ var TinaWebJS = function ( sigmacanvas ) {
.mousemove(function(e){
if(!isUndef(partialGraph)) {
// show/move selector circle cursor
if(TW.circleSize>0) circleTrackMouse(e);
if(TW.gui.circleSize>0) circleTrackMouse(e);
}
})
......
This diff is collapsed.
This diff is collapsed.
'use strict';
// @args is an object with 4 possible properties that define the new state
// ex: new selections: {sels: [268]}
// ex: new activetypes: {activetypes:[false, true]}
// ex: new level: {level:false}
TW.setState = function( args ) {
var bistate=false, typesKey=false;
// £TODO we could append the new state in this function too
var present = TW.states.slice(-1)[0]; // Last
var past = TW.states.slice(-2)[0] // avant Last
console.log("setState args: ", args);
if(!isUndef(args.activetypes)) {
// record into last state
present.activetypes = args.activetypes;
bistate= present.activetypes.map(Number).reduce(
function(a, b){return a+b;}
)
typesKey = present.activetypes.map(Number).join("|")
}
// console.log("printing the typesKey:", typesKey)
if(!isUndef(args.level)) present.level = args.level;
if(!isUndef(args.sels)) present.selections = args.sels;
if(!isUndef(args.oppos)) present.opposites = args.oppos;
present.LouvainFait = false;
// change level needs a selection
LevelButtonDisable(false); // £TODO rename toggleLevelButton
if( present.level
&& present.selections
&& present.selections.length==0)
LevelButtonDisable(true);
// case to go back
if(present.level==false && bistate>1)
LevelButtonDisable(true)
// recreate sliders after activetype or level changes
if (TW.conf.filterSliders
&& (present.level != past.level
|| present.activetypes.map(Number).join("|") != past.activetypes.map(Number).join("|"))) {
// terms
if(typesKey=="0|1") {
$(".for-nodecategory-0").hide()
$(".for-nodecategory-1").show();
NodeWeightFilter( "#slidercat1nodesweight" , TW.categories[1], "size");
EdgeWeightFilter("#slidercat1edgesweight", typesKey, "weight");
}
// docs
if(typesKey=="1|0") {
$(".for-nodecategory-0").show()
$(".for-nodecategory-1").hide();
NodeWeightFilter( "#slidercat0nodesweight" , TW.categories[0], "size");
EdgeWeightFilter("#slidercat0edgesweight", typesKey, "weight");
}
// terms and docs
if(typesKey=="1|1") {
$(".for-nodecategory-0").show()
$(".for-nodecategory-1").show();
NodeWeightFilter( "#slidercat0nodesweight" , TW.categories[0], "size");
NodeWeightFilter( "#slidercat1nodesweight" , TW.categories[1], "size");
EdgeWeightFilter("#slidercat0edgesweight", "1|0", "weight");
EdgeWeightFilter("#slidercat1edgesweight", "0|1", "weight");
}
}
};
// settings: {norender: Bool}
function cancelSelection (fromTagCloud, settings) {
if (TW.conf.debug.logSelections) { console.log("\t***in cancelSelection"); }
......@@ -12,10 +93,10 @@ function cancelSelection (fromTagCloud, settings) {
//selections.length = 0;
selections.splice(0, selections.length);
TW.partialGraph.states.slice(-1)[0].selections=[]
TW.states.slice(-1)[0].selections=[]
// global flag
TW.selectionActive = false
TW.gui.selectionActive = false
//Edges colors go back to normal
......@@ -75,7 +156,7 @@ function cancelSelection (fromTagCloud, settings) {
deselections={};
if(TW.partialGraph.states.slice(-1)[0].level)
if(TW.states.slice(-1)[0].level)
LevelButtonDisable(true);
if (!settings.norender) {
......@@ -91,7 +172,7 @@ function cancelSelection (fromTagCloud, settings) {
function getActivetypes() {
let currentTypes = []
let currentTypeIdx
let lastState = TW.partialGraph.states.slice(-1)[0]
let lastState = TW.states.slice(-1)[0]
for (var possType in TW.catDict) {
currentTypeIdx = TW.catDict[possType]
......@@ -105,7 +186,7 @@ function getActivetypes() {
}
function getActivetypesKey() {
let lastState = TW.partialGraph.states.slice(-1)[0]
let lastState = TW.states.slice(-1)[0]
// ex: '1' or '0|1' or '1|1'
return lastState.activetypes.map(Number).join('|')
......@@ -142,11 +223,11 @@ function highlightSelectedNodes(flag){
function alertCheckBox(eventCheck){
// NB: we use 2 booleans to adapt to SHIFT checking
// - var TW.checkBox ---------> has the real box state
// - var TW.manuallyChecked --> remembers if it was changed here
// - var TW.gui.checkBox ---------> has the real box state
// - var TW.gui.manuallyChecked --> remembers if it was changed here
if(!isUndef(eventCheck.checked)) {
TW.checkBox=eventCheck.checked;
TW.manuallyChecked = eventCheck.checked
TW.gui.checkBox=eventCheck.checked;
TW.gui.manuallyChecked = eventCheck.checked
}
}
......@@ -403,14 +484,16 @@ function htmlProportionalLabels(elems , limit, selectableFlag) {
let frecMax = elems[0].value
let frecMin = elems.slice(-1)[0].value
let sourceRange = frecMax - frecMin
let targetRange = TW.conf.tagcloudFontsizeMax - TW.conf.tagcloudFontsizeMin
for(var i in elems){
if(i==limit)
break
let id=elems[i].key
let frec=elems[i].value
// FIXME: works but is optimizable (precompute stable part)
fontSize = ((frec - frecMin) * (TW.conf.tagcloudFontsizeMax - TW.conf.tagcloudFontsizeMin) / (frecMax - frecMin)) + TW.conf.tagcloudFontsizeMin
fontSize = ((frec - frecMin) * (targetRange) / (sourceRange)) + TW.conf.tagcloudFontsizeMin
// debug
// console.log('htmlfied_tagcloud (',id, TW.Nodes[id].label,') freq',frec,' fontSize', fontSize)
......@@ -588,21 +671,21 @@ function graphTagCloudElem(nodes) {
nodesDict:nodes_2_colour,
edgesDict:edges_2_colour
});
TW.selectionActive = true
TW.gui.selectionActive = true
}
var present = TW.partialGraph.states.slice(-1)[0]; // Last
var present = TW.states.slice(-1)[0]; // Last
var level = present.level;
var lastpos = TW.partialGraph.states.length-1;
var lastpos = TW.states.length-1;
// like pushing down in a lifo state present becomes state penultimate
// £TODO setState should be doing this shifting
var avantlastpos = lastpos-1;
TW.partialGraph.states[avantlastpos] = {};
TW.partialGraph.states[avantlastpos].selections = present.selections;
TW.partialGraph.states[avantlastpos].level = present.level;
TW.partialGraph.states[avantlastpos].activetypes = present.activetypes;
TW.partialGraph.states[avantlastpos].opposites = present.opposites;
TW.states[avantlastpos] = {};
TW.states[avantlastpos].selections = present.selections;
TW.states[avantlastpos].level = present.level;
TW.states[avantlastpos].activetypes = present.activetypes;
TW.states[avantlastpos].opposites = present.opposites;
// recording the new state
TW.setState({
......@@ -839,16 +922,6 @@ function add1Elem(id) {
}
}
function pushFilterValue(filtername,arg){
if(lastFilter[filtername]["orig"]=="-") {
lastFilter[filtername]["orig"] = arg;
lastFilter[filtername]["last"] = arg;
return;
} else {
lastFilter[filtername]["last"] = arg;
return;
}
}
function saveGraph() {
......
......@@ -37,6 +37,7 @@ var ParseCustom = function ( format , data ) {
this.parseJSON = function(categories ) {
return dictfyJSON( this.data , categories );
}// output = [ nodes, edges, nodes1, ... ]
};
// Level-02
......@@ -457,8 +458,10 @@ function dictfyGexf( gexf , categories ){
var elsNodes = gexf.getElementsByTagName('nodes') // The list of xml nodes 'nodes' (plural)
TW.labels = [];
minNodeSize=10000000;
maxNodeSize=0;
// vars for stats => used in a posteriori normalization
let minNodeSize = Infinity
let maxNodeSize = 0
// debug: for local stats
// let allSizes = []
......@@ -561,7 +564,7 @@ function dictfyGexf( gexf , categories ){
node.attributes = atts;
let node_cat = ""
// nodew=parseInt(attributes["weight"]);
if ( atts["category"] ) {
node_cat = atts["category"];
}
......@@ -585,11 +588,11 @@ function dictfyGexf( gexf , categories ){
// save record
nodes[node.id] = node
if(parseInt(node.size) < parseInt(minNodeSize))
minNodeSize= node.size;
if(parseFloat(node.size) < minNodeSize)
minNodeSize= parseFloat(node.size);
if(parseInt(node.size) > parseInt(maxNodeSize))
maxNodeSize= node.size;
if(parseFloat(node.size) > maxNodeSize)
maxNodeSize= parseFloat(node.size);
// console.debug("node.attributes", node.attributes)
// creating a faceted index from node.attributes
......@@ -620,13 +623,15 @@ function dictfyGexf( gexf , categories ){
TW.Clusters = facetsBinning(tmpVals, Atts_2_Exclude)
//New scale for node size: now, between 2 and 5 instead [1,70]
for(var nid in nodes){
// console.log("dictfyGexf node", nid)
nodes[nid].size = desirableNodeSizeMIN+ (parseInt(nodes[nid].size)-1)*((desirableNodeSizeMAX-desirableNodeSizeMIN) / (maxNodeSize-minNodeSize));
// linear rescale node sizes
if (!isUndef(TW.conf.desirableNodeSizeMin) && !isUndef(TW.conf.desirableNodeSizeMax)) {
let desiSizeRange = TW.conf.desirableNodeSizeMax-TW.conf.desirableNodeSizeMin
let realSizeRange = maxNodeSize - minNodeSize
for(var nid in nodes){
nodes[nid].size = parseInt(1000 * ((parseFloat(nodes[nid].size) - minNodeSize) / realSizeRange * desiSizeRange + TW.conf.desirableNodeSizeMin)) / 1000
}
}
// looping source edges to conforming edge
// then updateRelations
var edgeId = 0;
......@@ -908,6 +913,10 @@ function dictfyJSON( data , categories ) {
nodes2={}, bipartiteD2N={}, bipartiteN2D={}
}
// normalization, same as parseGexf
let minNodeSize = Infinity
let maxNodeSize = 0
// if scanClusters, we'll also use:
var tmpVals = {}
var Atts_2_Exclude = {}
......@@ -936,6 +945,12 @@ function dictfyJSON( data , categories ) {
node.size = Math.sqrt(Number(n.term_occ))
}
if(parseFloat(node.size) < minNodeSize)
minNodeSize= parseFloat(node.size);
if(parseFloat(node.size) > maxNodeSize)
maxNodeSize= parseFloat(node.size);
if (!catCount[node.type]) catCount[node.type] = 0
catCount[node.type]++;
......@@ -952,6 +967,17 @@ function dictfyJSON( data , categories ) {
TW.Clusters = facetsBinning (tmpVals, Atts_2_Exclude)
// £TODO ask if wanted
// if we wanted linear rescale node sizes like dictfyGexf:
// if (!isUndef(TW.conf.desirableNodeSizeMin) && !isUndef(TW.conf.desirableNodeSizeMax)) {
// let desiSizeRange = TW.conf.desirableNodeSizeMax-TW.conf.desirableNodeSizeMin
// let realSizeRange = maxNodeSize - minNodeSize
// for(var nid in nodes){
// nodes[nid].size = parseInt(1000 * ((parseFloat(nodes[nid].size) - minNodeSize) / realSizeRange * desiSizeRange + TW.conf.desirableNodeSizeMin)) / 1000
// }
// }
TW.colorList.sort(function(){ return Math.random()-0.5; });
for (var i in nodes ){
if (nodes[i].color=="#FFFFFF") {
......
......@@ -292,7 +292,7 @@ var SigmaUtils = function () {
var nodeColor = node.color || settings('defaultNodeColor')
// mode variants
if (TW.selectionActive) {
if (TW.gui.selectionActive) {
// passive nodes should blend in the grey of twEdgeGreyColor
// cf settings_explorerjs, defgrey_color and greyEverything()
if (node.customAttrs.grey) {
......@@ -1180,9 +1180,9 @@ function colorsBy(daclass) {
// louvain needs preparation
if(daclass=="clust_louvain") {
if(!TW.partialGraph.states.slice(-1)[0].LouvainFait) {
if(!TW.states.slice(-1)[0].LouvainFait) {
RunLouvain()
TW.partialGraph.states.slice(-1)[0].LouvainFait = true
TW.states.slice(-1)[0].LouvainFait = true
}
}
......
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