So I made custom edge renderer that supports multiple same-directed connections (it increases radius in quadcurves) and
even connections onto same elements: http://shrani.si/f/R/kL/3Xwg75sd/tree.png
But I'm left with two remaining problems.
Currently I'm using building a list of parsed nodes in edge renderer, that way I know if same nodes were already on the list and I can increase radius of the curve.
Problem is that every time something gets changed on display, it will call edgerenderer again, this list will expand and edge radius will just increase. Is there a better solution than using a list of already visited nodes in edge renderer.
Another cosmetic problems are labels - I place them in center of rectangle bound, but I cannot find a way to get the shape and iterate trough it - is it possible at all?
this is a realy nice idea and I appreciate that you deliveded the source code as an example for better understanding.
How did you solve the problem of getting several parallel edges from the graph?
(If you say getEdge(node1, node2), did you save them as a list or do you parse all edges and filter the requested out?)
As I thought about that I found the following Idea to be promising. Currently you have a list thats "updated" everytime the renderer runs.
How about a list that is only updated when you add an edge?
(That´s why I asked how you manage this :) )
Let me explain this more in detail.
Asumme we have some kind of "code" that notices when explicitely (delete edge) or implicitely (delete one node) an edge set between two nodes is influenced. If one node is deleted nothing big will happen since all edges are removed but if a parallel edge is added or removed the radius values of parallel edges will have to be recalculated.
Maybe you want to assign new radiuses (sounds strange) to all involved edges in case of a change, maybe not.
Further I think the radius should be stored in each edge as an attribute for faster layouting, so you realy only have to use the list when adding/removing edges.
So if you add/demove an edge you search all parallel edges and watch if they have this attribute set. If not it´s a new edge and will be layouted with the highest value.
Of course you got to think about reducing radiuses (still looks strange) but I think that´s not a problem for you :)
To your second problem, what you mean by getting the shape and iterating through it?
You mean getting that stroke and running it along some way?
Greetings,
Marcus
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I don't use getEdge (I don't know such method), but I just assign my customEdgeRenderer to default renderer factory, so edges are all managed by prefuse library.
If you look at the source, "getRawShape(VisualItem item)" is where all the juice is being made -
first I check if processed paired nodes already exist (and how many times), then I multiply their count with a constant → this is what I use for radius. At last I add connected nodes to list.
I'm always connecting nodes as I get from the graph (start → end), so the quadCurve is always bulging to the outside + radius is increased if nodes were already connected in the past.
I'm also checking if nodes are self-connected "if (item1 == item2)", that way I draw an ellipse instead of quad curve, again with different radius if nodes are connected multiple times (using same logic and list from above).
This works, however every time something happens on display, the scene gets rerendered, and if you can imagine, list is increasing and this leads to bigger and bigger radius (which is not what I want).
This would be solved if I would know which node is the last in graph (which is the last to render). That way I would just fill up the list, calculate all radiuses and then stop that part of logic. Everytime scene would be updated, I wouldn't have to increase list nor radius.
I can imagine your idea, but don't know how to exactly acomplish this, since edge / label... renderer you just add it to render factory (is any other way?).
Probably I could rewrite RendererFactory and the use also custom parts I want? I don't know if this is the best approach.
---
The second problem I meant "getting that stroke and running it along some way ". Is this possible?
The problem is with placing the labels.
I just get rectangle bounds between rendered nodes of edge and I use center coordinates. Well that looks like labels are not attached to the edges, since the edge is not a straight line. I cannot compute edge curve outside edge renderer in main program, even if I could this woud be probably stupid, since you are doing same work twice.
Here is the updated code, now including also main program and a sample xml.
You start it by running:
java GraphViewPath <filename to xml>
a quick fix would be calling a
-> list.clear();
at the beginning of the redrawing. I think you could add a PaintListener and use the prePaint() method.
I don´t know if you are happy with the performance. Basically it´s the same as with your current go but it could be more efficient to calculate these sets only if something has changed.
As you can see you will no longer do anything in your layout. You more or less trigger the calculations manually (whenever you add/remove an edge).
Of course you can also implement another method that changes the list only partially to improve performance...
The trick is to hold the list in GraphViewPath. This list is build by regarding the edges of the graph once.
Based on this list the radiuses is calculated and you can save it as a field in the edge or wherever you want it.
------------
To the second problem, have you tried what q_curve.getPathIterator(...) does?
Sounds promising if you have a look at the API of PathIterator
Greetings,
Marcus
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thank you very much for your help! Now I'm much closer to the solution.
The second problem is that getPathIterator is only visible in edge renderer, but I'm adding labels inside GraphViewPathClass.
I'm thinking about adding another colum (onto edges) in which I will get needed coordinates for labes.
I'm using rectangleBounds currently - which is not effective on curves at all.
Again, thank you for you help.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I just hacked down the code and didn't test it, so I´ve overseen that cast problem :)
Anyways I think the idea with saving the coordinates for the lables sounds good to me.
Greetings,
Marcus
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
So I made custom edge renderer that supports multiple same-directed connections (it increases radius in quadcurves) and
even connections onto same elements:
http://shrani.si/f/R/kL/3Xwg75sd/tree.png
But I'm left with two remaining problems.
Currently I'm using building a list of parsed nodes in edge renderer, that way I know if same nodes were already on the list and I can increase radius of the curve.
Problem is that every time something gets changed on display, it will call edgerenderer again, this list will expand and edge radius will just increase. Is there a better solution than using a list of already visited nodes in edge renderer.
Another cosmetic problems are labels - I place them in center of rectangle bound, but I cannot find a way to get the shape and iterate trough it - is it possible at all?
Here is the link to the code, so anyone can see better the logic behind:
http://files.myopera.com/kriko/files/CustomEdgeRenderer.java
Hi,
this is a realy nice idea and I appreciate that you deliveded the source code as an example for better understanding.
How did you solve the problem of getting several parallel edges from the graph?
(If you say getEdge(node1, node2), did you save them as a list or do you parse all edges and filter the requested out?)
As I thought about that I found the following Idea to be promising. Currently you have a list thats "updated" everytime the renderer runs.
How about a list that is only updated when you add an edge?
(That´s why I asked how you manage this :) )
Let me explain this more in detail.
Asumme we have some kind of "code" that notices when explicitely (delete edge) or implicitely (delete one node) an edge set between two nodes is influenced. If one node is deleted nothing big will happen since all edges are removed but if a parallel edge is added or removed the radius values of parallel edges will have to be recalculated.
Maybe you want to assign new radiuses (sounds strange) to all involved edges in case of a change, maybe not.
Further I think the radius should be stored in each edge as an attribute for faster layouting, so you realy only have to use the list when adding/removing edges.
So if you add/demove an edge you search all parallel edges and watch if they have this attribute set. If not it´s a new edge and will be layouted with the highest value.
Of course you got to think about reducing radiuses (still looks strange) but I think that´s not a problem for you :)
To your second problem, what you mean by getting the shape and iterating through it?
You mean getting that stroke and running it along some way?
Greetings,
Marcus
Thank you for your reply, xcraptor!
I don't use getEdge (I don't know such method), but I just assign my customEdgeRenderer to default renderer factory, so edges are all managed by prefuse library.
If you look at the source, "getRawShape(VisualItem item)" is where all the juice is being made -
first I check if processed paired nodes already exist (and how many times), then I multiply their count with a constant → this is what I use for radius. At last I add connected nodes to list.
I'm always connecting nodes as I get from the graph (start → end), so the quadCurve is always bulging to the outside + radius is increased if nodes were already connected in the past.
I'm also checking if nodes are self-connected "if (item1 == item2)", that way I draw an ellipse instead of quad curve, again with different radius if nodes are connected multiple times (using same logic and list from above).
This works, however every time something happens on display, the scene gets rerendered, and if you can imagine, list is increasing and this leads to bigger and bigger radius (which is not what I want).
This would be solved if I would know which node is the last in graph (which is the last to render). That way I would just fill up the list, calculate all radiuses and then stop that part of logic. Everytime scene would be updated, I wouldn't have to increase list nor radius.
I can imagine your idea, but don't know how to exactly acomplish this, since edge / label... renderer you just add it to render factory (is any other way?).
Probably I could rewrite RendererFactory and the use also custom parts I want? I don't know if this is the best approach.
---
The second problem I meant "getting that stroke and running it along some way ". Is this possible?
The problem is with placing the labels.
I just get rectangle bounds between rendered nodes of edge and I use center coordinates. Well that looks like labels are not attached to the edges, since the edge is not a straight line. I cannot compute edge curve outside edge renderer in main program, even if I could this woud be probably stupid, since you are doing same work twice.
Here is the updated code, now including also main program and a sample xml.
You start it by running:
java GraphViewPath <filename to xml>
http://files.myopera.com/kriko/files/graph.zip
Hi,
a quick fix would be calling a
-> list.clear();
at the beginning of the redrawing. I think you could add a PaintListener and use the prePaint() method.
I don´t know if you are happy with the performance. Basically it´s the same as with your current go but it could be more efficient to calculate these sets only if something has changed.
My suggestion would be more like the one I posted here
http://goosebumps4all.net/34all/bb/showthread.php?tid=186
As you can see you will no longer do anything in your layout. You more or less trigger the calculations manually (whenever you add/remove an edge).
Of course you can also implement another method that changes the list only partially to improve performance...
The trick is to hold the list in GraphViewPath. This list is build by regarding the edges of the graph once.
Based on this list the radiuses is calculated and you can save it as a field in the edge or wherever you want it.
------------
To the second problem, have you tried what q_curve.getPathIterator(...) does?
Sounds promising if you have a look at the API of PathIterator
Greetings,
Marcus
Thank you! This helped me, however:
Iterator<Edge> edges = m_graph.getEdges().tuples();
while (edges.hasNext()) {
Edge edge = edges.next(); // causes exception
*TableTuple cannot be cast to prefuse.data.Edge*
Probably you meant :
Iterator<TableTuple> edges = m_graph.getEdges().tuples();
while (edges.hasNext()) {
TableTuple tTuple = (TableTuple) edges.next();
+ some modifications to the code due to this.
How can I also add a radius column to the graph - what classType it expects here?
m_graph.getEdges().addColumn("radius", ClassType, 0);
m_graph.getEdges().addColumn("radius", double.Class, 0);
lol, I have to go to get some sleep :P
Thank you very much for your help! Now I'm much closer to the solution.
The second problem is that getPathIterator is only visible in edge renderer, but I'm adding labels inside GraphViewPathClass.
I'm thinking about adding another colum (onto edges) in which I will get needed coordinates for labes.
I'm using rectangleBounds currently - which is not effective on curves at all.
Again, thank you for you help.
Hi,
I just hacked down the code and didn't test it, so I´ve overseen that cast problem :)
Anyways I think the idea with saving the coordinates for the lables sounds good to me.
Greetings,
Marcus
I did that and it works excellent!
I have just one problem to go (layout), but it doesn't belong to this thread anymore.
Thank you for your help.