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() {
function SomeEffect( ClusterCode ) {
console.log( ClusterCode )
// ex: ISItermsriskV2_140 & ISItermsriskV2_140||clust_default||7
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv vvvvv v
// type Cluster key clstID
var raw = ClusterCode.split("||")
var Type=raw[0], Cluster=raw[1], clstID=Number(raw[2]);
......@@ -129,22 +133,27 @@ function SomeEffect( ClusterCode ) {
var edges_2_colour = {};
var nodesV = getVisibleNodes()
for(var i in nodesV) {
var n = nodesV[i]
n.forceLabel = false;
var node = TW.Nodes[n.id]
if ( node.type==Type && !isUndef(node.attributes[Cluster]) && node.attributes[Cluster]==clstID ) {
// console.log( n.id + " | " + Cluster + " : " + node.attributes[Cluster] )
nodes_2_colour[n.id] = n.degree;
for(var j=0;j<TW.nNodes;j++) {
let n = TW.partialGraph.graph.nodes(TW.nodeIds[j])
if (n && !n.hidden) {
n.customAttrs.forceLabel = false
// 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) {
if(TW.Relations[str_type_t0] && TW.Relations[str_type_t0][s] ) {
neigh = TW.Relations[str_type_t0][s]
if(neigh) {
for(var j in neigh) {
for(j in neigh) {
t = neigh[j]
if( !isUndef(nodes_2_colour[t]) ) {
edges_2_colour[s+";"+t]=true;
......@@ -156,43 +165,46 @@ function SomeEffect( ClusterCode ) {
}
for(var i in nodes_2_colour) {
n = TW.partialGraph._core.graph.nodesIndex[i]
for(var nid in nodes_2_colour) {
n = TW.partialGraph.graph.nodes(nid)
if(n) {
n.color = n.customAttrs['true_color'];
n.customAttrs['grey'] = 0;
// new sigma js: we change only flags, rendering will adapt color accordingly
n.customAttrs['grey'] = false;
// highlight (like neighbors but with no selection)
n.customAttrs['highlight'] = true;
}
}
for(var i in edges_2_colour) {
an_edge = TW.partialGraph._core.graph.edgesIndex[i]
for(var eid in edges_2_colour) {
an_edge = TW.partialGraph.graph.edges(eid)
if(!isUndef(an_edge) && !an_edge.hidden){
// console.log(an_edge)
an_edge.color = an_edge.customAttrs['true_color'];
// new sigma js: we change only flags, rendering will adapt color accordingly
an_edge.customAttrs['grey'] = 0;
an_edge.customAttrs['activeEdge'] = 1;
}
}
var nodes_2_label = ArraySortByValue(nodes_2_colour, function(a,b){
return b-a
});
for(var n in nodes_2_label) {
if(n==4)
// force 4 first labels
for(var j in nodes_2_label) {
if(j==4)
break
var ID = nodes_2_label[n].key
TW.partialGraph._core.graph.nodesIndex[ID].forceLabel = true;
var ID = nodes_2_label[j].key
TW.partialGraph.graph.nodes(ID).customAttrs.forceLabel = true;
}
TW.selectionActive=true;
overNodes=true;
TW.partialGraph.draw()
// TW.partialGraph.render()
TW.partialGraph.refresh()
}
......@@ -450,20 +462,14 @@ function circleTrackMouse(e) {
// if(TW.partialGraph.camera.ratio < showLabelsIfZoom){
// for (var k of exactNodeset) {
// // if (! exactNodeset[k].hidden) {
// exactNodeset[k].forceLabel=true;
// exactNodeset[k].customAttrs.forceLabel=true;
// // }
// }
// }
// else {
// for(var k in exactNodeset){
// n = exactNodeset[k]
// n.forceLabel=false;
//
// // ?deprecated?
// if(typeof(n.neighbour)!=="undefined") {
// if(!n.neighbour) n.forceLabel=false;
// else n.forceLabel=true;
// } else n.forceLabel=false;
// n.customAttrs.forceLabel=false;
// }
// if(TW.partialGraph.forceatlas2 && TW.partialGraph.forceatlas2.count<=1) {
// TW.partialGraph.render()
......@@ -506,12 +512,6 @@ function circleGetAreaNodes(camX0, camY0) {
if( distance <= cursor_ray) {
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) {
......
......@@ -43,7 +43,7 @@ var TW = {}
// flag name is div class to be removed if false
// *and* subdirectory to import if true
// see also ProcessDivsFlags()
TW.DivsFlags["histogramModule"] = false ;
TW.DivsFlags["histogramModule"] = true ;
TW.DivsFlags["crowdsourcingModule"] = true ; // £TODO fix topPapers
TW.SystemStates = {}
......@@ -108,7 +108,9 @@ TW.nodesGreyBorderColor = "rgba(100, 100, 100, 0.5)";
TW.selectedColor = "node" // "node" for a background like the node's color,
// "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 > ============
......@@ -144,7 +146,7 @@ var sigmaJsDrawingProperties = {
fontStyle: "bold",
};
var sigmaJsGraphProperties = {
minEdgeSize: 2,
minEdgeSize: 1,
maxEdgeSize: 4
};
var sigmaJsMouseProperties = {
......
......@@ -232,12 +232,15 @@ function SelectionEngine() {
if(n) {
n.color = n.customAttrs['true_color'];
n.customAttrs['grey'] = 0;
// it's a selected node
if(nodes_2_colour[nid]) {
n.active = true;
// selections[nid]=1
}
// it's a neighbor
else {
n.customAttrs.neighbor = true;
n.customAttrs.highlight = true;
}
}
}
......@@ -550,8 +553,10 @@ TinaWebJS = function ( sigmacanvas ) {
console.log(" ############ changeLEVEL click");
changeLevel();
// FIXME intention unclear
// $("#tabs1").click()
ChangeGraphAppearanceByAtt(true) // cf. extras_explorer
// ChangeGraphAppearanceByAtt(true) // cf. extras_explorer
console.log(" ############ / changeLEVEL click");
console.log("")
});
......@@ -700,17 +705,19 @@ TinaWebJS = function ( sigmacanvas ) {
// when click in the empty background
// ==================================
TW.partialGraph.bind('clickStage', function(e) {
// console.log("clickStage event e", e)
if (TW.deselectOnclickStage) {
TW.partialGraph.bind('clickStage', function(e) {
// console.log("clickStage event e", e)
if (! e.data.captor.isDragging
&& Object.keys(selections).length
&& ! cursor_size) {
if (! e.data.captor.isDragging
&& Object.keys(selections).length
&& ! cursor_size) {
// we clear selections and all its effects
cancelSelection(false);
}
})
// we clear selections and all its effects
cancelSelection(false);
}
})
}
// for all TW.cam.goTo (move/zoom) events
// ===============
......
......@@ -69,7 +69,7 @@ function getGexfPath(v){
function jsActionOnGexfSelector(gexfBasename , db_json){
db_json = (db_json)?"&mode=db.json":""
gexfLegend = gexfBasename+".gexf"
let gexfLegend = gexfBasename+".gexf"
if(getGexfPath[gexfLegend])
window.location=window.location.origin+window.location.pathname+"?file="+encodeURIComponent(getGexfPath(gexfLegend))+db_json;
else
......@@ -170,10 +170,14 @@ if(RES["OK"]) {
console.log("parsing 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)
if (! categories) {
console.warn ('ParseCustom scanFile found no categories!!')
categories = []
}
var possibleStates = makeSystemStates( categories )
var initialState = buildInitialState( categories ) //[true,false]//
......
......@@ -38,6 +38,7 @@ function cancelSelection (fromTagCloud, settings) {
// n.color = n.customAttrs['grey'] ? n.customAttrs['true_color'] : n.color;
n.color = n.customAttrs['true_color'];
n.customAttrs.grey = 0
n.customAttrs.forceLabel = 0
}
}
......@@ -60,11 +61,11 @@ function cancelSelection (fromTagCloud, settings) {
for(var nid in deselections){
let n = TW.partialGraph.graph.nodes(nid)
if( !isUndef(n) ) {
n.forceLabel=false;
n.neighbour=false;
n.customAttrs.forceLabel = false;
n.customAttrs.highlight = false;
n.customAttrs.grey=false
// like old graphResetColor but now rather graphResetFlags...
n.active=false;
n.grey=false
}
}
......@@ -580,19 +581,24 @@ function unHide(nodeId) {
}
// 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
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])
if (n && !n.hidden && !n.customAttrs.grey) {
n.customAttrs['grey'] = 1
n.customAttrs.true_color = n.color
if (n && !n.hidden) {
// normal case handled by node renderers
// 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
if (notDefaultColors)
......@@ -601,11 +607,14 @@ function greyEverything(notDefaultColors){
}
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])
if (e && !e.hidden && !e.customAttrs.grey) {
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) {
// and quite enough in precision !!
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 = {
grey: false,
highlight: false,
true_color : n.color,
defgrey_color : "rgba("+hex2rga(n.color)+",.4)"
}
......@@ -706,6 +717,7 @@ function prepareEdgesRenderingProperties(edgesDict) {
e.color = "rgba("+rgbStr+","+TW.edgeDefaultOpacity+")"
e.customAttrs = {
grey: false,
activeEdge : false,
true_color : e.color,
rgb : rgbStr
}
......@@ -722,6 +734,10 @@ function add1Elem(id) {
if(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 = {}
// anode.id = n.id;
// anode.label = n.label;
......
......@@ -90,9 +90,9 @@ SigmaUtils = function () {
var fontSize,
prefix = settings('prefix') || '',
size = node[prefix + 'size'],
activeFlag = node['active'] || node['forceLabel']
activeFlag = node['active'] || node.customAttrs['forceLabel']
// NB active is used in all TW selections
// forceLabel is seldom used
// forceLabel is used in cluster highlighting
let X = node[prefix + 'x']
let Y = node[prefix + 'y']
......@@ -114,11 +114,7 @@ SigmaUtils = function () {
// Label background (aligned on hover equivalent):
var x,y,w,h,e,
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
fontStyle = settings('hoverFontStyle') || settings('fontStyle') // for label background
context.font = (fontStyle ? fontStyle + ' ' : '') +
fontSize + 'px ' + (settings('hoverFont') || settings('font'));
......@@ -201,13 +197,14 @@ SigmaUtils = function () {
//debug
// console.warn("rendering edge", edge)
var rgbStr = edge.customAttrs.rgb
var defSize = edge[prefix + 'size'] || 1
var defSize = edge[prefix + 'size'] || settings("minEdgeSize") || 1 ;
if (edge.customAttrs.activeEdge) {
size = defSize * 1.5
// color with less opacity
size = defSize * 2
// color with no opacity
// 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) {
color = TW.edgeGreyColor
......@@ -307,8 +304,8 @@ SigmaUtils = function () {
borderColor = TW.nodesGreyBorderColor
// cf settings_explorerjs, defgrey_color and greyEverything()
}
// neighbor nodes should be more visible
else if(node.customAttrs.neighbor) {
// neighbor nodes <=> (highlight flag AND selectionActive)
else if(node.customAttrs.highlight) {
// borderColor = "rgba(220, 220, 220, 0.7)"
nodeSize *= 1.4
borderSize *= 1.4
......@@ -318,6 +315,12 @@ SigmaUtils = function () {
// 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
if (settings('twNodeRendBorderSize') > 0) {
......@@ -491,20 +494,20 @@ SigmaUtils = function () {
// n = getVisibleNodes();
// for(i=0;i<n.length;i++) {
// if(n[i].hidden==false){
// if(n[i].inDegree==minIn && n[i].forceLabel==false) {
// n[i].forceLabel=true;
// if(n[i].inDegree==minIn && n[i].customAttrs.forceLabel==false) {
// n[i].customAttrs.forceLabel=true;
// counter++;
// }
// if(n[i].inDegree==maxIn && n[i].forceLabel==false) {
// n[i].forceLabel=true;
// if(n[i].inDegree==maxIn && n[i].customAttrs.forceLabel==false) {
// n[i].customAttrs.forceLabel=true;
// counter++;
// }
// if(n[i].outDegree==minOut && n[i].forceLabel==false) {
// n[i].forceLabel=true;
// if(n[i].outDegree==minOut && n[i].customAttrs.forceLabel==false) {
// n[i].customAttrs.forceLabel=true;
// counter++;
// }
// if(n[i].outDegree==maxOut && n[i].forceLabel==false) {
// n[i].forceLabel=true;
// if(n[i].outDegree==maxOut && n[i].customAttrs.forceLabel==false) {
// n[i].customAttrs.forceLabel=true;
// counter++;
// }
// 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