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"]) {
// custom labels rendering
// - based on the normal one sigma.canvas.labels.def
// - additionnaly supports 'forcelabel' node property
sigma.canvas.labels.def = sigma_utils.twRender.canvas.labels.def
// - additionnaly supports 'active/forcelabel' node property (magnify x 3)
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) {
return oppositesNodes
}
function manualForceLabel(nodeid,active) {
function manualForceLabel(nodeid, active, justHover) {
// console.log("manual|"+nodeid+"|"+active)
TW.partialGraph.graph.nodes(nodeid).active=active;
var nd = TW.partialGraph.graph.nodes(nodeid)
nd.active=active;
// full redraw
// TODO try single node redraw
// 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)
}
}
function clearHover() {
var hoverLayer = TW.rend.contexts.hover
hoverLayer.clearRect(
0, 0,
hoverLayer.canvas.width,
hoverLayer.canvas.height
)
}
function htmlfied_samenodes(elems) {
var sameNodes=[]
js1=' onmouseover="manualForceLabel(this.id,true);" ';
js2=' onmouseout="manualForceLabel(this.id,true);" ';
js1=' onmouseover="manualForceLabel(this.id,true, true);" ';
js2=' onmouseout="manualForceLabel(this.id,true, true);" ';
if(elems.length>0) {
var A = getVisibleNodes()
for (var a in A){
n = A[a]
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) {
if(!isUndef(TW.Nodes[id])){
// js1 js2
// 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>';
oppositesNodes.push(htmlfied_alternode)
}
......
......@@ -92,9 +92,9 @@ SigmaUtils = function () {
// cf. http://yomguithereal.github.io/articles/node-border-renderer/
// 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,
prefix = settings('prefix') || '',
size = node[prefix + 'size'];
......@@ -112,7 +112,7 @@ SigmaUtils = function () {
settings('defaultLabelSize') :
settings('labelSizeRatio') * size;
// we also boost size of active nodes
// our only customization: we boost size of active nodes
if (activeFlag) fontSize *= 3
......@@ -202,6 +202,106 @@ SigmaUtils = function () {
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 =====================
this.toggleEdges = function() {
......
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