Commit 0a809b0d authored by Romain Loth's avatar Romain Loth

WIP mini optimize render 1/2

start integrating neighbors in systemstate (objective: avoid loops on full graph when deselecting with greyEverything) + removed grey flag which was now always == (!active && !highlight)
parent 24baa5d2
......@@ -172,7 +172,7 @@ TW.conf = (function(TW){
TWConf.clusterColorsAtt = true; // show "Set colors" menu
TWConf.dragNodesAvailable = true; // allow dragging nodes with CTRL+click
TWConf.dragNodesAvailable = false; // allow dragging nodes with CTRL+click
TWConf.deselectOnclickStage = true // click on background remove selection ?
// (except when dragging)
......@@ -300,7 +300,7 @@ TW.conf = (function(TW){
logFacets: false, // ...about parsing node attribute:value facets
logSettings: false, // ...about settings at Tina and Sigma init time
logStates: false, // ...about TW.states array
logSelections: false
logSelections: true
}
......
......@@ -154,8 +154,6 @@ function SelectionEngine() {
if (!args) args = {}
if (isUndef(args.nodes)) args.nodes = []
if (isUndef(args.nodesDict)) args.nodesDict = {}
if (isUndef(args.edgesDict)) args.edgesDict = {}
if (TW.conf.debug.logSelections) {
var tMS2_deb = performance.now()
......@@ -164,6 +162,8 @@ function SelectionEngine() {
console.log("nodes", args.nodes)
}
console.warn('££TODO we could grey only active and neighbors if we kept neighbors')
greyEverything();
var sameSideNeighbors = {}
......@@ -179,17 +179,11 @@ function SelectionEngine() {
var activetypesKey = getActivetypesKey()
// console.log ("console.loging the Type:")
// console.log (activetypesKey)
// console.log (" - - - - - - ")
// Dictionaries of: selection+neighbors
var nodes_2_colour = args.nodesDict
var edges_2_colour = args.edgesDict
// Dictionaries of: selection+neighbors
let selections = {}
// targeted arg 'nodes' can be nid array or single nid
var ndsids=[]
if(args.nodes) {
......@@ -197,79 +191,57 @@ function SelectionEngine() {
else ndsids=args.nodes;
for(var i in ndsids) {
var s = ndsids[i];
var srcnid = ndsids[i];
if(TW.Relations[activetypesKey] && TW.Relations[activetypesKey][s] ) {
var neigh = TW.Relations[activetypesKey][s]
if(neigh) {
for(var j in neigh) {
var t = neigh[j]
if(TW.Relations[activetypesKey] && TW.Relations[activetypesKey][srcnid] ) {
var neighs = TW.Relations[activetypesKey][srcnid]
if(neighs) {
for(var j in neighs) {
var tgtnid = neighs[j]
let tgt = TW.partialGraph.graph.nodes(tgtnid)
// highlight edges (except if n hidden or e dropped (<=> lock))
// POSS: use sigma's own index to avoid checking if node exists or edge dropped
if (TW.partialGraph.graph.nodes(t)
&& ! TW.partialGraph.graph.nodes(t).hidden
&& (
(TW.Edges[s+";"+t] && !TW.Edges[s+";"+t].lock)
||
(TW.Edges[t+";"+s] && !TW.Edges[t+";"+s].lock)
)
) {
edges_2_colour[s+";"+t]=true;
edges_2_colour[t+";"+s]=true;
// POSS: use sigma's own index to avoid checking if edge dropped
if (tgt && !tgt.hidden) {
// we add as neighbor to color it (except if already in targeted)
if (!nodes_2_colour[t]) nodes_2_colour[t]=false;
let eid1 = srcnid+';'+tgtnid
let eid2 = tgtnid+';'+srcnid
// since we're there we keep the neighbors info
if (typeof sameSideNeighbors[t] == 'undefined') {
sameSideNeighbors[t]=0
}
if ( (TW.Edges[eid1] && !TW.Edges[eid1].lock)
||
(TW.Edges[eid2] && !TW.Edges[eid2].lock) ) {
if (TW.Edges[s+";"+t])
sameSideNeighbors[t] += TW.Edges[s+";"+t].weight || 1
let e1 = TW.partialGraph.graph.edges(eid1)
let e2 = TW.partialGraph.graph.edges(eid2)
if (TW.Edges[t+";"+s])
sameSideNeighbors[t] += TW.Edges[t+";"+s].weight || 1
}
}
// since we're there we'll also keep the neighbors info
if (typeof sameSideNeighbors[tgtnid] == 'undefined') {
sameSideNeighbors[tgtnid]=0
}
}
// we make the selected (source) node active too
nodes_2_colour[s]=true;
// update local selections dict
selections[ndsids[i]]=1;
// **make the edge active**
if (e1 && !e1.hidden) {
e1.customAttrs.activeEdge = 1;
sameSideNeighbors[tgtnid] += e1.weight || 1
}
if (e2 && !e2.hidden) {
e2.customAttrs.activeEdge = 1;
sameSideNeighbors[tgtnid] += e2.weight || 1
}
// separate loop to allow nodes_2_colour without nodes as args (only used in changeType)
for(var nid in nodes_2_colour) {
if(nid) {
n = TW.partialGraph.graph.nodes(nid)
if(n) {
// our deselected flag
n.customAttrs['grey'] = 0;
// it's a selected node
if(nodes_2_colour[nid]) {
n.active = true;
// we add as neighbor to color it (except if already in targeted)
if (!tgt.customAttrs.active) tgt.customAttrs.highlight = 1;
}
// it's a neighbor
else {
n.customAttrs.highlight = true;
}
}
}
}
// we make the selected (source) node active too
let src = TW.partialGraph.graph.nodes(srcnid)
src.customAttrs.active = true;
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)
if(!isUndef(an_edge) && !an_edge.hidden){
an_edge.customAttrs['grey'] = 0;
an_edge.customAttrs['activeEdge'] = 1;
// update local selections dict
selections[ndsids[i]]=1;
}
}
......@@ -278,29 +250,17 @@ function SelectionEngine() {
let theSelection = Object.keys(selections)
// it's a new SystemState
TW.pushState( { sels: theSelection } )
// we send our "gotNodeSet" event
// (signal for plugins that a search-selection was done or a new hand picked selection)
$('#searchinput').trigger({
type: "tw:gotNodeSet",
q: $("#searchinput").val(),
nodeIds: theSelection
});
// console.log("Event [gotNodeSet] sent from Tinaweb MultipleSelection2")
// neighbors of the opposite type
if(TW.Relations["1|1"]) {
for(var s in theSelection) {
var bipaNeighs = TW.Relations["1|1"][theSelection[s]];
for(var srcnid in theSelection) {
var bipaNeighs = TW.Relations["1|1"][theSelection[srcnid]];
for(var n in bipaNeighs) {
if (typeof oppositeSideNeighbors[bipaNeighs[n]] == "undefined")
oppositeSideNeighbors[bipaNeighs[n]] = 0;
for(var k in bipaNeighs) {
if (typeof oppositeSideNeighbors[bipaNeighs[k]] == "undefined")
oppositeSideNeighbors[bipaNeighs[k]] = 0;
// £TODO weighted increment
oppositeSideNeighbors[bipaNeighs[n]]++;
oppositeSideNeighbors[bipaNeighs[k]]++;
}
}
}
......@@ -315,11 +275,22 @@ function SelectionEngine() {
});
if (TW.conf.debug.logSelections) {
console.debug('new states\'s selectionNids', theSelection)
console.debug('oppos', oppos)
console.debug('same', same)
console.log('new states\'s selectionNids', theSelection)
console.log('oppos', oppos)
console.log('same', same)
}
// it's a new SystemState
TW.pushState( { 'sels': theSelection, 'same': same, 'oppos': oppos } )
// we send our "gotNodeSet" event
// (signal for plugins that a search-selection was done or a new hand picked selection)
$('#searchinput').trigger({
type: "tw:gotNodeSet",
q: $("#searchinput").val(),
nodeIds: theSelection
});
// global flag
TW.gui.selectionActive = true
......@@ -466,13 +437,14 @@ var TinaWebJS = function ( sigmacanvas ) {
// custom labels rendering
// - based on the normal one sigma.canvas.labels.def
// - additionnaly supports 'active/forcelabel' node property (magnify x 3)
// - additionnaly supports 'active/highlight' node property (magnify x 3)
// - also handles 'forceLabel' property
sigmaModule.canvas.labels.def = tempo.twRender.canvas.labels.largeractive
// custom hovers rendering
// - based on the normal one sigma.canvas.hovers.def
// - additionnaly magnifies all labels x 2
// - additionnaly supports 'active/forcelabel' node property (magnify x 3)
// - additionnaly supports 'active/highlight' node property (magnify x 3)
sigmaModule.canvas.hovers.def = tempo.twRender.canvas.hovers.largerall
if (TW.conf.debug.logSettings) console.log('tw renderers registered in sigma module')
......@@ -576,6 +548,8 @@ var TinaWebJS = function ( sigmacanvas ) {
console.log(" ############ changeTYPE click");
if (TW.partialGraph.isForceAtlas2Running())
sigma_utils.ourStopFA2();
console.log("DBG before changeType SystemState:", TW.SystemState())
changeType();
setTimeout(function(){
......@@ -851,11 +825,6 @@ var TinaWebJS = function ( sigmacanvas ) {
currsels:[theNodeId],
prevsels: TW.SystemState().selectionNids
} )
//
// not needed because selInst calls greyEverything
// cancelSelection(false, {norender:true}); // no need to render before MS2
// 2)
if(targeted.length>0) {
selInst.MultipleSelection2( {nodes:targeted} )
......
......@@ -374,7 +374,7 @@ function mainStartGraph(inFormat, inData, twInstance) {
TW.nodeIds = Object.keys(dicts.nodes) // useful for loops
TW.edgeIds = Object.keys(dicts.edges)
// in-place: pre-compute all color/grey/size properties
// in-place: pre-compute all color/unselected color/size properties
prepareNodesRenderingProperties(TW.Nodes)
prepareEdgesRenderingProperties(TW.Edges, TW.Nodes)
......
......@@ -23,7 +23,10 @@ TW.pushState = function( args ) {
if (!isUndef(args.activetypes)) newState.activetypes = args.activetypes
if (!isUndef(args.level)) newState.level = args.level;
// POSS1: add neighbors (of both types) in a .neighborsNids[type] slot
// neighbors (of both types) in a .neighborsNids[type] slot
if(!isUndef(args.same)) newState.samesideSortdNeighs = args.same;
if(!isUndef(args.oppos)) newState.opposideSortdNeighs = args.oppos;
// POSS2: add filterSliders params to be able to recreate subsets at a given time
// useful shortcut
......@@ -124,7 +127,7 @@ function cancelSelection (fromTagCloud, settings) {
// clear the current state's selection and neighbors arrays
// new state
TW.pushState({sels:[]})
TW.pushState({sels:[], oppos:[], same:[]})
// global flag
TW.gui.selectionActive = false
......@@ -137,7 +140,6 @@ function cancelSelection (fromTagCloud, settings) {
// console.log("cancelSelection: edge", e)
if (e) {
e.color = e.customAttrs['true_color'];
e.customAttrs.grey = 0;
if (e.customAttrs.activeEdge) {
e.customAttrs.activeEdge = 0;
......@@ -147,17 +149,16 @@ function cancelSelection (fromTagCloud, settings) {
}
//Nodes colors go back to previous
// £TODO partly duplicate effort with (de)highlightSelectedNodes and greyEverything
// ££TODO partly duplicate effort with (de)highlightSelectedNodes and greyEverything
// => could be replaced by a (de)highlightSelectedAndNeighbors
// on smaller set (here entire nodeset!)
for(let j in TW.nodeIds){
let n = TW.partialGraph.graph.nodes(TW.nodeIds[j])
// console.log("cancelSelection: node", n)
if (n) {
n.active = false;
n.customAttrs.grey = 0
n.customAttrs.forceLabel = 0
n.customAttrs.active = 0
n.customAttrs.highlight = 0
n.customAttrs.forceLabel = 0
// some colorings cases also modify size and label
if (settings.resetLabels) {
......@@ -246,19 +247,14 @@ function highlightSelectedNodes(flag){
console.log("\t***methods.js:highlightSelectedNodes(flag)"+flag+" sel:"+sels)
for(let i in sels) {
let nid = sels[i]
TW.partialGraph.graph.nodes(nid).active = flag
TW.partialGraph.graph.nodes(nid).customAttrs.active = flag
}
}
function manualForceLabel(nodeid, active, justHover) {
// console.log("manual|"+nodeid+"|"+active)
var nd = TW.partialGraph.graph.nodes(nodeid)
// TODO harmonize with other status => bien re-distinguer neighbor et active
// nd.active=active;
let nd = TW.partialGraph.graph.nodes(nodeid)
// console.log('justHover', justHover)
// var t0, t1
nd.customAttrs.forceLabel = true
if (justHover) {
// using single node redraw in hover layer (much faster ~ 0.5ms)
......@@ -461,7 +457,7 @@ function LevelButtonDisable( TF ){
// NB: we just change the flags, not the colors
// renderer will see the flags and handle the case accordingly
// £TODO rendering optimization: reduce effort by looping only on previously selected and neighbors
// ££TODO rendering optimization: reduce effort by looping only on previously selected and neighbors
// and having (!active && !highlight) tested instead of then useless grey flag
function greyEverything(){
......@@ -470,10 +466,8 @@ function greyEverything(){
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
// will trigger defgrey_color if (!active && !highlight)
n.customAttrs.active = false
n.customAttrs.forceLabel = false;
n.customAttrs.highlight = false;
}
......@@ -482,8 +476,7 @@ function greyEverything(){
if (TW.partialGraph.settings('drawEdges')) {
for(var i in TW.edgeIds){
let e = TW.partialGraph.graph.edges(TW.edgeIds[i])
if (e && !e.hidden && !e.customAttrs.grey) {
e.customAttrs.grey = 1
if (e && !e.hidden && e.customAttrs.activeEdge) {
e.customAttrs.activeEdge = 0
}
}
......@@ -508,7 +501,6 @@ function prepareNodesRenderingProperties(nodesDict) {
n.size = Math.round(n.size*sizeFactor*1000)/1000
// new initial setup of properties
n.active = false
var rgba, rgbStr, invalidFormat = false;
......@@ -551,8 +543,8 @@ function prepareNodesRenderingProperties(nodesDict) {
n.customAttrs = {
// status flags
grey: false, // deselected
highlight: false, // neighbors or legend's click
active: false, // when selected
highlight: false, // when neighbors or legend's click
// default unselected color
defgrey_color : "rgba("+rgbStr+","+TW.conf.sigmaJsDrawingProperties.twNodesGreyOpacity+")",
......@@ -565,14 +557,13 @@ function prepareNodesRenderingProperties(nodesDict) {
// POSS n.type: distinguish rendtype and twtype
// POSS flags like this
// // sigma's flags: active and hidden
// active: false,
// // sigma's flag: hidden (not used)
// hidden: false,
// customFlags : {
// // our status flags
// grey: false,
// active: false,
// highlight: false,
// // forceLabel: false,
// forceLabel: false,
// }
}
}
......@@ -588,7 +579,6 @@ function prepareEdgesRenderingProperties(edgesDict, nodesDict) {
e.color = "rgba("+rgbStr+","+TW.conf.sigmaJsDrawingProperties.twEdgeDefaultOpacity+")"
e.customAttrs = {
grey: false,
activeEdge : false,
true_color : e.color,
rgb : rgbStr
......
......@@ -74,7 +74,7 @@ var SigmaUtils = function () {
var fontSize,
prefix = settings('prefix') || '',
size = node[prefix + 'size'],
activeFlag = node['active'] || node.customAttrs['forceLabel'],
activeFlag = node.customAttrs['active'] || node.customAttrs['forceLabel'],
neighborFlag = node.customAttrs['highlight'],
labelColor = (settings('labelColor') === 'node') ?
(node.color || settings('defaultNodeColor')) :
......@@ -153,7 +153,7 @@ var SigmaUtils = function () {
}
else if (neighborFlag) {
// larger neighbors or highlight
fontSize *= 1.4
fontSize *= 1.3
}
context.font = (settings('fontStyle') ? settings('fontStyle') + ' ' : '') +
......@@ -191,12 +191,8 @@ var SigmaUtils = function () {
// console.debug(`t=${tstamp()} curve render activeedge: ${edgeInfos(edge)})`)
}
else if (edge.customAttrs.grey) {
color = settings('twEdgeGreyColor')
size = 1
}
else {
color = "rgba( "+baseRGB+" , "+TW.conf.sigmaJsDrawingProperties.twEdgeDefaultOpacity+")";
color = settings('twEdgeGreyColor')
size = defSize
}
......@@ -243,13 +239,8 @@ var SigmaUtils = function () {
// cf. sigmaTools.edgeColor
color = 'rgba('+rgb.join()+',.7)'
}
else if (edge.customAttrs.grey) {
color = settings('twEdgeGreyColor')
size = 1
}
else {
// color = "rgba( "+rgb.join()+" , "+TW.conf.sigmaJsDrawingProperties.twEdgeDefaultOpacity+")";
color = edge.customAttrs.true_color
color = settings('twEdgeGreyColor')
size = defSize
}
......@@ -302,9 +293,23 @@ var SigmaUtils = function () {
// mode variants 2: if node is selected, highlighted or unselected
if (TW.gui.selectionActive) {
// the selected node(s)
if (node.customAttrs.active) {
// called by label+background overlay cf. "subcall"
nodeSize *= 1.1
borderSize *= 1.1
nodeColor = "#222" // metro ticket
}
// the neighbor node(s)
else if (node.customAttrs.highlight) {
nodeSize *= 1.3
borderSize *= 1.3
}
// passive nodes should blend in the grey of twEdgeGreyColor
// cf settings_explorerjs, defgrey_color and greyEverything()
if (node.customAttrs.grey) {
else {
if (! TW.gui.handpickedcolor) {
nodeColor = node.customAttrs.defgrey_color
}
......@@ -314,20 +319,11 @@ var SigmaUtils = function () {
// nice looking uniform grey
borderColor = TW.conf.sigmaJsDrawingProperties.twBorderGreyColor
}
else {
nodeSize *= 1.4
borderSize *= 1.4
if(node.active) {
// called by label+background overlay cf. "subcall"
nodeColor = "#222" // metro ticket
}
}
}
// highlight AND (NOT selectionActive) => highlight just this one time
else if (node.customAttrs.highlight) {
nodeSize *= 1.4
borderSize *= 1.4
nodeSize *= 1.3
borderSize *= 1.3
node.customAttrs.highlight = false
}
......@@ -408,8 +404,8 @@ var SigmaUtils = function () {
settings('labelSizeRatio') * size;
// largerall: our customized size boosts
if (!node.active) {
fontSize *= 1.4
if (!node.customAttrs.active) {
fontSize *= 1.3
let X = node[prefix + 'x']
let Y = node[prefix + 'y']
......
......@@ -25,10 +25,9 @@ sigmaTools = (function(stools) {
y: rawNode.viz.position.y,
color: rawNode.viz.color,
size: Math.round(rawNode.viz.size*1000)/1000,
active: false,
hidden: false,
customAttrs: {
grey: false,
active: false,
highlight: false,
defgrey_color : "rgba("+rgbStr+",.4)"
},
......@@ -54,7 +53,6 @@ sigmaTools = (function(stools) {
color: leColor,
weight: Math.round(rawEdge.weight*1000)/1000,
customAttrs: {
grey: false,
activeEdge: false,
true_color: leColor,
rgb: rgbStr
......
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