After a lot a investigations, I don't achieve to find a convenient answer to the following question: how to p开发者_开发问答rogramatically pan a VisualizationViewer with Jung?
I have a GUI with the list of the vertices of my graph, and I want that a double click on one item of the list (i.e. a node description) perform a "centering action" of my VisualizationViewer for the clicked node. How to code such a behavior? it seems simple but I found no convenient answer.
If someone could help, thanks!
njames
Here is how to popup a menu after right-clicking on a node in JUNG2 and later choose to center to this node:
graphMouse.add(new MyPopupGraphMousePlugin());
/**
* a GraphMousePlugin that offers popup
* menu support
*/
protected class MyPopupGraphMousePlugin extends AbstractPopupGraphMousePlugin
implements MouseListener {
public MyPopupGraphMousePlugin() {
this(MouseEvent.BUTTON3_MASK);
}
public MyPopupGraphMousePlugin(int modifiers) {
super(modifiers);
}
/**
* If this event is over a node, pop up a menu to
* allow the user to center view to the node
*
* @param e
*/
protected void handlePopup(MouseEvent e) {
final VisualizationViewer<Node,Link> vv =
(VisualizationViewer<Node,Link>)e.getSource();
final Point2D p = e.getPoint();
GraphElementAccessor<Node,Link> pickSupport = vv.getPickSupport();
if(pickSupport != null) {
final Node station = pickSupport.getVertex(vv.getGraphLayout(), p.getX(), p.getY());
if(station != null) {
JPopupMenu popup = new JPopupMenu();
String center = "Center to Node";
popup.add(new AbstractAction("<html><center>" + center) {
public void actionPerformed(ActionEvent e) {
MutableTransformer view = vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW);
MutableTransformer layout = vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT);
Point2D ctr = vv.getCenter();
Point2D pnt = view.inverseTransform(ctr);
double scale = vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW).getScale();
double deltaX = (ctr.getX() - p.getX())*1/scale;
double deltaY = (ctr.getY() - p.getY())*1/scale;
Point2D delta = new Point2D.Double(deltaX, deltaY);
layout.translate(deltaX, deltaY);
}
});
popup.show(vv, e.getX(), e.getY());
} else {
}
}
}
}
Edited: Finally! the correct node-to-center-view with scale factor calculation...
public void centerViewsOnVertex(SynsetVertex v) {
//the following location have sense in the space of the layout
Point2D v_location = layout.transform(v);
Point2D vv1_center_location = vv1.getRenderContext()
.getMultiLayerTransformer()
.inverseTransform(Layer.LAYOUT, vv1.getCenter());
double scale = vv1.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW).getScale();
vv1.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT).translate(
-(v_location.getX() - vv1_center_location.getX()) * 1
/ scale,
-(v_location.getY() - vv1_center_location.getY()) * 1
/ scale);
refreshViews();
}
Since I was just looking for an answer to this and the above worked terribly; here's a code snippet I found in AnimatedPickingGraphMousePlugin that will recenter:
Layout<V,E> layout = vv.getGraphLayout();
Point2D q = layout.transform(vertex);
Point2D lvc =
vv.getRenderContext().getMultiLayerTransformer().inverseTransform(vv.getCenter());
final double dx = (lvc.getX() - q.getX());
final double dy = (lvc.getY() - q.getY());
vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT).translate(dx, dy);
Actually, I have found by the next a solution:
//the following location have sense in the space of the layout
Point2D v_location = layout.transform(v);
Point2D vv1_center_location = vv1.getRenderContext()
.getMultiLayerTransformer()
.inverseTransform(Layer.LAYOUT, vv1.getCenter());
vv1.getRenderContext()
.getMultiLayerTransformer()
.getTransformer(Layer.LAYOUT)
.translate(-(v_location.getX() - vv1_center_location.getX()),
-(v_location.getY() - vv1_center_location.getY()));
The center on node function is already implemented in the AnimatedPickingGraphMousePlugin
http://sourceforge.net/p/jung/discussion/252062/thread/18b4b941
In picking mode ctrl+click on a vertex to center on it.
@SuppressWarnings("unchecked")
public void mouseReleased(MouseEvent e) {
if (e.getModifiers() == modifiers) {
final VisualizationViewer<V,E> vv = (VisualizationViewer<V,E>) e.getSource();
if (vertex != null) {
Layout<V,E> layout = vv.getGraphLayout();
Point2D q = layout.transform(vertex);
Point2D lvc = vv.getRenderContext().getMultiLayerTransformer().inverseTransform(vv.getCenter());
final double dx = (lvc.getX() - q.getX()) / 10;
final double dy = (lvc.getY() - q.getY()) / 10;
Runnable animator = new Runnable() {
public void run() {
for (int i = 0; i < 10; i++) {
vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT).translate(dx, dy);
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
}
}
};
Thread thread = new Thread(animator);
thread.start();
}
}
}
I was trying to figure out how to center on a given vertex and came across this, but unfortunately it was not particularly helpful and I spent a fair amount of time figuring out how to do it. So, sharing my experience here in case it may be helpful for others.
The application I'm writing has a VisualizationViewer, that is loaded inside a GraphZoomScrollPane. I have a GraphMouseListener that I've added to the VisualizationViewer, which allows a user to right click on a vertex in the viewable area of the scroll pane and in the popup menu they can choose to center on the vertex.
The top voted answer on this thread references usage of a MutableTransformer from the LAYOUT layer and it uses the translate method of that transformer to do the centering action. Unfortunately, if you are using a zoom/scroll then you don't really know the size and positioning of the layout layer in relation to the view layer without doing a bunch of extra math.
When using zoom/scroll pane, I'd recommend finding the location of the vertex in the viewable area of the graph as represented by the pane, and then adjusting where the view pane is at.
Here is a snippet of the code I worked out:
void center(MouseEvent me, GraphZoomScrollPane gzsp) {
VisualizationViewer<V,E> vv =
(VisualizationViewer<V,E>)me.getSource();
MutableTransformer viewTransformer =
vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW);
double scaleFromViewTransformer = viewTransformer.getScale();
Dimension paneSize = gzsp.getSize();
Point2D positionOfVertexInPane = me.getPoint();
double[] centerOfPane = new double[] {
paneSize.getWidth()/2d,
paneSize.getHeight()/2d
};
double[] amountToMovePane = new double[] {
(centerOfPane[0]-positionOfVertexInPane.getX())/scaleFromViewTransformer,
(centerOfPane[1]-positionOfVertexInPane.getY())/scaleFromViewTransformer
};
viewTransformer.translate(amountToMovePane[0], amountToMovePane[1]);
}
精彩评论