JUNG : Changing the vertex colour - java

I have used JUNG library to visualize one network consisted of servers and links through graph.
So I initialize my graph like this, Server and Link are classes in my project:
Graph<Server, Link> g;
g = new SparseMultigraph<Server, Link>();
Now I need to change the color of specific vertices..
so I used the code below:
// Setup up a new vertex to paint transformer
Transformer<Integer,Paint> vertexPaint = new Transformer<Integer,Paint>() {
public Paint transform(Integer i) {
return Color.GREEN;
}
};
vv.getRenderContext().setVertexFillPaintTransformer(vertexPaint);
I got java.lang.ClassCastException exception as following!!
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: network.Server cannot be cast to java.lang.Integer
at GUI.GUI$9.transform(GUI.java:1)
at edu.uci.ics.jung.visualization.renderers.BasicVertexRenderer.paintShapeForVertex(BasicVertexRenderer.java:98)
at edu.uci.ics.jung.visualization.renderers.BasicVertexRenderer.paintIconForVertex(BasicVertexRenderer.java:74)
at edu.uci.ics.jung.visualization.renderers.BasicVertexRenderer.paintVertex(BasicVertexRenderer.java:37)
at edu.uci.ics.jung.visualization.renderers.BasicRenderer.renderVertex(BasicRenderer.java:70)
at edu.uci.ics.jung.visualization.renderers.BasicRenderer.render(BasicRenderer.java:55)
at edu.uci.ics.jung.visualization.BasicVisualizationServer.renderGraph(BasicVisualizationServer.java:367)
at edu.uci.ics.jung.visualization.BasicVisualizationServer.paintComponent(BasicVisualizationServer.java:321)
at javax.swing.JComponent.paint(Unknown Source)
My complete code to update the graph is here:
private static BasicVisualizationServer updateGraph(Network network) {
Set<Server> servers = network.getServers();
Set<Link> links = network.getLinks();
Graph<Server, Link> g;
// Graph<V, E> where V is the type of the vertices and E is the type of
// the edges
g = new SparseMultigraph<Server, Link>();
// Add some vertices and edges
for (Server server : servers) {
g.addVertex(server);
}
int i = 0;
for (Link link : links) {
g.addEdge(link, link.getSource(), link.getDest(), EdgeType.DIRECTED);
i++;
}
// Layout<V, E>, VisualizationViewer<V,E>
Layout<Integer, String> layout = new CircleLayout(g);
layout.setSize(new Dimension(300, 300));
VisualizationViewer<Integer, String> vv = new VisualizationViewer<Integer, String>(
layout);
vv.setPreferredSize(new Dimension(350, 350));
// Show vertex and edge labels
vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
vv.getRenderContext().setEdgeLabelTransformer(new ToStringLabeller());
// Setup up a new vertex to paint transformer...
Transformer<Integer,Paint> vertexPaint = new Transformer<Integer,Paint>() {
public Paint transform(Integer i) {
return Color.GREEN;
}
};
vv.getRenderContext().setVertexFillPaintTransformer(vertexPaint);
// Create a graph mouse and add it to the visualization component
DefaultModalGraphMouse gm = new DefaultModalGraphMouse();
gm.setMode(ModalGraphMouse.Mode.TRANSFORMING);
vv.setGraphMouse(gm);
rightPanel.setTopComponent(vv);
//Detecting selection of vertices
final PickedState<Integer> pickedState = vv.getPickedVertexState();
// Attach the listener that will print when the vertices selection changes.
pickedState.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
Object subject = e.getItem();
// The graph uses Integers for vertices.
if (subject instanceof Integer) {
Integer vertex = (Integer) subject;
if (pickedState.isPicked(vertex)) {
System.out.println("Vertex " + vertex
+ " is now selected");
} else {
System.out.println("Vertex " + vertex
+ " no longer selected");
}
}
}
});
return vv;
}

Your graph vertex type is Server, but your Transformer is expecting an Integer as input. You need to alter your code so that those match.

Related

JGraphX new initialization of graph/graphComponent does not work as expected and causes artefacts

