Commit a0aa844c authored by Romain Loth's avatar Romain Loth

rationalize flags handling in customAttrs + fix cluster highlight + deselect option

flags: systematize handling (set in initial setup, cancelSelection, greyEverything, used as params in rendering), rationalize forceLabel, rename customAttrs.neighbors to highlight ; cluster highlight: on click in legend, highlight like neighbors but once ; deselect: background click to deselect is optional
parent 1eec2fa8
...@@ -114,6 +114,10 @@ function RunLouvain() { ...@@ -114,6 +114,10 @@ function RunLouvain() {
function SomeEffect( ClusterCode ) { function SomeEffect( ClusterCode ) {
console.log( ClusterCode ) console.log( ClusterCode )
// ex: ISItermsriskV2_140 & ISItermsriskV2_140||clust_default||7
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv vvvvv v
// type Cluster key clstID
var raw = ClusterCode.split("||") var raw = ClusterCode.split("||")
var Type=raw[0], Cluster=raw[1], clstID=Number(raw[2]); var Type=raw[0], Cluster=raw[1], clstID=Number(raw[2]);
...@@ -129,22 +133,27 @@ function SomeEffect( ClusterCode ) { ...@@ -129,22 +133,27 @@ function SomeEffect( ClusterCode ) {
var edges_2_colour = {}; var edges_2_colour = {};
var nodesV = getVisibleNodes() var nodesV = getVisibleNodes()
for(var i in nodesV) {
var n = nodesV[i] for(var j=0;j<TW.nNodes;j++) {
n.forceLabel = false; let n = TW.partialGraph.graph.nodes(TW.nodeIds[j])
var node = TW.Nodes[n.id] if (n && !n.hidden) {
if ( node.type==Type && !isUndef(node.attributes[Cluster]) && node.attributes[Cluster]==clstID ) { n.customAttrs.forceLabel = false
// console.log( n.id + " | " + Cluster + " : " + node.attributes[Cluster] )
nodes_2_colour[n.id] = n.degree; // we look also at the original gexf node to get access to gexf attributes like cluster
var gNode = TW.Nodes[n.id]
if (gNode.type = Type && !isUndef(gNode.attributes[Cluster]) && gNode.attributes[Cluster]==clstID) {
// console.log( n.id + " | " + Cluster + " : " + node.attributes[Cluster] )
// nodes_2_colour[n.id] = n.degree;
nodes_2_colour[n.id] = 1;
} }
}
} }
for(var s in nodes_2_colour) { for(var s in nodes_2_colour) {
if(TW.Relations[str_type_t0] && TW.Relations[str_type_t0][s] ) { if(TW.Relations[str_type_t0] && TW.Relations[str_type_t0][s] ) {
neigh = TW.Relations[str_type_t0][s] neigh = TW.Relations[str_type_t0][s]
if(neigh) { if(neigh) {
for(var j in neigh) { for(j in neigh) {
t = neigh[j] t = neigh[j]
if( !isUndef(nodes_2_colour[t]) ) { if( !isUndef(nodes_2_colour[t]) ) {
edges_2_colour[s+";"+t]=true; edges_2_colour[s+";"+t]=true;
...@@ -156,43 +165,46 @@ function SomeEffect( ClusterCode ) { ...@@ -156,43 +165,46 @@ function SomeEffect( ClusterCode ) {
} }
for(var i in nodes_2_colour) { for(var nid in nodes_2_colour) {
n = TW.partialGraph._core.graph.nodesIndex[i] n = TW.partialGraph.graph.nodes(nid)
if(n) { if(n) {
n.color = n.customAttrs['true_color']; // new sigma js: we change only flags, rendering will adapt color accordingly
n.customAttrs['grey'] = 0; n.customAttrs['grey'] = false;
// highlight (like neighbors but with no selection)
n.customAttrs['highlight'] = true;
} }
} }
for(var i in edges_2_colour) { for(var eid in edges_2_colour) {
an_edge = TW.partialGraph._core.graph.edgesIndex[i] an_edge = TW.partialGraph.graph.edges(eid)
if(!isUndef(an_edge) && !an_edge.hidden){ if(!isUndef(an_edge) && !an_edge.hidden){
// console.log(an_edge) // new sigma js: we change only flags, rendering will adapt color accordingly
an_edge.color = an_edge.customAttrs['true_color'];
an_edge.customAttrs['grey'] = 0; an_edge.customAttrs['grey'] = 0;
an_edge.customAttrs['activeEdge'] = 1;
} }
} }
var nodes_2_label = ArraySortByValue(nodes_2_colour, function(a,b){ var nodes_2_label = ArraySortByValue(nodes_2_colour, function(a,b){
return b-a return b-a
}); });
for(var n in nodes_2_label) { // force 4 first labels
if(n==4) for(var j in nodes_2_label) {
if(j==4)
break break
var ID = nodes_2_label[n].key var ID = nodes_2_label[j].key
TW.partialGraph._core.graph.nodesIndex[ID].forceLabel = true; TW.partialGraph.graph.nodes(ID).customAttrs.forceLabel = true;
} }
TW.selectionActive=true;
overNodes=true; // TW.partialGraph.render()
TW.partialGraph.draw() TW.partialGraph.refresh()
} }
...@@ -450,20 +462,14 @@ function circleTrackMouse(e) { ...@@ -450,20 +462,14 @@ function circleTrackMouse(e) {
// if(TW.partialGraph.camera.ratio < showLabelsIfZoom){ // if(TW.partialGraph.camera.ratio < showLabelsIfZoom){
// for (var k of exactNodeset) { // for (var k of exactNodeset) {
// // if (! exactNodeset[k].hidden) { // // if (! exactNodeset[k].hidden) {
// exactNodeset[k].forceLabel=true; // exactNodeset[k].customAttrs.forceLabel=true;
// // } // // }
// } // }
// } // }
// else { // else {
// for(var k in exactNodeset){ // for(var k in exactNodeset){
// n = exactNodeset[k] // n = exactNodeset[k]
// n.forceLabel=false; // n.customAttrs.forceLabel=false;
//
// // ?deprecated?
// if(typeof(n.neighbour)!=="undefined") {
// if(!n.neighbour) n.forceLabel=false;
// else n.forceLabel=true;
// } else n.forceLabel=false;
// } // }
// if(TW.partialGraph.forceatlas2 && TW.partialGraph.forceatlas2.count<=1) { // if(TW.partialGraph.forceatlas2 && TW.partialGraph.forceatlas2.count<=1) {
// TW.partialGraph.render() // TW.partialGraph.render()
...@@ -506,12 +512,6 @@ function circleGetAreaNodes(camX0, camY0) { ...@@ -506,12 +512,6 @@ function circleGetAreaNodes(camX0, camY0) {
if( distance <= cursor_ray) { if( distance <= cursor_ray) {
exactNodeset.push(n.id) exactNodeset.push(n.id)
} }
else {
// ?deprecated?
if(typeof(n.neighbour)!=="undefined") {
if(!n.neighbour) n.forceLabel=false;
} else n.forceLabel=false;
}
} }
} }
if(TW.partialGraph.forceatlas2 && TW.partialGraph.forceatlas2.count<=1) { if(TW.partialGraph.forceatlas2 && TW.partialGraph.forceatlas2.count<=1) {
......
...@@ -43,7 +43,7 @@ var TW = {} ...@@ -43,7 +43,7 @@ var TW = {}
// flag name is div class to be removed if false // flag name is div class to be removed if false
// *and* subdirectory to import if true // *and* subdirectory to import if true
// see also ProcessDivsFlags() // see also ProcessDivsFlags()
TW.DivsFlags["histogramModule"] = false ; TW.DivsFlags["histogramModule"] = true ;
TW.DivsFlags["crowdsourcingModule"] = true ; // £TODO fix topPapers TW.DivsFlags["crowdsourcingModule"] = true ; // £TODO fix topPapers
TW.SystemStates = {} TW.SystemStates = {}
...@@ -108,7 +108,9 @@ TW.nodesGreyBorderColor = "rgba(100, 100, 100, 0.5)"; ...@@ -108,7 +108,9 @@ TW.nodesGreyBorderColor = "rgba(100, 100, 100, 0.5)";
TW.selectedColor = "node" // "node" for a background like the node's color, TW.selectedColor = "node" // "node" for a background like the node's color,
// "default" for note-like yellow // "default" for note-like yellow
TW.overSampling = false // costly hi-def rendering (true => pixelRatio x 2) TW.overSampling = true // costly hi-def rendering (true => pixelRatio x 2)
TW.deselectOnclickStage = false // will a click on the background remove selection ? (except when dragging)
// ============ < / DEVELOPER OPTIONS > ============ // ============ < / DEVELOPER OPTIONS > ============
...@@ -144,7 +146,7 @@ var sigmaJsDrawingProperties = { ...@@ -144,7 +146,7 @@ var sigmaJsDrawingProperties = {
fontStyle: "bold", fontStyle: "bold",
}; };
var sigmaJsGraphProperties = { var sigmaJsGraphProperties = {
minEdgeSize: 2, minEdgeSize: 1,
maxEdgeSize: 4 maxEdgeSize: 4
}; };
var sigmaJsMouseProperties = { var sigmaJsMouseProperties = {
......
...@@ -232,12 +232,15 @@ function SelectionEngine() { ...@@ -232,12 +232,15 @@ function SelectionEngine() {
if(n) { if(n) {
n.color = n.customAttrs['true_color']; n.color = n.customAttrs['true_color'];
n.customAttrs['grey'] = 0; n.customAttrs['grey'] = 0;
// it's a selected node
if(nodes_2_colour[nid]) { if(nodes_2_colour[nid]) {
n.active = true; n.active = true;
// selections[nid]=1 // selections[nid]=1
} }
// it's a neighbor
else { else {
n.customAttrs.neighbor = true; n.customAttrs.highlight = true;
} }
} }
} }
...@@ -550,8 +553,10 @@ TinaWebJS = function ( sigmacanvas ) { ...@@ -550,8 +553,10 @@ TinaWebJS = function ( sigmacanvas ) {
console.log(" ############ changeLEVEL click"); console.log(" ############ changeLEVEL click");
changeLevel(); changeLevel();
// FIXME intention unclear
// $("#tabs1").click() // $("#tabs1").click()
ChangeGraphAppearanceByAtt(true) // cf. extras_explorer // ChangeGraphAppearanceByAtt(true) // cf. extras_explorer
console.log(" ############ / changeLEVEL click"); console.log(" ############ / changeLEVEL click");
console.log("") console.log("")
}); });
...@@ -700,17 +705,19 @@ TinaWebJS = function ( sigmacanvas ) { ...@@ -700,17 +705,19 @@ TinaWebJS = function ( sigmacanvas ) {
// when click in the empty background // when click in the empty background
// ================================== // ==================================
TW.partialGraph.bind('clickStage', function(e) { if (TW.deselectOnclickStage) {
// console.log("clickStage event e", e) TW.partialGraph.bind('clickStage', function(e) {
// console.log("clickStage event e", e)
if (! e.data.captor.isDragging if (! e.data.captor.isDragging
&& Object.keys(selections).length && Object.keys(selections).length
&& ! cursor_size) { && ! cursor_size) {
// we clear selections and all its effects // we clear selections and all its effects
cancelSelection(false); cancelSelection(false);
} }
}) })
}
// for all TW.cam.goTo (move/zoom) events // for all TW.cam.goTo (move/zoom) events
// =============== // ===============
......
...@@ -69,7 +69,7 @@ function getGexfPath(v){ ...@@ -69,7 +69,7 @@ function getGexfPath(v){
function jsActionOnGexfSelector(gexfBasename , db_json){ function jsActionOnGexfSelector(gexfBasename , db_json){
db_json = (db_json)?"&mode=db.json":"" db_json = (db_json)?"&mode=db.json":""
gexfLegend = gexfBasename+".gexf" let gexfLegend = gexfBasename+".gexf"
if(getGexfPath[gexfLegend]) if(getGexfPath[gexfLegend])
window.location=window.location.origin+window.location.pathname+"?file="+encodeURIComponent(getGexfPath(gexfLegend))+db_json; window.location=window.location.origin+window.location.pathname+"?file="+encodeURIComponent(getGexfPath(gexfLegend))+db_json;
else else
...@@ -170,10 +170,14 @@ if(RES["OK"]) { ...@@ -170,10 +170,14 @@ if(RES["OK"]) {
console.log("parsing the data") console.log("parsing the data")
var start = new ParseCustom( fileparam , the_data ); var start = new ParseCustom( fileparam , the_data );
categories = start.scanFile(); //user should choose the order of categories var categories = start.scanFile(); //user should choose the order of categories
// console.log("Categories: ") // console.log("Categories: ")
// console.log(categories) // console.log(categories)
if (! categories) {
console.warn ('ParseCustom scanFile found no categories!!')
categories = []
}
var possibleStates = makeSystemStates( categories ) var possibleStates = makeSystemStates( categories )
var initialState = buildInitialState( categories ) //[true,false]// var initialState = buildInitialState( categories ) //[true,false]//
......
...@@ -38,6 +38,7 @@ function cancelSelection (fromTagCloud, settings) { ...@@ -38,6 +38,7 @@ function cancelSelection (fromTagCloud, settings) {
// n.color = n.customAttrs['grey'] ? n.customAttrs['true_color'] : n.color; // n.color = n.customAttrs['grey'] ? n.customAttrs['true_color'] : n.color;
n.color = n.customAttrs['true_color']; n.color = n.customAttrs['true_color'];
n.customAttrs.grey = 0 n.customAttrs.grey = 0
n.customAttrs.forceLabel = 0
} }
} }
...@@ -60,11 +61,11 @@ function cancelSelection (fromTagCloud, settings) { ...@@ -60,11 +61,11 @@ function cancelSelection (fromTagCloud, settings) {
for(var nid in deselections){ for(var nid in deselections){
let n = TW.partialGraph.graph.nodes(nid) let n = TW.partialGraph.graph.nodes(nid)
if( !isUndef(n) ) { if( !isUndef(n) ) {
n.forceLabel=false; n.customAttrs.forceLabel = false;
n.neighbour=false; n.customAttrs.highlight = false;
n.customAttrs.grey=false
// like old graphResetColor but now rather graphResetFlags... // like old graphResetColor but now rather graphResetFlags...
n.active=false; n.active=false;
n.grey=false
} }
} }
...@@ -580,19 +581,24 @@ function unHide(nodeId) { ...@@ -580,19 +581,24 @@ function unHide(nodeId) {
} }
// edges greyish color for unselected, when we have a selection // edges greyish color for unselected, when we have a selection
// case default: color is precomputed as node true_color + alpha .5 // case default: we just change the flags
// - greyish color was precomputed in prepareNodesRenderingProperties
// as n.customAttrs.defgrey_color
// - renderer will see the flags and and handle the case accordingly
// cases when coloredBy (ex: centrality): color must be recomputed here // cases when coloredBy (ex: centrality): color must be recomputed here
function greyEverything(notDefaultColors){ function greyEverything(notDefaultColors){
for(let j=0 ; j<TW.nNodes ; j++){ for(var j=0 ; j<TW.nNodes ; j++){
let n = TW.partialGraph.graph.nodes(TW.nodeIds[j]) let n = TW.partialGraph.graph.nodes(TW.nodeIds[j])
if (n && !n.hidden && !n.customAttrs.grey) { if (n && !n.hidden) {
n.customAttrs['grey'] = 1
n.customAttrs.true_color = n.color
// normal case handled by node renderers // normal case handled by node renderers
// will see the n.customAttrs.grey flag => use n.customAttrs.defgrey_color // will see the n.customAttrs.grey flag => use n.customAttrs.defgrey_color
n.customAttrs.grey=1
n.active = false
n.customAttrs.forceLabel = false;
n.customAttrs.highlight = false;
// special case after a coloredBy or clustersBy // special case after a coloredBy or clustersBy
if (notDefaultColors) if (notDefaultColors)
...@@ -601,11 +607,14 @@ function greyEverything(notDefaultColors){ ...@@ -601,11 +607,14 @@ function greyEverything(notDefaultColors){
} }
if (TW.partialGraph.settings('drawEdges')) { if (TW.partialGraph.settings('drawEdges')) {
for(let i=0;i<TW.nEdges;i++){ for(var i=0;i<TW.nEdges;i++){
let e = TW.partialGraph.graph.edges(TW.edgeIds[i]) let e = TW.partialGraph.graph.edges(TW.edgeIds[i])
if (e && !e.hidden && !e.customAttrs.grey) { if (e && !e.hidden && !e.customAttrs.grey) {
e.customAttrs.grey = 1 e.customAttrs.grey = 1
e.customAttrs.true_color = e.color e.customAttrs.activeEdge = 0
// new specification: coloredBy does not affect edges
// (ie no special case for notDefaultColors)
} }
} }
} }
...@@ -672,9 +681,11 @@ function prepareNodesRenderingProperties(nodesDict) { ...@@ -672,9 +681,11 @@ function prepareNodesRenderingProperties(nodesDict) {
// and quite enough in precision !! // and quite enough in precision !!
n.size = Math.round(n.size*1000)/1000 n.size = Math.round(n.size*1000)/1000
// new setup (TODO rm the old at TinaWebJS nodes_2_colour) // new initial setup of properties
n.active = false
n.customAttrs = { n.customAttrs = {
grey: false, grey: false,
highlight: false,
true_color : n.color, true_color : n.color,
defgrey_color : "rgba("+hex2rga(n.color)+",.4)" defgrey_color : "rgba("+hex2rga(n.color)+",.4)"
} }
...@@ -706,6 +717,7 @@ function prepareEdgesRenderingProperties(edgesDict) { ...@@ -706,6 +717,7 @@ function prepareEdgesRenderingProperties(edgesDict) {
e.color = "rgba("+rgbStr+","+TW.edgeDefaultOpacity+")" e.color = "rgba("+rgbStr+","+TW.edgeDefaultOpacity+")"
e.customAttrs = { e.customAttrs = {
grey: false, grey: false,
activeEdge : false,
true_color : e.color, true_color : e.color,
rgb : rgbStr rgb : rgbStr
} }
...@@ -722,6 +734,10 @@ function add1Elem(id) { ...@@ -722,6 +734,10 @@ function add1Elem(id) {
if(TW.Nodes[id]) { if(TW.Nodes[id]) {
var n = TW.Nodes[id] var n = TW.Nodes[id]
// WE AVOIDED A COPY HERE BECAUSE properties are already complete
// ... however, TODO check if we shouldn't remove the n.attributes Obj
// var anode = {} // var anode = {}
// anode.id = n.id; // anode.id = n.id;
// anode.label = n.label; // anode.label = n.label;
......
...@@ -90,9 +90,9 @@ SigmaUtils = function () { ...@@ -90,9 +90,9 @@ SigmaUtils = function () {
var fontSize, var fontSize,
prefix = settings('prefix') || '', prefix = settings('prefix') || '',
size = node[prefix + 'size'], size = node[prefix + 'size'],
activeFlag = node['active'] || node['forceLabel'] activeFlag = node['active'] || node.customAttrs['forceLabel']
// NB active is used in all TW selections // NB active is used in all TW selections
// forceLabel is seldom used // forceLabel is used in cluster highlighting
let X = node[prefix + 'x'] let X = node[prefix + 'x']
let Y = node[prefix + 'y'] let Y = node[prefix + 'y']
...@@ -114,11 +114,7 @@ SigmaUtils = function () { ...@@ -114,11 +114,7 @@ SigmaUtils = function () {
// Label background (aligned on hover equivalent): // Label background (aligned on hover equivalent):
var x,y,w,h,e, var x,y,w,h,e,
fontStyle = settings('hoverFontStyle') || settings('fontStyle'), // for label background fontStyle = settings('hoverFontStyle') || settings('fontStyle') // for label background
activeFlag = node['active'] || node['forceLabel']
// NB active is used in all TW selections
// forceLabel is seldom used
context.font = (fontStyle ? fontStyle + ' ' : '') + context.font = (fontStyle ? fontStyle + ' ' : '') +
fontSize + 'px ' + (settings('hoverFont') || settings('font')); fontSize + 'px ' + (settings('hoverFont') || settings('font'));
...@@ -201,13 +197,14 @@ SigmaUtils = function () { ...@@ -201,13 +197,14 @@ SigmaUtils = function () {
//debug //debug
// console.warn("rendering edge", edge) // console.warn("rendering edge", edge)
var rgbStr = edge.customAttrs.rgb var defSize = edge[prefix + 'size'] || settings("minEdgeSize") || 1 ;
var defSize = edge[prefix + 'size'] || 1
if (edge.customAttrs.activeEdge) { if (edge.customAttrs.activeEdge) {
size = defSize * 1.5 size = defSize * 2
// color with less opacity // color with no opacity
// cf. sigmaTools.edgeRGB // cf. sigmaTools.edgeRGB
color = 'rgba('+rgbStr+',.7)' color = 'rgb('+edge.customAttrs.rgb+')'
// console.log("drawing activeEdge with size", size)
edge.customAttrs.activeEdge = false
} }
else if (edge.customAttrs.grey) { else if (edge.customAttrs.grey) {
color = TW.edgeGreyColor color = TW.edgeGreyColor
...@@ -307,8 +304,8 @@ SigmaUtils = function () { ...@@ -307,8 +304,8 @@ SigmaUtils = function () {
borderColor = TW.nodesGreyBorderColor borderColor = TW.nodesGreyBorderColor
// cf settings_explorerjs, defgrey_color and greyEverything() // cf settings_explorerjs, defgrey_color and greyEverything()
} }
// neighbor nodes should be more visible // neighbor nodes <=> (highlight flag AND selectionActive)
else if(node.customAttrs.neighbor) { else if(node.customAttrs.highlight) {
// borderColor = "rgba(220, 220, 220, 0.7)" // borderColor = "rgba(220, 220, 220, 0.7)"
nodeSize *= 1.4 nodeSize *= 1.4
borderSize *= 1.4 borderSize *= 1.4
...@@ -318,6 +315,12 @@ SigmaUtils = function () { ...@@ -318,6 +315,12 @@ SigmaUtils = function () {
// the selected nodes: fill not important because label+background overlay // the selected nodes: fill not important because label+background overlay
} }
} }
// highlight AND (NOT selectionActive) => highlight just this one time
else if (node.customAttrs.highlight) {
nodeSize *= 1.4
borderSize *= 1.4
node.customAttrs.highlight = false
}
// actual drawing // actual drawing
if (settings('twNodeRendBorderSize') > 0) { if (settings('twNodeRendBorderSize') > 0) {
...@@ -491,20 +494,20 @@ SigmaUtils = function () { ...@@ -491,20 +494,20 @@ SigmaUtils = function () {
// n = getVisibleNodes(); // n = getVisibleNodes();
// for(i=0;i<n.length;i++) { // for(i=0;i<n.length;i++) {
// if(n[i].hidden==false){ // if(n[i].hidden==false){
// if(n[i].inDegree==minIn && n[i].forceLabel==false) { // if(n[i].inDegree==minIn && n[i].customAttrs.forceLabel==false) {
// n[i].forceLabel=true; // n[i].customAttrs.forceLabel=true;
// counter++; // counter++;
// } // }
// if(n[i].inDegree==maxIn && n[i].forceLabel==false) { // if(n[i].inDegree==maxIn && n[i].customAttrs.forceLabel==false) {
// n[i].forceLabel=true; // n[i].customAttrs.forceLabel=true;
// counter++; // counter++;
// } // }
// if(n[i].outDegree==minOut && n[i].forceLabel==false) { // if(n[i].outDegree==minOut && n[i].customAttrs.forceLabel==false) {
// n[i].forceLabel=true; // n[i].customAttrs.forceLabel=true;
// counter++; // counter++;
// } // }
// if(n[i].outDegree==maxOut && n[i].forceLabel==false) { // if(n[i].outDegree==maxOut && n[i].customAttrs.forceLabel==false) {
// n[i].forceLabel=true; // n[i].customAttrs.forceLabel=true;
// counter++; // counter++;
// } // }
// if(counter==N) break; // if(counter==N) break;
......
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