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);
}
})
......
......@@ -78,9 +78,9 @@ function createFilechooserEl () {
// Documentation Level: *****
function changeType() {
var present = TW.partialGraph.states.slice(-1)[0]; // Last
var past = TW.partialGraph.states.slice(-2)[0] // avant Last
var lastpos = TW.partialGraph.states.length-1;
var present = TW.states.slice(-1)[0]; // Last
var past = TW.states.slice(-2)[0] // avant Last
var lastpos = TW.states.length-1;
var avantlastpos = lastpos-1;
......@@ -327,15 +327,15 @@ function changeType() {
// edgesDict:edges_2_colour
// });
TW.instance.selNgn.MultipleSelection2({ nodes: sels });
TW.selectionActive=true;
TW.gui.selectionActive=true;
}
TW.partialGraph.states[avantlastpos] = {};
TW.partialGraph.states[avantlastpos].LouvainFait = false;
TW.partialGraph.states[avantlastpos].level = present.level;
TW.partialGraph.states[avantlastpos].selections = selsbackup;
TW.partialGraph.states[avantlastpos].activetypes = present.activetypes;
TW.partialGraph.states[avantlastpos].opposites = present.opposites;
TW.states[avantlastpos] = {};
TW.states[avantlastpos].LouvainFait = false;
TW.states[avantlastpos].level = present.level;
TW.states[avantlastpos].selections = selsbackup;
TW.states[avantlastpos].activetypes = present.activetypes;
TW.states[avantlastpos].opposites = present.opposites;
TW.setState({
activetypes: nextState,
......@@ -365,7 +365,7 @@ function changeType() {
// v
// local selection SysSt = {level: false, type:XY}
//
// where SysSt is the last state aka TW.partialGraph.states.slice(-1)[0]
// where SysSt is the last state aka TW.states.slice(-1)[0]
// and SysSt.level is aka swMacro
function changeLevel() {
......@@ -374,13 +374,13 @@ function changeLevel() {
// let the waiting cursor appear
setTimeout(function() {
var present = TW.partialGraph.states.slice(-1)[0]; // Last
var past = TW.partialGraph.states.slice(-2)[0] // avant Last
var lastpos = TW.partialGraph.states.length-1;
var present = TW.states.slice(-1)[0]; // Last
var past = TW.states.slice(-2)[0] // avant Last
var lastpos = TW.states.length-1;
var avantlastpos = lastpos-1;
var level = present.level;
var sels = present.selections;//[144, 384, 543]//TW.partialGraph.states.selections;
var sels = present.selections;//[144, 384, 543]//TW.states.selections;
// type "grammar"
......@@ -473,18 +473,18 @@ function changeLevel() {
nodesDict:nodes_2_colour,
edgesDict:edges_2_colour
});
TW.selectionActive=true;
TW.gui.selectionActive=true;
}
}
// console.log("enviroment changeLevel nodes_2_colour", nodes_2_colour)
TW.partialGraph.states[avantlastpos] = {};
TW.partialGraph.states[avantlastpos].level = present.level;
TW.partialGraph.states[avantlastpos].selections = present.selections;
TW.partialGraph.states[avantlastpos].activetypes = present.activetypes;
TW.partialGraph.states[avantlastpos].opposites = present.opposites;
TW.states[avantlastpos] = {};
TW.states[avantlastpos].level = present.level;
TW.states[avantlastpos].selections = present.selections;
TW.states[avantlastpos].activetypes = present.activetypes;
TW.states[avantlastpos].opposites = present.opposites;
TW.setState({
activetypes: present.activetypes,
......@@ -580,11 +580,11 @@ function EdgeWeightFilter(sliderDivID , typestr , criteria) {
}
var lastvalue=("0-"+(steps-1));
// cache initial value
var initialValue=("0-"+(steps-1));
TW.gui.lastFilters[sliderDivID] = initialValue
pushFilterValue( sliderDivID , lastvalue )
var present = TW.partialGraph.states.slice(-1)[0];
var present = TW.states.slice(-1)[0];
// console.log('init freshslider for edges, steps:', steps, sliderDivID)
......@@ -606,7 +606,7 @@ function EdgeWeightFilter(sliderDivID , typestr , criteria) {
onchange:function(low, high) {
theHtml.classList.add('waiting');
// 500ms timeout to let the waiting cursor appear
// 40ms timeout to let the waiting cursor appear
setTimeout(function() {
var totalDeletingTime = 0
......@@ -619,17 +619,14 @@ function EdgeWeightFilter(sliderDivID , typestr , criteria) {
// scheduled: costly graph rm edges
edgeSlideTimeout = setTimeout ( function () {
var filtervalue = low+"-"+high
if(filtervalue!=lastFilter[sliderDivID]["last"]) {
// £TODO better memoize the last filter value
// $.doTimeout(sliderDivID+"_"+lastFilter[sliderDivID]["last"]);
var filtervalue = low+"-"+high
var lastvalue = TW.gui.lastFilters[sliderDivID]
// sliderDivID+"_"+filtervalue
// sliderDivID+"_"+filtervalue
// console.debug("\nprevious value "+lastvalue+" | current value "+filtervalue)
console.log("\nprevious value "+lastvalue+" | current value "+filtervalue)
if(filtervalue!=lastvalue) {
// [ Stopping FA2 ]
if (TW.partialGraph.isForceAtlas2Running())
......@@ -643,7 +640,6 @@ function EdgeWeightFilter(sliderDivID , typestr , criteria) {
var iterarr = []
if(mint0!=mint1) {
if(mint0<mint1) {
delflag = true;
......@@ -760,19 +756,23 @@ function EdgeWeightFilter(sliderDivID , typestr , criteria) {
}, 10)
// [ / Starting FA2 ]
lastvalue = filtervalue;
pushFilterValue( sliderDivID , filtervalue )
console.log("lastvalue===", lastvalue)
TW.gui.lastFilters[sliderDivID] = lastvalue
// pushFilterValue( sliderDivID , lastvalue )
}
else {
// console.log('edges:::same position')
}
// in any case
setTimeout( function() {
theHtml.classList.remove('waiting')
}, 20)
}, 700) // large-ish debounce timeout
}, 1500) // large-ish debounce timeout
}, 500) // wait cursor timeout
}, 40) // wait cursor timeout
}
});
......@@ -824,7 +824,10 @@ function NodeWeightFilter( sliderDivID , tgtNodeType , criteria) {
var nodeSlideTimeout = null
//finished
// cache initial value
TW.gui.lastFilters[sliderDivID] = `0-${steps-1}`
// freshslider widget
$(sliderDivID).freshslider({
range: true,
step: 1,
......@@ -832,61 +835,57 @@ function NodeWeightFilter( sliderDivID , tgtNodeType , criteria) {
max:steps-1,
bgcolor:( tgtNodeType==TW.categories[0] )?"#27c470":"#FFA500" ,
value:[0,steps-1],
// handler
onchange:function(low, high){
var filtervalue = low+"-"+high
if(filtervalue!=lastFilter[sliderDivID]["last"]) {
if(lastFilter[sliderDivID]["orig"]=="-") {
pushFilterValue( sliderDivID , filtervalue )
return false
}
// [ Stopping FA2 ]
if (TW.partialGraph.isForceAtlas2Running())
sigma_utils.ourStopFA2();
// [ / Stopping FA2 ]
// [ Stopping FA2 ]
if (TW.partialGraph.isForceAtlas2Running())
sigma_utils.ourStopFA2();
// [ / Stopping FA2 ]
// debounced
if (nodeSlideTimeout){
clearTimeout(nodeSlideTimeout)
}
// scheduled: graph rm nodes
nodeSlideTimeout = setTimeout ( function () {
// debounced
if (nodeSlideTimeout){
// console.log('clearing updated function', nodeSlideTimeout)
clearTimeout(nodeSlideTimeout)
}
// check memoized value to see if any changes needed
if(filtervalue!=TW.gui.lastFilters[sliderDivID]) {
// scheduled: graph rm nodes
nodeSlideTimeout = setTimeout ( function () {
for(var i in stepToIdsArr) {
ids = stepToIdsArr[i]
if(i>=low && i<=high){
for(var id in ids) {
ID = ids[id]
TW.Nodes[ID].lock = false;
if(TW.partialGraph.graph.nodes(ID))
TW.partialGraph.graph.nodes(ID).hidden = false;
}
} else {
for(var id in ids) {
ID = ids[id]
TW.Nodes[ID].lock = true;
if(TW.partialGraph.graph.nodes(ID))
TW.partialGraph.graph.nodes(ID).hidden = true;
}
}
}
pushFilterValue(sliderDivID,filtervalue)
for(var i in stepToIdsArr) {
ids = stepToIdsArr[i]
if(i>=low && i<=high){
for(var id in ids) {
ID = ids[id]
TW.Nodes[ID].lock = false;
if(TW.partialGraph.graph.nodes(ID))
TW.partialGraph.graph.nodes(ID).hidden = false;
}
} else {
for(var id in ids) {
ID = ids[id]
TW.Nodes[ID].lock = true;
if(TW.partialGraph.graph.nodes(ID))
TW.partialGraph.graph.nodes(ID).hidden = true;
}
}
}
TW.gui.lastFilters[sliderDivID] = filtervalue
TW.partialGraph.render()
TW.partialGraph.render()
// [ Starting FA2 ]
setTimeout(function() {
sigma_utils.smartForceAtlas(2000) // shorter FA2 sufficient
}, 10)
// [ Starting FA2 ]
setTimeout(function() {
sigma_utils.smartForceAtlas(2000) // shorter FA2 sufficient
}, 10)
// [ / Starting FA2 ]
}, 300)
}
}
}, 1000)
}
});
}
......
'use strict';
// ======= [ variable initialization ] ======== //
// ======= [ main TW properties initialization ] ======== //
// INITIALIZED VARS
// ================
TW.Nodes = [];
TW.Edges = [];
TW.Relations = {}
TW.Clusters = []; // A "by value" index, built in parseCustom, (aka facets)
TW.Relations = {} // edges sorted by source/target type
TW.Clusters = []; // "by value" facet index built in parseCustom
TW.gexfPaths={};
TW.labels=[];
TW.partialGraph = null // will contain the sigma visible graph instance
// FIXME should become TW.*
TW.labels=[]; // fulltext search list
TW.gexfPaths={}; // for file selectors iff servermenu
TW.categories = []; // possible node types and their inverted map
TW.catDict = {};
// SystemState is a summary of current situation
TW.SystemState = {}
TW.SystemState.level = true;
TW.SystemState.activetypes = [] // will be filled from TW.categories
TW.SystemState.selections = [];
TW.SystemState.opposites = [];
TW.SystemState.LouvainFait = false;
// states[] is an array of SystemStates for future CTRL+Z or usage track
TW.states = []
TW.states[0] = false;
TW.states[1] = TW.SystemState
// £TODO should become TW.* or TW.SystemState.*
var selections = [];
var deselections={};
var opossites = {};
......@@ -26,51 +43,27 @@ var nodes2 = {};
var bipartiteD2N = {};
var bipartiteN2D = {};
// possible node types and their inverted map
TW.categories = [];
TW.catDict = {};
var gexfFile;
//var zoom=0;
TW.checkBox=false;
TW.shiftKey=false;
TW.manuallyChecked = false;
TW.SystemState = {}
TW.SystemState.level = true;
TW.SystemState.type = [ true, false ] // usually overridden by initialActivetypes
TW.SystemState.selections = [];
TW.SystemState.opposites = [];
// GUI vars
TW.gui = {}
TW.gui.selectionActive = false // <== changes rendering mode
TW.gui.circleSize = 0;
TW.gui.checkBox=false;
TW.gui.shiftKey=false;
TW.gui.manuallyChecked = false;
TW.gui.lastFilters = {}
TW.colorList = ["#000000", "#FFFF00", "#1CE6FF", "#FF34FF", "#FF4A46", "#008941", "#006FA6", "#A30059", "#FFDBE5", "#7A4900", "#0000A6", "#63FFAC", "#B79762", "#004D43", "#8FB0FF", "#997D87", "#5A0007", "#809693", "#FEFFE6", "#1B4400", "#4FC601", "#3B5DFF", "#4A3B53", "#FF2F80", "#61615A", "#BA0900", "#6B7900", "#00C2A0", "#FFAA92", "#FF90C9", "#B903AA", "#D16100", "#DDEFFF", "#000035", "#7B4F4B", "#A1C299", "#300018", "#0AA6D8", "#013349", "#00846F", "#372101", "#FFB500", "#C2FFED", "#A079BF", "#CC0744", "#C0B9B2", "#C2FF99", "#001E09", "#00489C", "#6F0062", "#0CBD66", "#EEC3FF", "#456D75", "#B77B68", "#7A87A1", "#788D66", "#885578", "#FAD09F", "#FF8A9A", "#D157A0", "#BEC459", "#456648", "#0086ED", "#886F4C","#34362D", "#B4A8BD", "#00A6AA", "#452C2C", "#636375", "#A3C8C9", "#FF913F", "#938A81", "#575329", "#00FECF", "#B05B6F", "#8CD0FF", "#3B9700", "#04F757", "#C8A1A1", "#1E6E00", "#7900D7", "#A77500", "#6367A9", "#A05837", "#6B002C", "#772600", "#D790FF", "#9B9700", "#549E79", "#FFF69F", "#201625", "#72418F", "#BC23FF", "#99ADC0", "#3A2465", "#922329", "#5B4534", "#FDE8DC", "#404E55", "#0089A3", "#CB7E98", "#A4E804", "#324E72", "#6A3A4C", "#83AB58", "#001C1E", "#D1F7CE", "#004B28", "#C8D0F6", "#A3A489", "#806C66", "#222800", "#BF5650", "#E83000", "#66796D", "#DA007C", "#FF1A59", "#8ADBB4", "#1E0200", "#5B4E51", "#C895C5", "#320033", "#FF6832", "#66E1D3", "#CFCDAC", "#D0AC94", "#7ED379", "#012C58"];
// £TODO à ranger
TW.circleSize= 0;
var lastFilter = []
lastFilter["#slidercat0nodesweight"] = {"orig":"-" , "last":"-"}
lastFilter["#slidercat1nodesweight"] = {"orig":"-" , "last":"-"}
lastFilter["#slidercat0edgesweight"] = {"orig":"-" , "last":"-"}
lastFilter["#slidercat1edgesweight"] = {"orig":"-" , "last":"-"}
var desirableNodeSizeMIN=1;
var desirableNodeSizeMAX=12;
// These variables will be updated in sigma.parseCustom.js
var minNodeSize
var maxNodeSize
// ======== [ what to do at start ] ========= //
console.log("Starting TWJS")
// NB this method-holding instance could be initialized just once or even removed?
var sigma_utils = new SigmaUtils();
// POSS: ideally this should take a TW.settings as parameter
// POSS: ideally this should take a TW.conf as parameter
TW.instance = new TinaWebJS('#sigma-contnr');
// add once our tw rendering and index customizations into sigma module
......@@ -241,7 +234,7 @@ function syncRemoteGraphData () {
console.log("input case: server-side file, using TW.conf.sourceMenu or getUrlParam.file or TW.conf.sourceFile")
// -> @mode is servermenu, files are listed in db.json file (preRes ajax)
// --> if @file also in url, choose the db.json one matching <=== £TODO THIS CASE STILL TO FIX
// --> if @file also in url, choose the db.json one matching
// --> otherwise, choose the "first_file" from db.json list
// -> @mode is serverfile
......@@ -300,7 +293,6 @@ function syncRemoteGraphData () {
if (TW.conf.debug.logFetchers)
console.log("\t\t\t"+gexfBasename+ " -> table:" +theGexfs[aGexf]["semantic"]["table"] )
// -------------------------->8------------------------------------------
// £TODO this part is underspecified
// if used in some usecases, port it to nodetypes
......@@ -316,7 +308,6 @@ function syncRemoteGraphData () {
// console.log( files_selector )
}
files_selector += "</select>"
console.log("files_selector HTML", files_selector)
$("#network").html(files_selector)
}
......@@ -381,14 +372,15 @@ function mainStartGraph(inFormat, inData, twInstance) {
if (! TW.categories) {
console.warn ('ParseCustom scanFile found no categories!!')
TW.categories = []
TW.catDict = {}
}
// activetypes: the node categorie(s) that is (are) currently displayed
// ex: [true,false] = [nodes of type 0 shown ; nodes of type 1 not drawn]
var initialActivetypes = TW.instance.initialActivetypes( TW.categories )
var possibleActivetypes = TW.instance.allPossibleActivetypes( TW.categories )
// remember it
TW.states[1].activetypes = initialActivetypes ;
// XML parsing from ParseCustom
var dicts = start.makeDicts(TW.categories); // > parse json or gexf, dictfy
......@@ -405,8 +397,6 @@ function mainStartGraph(inFormat, inData, twInstance) {
prepareNodesRenderingProperties(TW.Nodes)
prepareEdgesRenderingProperties(TW.Edges, TW.Nodes)
TW.selectionActive = false // changes rendering mode
if (inData.clusters) TW.Clusters = inData.clusters
// £TODO remove from parseCustom or start using
......@@ -445,7 +435,8 @@ function mainStartGraph(inFormat, inData, twInstance) {
// [ Poblating the Sigma-Graph ]
// preparing the data and settings
// preparing the data (TW.Nodes and TW.Edges filtered by initial type)
// POSS: avoid this step and use the filters at rendering time!
TW.graphData = {nodes: [], edges: []}
TW.graphData = sigma_utils.FillGraph( initialActivetypes , TW.catDict , TW.Nodes , TW.Edges , TW.graphData );
......@@ -547,110 +538,11 @@ 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)
// POSS make it TW.states
TW.partialGraph.states = []
TW.partialGraph.states[0] = false;
// from settings_explorer (everything except the type)
TW.partialGraph.states[1] = TW.SystemState
// activetypes: the node categorie(s) that is (are) currently displayed
TW.partialGraph.states[1].activetypes = initialActivetypes ;
TW.partialGraph.states[1].LouvainFait = false;
// NB specs: categories don't change within a given 'states' array so we don't include them
// (new graph => new categories combinations => new array)
// now that we have a sigma instance, let's bind our click handlers to it
TW.instance.initSigmaListeners(TW.partialGraph, initialActivetypes)
// [ / Poblating the Sigma-Graph ]
// @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.partialGraph.states.slice(-1)[0]; // Last
var past = TW.partialGraph.states.slice(-2)[0] // avant Last
console.log("IN THE SET STATE METHOD:", this)
console.log(" % % % % % % % % % % ")
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");
}
}
};
if (!TW.conf.filterSliders) {
var filterEls = document.getElementsByClassName('weight-selectors')
......
'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