Commit 09c12d64 authored by Romain Loth's avatar Romain Loth

better neighbors data structure and render

1) fixed logic where same side neighboors where computed several times (=> pass them as argument) 2) renamed updateLeftPanel to clearer updateRelatedNodesPanel 3) passed part of the color switching mecanisms to renderers, based on flags 4) adjust some css and remove some debug comments
parent 9e4afff2
...@@ -56,37 +56,37 @@ ...@@ -56,37 +56,37 @@
font-weight: bold; font-weight: bold;
font-size: 90%; font-size: 90%;
} }
.my-legend .legend-scale ul { .my-legend .legend-scale ul {
margin: 0; margin: 0;
margin-bottom: 5px; margin-bottom: 5px;
padding: 0; padding: 0;
float: left; float: left;
list-style: none; list-style: none;
} }
.my-legend .legend-scale ul li { .my-legend .legend-scale ul li {
font-size: 80%; font-size: 80%;
list-style: none; list-style: none;
margin-left: 0; margin-left: 0;
line-height: 18px; line-height: 16px;
margin-bottom: 2px; margin-bottom: 2px;
} }
.my-legend ul.legend-labels li span { .my-legend ul.legend-labels li span {
display: block; display: block;
float: left; float: left;
height: 16px; height: 16px;
width: 30px; width: 30px;
margin-right: 5px; margin-right: 5px;
margin-left: 0; margin-left: 0;
border: 1px solid #999; border: 1px solid #999;
} }
.my-legend .legend-source { .my-legend .legend-source {
font-size: 70%; font-size: 70%;
color: #999; color: #999;
clear: both; clear: both;
} }
.my-legend a { .my-legend a {
color: #777; color: #777;
} }
/*.btn-sm[normal] {*/ /*.btn-sm[normal] {*/
......
...@@ -5,7 +5,7 @@ var TW = {} ...@@ -5,7 +5,7 @@ var TW = {}
TW.colorByAtt = false; TW.colorByAtt = false;
TW.twittertimeline = false; TW.twittertimeline = false;
TW.minimap=false; TW.minimap=false;
TW.getAdditionalInfo=false;// True: Activate TopPapers feature. TW.getAdditionalInfo=true;// True: Activate TopPapers feature.
//TW.mainfile = ["db.json"]; //TW.mainfile = ["db.json"];
// // TW.mainfile = "api.json"; // // TW.mainfile = "api.json";
TW.mainfile = [ TW.mainfile = [
...@@ -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"] = true ; TW.DivsFlags["histogramModule"] = false ;
TW.DivsFlags["crowdsourcingModule"] = true ; // £TODO fix topPapers TW.DivsFlags["crowdsourcingModule"] = true ; // £TODO fix topPapers
TW.SystemStates = {} TW.SystemStates = {}
...@@ -102,8 +102,13 @@ var semanticConverged=false; ...@@ -102,8 +102,13 @@ var semanticConverged=false;
// ============ < / DEVELOPER OPTIONS > ============ // ============ < / DEVELOPER OPTIONS > ============
var showLabelsIfZoom=1.0; var showLabelsIfZoom=1.0;
TW.edgeDefaultOpacity = 0.3 // opacity when true_color TW.edgeDefaultOpacity = 0.5 // opacity when true_color
TW.edgeGreyColor = "rgba(200, 200, 200, 0.5)"; TW.edgeGreyColor = "rgba(150, 150, 150, 0.2)";
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 = true // costly hi-def rendering (true => pixelRatio x 2) TW.overSampling = true // costly hi-def rendering (true => pixelRatio x 2)
// ============ < / DEVELOPER OPTIONS > ============ // ============ < / DEVELOPER OPTIONS > ============
......
...@@ -5,7 +5,7 @@ function SelectionEngine() { ...@@ -5,7 +5,7 @@ function SelectionEngine() {
// creates the union of prevsels and currsels, if addvalue // creates the union of prevsels and currsels, if addvalue
this.SelectorEngine = (function(addvalue , prevsels , currsels ) { this.SelectorEngine = (function(addvalue , prevsels , currsels ) {
console.log("addvalue, prevsels, currsels",addvalue, prevsels, currsels) // console.log("addvalue, prevsels, currsels",addvalue, prevsels, currsels)
var targeted = [] var targeted = []
var buffer = Object.keys(prevsels).map(Number).sort(this.sortNumber); var buffer = Object.keys(prevsels).map(Number).sort(this.sortNumber);
...@@ -19,7 +19,9 @@ function SelectionEngine() { ...@@ -19,7 +19,9 @@ function SelectionEngine() {
} else targeted = currsels; } else targeted = currsels;
targeted = targeted.map(Number) targeted = targeted.map(Number)
console.log("targeted::", targeted)
// debug
// console.log("targeted::", targeted)
// NB new sigma: my REFA deprecated clicktype=="double" // NB new sigma: my REFA deprecated clicktype=="double"
if(targeted.length==0) return []; if(targeted.length==0) return [];
...@@ -142,15 +144,30 @@ function SelectionEngine() { ...@@ -142,15 +144,30 @@ function SelectionEngine() {
* Main function for any selecting action * Main function for any selecting action
* *
* @nodes: eg targeted array (only ids) * @nodes: eg targeted array (only ids)
*
* external usage : partialGraph.states,
* updateRelatedNodesPanel();
*/ */
// external usage : partialGraph , updateLeftPanel_fix(); // ====================
this.MultipleSelection2 = (function(nodes,nodesDict,edgesDict) { this.MultipleSelection2 = (function(nodes,nodesDict,edgesDict) {
// =====
console.log("IN SelectionEngine.MultipleSelection2:") console.log("IN SelectionEngine.MultipleSelection2:")
console.log("nodes", nodes) console.log("nodes", nodes)
greyEverything(); greyEverything();
var sameSideNeighbors = {}
var oppositeSideNeighbors = {}
// TW.partialGraph.states.slice(-1)[0] is the present graph state // TW.partialGraph.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
// opposites:
// selections:
// type:[0]}
var typeNow = TW.partialGraph.states.slice(-1)[0].type.map(Number).join("|") var typeNow = TW.partialGraph.states.slice(-1)[0].type.map(Number).join("|")
// console.log ("console.loging the Type:") // console.log ("console.loging the Type:")
// console.log (typeNow) // console.log (typeNow)
...@@ -167,22 +184,31 @@ function SelectionEngine() { ...@@ -167,22 +184,31 @@ function SelectionEngine() {
if(! $.isArray(nodes)) ndsids.push(nodes); if(! $.isArray(nodes)) ndsids.push(nodes);
else ndsids=nodes; else ndsids=nodes;
for(var i in ndsids) { for(var i in ndsids) {
s = ndsids[i]; var s = ndsids[i];
if(TW.Relations[typeNow] && TW.Relations[typeNow][s] ) { if(TW.Relations[typeNow] && TW.Relations[typeNow][s] ) {
let neigh = TW.Relations[typeNow][s] var neigh = TW.Relations[typeNow][s]
if(neigh) { if(neigh) {
for(var j in neigh) { for(var j in neigh) {
let t = neigh[j] var t = neigh[j]
nodes_2_colour[t]=false; // we add as neighbor to color it (except if already in targeted)
if (!nodes_2_colour[t]) nodes_2_colour[t]=false;
edges_2_colour[s+";"+t]=true; edges_2_colour[s+";"+t]=true;
edges_2_colour[t+";"+s]=true; edges_2_colour[t+";"+s]=true;
// since we're there we keep the info
if (typeof sameSideNeighbors[t] == 'undefined') {
sameSideNeighbors[t]=0
}
sameSideNeighbors[t]++
} }
} }
} }
} // we make the selected (source) node active too
for(var i in ndsids) { nodes_2_colour[s]=true;
nodes_2_colour[ndsids[i]]=true;
selections[ndsids[i]]=1; // to delete please // update GLOBAL selections dict
// (FIXME it's widely used but TW.SystemStates.selections has the same)
selections[ndsids[i]]=1;
} }
} }
...@@ -194,16 +220,18 @@ function SelectionEngine() { ...@@ -194,16 +220,18 @@ function SelectionEngine() {
n.customAttrs['grey'] = 0; n.customAttrs['grey'] = 0;
if(nodes_2_colour[nid]) { if(nodes_2_colour[nid]) {
n.active = true; n.active = true;
selections[nid]=1 // selections[nid]=1
}
else {
n.customAttrs.neighbor = true;
} }
} }
} }
} }
console.log('edges_2_colour', edges_2_colour)
for(var eid in edges_2_colour) {
// console.log(eid) for(var eid in edges_2_colour) {
// at this point all edges are grey b/c greyEverything() was called
let an_edge = TW.partialGraph.graph.edges(eid) let an_edge = TW.partialGraph.graph.edges(eid)
if(!isUndef(an_edge) && !an_edge.hidden){ if(!isUndef(an_edge) && !an_edge.hidden){
...@@ -211,6 +239,7 @@ function SelectionEngine() { ...@@ -211,6 +239,7 @@ function SelectionEngine() {
// make all color etc changes in renderers depending on flags // make all color etc changes in renderers depending on flags
an_edge.color = an_edge.customAttrs['true_color']; an_edge.color = an_edge.customAttrs['true_color'];
an_edge.customAttrs['grey'] = 0; an_edge.customAttrs['grey'] = 0;
an_edge.customAttrs['activeEdge'] = 1;
} }
} }
...@@ -223,6 +252,9 @@ function SelectionEngine() { ...@@ -223,6 +252,9 @@ function SelectionEngine() {
// alert("MultipleSelection2=======\nthe_new_sels:" + JSON.stringify(the_new_sels)) // alert("MultipleSelection2=======\nthe_new_sels:" + JSON.stringify(the_new_sels))
// global flag
TW.selectionActive = true
// we send our "gotNodeSet" event // we send our "gotNodeSet" event
// (signal for plugins that a search-selection was done or a new hand picked selection) // (signal for plugins that a search-selection was done or a new hand picked selection)
$('#searchinput').trigger({ $('#searchinput').trigger({
...@@ -232,37 +264,49 @@ function SelectionEngine() { ...@@ -232,37 +264,49 @@ function SelectionEngine() {
}); });
// console.log("Event [gotNodeSet] sent from Tinaweb MultipleSelection2") // console.log("Event [gotNodeSet] sent from Tinaweb MultipleSelection2")
// TODO REFA this used for bipartite case but needs testing with correct typestring case
var neighsDict = {}
if(TW.Relations["1|1"]) { if(TW.Relations["1|1"]) {
for(var s in the_new_sels) { for(var s in the_new_sels) {
var neighs = TW.Relations["1|1"][the_new_sels[s]]; var bipaNeighs = TW.Relations["1|1"][the_new_sels[s]];
for(var n in neighs) { for(var n in neighs) {
if (!neighsDict[neighs[n]]) if (typeof oppositeSideNeighbors[bipaNeighs[n]] == "undefined")
neighsDict[neighs[n]] = 0; oppositeSideNeighbors[bipaNeighs[n]] = 0;
neighsDict[neighs[n]]++; oppositeSideNeighbors[bipaNeighs[n]]++;
} }
} }
} }
var oppos = ArraySortByValue(neighsDict, function(a,b){ // debug
// var neiLabls = []
// for (var neiId in sameSideNeighbors) {
// neiLabls.push(TW.Nodes[neiId].label)
// }
// console.log('sameSideNeighbors labels', neiLabls)
// NB doesn't only sort by value but also
// rewrites dict[id]: val
// as array[order]: {key:id, value:val}
var oppos = ArraySortByValue(oppositeSideNeighbors, function(a,b){
return b-a
});
var same = ArraySortByValue(sameSideNeighbors, function(a,b){
return b-a return b-a
}); });
// console.debug('oppos', oppos)
// console.debug('same', same)
//
overNodes=true; overNodes=true;
TW.partialGraph.render(); TW.partialGraph.render();
updateLeftPanel( selections , oppos ); updateRelatedNodesPanel( selections , same, oppos );
for(var n in neighsDict)
delete neighsDict[n]
}).index() }).index()
}; };
// REFA tempo expose selectionEngine and methods // TODO TW.SelInst
var SelInst var SelInst
......
...@@ -97,14 +97,14 @@ getUrlParam = (function () { ...@@ -97,14 +97,14 @@ getUrlParam = (function () {
function ArraySortByValue(array, sortFunc){ function ArraySortByValue(array, sortFunc){
var tmp = []; var tmp = [];
oposMAX=0; // oposMAX=0;
for (var k in array) { for (var k in array) {
if (array.hasOwnProperty(k)) { if (array.hasOwnProperty(k)) {
tmp.push({ tmp.push({
key: k, key: k,
value: array[k] value: array[k]
}); });
if((array[k]) > oposMAX) oposMAX= array[k]; // if((array[k]) > oposMAX) oposMAX= array[k];
} }
} }
......
...@@ -182,9 +182,12 @@ if(RES["OK"]) { ...@@ -182,9 +182,12 @@ if(RES["OK"]) {
TW.Edges = dicts.edges; TW.Edges = dicts.edges;
TW.nodeIds = Object.keys(dicts.nodes) // useful for loops TW.nodeIds = Object.keys(dicts.nodes) // useful for loops
TW.edgeIds = Object.keys(dicts.edges) TW.edgeIds = Object.keys(dicts.edges)
TW.selectionActive = false // changes rendering mode
if (the_data.clusters) TW.Clusters = the_data.clusters if (the_data.clusters) TW.Clusters = the_data.clusters
TW.nodes1 = dicts.n1;//not used // TW.nodes1 = dicts.n1;//not used
var catDict = dicts.catDict var catDict = dicts.catDict
// console.log("CategoriesDict: ") // console.log("CategoriesDict: ")
// console.log(catDict) // console.log(catDict)
......
...@@ -19,7 +19,8 @@ function cancelSelection (fromTagCloud) { ...@@ -19,7 +19,8 @@ function cancelSelection (fromTagCloud) {
// console.log("cancelSelection: edge", e) // console.log("cancelSelection: edge", e)
if (e) { if (e) {
e.color = e.customAttrs['grey'] ? e.customAttrs['true_color'] : e.color; e.color = e.customAttrs['grey'] ? e.customAttrs['true_color'] : e.color;
e.customAttrs['grey'] = 0; e.customAttrs.grey = 0;
e.customAttrs.activeEdge = 0;
} }
} }
} }
...@@ -32,7 +33,7 @@ function cancelSelection (fromTagCloud) { ...@@ -32,7 +33,7 @@ function cancelSelection (fromTagCloud) {
n.active = false; n.active = false;
// 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
} }
} }
...@@ -68,6 +69,9 @@ function cancelSelection (fromTagCloud) { ...@@ -68,6 +69,9 @@ function cancelSelection (fromTagCloud) {
if(TW.partialGraph.states.slice(-1)[0].level) if(TW.partialGraph.states.slice(-1)[0].level)
LevelButtonDisable(true); LevelButtonDisable(true);
// global flag
TW.selectionActive = false
// finally redraw // finally redraw
TW.partialGraph.render(); TW.partialGraph.render();
} }
...@@ -187,12 +191,14 @@ function pushSWClick(arg){ ...@@ -187,12 +191,14 @@ function pushSWClick(arg){
// tag cloud div // tag cloud div
function htmlfied_alternodes(elems) { function htmlfied_alternodes(elems) {
var oppositesNodes=[] var oppositesNodes=[]
js1='onclick="graphTagCloudElem(\''; var js1='onclick="graphTagCloudElem(\'';
js2="');\"" var js2="');\""
frecMAX=elems[0].value var frecMAX=elems[0].value
for(var i in elems){ for(var i in elems){
id=elems[i].key var id=elems[i].key
frec=elems[i].value var frec=elems[i].value
var fontSize
var htmlfied_alternode
if(frecMAX==1) fontSize=desirableTagCloudFont_MIN; if(frecMAX==1) fontSize=desirableTagCloudFont_MIN;
else { else {
fontSize= fontSize=
...@@ -201,8 +207,7 @@ function htmlfied_alternodes(elems) { ...@@ -201,8 +207,7 @@ function htmlfied_alternodes(elems) {
((desirableTagCloudFont_MAX-desirableTagCloudFont_MIN)/(frecMAX-1)); ((desirableTagCloudFont_MAX-desirableTagCloudFont_MIN)/(frecMAX-1));
} }
if(!isUndef(TW.Nodes[id])){ if(!isUndef(TW.Nodes[id])){
// js1 js2
// onclick="graphTagCloudElem(' ');
htmlfied_alternode = '<span class="tagcloud-item" style="font-size:'+fontSize+'px;" '+js1+id+js2+'>'+ TW.Nodes[id].label+ '</span>'; htmlfied_alternode = '<span class="tagcloud-item" style="font-size:'+fontSize+'px;" '+js1+id+js2+'>'+ TW.Nodes[id].label+ '</span>';
oppositesNodes.push(htmlfied_alternode) oppositesNodes.push(htmlfied_alternode)
} }
...@@ -213,7 +218,9 @@ function htmlfied_alternodes(elems) { ...@@ -213,7 +218,9 @@ function htmlfied_alternodes(elems) {
function manualForceLabel(nodeid, active, justHover) { function manualForceLabel(nodeid, active, justHover) {
// console.log("manual|"+nodeid+"|"+active) // console.log("manual|"+nodeid+"|"+active)
var nd = TW.partialGraph.graph.nodes(nodeid) var nd = TW.partialGraph.graph.nodes(nodeid)
nd.active=active;
// TODO harmonize with other status => bien re-distinguer neighbor et active
// nd.active=active;
// console.log('justHover', justHover) // console.log('justHover', justHover)
// var t0, t1 // var t0, t1
...@@ -261,22 +268,22 @@ function clearHover() { ...@@ -261,22 +268,22 @@ function clearHover() {
) )
} }
// TODO rm ? function doesn't make sense, probably replaced by htmlfied_tagcloud
function htmlfied_samenodes(elems) { // function htmlfied_samenodes(elems) {
var sameNodes=[] // var sameNodes=[]
js1=' onmouseover="manualForceLabel(this.id,true, true);" '; // js1=' onmouseover="manualForceLabel(this.id,true, true);" ';
js2=' onmouseout="manualForceLabel(this.id,true, true);" '; // js2=' onmouseout="manualForceLabel(this.id,true, true);" ';
if(elems.length>0) { // if(elems.length>0) {
var A = getVisibleNodes() // var A = getVisibleNodes()
for (var a in A){ // for (var a in A){
n = A[a] // n = A[a]
if(!n.active && n.color.charAt(0)=="#" ) { // if(!n.active && n.color.charAt(0)=="#" ) {
sameNodes.push('<li onmouseover="manualForceLabel(\''+n.id+'\',true, true)" onmouseout="manualForceLabel(\''+n.id+'\',false, true)" ><a>'+ n.label+ '</a></li>') // sameNodes.push('<li onmouseover="manualForceLabel(\''+n.id+'\',true, true)" onmouseout="manualForceLabel(\''+n.id+'\',false, true)" ><a>'+ n.label+ '</a></li>')
} // }
} // }
} // }
return sameNodes // return sameNodes
} // }
// nodes information div // nodes information div
function htmlfied_nodesatts(elems){ function htmlfied_nodesatts(elems){
...@@ -344,11 +351,15 @@ function htmlfied_tagcloud(elems , limit) { ...@@ -344,11 +351,15 @@ function htmlfied_tagcloud(elems , limit) {
let id=elems[i].key let id=elems[i].key
let frec=elems[i].value let frec=elems[i].value
if(frecMAX > 1) { if(frecMAX > 1) {
let fontSize= fontSize=
desirableTagCloudFont_MIN+ desirableTagCloudFont_MIN+
(frec-1)* (frec-1)*
((desirableTagCloudFont_MAX-desirableTagCloudFont_MIN)/(frecMAX-1)); ((desirableTagCloudFont_MAX-desirableTagCloudFont_MIN)/(frecMAX-1));
} }
// debug
// console.log('htmlfied_tagcloud (',id, TW.Nodes[id].label,') freq',frec,' fontSize', fontSize)
if(!isUndef(TW.Nodes[id])){ if(!isUndef(TW.Nodes[id])){
var jspart = ' onclick="manualSelectNode(\''+id+'\')" onmouseover="manualForceLabel(\''+id+'\',true, true)" onmouseout="manualForceLabel(\''+id+'\',false, true)"' var jspart = ' onclick="manualSelectNode(\''+id+'\')" onmouseover="manualForceLabel(\''+id+'\',true, true)" onmouseout="manualForceLabel(\''+id+'\',false, true)"'
let htmlfied_alternode = '<span class="tagcloud-item" style="font-size:'+fontSize+'px;" '+jspart+'>'+ TW.Nodes[id].label+ '</span>'; let htmlfied_alternode = '<span class="tagcloud-item" style="font-size:'+fontSize+'px;" '+jspart+'>'+ TW.Nodes[id].label+ '</span>';
...@@ -360,7 +371,23 @@ function htmlfied_tagcloud(elems , limit) { ...@@ -360,7 +371,23 @@ function htmlfied_tagcloud(elems , limit) {
//missing: getTopPapers for both node types //missing: getTopPapers for both node types
//considering complete graphs case! <= maybe i should mv it //considering complete graphs case! <= maybe i should mv it
function updateLeftPanel( sels , oppos ) { function updateRelatedNodesPanel( sels , same, oppos ) {
// debug
// neiLabls = []
// for (var l in same) {
// var neiId = same[l].key
// if (TW.Nodes[neiId]) {
//
// neiLabls.push(TW.Nodes[neiId].label)
// }
// else {
// console.warn("missing entry for neiId", neiId)
// }
// }
// console.log("updateRelatedNodesPanel, same:",neiLabls)
var namesDIV='' var namesDIV=''
var alterNodesDIV='' var alterNodesDIV=''
var informationDIV='' var informationDIV=''
...@@ -379,19 +406,8 @@ function updateLeftPanel( sels , oppos ) { ...@@ -379,19 +406,8 @@ function updateLeftPanel( sels , oppos ) {
var sameNodesDIV = ""; var sameNodesDIV = "";
if(getNodeIDs(sels).length>0) { if(getNodeIDs(sels).length>0) {
var temp_voisinage = {}
var A = getVisibleNodes()
for (var a in A){
var n = A[a]
if(!n.active && n.color.charAt(0)=="#" ) {
temp_voisinage[n.id] = Math.round(TW.Nodes[n.id].size)
}
}
var voisinage = ArraySortByValue(temp_voisinage, function(a,b){
return b-a
});
sameNodesDIV+='<div id="sameNodes">';//tagcloud sameNodesDIV+='<div id="sameNodes">';//tagcloud
var tagcloud_opposite_neigh = htmlfied_tagcloud( voisinage , TW.tagcloud_limit) var tagcloud_opposite_neigh = htmlfied_tagcloud( same , TW.tagcloud_limit)
sameNodesDIV+= (tagcloud_opposite_neigh!=false) ? tagcloud_opposite_neigh.join("\n") : "No related terms."; sameNodesDIV+= (tagcloud_opposite_neigh!=false) ? tagcloud_opposite_neigh.join("\n") : "No related terms.";
sameNodesDIV+= '</div>'; sameNodesDIV+= '</div>';
} }
...@@ -547,18 +563,23 @@ function graphTagCloudElem(nodes) { ...@@ -547,18 +563,23 @@ function graphTagCloudElem(nodes) {
} }
// /!\ £TODO change only *flags* here, and then // edges greyish color for unselected, when we have a selection
// make all color etc changes in renderers depending on flags // case default: color is precomputed as node true_color + alpha .5
function greyEverything(){ // cases when coloredBy (ex: centrality): color must be recomputed here
function greyEverything(notDefaultColors){
for(let j=0 ; j<TW.nNodes ; j++){ for(let 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) {
n.customAttrs.true_color = n.color
// TODO check if no simpler strategy than reinvoke hex2rga each time
// n.color = "rgba("+hex2rga(n.color)+",0.5)"
n.color = "rgba(15,15,15,0.5)"
n.customAttrs['grey'] = 1 n.customAttrs['grey'] = 1
n.customAttrs.true_color = n.color
// normal case handled by node renderers
// will see the n.customAttrs.grey flag => use n.customAttrs.defgrey_color
// special case after a coloredBy or clustersBy
if (notDefaultColors)
n.color = "rgba("+hex2rga(n.color)+",0.5)"
} }
} }
...@@ -566,9 +587,8 @@ function greyEverything(){ ...@@ -566,9 +587,8 @@ function greyEverything(){
for(let i=0;i<TW.nEdges;i++){ for(let 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.true_color = e.color
e.color = TW.edgeGreyColor
e.customAttrs.grey = 1 e.customAttrs.grey = 1
e.customAttrs.true_color = e.color
} }
} }
} }
...@@ -576,6 +596,7 @@ function greyEverything(){ ...@@ -576,6 +596,7 @@ function greyEverything(){
} }
// new sigma.js: TODO change logic (the reverse of greyEverything is done by redraw for the colors, and cancelSelection for the flags...) // new sigma.js: TODO change logic (the reverse of greyEverything is done by redraw for the colors, and cancelSelection for the flags...)
// but this could be used for colorsBy menu
// function graphResetColor(){ // function graphResetColor(){
// nds = TW.partialGraph.graph.nodes().filter(function(x) { // nds = TW.partialGraph.graph.nodes().filter(function(x) {
// return !x['hidden']; // return !x['hidden'];
......
...@@ -24,9 +24,20 @@ SigmaUtils = function () { ...@@ -24,9 +24,20 @@ SigmaUtils = function () {
type : n.type, type : n.type,
// new setup (TODO rm the old at TinaWebJS nodes_2_colour) // new setup (TODO rm the old at TinaWebJS nodes_2_colour)
customAttrs : { customAttrs : {
grey: 0, grey: false,
true_color : n.color true_color : n.color,
} defgrey_color : "rgba("+hex2rga(n.color)+",.4)"
},
// £TODO gather all flags like this
// customFlags : {
// // status flags
// grey: false,
// active: false,
// hidden: false,
// // forceLabel: false,
// neighbour: false,
// }
} }
if(n.shape) node.shape = n.shape; if(n.shape) node.shape = n.shape;
// console.log("FillGraph, created new node:", node) // console.log("FillGraph, created new node:", node)
...@@ -50,6 +61,8 @@ SigmaUtils = function () { ...@@ -50,6 +61,8 @@ SigmaUtils = function () {
let e = TW.Edges[s+";"+t] let e = TW.Edges[s+";"+t]
if(e) { if(e) {
if(e.source != e.target) { if(e.source != e.target) {
var computedColorInfo = sigmaTools.edgeColor(e.source, e.target, nodes)
var edge = { var edge = {
// sigma mandatory properties // sigma mandatory properties
...@@ -58,16 +71,17 @@ SigmaUtils = function () { ...@@ -58,16 +71,17 @@ SigmaUtils = function () {
source : e.source, source : e.source,
target : e.target, target : e.target,
weight : e.weight, weight : e.weight,
// size : e.weight, // REFA s/weight/size/ ? size : e.weight, // REFA s/weight/size/ ?
color : sigmaTools.edgeColor(e.source, e.target, nodes), color : computedColorInfo.res,
hidden : false, hidden : false,
// twjs additional properties // twjs additional properties
type : e.type, type : e.type,
customAttrs : { customAttrs : {
grey: 0, grey: 0,
true_color : n.color true_color : computedColorInfo.res,
rgb : computedColorInfo.rgb_array
} }
} }
...@@ -132,7 +146,11 @@ SigmaUtils = function () { ...@@ -132,7 +146,11 @@ SigmaUtils = function () {
fontSize + 'px ' + (settings('hoverFont') || settings('font')); fontSize + 'px ' + (settings('hoverFont') || settings('font'));
context.beginPath(); context.beginPath();
context.fillStyle = "#F7E521"; // yellow
if (TW.selectedColor == "node")
context.fillStyle = node.color; // node's
else
context.fillStyle = "#F7E521"; // yellow
if (node.label && settings('labelHoverShadow')) { if (node.label && settings('labelHoverShadow')) {
context.shadowOffsetX = 0; context.shadowOffsetX = 0;
...@@ -196,29 +214,37 @@ SigmaUtils = function () { ...@@ -196,29 +214,37 @@ SigmaUtils = function () {
}; };
// source: github.com/jacomyal/sigma.js/commit/25e2153 // source: github.com/jacomyal/sigma.js/commit/25e2153
// POSS: modify to incorporate mix colors (repaintEdges) // + boosting edges with property edge.customAttrs.activeEdge
this.twRender.canvas.edges.curve = function(edge, source, target, context, settings) { this.twRender.canvas.edges.curve = function(edge, source, target, context, settings) {
var color = edge.color, var color, size,
prefix = settings('prefix') || '', prefix = settings('prefix') || ''
edgeColor = settings('edgeColor'),
defaultNodeColor = settings('defaultNodeColor'),
defaultEdgeColor = settings('defaultEdgeColor'); //debug
// console.warn("rendering edge", edge)
if (!color)
switch (edgeColor) { var rgb = edge.customAttrs.rgb
case 'source': var defSize = edge[prefix + 'size'] || 1
color = source.color || defaultNodeColor; if (edge.customAttrs.activeEdge) {
break; size = defSize * 1.5
case 'target': // color with less opacity
color = target.color || defaultNodeColor; // cf. sigmaTools.edgeColor
break; color = 'rgba('+rgb.join()+',.7)'
default: }
color = defaultEdgeColor; else if (edge.customAttrs.grey) {
break; color = TW.edgeGreyColor
} size = 1
}
else {
// color = "rgba( "+rgb.join()+" , "+TW.edgeDefaultOpacity+")";
color = edge.customAttrs.true_color
size = defSize
}
context.strokeStyle = color; context.strokeStyle = color;
context.lineWidth = edge[prefix + 'size'] || 1; context.lineWidth = size ;
context.beginPath(); context.beginPath();
context.moveTo( context.moveTo(
source[prefix + 'x'], source[prefix + 'x'],
...@@ -235,18 +261,44 @@ SigmaUtils = function () { ...@@ -235,18 +261,44 @@ SigmaUtils = function () {
context.stroke(); context.stroke();
}; };
// node rendering with borders // node rendering with borders and sensitive to current selection mode
this.twRender.canvas.nodes.withBorders = function(node, context, settings) { this.twRender.canvas.nodes.withBorders = function(node, context, settings) {
var prefix = settings('prefix') || ''; var prefix = settings('prefix') || '';
let X = node[prefix + 'x'] let X = node[prefix + 'x']
let Y = node[prefix + 'y'] let Y = node[prefix + 'y']
var borderSize = node[prefix + 'size'] + settings('twNodeRendBorderSize')
var borderColor = settings('twNodeRendBorderColor') || "#000"
var nodeSize = node[prefix + 'size']
var nodeColor = node.color || settings('defaultNodeColor')
// mode variants
if (TW.selectionActive) {
// passive nodes should blend in the grey of TW.edgeGreyColor
if (node.customAttrs.grey) {
nodeColor = node.customAttrs.defgrey_color
borderColor = TW.nodesGreyBorderColor
// cf settings_explorerjs, defgrey_color and greyEverything()
}
// neighbor nodes should be more visible
else if(node.customAttrs.neighbor) {
// borderColor = "rgba(220, 220, 220, 0.7)"
nodeSize *= 1.4
borderSize *= 1.4
}
else if(node.active) {
borderColor = null
// the selected nodes: fill not important because label+background overlay
}
}
// actual drawing
if (settings('twNodeRendBorderSize') > 0) { if (settings('twNodeRendBorderSize') > 0) {
context.fillStyle = borderColor
context.beginPath(); context.beginPath();
context.fillStyle = settings('twNodeRendBorderColor') || "#000"
context.arc( context.arc(
X,Y, X,Y,
node[prefix + 'size'] + settings('twNodeRendBorderSize'), borderSize,
0, 0,
Math.PI * 2, Math.PI * 2,
true true
...@@ -255,11 +307,11 @@ SigmaUtils = function () { ...@@ -255,11 +307,11 @@ SigmaUtils = function () {
context.fill(); context.fill();
} }
context.fillStyle = node.color || settings('defaultNodeColor'); context.fillStyle = nodeColor;
context.beginPath(); context.beginPath();
context.arc( context.arc(
X,Y, X,Y,
node[prefix + 'size'], nodeSize,
0, 0,
Math.PI * 2, Math.PI * 2,
true true
...@@ -675,7 +727,11 @@ function repaintEdges() { ...@@ -675,7 +727,11 @@ function repaintEdges() {
var r = (a[0] + b[0]) >> 1; var r = (a[0] + b[0]) >> 1;
var g = (a[1] + b[1]) >> 1; var g = (a[1] + b[1]) >> 1;
var b = (a[2] + b[2]) >> 1; var b = (a[2] + b[2]) >> 1;
TW.partialGraph.graph.edges(e_id).color = "rgba("+[r,g,b].join(",")+",0.5)"; TW.partialGraph.graph.edges(e_id).color = "rgba("+[r,g,b].join(",")+",0.5)";
// also keep components array (useful if we change opacity when selected)
TW.partialGraph.graph.edges(e_id).customAttrs.rgb = [r,g,b]
} }
} }
......
...@@ -20,6 +20,7 @@ sigmaTools = (function(stools) { ...@@ -20,6 +20,7 @@ sigmaTools = (function(stools) {
'0123456789ABCDEF'.charAt(n % 16); '0123456789ABCDEF'.charAt(n % 16);
}; };
// TODO check duplicate functionalities with repaintEdges
stools.edgeColor = function(src_id, tgt_id, nodes) { stools.edgeColor = function(src_id, tgt_id, nodes) {
//edge color will be the combination of the 2 node colors //edge color will be the combination of the 2 node colors
var a = nodes[src_id]['color']; var a = nodes[src_id]['color'];
...@@ -46,7 +47,7 @@ sigmaTools = (function(stools) { ...@@ -46,7 +47,7 @@ sigmaTools = (function(stools) {
// var color = '#'+sigma.tools.rgbToHex(parseFloat(r),parseFloat(g),parseFloat(b)) // var color = '#'+sigma.tools.rgbToHex(parseFloat(r),parseFloat(g),parseFloat(b))
var color = "rgba( "+r+", "+g+" , "+b+" , "+TW.edgeDefaultOpacity+")"; var color = "rgba( "+r+", "+g+" , "+b+" , "+TW.edgeDefaultOpacity+")";
return color return {'res':color, 'rgb_array':[r,g,b]}
} }
return stools return stools
......
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