Commit c1c21fd9 authored by Romain Loth's avatar Romain Loth

Using single hover render for active nodes

Redrawing just the actives (eg selection neighbors) is possible in the canvas context of hover layer and is 140 x faster than full redraw
parent 7e263594
...@@ -262,8 +262,14 @@ if(RES["OK"]) { ...@@ -262,8 +262,14 @@ if(RES["OK"]) {
// custom labels rendering // custom labels rendering
// - based on the normal one sigma.canvas.labels.def // - based on the normal one sigma.canvas.labels.def
// - additionnaly supports 'forcelabel' node property // - additionnaly supports 'active/forcelabel' node property (magnify x 3)
sigma.canvas.labels.def = sigma_utils.twRender.canvas.labels.def sigma.canvas.labels.def = sigma_utils.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)
sigma.canvas.hovers.def = sigma_utils.twRender.canvas.hovers.largerall
// ================================================================== // ==================================================================
......
...@@ -205,25 +205,68 @@ function htmlfied_alternodes(elems) { ...@@ -205,25 +205,68 @@ function htmlfied_alternodes(elems) {
return oppositesNodes return oppositesNodes
} }
function manualForceLabel(nodeid,active) { function manualForceLabel(nodeid, active, justHover) {
// console.log("manual|"+nodeid+"|"+active) // console.log("manual|"+nodeid+"|"+active)
TW.partialGraph.graph.nodes(nodeid).active=active; var nd = TW.partialGraph.graph.nodes(nodeid)
nd.active=active;
// console.log('justHover', justHover)
// var t0, t1
if (justHover) {
// using single node redraw in hover layer (much faster ~ 0.5ms)
redrawNodesInHoverLayer([nd])
}
else {
// using full redraw in permanent layers (slow ~ 70ms)
TW.partialGraph.render();
}
}
// Here we draw within hover layer instead of nodes layer, labels layer
//
// Explanation: it's perfect for temporary change cases because hover layer
// is *over* all other layers and contains nothing by default
// (this way step A can reset B avoiding whole graph refresh)
function redrawNodesInHoverLayer(someNodes) {
var targetLayer = TW.rend.contexts.hover
// A - clear entire targetLayer
targetLayer.clearRect(
0, 0,
targetLayer.canvas.width,
targetLayer.canvas.height
)
var locSettings = TW.partialGraph.settings.embedObjects({prefix:'renderer1:'})
for (var k in someNodes) {
// B - we use our largerall renderer to write single nodes to overlay
sigma.canvas.hovers.def( someNodes[k], targetLayer, locSettings)
}
}
// full redraw function clearHover() {
// TODO try single node redraw var hoverLayer = TW.rend.contexts.hover
TW.partialGraph.render(); hoverLayer.clearRect(
0, 0,
hoverLayer.canvas.width,
hoverLayer.canvas.height
)
} }
function htmlfied_samenodes(elems) { function htmlfied_samenodes(elems) {
var sameNodes=[] var sameNodes=[]
js1=' onmouseover="manualForceLabel(this.id,true);" '; js1=' onmouseover="manualForceLabel(this.id,true, true);" ';
js2=' onmouseout="manualForceLabel(this.id,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)" onmouseout="manualForceLabel(\''+n.id+'\',false)" ><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>')
} }
} }
} }
...@@ -306,7 +349,7 @@ function htmlfied_tagcloud(elems , limit) { ...@@ -306,7 +349,7 @@ function htmlfied_tagcloud(elems , limit) {
if(!isUndef(TW.Nodes[id])){ if(!isUndef(TW.Nodes[id])){
// js1 js2 // js1 js2
// onclick="graphTagCloudElem(' '); // onclick="graphTagCloudElem(' ');
var jspart = ' onclick="manualSelectNode(\''+id+'\')" onmouseover="manualForceLabel(\''+id+'\',true)" onmouseout="manualForceLabel(\''+id+'\',false)"' var jspart = ' onclick="manualSelectNode(\''+id+'\')" onmouseover="manualForceLabel(\''+id+'\',true, true)" onmouseout="manualForceLabel(\''+id+'\',false, true)"'
htmlfied_alternode = '<span class="tagcloud-item" style="font-size:'+fontSize+'px;" '+jspart+'>'+ TW.Nodes[id].label+ '</span>'; htmlfied_alternode = '<span class="tagcloud-item" style="font-size:'+fontSize+'px;" '+jspart+'>'+ TW.Nodes[id].label+ '</span>';
oppositesNodes.push(htmlfied_alternode) oppositesNodes.push(htmlfied_alternode)
} }
......
...@@ -92,9 +92,9 @@ SigmaUtils = function () { ...@@ -92,9 +92,9 @@ SigmaUtils = function () {
// cf. http://yomguithereal.github.io/articles/node-border-renderer/ // cf. http://yomguithereal.github.io/articles/node-border-renderer/
// same hierarchy as in sigma.canvas // same hierarchy as in sigma.canvas
this.twRender = {canvas: {nodes: {}, edges: {}, labels: {}}} this.twRender = {canvas: {nodes: {}, edges: {}, labels: {}, hovers: {}}}
this.twRender.canvas.labels.def = function(node, context, settings) { this.twRender.canvas.labels.largeractive = function(node, context, settings) {
var fontSize, var fontSize,
prefix = settings('prefix') || '', prefix = settings('prefix') || '',
size = node[prefix + 'size']; size = node[prefix + 'size'];
...@@ -112,7 +112,7 @@ SigmaUtils = function () { ...@@ -112,7 +112,7 @@ SigmaUtils = function () {
settings('defaultLabelSize') : settings('defaultLabelSize') :
settings('labelSizeRatio') * size; settings('labelSizeRatio') * size;
// we also boost size of active nodes // our only customization: we boost size of active nodes
if (activeFlag) fontSize *= 3 if (activeFlag) fontSize *= 3
...@@ -200,6 +200,106 @@ SigmaUtils = function () { ...@@ -200,6 +200,106 @@ SigmaUtils = function () {
); );
context.closePath(); context.closePath();
context.fill(); context.fill();
};
// hover rendering with size boost
this.twRender.canvas.hovers.largerall = function(node, context, settings) {
var x,
y,
w,
h,
e,
fontStyle = settings('hoverFontStyle') || settings('fontStyle'),
prefix = settings('prefix') || '',
size = node[prefix + 'size'],
fontSize = (settings('labelSize') === 'fixed') ?
settings('defaultLabelSize') :
settings('labelSizeRatio') * size;
// largerall: our customized size boosts
if (node.active || node.forceLabel) {
fontSize *= 3
}
else {
fontSize *= 2
}
// Label background:
context.font = (fontStyle ? fontStyle + ' ' : '') +
fontSize + 'px ' + (settings('hoverFont') || settings('font'));
context.beginPath();
context.fillStyle = settings('labelHoverBGColor') === 'node' ?
(node.color || settings('defaultNodeColor')) :
settings('defaultHoverLabelBGColor');
if (node.label && settings('labelHoverShadow')) {
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.shadowBlur = 8;
context.shadowColor = settings('labelHoverShadowColor');
}
if (node.label && typeof node.label === 'string') {
x = Math.round(node[prefix + 'x'] - fontSize / 2 - 2);
y = Math.round(node[prefix + 'y'] - fontSize / 2 - 2);
w = Math.round(
context.measureText(node.label).width + fontSize / 2 + size + 7
);
h = Math.round(fontSize + 4);
e = Math.round(fontSize / 2 + 2);
context.moveTo(x, y + e);
context.arcTo(x, y, x + e, y, e);
context.lineTo(x + w, y);
context.lineTo(x + w, y + h);
context.lineTo(x + e, y + h);
context.arcTo(x, y + h, x, y + h - e, e);
context.lineTo(x, y + e);
context.closePath();
context.fill();
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.shadowBlur = 0;
}
// Node border:
if (settings('borderSize') > 0) {
context.beginPath();
context.fillStyle = settings('nodeBorderColor') === 'node' ?
(node.color || settings('defaultNodeColor')) :
settings('defaultNodeBorderColor');
context.arc(
node[prefix + 'x'],
node[prefix + 'y'],
size + settings('borderSize'),
0,
Math.PI * 2,
true
);
context.closePath();
context.fill();
}
// Node:
var nodeRenderer = sigma.canvas.nodes[node.type] || sigma.canvas.nodes.def;
nodeRenderer(node, context, settings);
// Display the label:
if (node.label && typeof node.label === 'string') {
context.fillStyle = (settings('labelHoverColor') === 'node') ?
(node.color || settings('defaultNodeColor')) :
settings('defaultLabelHoverColor');
context.fillText(
node.label,
Math.round(node[prefix + 'x'] + size + 3),
Math.round(node[prefix + 'y'] + fontSize / 3)
);
}
}; };
// ================ /alternative rendering ===================== // ================ /alternative rendering =====================
......
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