Custom zoom and pan in force directed graph

102 views
Skip to first unread message

Giovanni

unread,
Feb 28, 2011, 3:38:10 PM2/28/11
to protovis
Hi everybody,
I would like to create a custom pan and zoom based on buttons instead
of mouse (something like google maps).

I know that there have been other discussions on this topic, but I
cannot find a solution to my problem.

I can easily zoom using a my function connected to a button:

cur_zoom = 1;
function zoom_in()
{
cur_zoom = cur_zoom + 0.5;

vis.transform(pv.Transform.identity.scale(cur_zoom).translate((Math.round(w/
cur_zoom) - w)/2, (Math.round(h/cur_zoom) - h)/2));
vis.render();
};

(where w and h are the width and height of the panel).

The problem of this approach is that the graph zooms always at the
center, even if I previously moved my graph in some way.

The ideal solution to this problem could be to use the offset of the
visible graph before the zoom and calculate the offset of the new
graph after the zoom to translate the graph properly. (I hope I was
clear)
Anyway, is there a way to calculate the offset of the graph?

I saw that the nodes have offset values and it could be a good
solution also to use always the same node (maybe the one with index
0 ) and calculate everything based on that values.
In this case my problem is that I don't know how to access to the node
properties given only the "vis" variable!

Is there anybody that can help me to find the right direction to solve
this problem?

Thanks!

Jan van Gemert

unread,
Mar 1, 2011, 6:27:29 AM3/1/11
to protovis
Hi,
Perhaps you can access the current transformation paramters for this?
vis.transform().x, vis.transform().y and vis.transform().k

Best,
Jan

Giovanni

unread,
Mar 8, 2011, 11:59:33 AM3/8/11
to protovis
Thanks for your help:
The code I generated (and that I hope can be useful for someone else)
is attached.

Giovanni

//function that zooms in the graph
function zoom(type_zoom)
{
//I set the default zoom ratio
var zoom_ratio = 0.5;
//I extract some information about the graph before the
transformation
var x0 = vis.transform().x;
var y0 = vis.transform().y;
var k0 = vis.transform().k;
var w = vis.width();
var h = vis.height();

//I calculate the original values I submitted (the values before and
after the rendering are different)
var x0_submitted = (x0/k0)
var x0_central = ((w/k0) - w)/2;
var delta_x0 = x0_submitted - x0_central;

var y0_submitted = (y0/k0)
var y0_central = ((h/k0) - h)/2;
var delta_y0 = y0_submitted - y0_central;

//I calculate the zoom that cannot be less then 1
if (type_zoom == 'in')
var k1 = k0 + zoom_ratio;
else
{
if ((k0 > 1) && ((k0 - zoom_ratio) > 1))
var k1 = k0 - zoom_ratio;
else
var k1 = 1;
}

//I calculate the delta between the zoom in the center and the actual
zoom (the pan)
var delta_x1 = Math.round((delta_x0 * k1) / k0);
var delta_y1 = Math.round((delta_y0 * k1) / k0);

//so I have the final values
var x1 = ((w/k1) - w)/2 + delta_x1;
var y1 = ((h/k1) - h)/2 + delta_y1;


//I make the actual transformation
vis.transform(pv.Transform.identity.scale(k1).translate(x1, y1));
vis.render();
};


//function that pans in the graph
function pan(type_pan)
{
//number of pixel to shift
var pan_size = 50;

//I extract some information about the graph before the
transformation
var x0 = vis.transform().x;
var y0 = vis.transform().y;
var k0 = vis.transform().k;
var w = vis.width();
var h = vis.height();

//I calculate the original values I submitted (the values before and
after the rendering are different)
var x0_submitted = (x0/k0)
var y0_submitted = (y0/k0)

//I check which kind of pan I have to do
if (type_pan == 'top')
var delta_y = pan_size * k0;
else if (type_pan == 'bottom')
var delta_y = -1 * pan_size * k0;
else if (type_pan == 'left')
var delta_x = pan_size * k0;
else if (type_pan == 'right')
var delta_x = -1 * pan_size * k0;

if (delta_x)
{
var x = delta_x + x0_submitted;
var y = 0 + y0_submitted;
}
if (delta_y)
{
var x = 0 + x0_submitted;
var y = delta_y + y0_submitted;
}

//I make the actual transformation
vis.transform(pv.Transform.identity.scale(k0).translate(x, y));
vis.render();
};
Reply all
Reply to author
Forward
0 new messages