Hi I am using JGraphX to build some kind of Java swing based graph editor application. The application in general works fine and as intended under normal
circumstances. In general I have an class called Editor which contains all essential declarations for the graph, as seen in the code example below.
initializing the graph and overriding some of its methods
public class Editor extends JFrame implements Serializable {
Handler handler;
JTabbedPane tabPane;
mxGraphComponent graphComponent;
EntityDataTable dataTable;
protected static mxGraph graph = new mxGraph() {
// Overrides method to disallow edge label editing
public boolean isCellEditable(Object cell) {
if (cell instanceof mxCell) {
mxCell c = (mxCell) cell;
if (c.isEdge()) {
return false;
} else {
return false;
}
}
return false;
}
// Overrides method to disallow edge selection
public boolean isCellSelectable(Object cell)
{
if (model.isEdge(cell))
{
return false;
}
return super.isCellSelectable(cell);
}
// Overrides method to provide a cell label in the display
public String convertValueToString(Object cell) {
if (cell instanceof mxCell) {
Object value = ((mxCell) cell).getValue();
if (value instanceof Element) {
Element elt = (Element) value;
// String tag = elt.getTagName();
String tag = elt.getAttribute("name");
return tag;
}
}
return super.convertValueToString(cell);
}
public String getToolTipForCell(Object cell){
return "Double Click to Edit";
}
};
...
restricts certain undoEvents
protected mxEventSource.mxIEventListener undoHandler = new mxEventSource.mxIEventListener(){
public void invoke(Object source, mxEventObject evt)
{
mxUndoableEdit evt1 = (mxUndoableEdit) evt.getProperty("edit");
List<mxUndoableEdit.mxUndoableChange> changes = evt1.getChanges();
Object[] temp = graph.getSelectionCellsForChanges(changes);
boolean islegal = true;
for (int i = 0; i < temp.length; i++)
{
mxCell cell = (mxCell)temp[i];
String value = cell.getValue().toString();
if (value.equals("subprocess")||value.equals("optional")||value.equals("parallel")||value.equals("synchronous")||value.equals("activating")||value.equals("deactivating")){
//System.out.println("is not legal");
islegal = false;
}
}
for (int i = 0; i < changes.size(); i++){
if (changes.get(i).toString().contains("mxValueChange")){
islegal = false;
}
}
graph.setSelectionCells(graph.getSelectionCellsForChanges(changes));
if (islegal == true){
undoManager.undoableEditHappened((mxUndoableEdit) evt
.getProperty("edit"));
}else{
// System.out.println("illegal undo");
}
}};
...
protected boolean modified = false;
protected mxGraphOutline graphOutline;
protected JPanel actionPane;
mxUndoManager undoManager;
public Editor() {
handler = new Handler(this);
dataTable = new EntityDataTable(handler);
initGUI();
initGraphSettings();
}
public Editor(SaveData saveData) {
handler = new Handler(this);
dataTable = new EntityDataTable(handler);
initGUI();
initGraphSettings();
//erst alle entities erstellen und submitten, dann alle verbindungselemente zu den entities hinzufügen und nochmal submit
//Load entities
ArrayList<DataSaveElement> saveDataList = saveData.getSaveData(); for (int i = 0; i < saveDataList.size(); i++){
System.out.println("Loaded "+saveDataList.get(i).getType()+" "+saveDataList.get(i).getName());
if (saveDataList.get(i).getType().equals("Process")){
ProcessPopUp temp = new ProcessPopUp(handler, this);
temp.setGlobalID(saveDataList.get(i).getGlobalID());
temp.setName(saveDataList.get(i).getName());
temp.setDesc(saveDataList.get(i).getDescription());
temp.setType(saveDataList.get(i).getType());
... a lot of code for rebuilding, some graph settings, the gui etc.
Inside of the initGui() my mxGraphComponent is initialized
graphComponent = new mxGraphComponent(graph);
Since the graph visualization is only one part of the application and other data exists in the background, while saving all data values are stored including the postions for vertices etc. So when loading a save file a fresh application is build from the ground up simply adding all saved data values step by step. When I close the entire java application, start it again and load my saved file there is no problem at all. The problem occures when loading a saved file while the application is still running like e. g.
menuItem = new JMenuItem("Open...",
new ImageIcon("images/middle.gif"));
menuItem.addActionListener(new ActionListener() {
#java.lang.Override
public void actionPerformed(ActionEvent e) {
LoadAndSaveManager manager = new LoadAndSaveManager();
try {
Object o = manager.load(new FileChooser(0).getSelectedFile().getAbsolutePath());
SaveData saveData =(SaveData) o;
Editor editorNew = new Editor(saveData);
new MenuBar(editorNew);
editorNew.setVisible(true);
editor.dispose();
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
menu.add(menuItem);
My menubar is quite basic an gets the editor als parameter. Since a new Editor is created which creates a new mxGraph, as well as a new mxGraphComponent and finally disposes the old editor there should be no interference...at least as far as I know. However, despite having a new Editor instance which has its own new Graph and GraphComponent the old one is still used somehow. As shown in the example images below.
This will be saved and the application is closed completely.
Two nodes and a link for saving:
When starting the application and loading the saved data nothing is wrong.
Next I start a new one and add for example three nodes and two links.
Three nodes and two links:
Now I load the previously saved data. I would expect that the the window closes and a new one with the prevois data pops up. This is not the case. The data is loaded, but the old graph seems still active somehow and all nodes and links are on the graph.
Mixed up data:
If this would be the only problem I could simply clear the graph and add all "loading data" afterwards, however somehow the graphComponent seems to be broken as well. When dragging nodes the links sometimes are disrupted.
Disrupted links:
From my observations so far this seems to fix itself when selecting an area (I think this forces the graphComponent to refresh())
Selecting:
Unfortunately posting the entire code is not that much of an option, so I posted some code I think might be of importance for the problem. If further code is required I will specifically post it afterwards.
I am not sure why this happens and after hours of research I somehow hit a wall and and I am not sure what I am doing wrong. I would really appreciate some advice.
Here is an minimal full code example of the problem regarding the graphComponents interference problem when declaring a new one.
public class Main {
Editor editor;
public Main() {
editor = new Editor();
new MenuBar(editor);
editor.setVisible(true);
}
public static void main(String args[]) {
new Main();
}}
public class Editor extends JFrame {
mxGraphComponent graphComponent;
protected static mxGraph graph = new mxGraph() {
// Overrides method to disallow edge label editing
public boolean isCellEditable(Object cell) {
if (cell instanceof mxCell) {
mxCell c = (mxCell) cell;
if (c.isEdge()) {
return false;
} else {
return false;
}
}
return false;
}
// Overrides method to disallow edge selection
public boolean isCellSelectable(Object cell)
{
if (model.isEdge(cell))
{
return false;
}
return super.isCellSelectable(cell);
}
// Overrides method to provide a cell label in the display
public String convertValueToString(Object cell) {
if (cell instanceof mxCell) {
Object value = ((mxCell) cell).getValue();
if (value instanceof Element) {
Element elt = (Element) value;
// String tag = elt.getTagName();
String tag = elt.getAttribute("name");
return tag;
}
}
return super.convertValueToString(cell);
}
public String getToolTipForCell(Object cell){
return "Double Click to Edit";
}
};
public Editor() {
initGUI();
initGraphSettings();
}
public Editor(ArrayList<SaveDataElement> saveData) {
initGUI();
initGraphSettings();
//Load data
addToGraph(saveData);
}
public void initGUI(){
setExtendedState(JFrame.MAXIMIZED_BOTH);
setSize(new Dimension(1200, 900));
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
graphComponent = new mxGraphComponent(graph);
JPanel graphPanel = new JPanel(new BorderLayout());
graphPanel.add(graphComponent);
add(graphPanel);
}
public void initGraphSettings(){
Map<String, Object> style = graph.getStylesheet().getDefaultEdgeStyle();
style.put(mxConstants.STYLE_ALIGN, true);
style.put(mxConstants.STYLE_EDGE, mxConstants.EDGESTYLE_TOPTOBOTTOM);
graph.setCellsCloneable(false);
graphComponent.setConnectable(false);
graphComponent.getViewport().setBackground(Color.WHITE);
new mxRubberband(graphComponent);
}
public mxGraph getGraph(){
return graph;
}
public void addToGraph(ArrayList<SaveDataElement> saveData){
for (int i = 0; i < saveData.size(); i++) {
String name = saveData.get(i).getName();
int vertPosX = saveData.get(i).getPosX();
int vertPosY = saveData.get(i).getPosY();
new AddGraphNode("node", name, "rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;", vertPosX, vertPosY);
}
Object[] cells = graph.getChildVertices(graph.getDefaultParent());
Object startCell = null;
Object endCell = null;
for (int i = 0; i < saveData.size(); i++){
for (int j = 0; j < cells.length; j++){
if (((mxCell)cells[j]).getAttribute("name").equals(saveData.get(i).getName()))
startCell = cells[j];
for (int k = 0; k < saveData.get(i).getTargets().size(); k++){
if (((mxCell)cells[j]).getAttribute("name").equals(saveData.get(i).getTargets().get(k))){
endCell = cells[j];
new AddGraphLink(startCell, endCell,"Link", "endArrow=classic;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;verticalLabelPosition=bottom'");
}
}
}
}
}}
public class MenuBar extends JMenuBar {
MenuBar(Editor editor){
JMenuBar menuBar = new JMenuBar();
JMenuItem menuItem;
JMenu menu = new JMenu("File");
menuBar.add(menu);
menuItem = new JMenuItem("Add");
menuItem.addActionListener(new ActionListener() {
#java.lang.Override
public void actionPerformed(ActionEvent e) {
//Setting up some data to create nodes and links
ArrayList<SaveDataElement> saveData = new ArrayList<SaveDataElement>();
ArrayList<String> targetsForTestX = new ArrayList<String>();
targetsForTestX.add("Test Y");
targetsForTestX.add("Test Z");
saveData.add(new SaveDataElement("Test X", 200, 300, targetsForTestX));
ArrayList<String> targetsForTestY = new ArrayList<String>();
saveData.add(new SaveDataElement("Test Y", 300, 420, targetsForTestY));
ArrayList<String> targetsForTestZ = new ArrayList<String>();
saveData.add(new SaveDataElement("Test Z", 100, 420, targetsForTestZ));
editor.addToGraph(saveData);
}
});
menu.add(menuItem);
menuItem = new JMenuItem("Load 1");
menuItem.addActionListener(new ActionListener() {
#java.lang.Override
public void actionPerformed(ActionEvent e) {
//Setting up some data to create nodes and links
ArrayList<SaveDataElement> saveData = new ArrayList<SaveDataElement>();
ArrayList<String> targetsForTest1 = new ArrayList<String>();
targetsForTest1.add("Test 2");
saveData.add(new SaveDataElement("Test 1", 40, 40, targetsForTest1));
ArrayList<String> targetsForTest2 = new ArrayList<String>();
saveData.add(new SaveDataElement("Test 2", 200, 40, targetsForTest2));
Editor editorNew = new Editor(saveData);
new MenuBar(editorNew);
editorNew.setVisible(true);
editor.dispose();
}
});
menu.add(menuItem);
editor.setJMenuBar(menuBar);
}}
public class SaveDataElement {
String name;
int posX, posY;
ArrayList<String> targets;
public SaveDataElement(String name, int posX, int posY, ArrayList<String> targets){
this.name = name;
this.posX = posX;
this.posY = posY;
this.targets = targets;
}
public String getName() {
return name;
}
public int getPosX() {
return posX;
}
public int getPosY() {
return posY;
}
public ArrayList<String> getTargets() {
return targets;
}}
public class AddGraphNode extends Editor {
public AddGraphNode(String tag, String name, String style, int vertPosX, int vertPoxY){
this.getGraph().getModel().beginUpdate();
Object parent = this.getGraph().getDefaultParent();
Document doc = mxDomUtils.createDocument();
Element entity = doc.createElement(tag);
entity.setAttribute("name", name);
try
{
Object v1 = this.getGraph().insertVertex(parent, "1",entity, vertPosX, vertPoxY, (int)(name.length()*8) ,
40, style);
}
finally
{
this.getGraph().getModel().endUpdate();
}
}}
public class AddGraphLink extends Editor{
public AddGraphLink(Object v1, Object v2, String relation, String style){
this.getGraph().getModel().beginUpdate();
Object parent = this.getGraph().getDefaultParent();
try
{
this.getGraph().insertEdge(parent, null, relation, v1, v2,style);
}
finally
{
this.getGraph().getModel().endUpdate();
}
}}
When using the the add menu item some nodes and links are added to the graph and with the load 1 menu item a new Editor will be created (creating a new graph and graphComponent). However, the added nodes and links are still present on the new component.
Regarding the visually broken links I mentioned above, this does not occur...I will investigate this further. Despite that this might also be connected with the graphComponent problem.
I see 3 major problems in your code:
Inappropriate use of a static field: protected static mxGraph graph = new mxGraph() {
Inappropriate inheritance: public class AddGraphLink extends Editor {
And again, inappropriate inheritance: class AddGraphNode extends Editor {
By making the graph field static, changes made to one variable will be felt in all variables, and this is the likely cause for your so-called "artifacts". And the reason that you feel that you must make the field static is because since the two classes above are inheriting from Editor (again inappropriately). The solution is obvious:
Make the graph field an instance field, not a static one, and
Don't use inheritance where it doesn't belong. Instead your AddGraphXxxx classes should not extend Editor but rather should have Editor fields within them, one that you can set via the constructor, and one whose methods you can call, something like this, for example:
// protected static mxGraph graph = new mxGraph() { //!! **** NO ****
private mxGraph graph = new mxGraph() { //!! **** YES ****
.....
.....
public class AddGraphNode {
public AddGraphNode(Editor editor, String tag, String name, String style, int vertPosX, int vertPoxY) {
// **** note use of the editor parameter below ****
editor.getGraph().getModel().beginUpdate();
Object parent = editor.getGraph().getDefaultParent();
Document doc = mxDomUtils.createDocument();
Element entity = doc.createElement(tag);
entity.setAttribute("name", name);
try {
// **** same here ****
Object v1 = editor.getGraph().insertVertex(parent, "1", entity, vertPosX, vertPoxY,
(int) (name.length() * 8), 40, style);
} finally {
// **** and the same here ****
editor.getGraph().getModel().endUpdate();
}
}
}
and you would create this instance within Editor by passing in the this parameter:
new AddGraphNode2(this, "node", name,
"rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;",
vertPosX, vertPosY);
You would make simiar changes to the AddGraphLink class.
Side note, please check out the The Use of Multiple JFrames, Good/Bad Practice? to see why swapping JFrames is not the best program design, and how you can change the code to improve its structure and user experience.

How do i connect two nodes with a line

How do I connect a node which lies in the first container to another node in the second container, i.e if i have a pane which has a sub node in it how will i connect it to another pane sub node, I've only manged to connect nodes that are is the same container but that's is not what i need, i want something like this.
enter code here
public class Main extends Application {
static Pane root = new Pane();
#Override
public void start(Stage primaryStage) throws Exception{
Circuit c1 = new Circuit(10,10);
Circuit c2 = new Circuit(200,10);
Circuit c3 = new Circuit(10,200);
Circuit c4 = new Circuit(200,200);
root.getChildren().addAll(c1, c2, c3, c4);
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The circuit Class
enter code here
import static sample.Main.root;
public class Circuit extends Pane{
Circuit(int LOCATION_X, int LOCATION_Y){
setStyle("-fx-background-color: red");
setPrefSize(150,150);
setLayoutX(LOCATION_X);
setLayoutY(LOCATION_Y);
createCircle cir = new createCircle();
cir.setLayoutX(75);
cir.setLayoutY(75);
// register handlers
cir.setOnDragDetected(startHandler);
cir.setOnMouseDragReleased(dragReleaseHandler);
cir.setOnMouseDragEntered(dragEnteredHandler);
// add info allowing to identify this node as drag source/target
cir.setUserData(Boolean.TRUE);
getChildren().add(cir);
root.setOnMouseReleased(evt -> {
// mouse released outside of a target -> remove line
root.getChildren().remove(startHandler.line);
startHandler.line = null;
});
root.setOnMouseDragged(evt -> {
if (startHandler.line != null) {
Node pickResult = evt.getPickResult().getIntersectedNode();
if (pickResult == null || pickResult.getUserData() != Boolean.TRUE) {
// mouse outside of target -> set line end to mouse position
startHandler.line.setEndX(evt.getX());
startHandler.line.setEndY(evt.getY());
}
}
});
}
class DragStartHandler implements EventHandler<MouseEvent> {
public Line line;
#Override
public void handle(MouseEvent event) {
if (line == null) {
Node sourceNode = (Node) event.getSource();
line = new Line();
Bounds bounds = sourceNode.getBoundsInParent();
// start line at center of node
line.setStartX((bounds.getMinX() + bounds.getMaxX()) / 2);
line.setStartY((bounds.getMinY() + bounds.getMaxY()) / 2);
line.setEndX(line.getStartX());
line.setEndY(line.getStartY());
sourceNode.startFullDrag();
root.getChildren().add(0, line);
}
}
}
DragStartHandler startHandler = new DragStartHandler();
EventHandler<MouseDragEvent> dragReleaseHandler = evt -> {
if (evt.getGestureSource() == evt.getSource()) {
// remove line, if it starts and ends in the same node
root.getChildren().remove(startHandler.line);
}
evt.consume();
startHandler.line = null;
};
EventHandler<MouseEvent> dragEnteredHandler = evt -> {
if (startHandler.line != null) {
// snap line end to node center
Node node = (Node) evt.getSource();
Bounds bounds = node.getBoundsInParent();
startHandler.line.setEndX((bounds.getMinX()+bounds.getMaxX())/2);
startHandler.line.setEndY((bounds.getMinY()+bounds.getMaxY())/2);
}
};
}
The point from where the wire will drawn out and connected to
enter code here
public class createCircle extends Circle {
createCircle(){
super(25, Color.BLACK.deriveColor(0, 1, 1, 0.5));
}
}
You are mixing coordinate systems.
Bounds bounds = sourceNode.getBoundsInParent();
will give you the bounds of sourceNode in the coordinate system of the sourceNode's parent, which is going to be the current Circuit instance (if I read your code correctly). However, you are using those bounds to calculate the coordinates of the line, which is placed in the root node, so you need the coordinates in the coordinate system of the root.
You can transform the coordinates by doing something like
Bounds boundsInScene = sourceNode.localToScene(sourceNode.getBoundsInLocal());
Bounds boundsInRoot = root.sceneToLocal(boundsInScene);
Now boundsInRoot represents the bounds of sourceNode in the coordinate system of root, so you can use it to compute the coordinates of the line. There are likely similar transforms you need to make throughout the code.

Is it possible add multiple edges using TreeLayout?

I've to display a graph like a tree level in hierarchy so I use the TreeLayout included in Jung, but I don't know if it's possible use this layout to add multiple edges between nodes. And if it's not possible, how you recommend me to do that?
Thanks!
public class Visualizacion extends JApplet {
/**
* the graph
*/
Graph<String,String> graph;
Forest<String,String> tree;
Funciones f=new Funciones();
/**
* the visual component and renderer for the graph
*/
VisualizationViewer<String,String> vv;
String root;
Layout<String,String> layout;
Layout<String,String> layout2; ;
public Visualizacion(org.graphstream.graph.Graph grafito) {
graph= new DirectedSparseMultigraph<String, String>();
createTree(grafito);
MinimumSpanningForest2<String,String> prim =
new MinimumSpanningForest2<String,String>(graph,
new DelegateForest<String,String>(), DelegateTree.<String,String>getFactory(),
new ConstantTransformer(1.0));
tree = prim.getForest();
layout = new TreeLayout<String,String>(tree,100,100);
layout2 = new StaticLayout<String,String>(graph, layout);
Transformer<String,Paint>vertexPaint= new Transformer<String,Paint>(){
public Paint transform(String i){
Node node=grafito.getNode(i);
if(node.hasAttribute("ExcedeCaudal")){
return Color.RED;}
else{
return Color.lightGray;}
}
};
vv = new VisualizationViewer<String,String>(layout2, new Dimension(800,600));
vv.addGraphMouseListener(new TestGraphMouseListener<String>());
vv.setBackground(Color.white);
vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Line());
vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
vv.getRenderContext().setEdgeLabelTransformer(new ToStringLabeller());
vv.getRenderContext().setVertexShapeTransformer(new ClusterVertexShapeFunction());
vv.getRenderContext().setVertexFillPaintTransformer(vertexPaint);
// add a listener for ToolTips
vv.setVertexToolTipTransformer(new ToStringLabeller());
vv.getRenderContext().setArrowFillPaintTransformer(new ConstantTransformer(Color.lightGray));
vv.getRenderContext().setEdgeLabelTransformer(new EdgeLabelTransformer<String>());
Container content = getContentPane();
final GraphZoomScrollPane panel = new GraphZoomScrollPane(vv);
content.add(panel);
final DefaultModalGraphMouse graphMouse = new DefaultModalGraphMouse();
vv.setGraphMouse(graphMouse);
//ver cual nodo se selecciona
final PickedState<String> pickedState=vv.getPickedVertexState();
pickedState.addItemListener(new ItemListener(){
#Override
public void itemStateChanged(ItemEvent e){
Object subject=e.getItem();
if(subject instanceof String){
String vertice=(String)subject;
if(pickedState.isPicked(vertice)){
System.out.println("Vertice "+vertice+" está seleccionado");
}
else{
System.out.println("Vertice "+vertice+"no está seleccionado");
}
}
}
});
}private void createTree(org.graphstream.graph.Graph grafito) {
for(Node node:grafito){
graph.addVertex(node.getId());
}
int count=0;
for (Edge edge: grafito.getEachEdge()){
String padre=edge.getNode0().getId();
String hijo=edge.getNode1().getId();
String caudal=(edge.getAttribute("Caudal"));
graph.addEdge(caudal+"-"+count, padre,hijo,EdgeType.DIRECTED);
System.out.println("intento agregar "+edge.getAttribute("Caudal")+" cuyo padre es "+padre+" e hijo "+hijo);
count++;
}}private class EdgeLabelTransformer<V>implements Transformer<V,String>{
public String transform(V v){
return v.toString().split("-")[0];
}
}
class ClusterVertexShapeFunction<V> extends EllipseVertexShapeTransformer<V> {
ClusterVertexShapeFunction() {
setSizeTransformer(new ClusterVertexSizeFunction<V>(20));
}
#SuppressWarnings("unchecked")
#Override
public Shape transform(V v) {
if(v instanceof Graph) {
int size = ((Graph)v).getVertexCount();
if (size < 8) {
int sides = Math.max(size, 3);
return factory.getRegularPolygon(v, sides);
}
else {
return factory.getRegularStar(v, size);
}
}
return super.transform(v);
}
}
class ClusterVertexSizeFunction<V> implements Transformer<V,Integer> {
int size;
public ClusterVertexSizeFunction(Integer size) {
this.size = size;
}
public Integer transform(V v) {
if(v instanceof Graph) {
return 30;
}
return size;
}
}
static class TestGraphMouseListener<V> implements GraphMouseListener<V> {
public void graphClicked(V v, MouseEvent me) {
if(me.getClickCount()==2){
System.err.println("Vertex "+v+" fui doble click");
}
System.err.println("Vertex "+v+" was clicked at ("+me.getX()+","+me.getY()+")");
}
public void graphPressed(V v, MouseEvent me) {
System.err.println("Vertex "+v+" was pressed at ("+me.getX()+","+me.getY()+")");
}
public void graphReleased(V v, MouseEvent me) {
System.err.println("Vertex "+v+" was released at ("+me.getX()+","+me.getY()+")");
}
}
public void execute(org.graphstream.graph.Graph grafito){
JFrame frame = new JFrame();
Container content = frame.getContentPane();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
content.add(new Visualizacion(grafito));
frame.pack();
frame.setVisible(true);}}
JUNG Layout instances determine vertex positions, not edge positions; edge rendering is determined automatically based on the edge shape that you use and the number of connecting edges.
JUNG Tree objects, however, can only have one edge connecting any pair of vertices (otherwise it's not a tree).
So if you want a Graph whose vertices are laid out using TreeLayout, but which is not directly representable as a Tree, this is what you can do:
(1) Construct a Tree which encodes the structural relationships that you want (from your original Graph), but doesn't have the parallel edges you want. You can do this either directly yourself (by constructing a copy that removing parallel edges where they exist, or just not adding them initially if that's feasible), or by using the MinimumWeightSpanningTree algorithm to extract a Tree from your original Graph.
(2) Generate a TreeLayout for this Tree.
(3) Create a StaticLayout which copies the positions used by the TreeLayout.
(4) Use this StaticLayout as a layout algorithm for your original Graph.
You can see this process demonstrated in the JUNG MinimumSpanningTreeDemo.java, in the provided sample code that's part of the JUNG source distribution. If you just want to see the code, it's here: http://jung.sourceforge.net/site/jung-samples/xref/edu/uci/ics/jung/samples/MinimumSpanningTreeDemo.html

Override hover method in JUNG

i am using the framework vl-jung to simulate a bubble GUI for directory browsing, now i am trying to override the hover method so that when i hover on a square it draws something else "add other nodes" i am using the demo in the library.
public void hoverChanged(ObjectSceneEvent event, Object previousHoveredObject, Object newHoveredObject) {
//System.out.println("hover" + Number);
if (newHoveredObject instanceof Number) {
hover = (Number) newHoveredObject;
widget = findWidget(hover);
task.schedule(750);
} else {
widget = null;
hover = null;
task.cancel();
getSceneAnimator().animateForegroundColor(label, new Color(255, 255, 255, 0));
}
}
i tried adding the code of drawing the first time to the method but it's not working
Factory<Integer> edgeFactory = new Factory<Integer>() {
int i = 0;
public Integer create() {
return i++;
}
};
Forest<String, Integer> createTree(Forest<String, Integer> graph) {
//graph.addVertex("A0");
graph.addEdge(edgeFactory.create(), "MyComp", "B0");
graph.addEdge(edgeFactory.create(), "MyComp", "B1");
graph.addEdge(edgeFactory.create(), "MyComp", "B2");
}

How to manually set the zoom on a Jung visualisation?

I have a jung tree displayed in a JPanel. The constructor of my tree looks like this:
Forest<String, Integer> graph = new DelegateForest<String, Integer>();
static GraphZoomScrollPane panel = null;
static DefaultModalGraphMouse graphMouse = null;
static JComboBox modeBox = null;
static ScalingControl scaler;
public PanelTree(List<Cluster> clist) {
setBounds(215, 10, 550, 550);
updateData(clist); // adds vertex and edges to graph
treeLayout = new TreeLayout<String, Integer>(graph);
vv = new VisualizationViewer<String, Integer>(treeLayout, new Dimension(500, 500));
vv.setBackground(Color.white);
vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Line());
vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
// add a listener for ToolTips
vv.setVertexToolTipTransformer(new ToStringLabeller());
vv.getRenderContext()
.setArrowFillPaintTransformer(new ConstantTransformer(Color.lightGray));
panel = new GraphZoomScrollPane(vv);
add(panel);
graphMouse = new DefaultModalGraphMouse();
vv.setGraphMouse(graphMouse);
modeBox = graphMouse.getModeComboBox();
modeBox.addItemListener(graphMouse.getModeListener());
graphMouse.setMode(ModalGraphMouse.Mode.TRANSFORMING);
scaler = new CrossoverScalingControl();
}
But the tree is quite large. So I want to know is there is a way to either automatically zoom out so the tree fits in the windows, and otherwise just set a default zoom that is less than the default one. How can I do that ?
ScalingControl scaler = new CrossoverScalingControl();
public void zoomIn() {
setZoom(1);
}
public void zoomOut() {
setZoom(-1);
}
private void setZoom(int amount) {
scaler.scale(vv, amount > 0 ? 1.1f : 1 / 1.1f, vv.getCenter());
}
To fits the graph on the window, you can calculate the diference between the graph size and the panel size, and call the setZoom() method passing the factor of diference.
ScalingControl is not good method if you use Mouse Transformer.
Try to:
// for zoom:
vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT).setScale(scale_x1, scale_y1, vv.getCenter());
// for out:
vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW).setScale(scale_x2, scale_y2, vv.getCenter());

Categories

Resources