Win a copy of The Little Book of Impediments (e-book only) this week in the Agile and Other Processes forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Making streets in JavaFX (cool rhyme)

 
Alex Shykhman
Greenhorn
Posts: 6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi, all! I'm new on this forum and I'm glad to join you.

And here is my question. For now I'm making a pet-project on JavaFX. Its' main purpose - find the shortest way between all nodes considering edge weights. Algorithm is quite simple, but I got a problem with GUI.

I have a pane. It has kids: nodes and edges in the form of separate panes. Each node can be connected to any other node. A connection(graph's edge) should be like a line and a distance written above it. All connections should hide behind nodes* . All nodes should be draggable. That mean all connections should dynamically move after dragged node and the distance sign should also move toward the center of connection**. So here are my current tasks I need your help with. Thank you in advance.


* - since all nodes are rendered before we created any connections, latter overlap former. toFront() and toBack() methods didn't help for some reason.
** - of course if we moved left node and right node and then swapped them, we may end up in situations when the text is upside down. So I should just... turn it somehow?
 
John Damien Smith
Ranch Hand
Posts: 299
15
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
As this is your pet project, I doubt you would want somebody else to implement it for you, probably what you want to do is break the project down into small manageable problems, such as: how to drag nodes? how to connect the dragged nodes? how to update the distances between nodes? etc. Then try to solve only those problems (as stand-alone applications) and, if you get stuck on one of those pieces, post your code attempt for one of those problems together with a specific question on how to get one of those parts working.

Perhaps read up on the site FAQ, as understanding and applying it may help you in getting good answers.
http://www.coderanch.com/t/660146/Wiki/Questions-Java-Ranch
http://www.coderanch.com/t/660112/Wiki/Isolate
http://www.coderanch.com/t/659815/Wiki/Details
http://www.coderanch.com/t/659941/Wiki/Post-Real-Code
http://homepage1.nifty.com/algafield/sscce.html
http://www.coderanch.com/t/659862/Wiki/Show-Effort
http://www.coderanch.com/t/659991/Wiki/Code-Mill

To get you started, you could look to:
http://stackoverflow.com/questions/19748744/javafx-how-to-connect-two-nodes-by-a-line
https://en.wikipedia.org/wiki/Shortest_path_problem
 
Alex Shykhman
Greenhorn
Posts: 6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you for reply, John!
Well, I've already created the whole system. It already has all the backend.
It has a GUI. GUI allows to create Nodes and Connections between them. Nodes are draggable, connections move after them.

My real problem includes next questions:
1. I don't know how to create a separate line with a text above it (or two lines with a white fill where text could be placed). It is a separate task. What I have now you can see in the code below.

2. I don't know how to provide ability for text to roll if the line after node dragging ended upside down. Let's imagine the code:


3. Connections overlap nodes. It's said that on the pane children overlap each other as they are rendered. And there are toBack() and toFront() methods that didn't work in my case.
Node creation:

Connection creation:
 
John Damien Smith
Ranch Hand
Posts: 299
15
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Code below will:

1. Create a separate line with a text below it
2. Ensure that the text always remains under the line and printed in the right direction (left to right with the characters correctly oriented rather than flipping upside down as the line is rotated).

This is just a quick sample code. It uses a lot of binding. Another approach (more general purpose) would be to subclass Labeled and build a custom control with a skin that includes both the line and the label, but that is quite bit more complex, so I don't do that or explain that here.



For your node overlapping point (3. Connections overlap nodes.), the drawing depends upon the order of items in the child list. You can change the order of the items in the child list to change their order of rendering.

So for the code below, the line connection line will be rendered under the start anchor, which is under the end anchor, which is under the distance label. You can set this ordering as below when the parent is created:

Or you can change it later, for example, after the label is the group, to move the label to the back you could either call:

Or



 
Alex Shykhman
Greenhorn
Posts: 6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you, John! I'll try to completely understand how does your code work and to use it in my application. You really did a big work for me, it's a little awkward...
 
John Damien Smith
Ranch Hand
Posts: 299
15
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No worries Alex, I had the time. Some problems are more interesting than others and this was one of the more interesting ones to solve. Hopefully it is worthwhile for you.
 
Alex Shykhman
Greenhorn
Posts: 6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
John Damien Smith wrote:No worries Alex, I had the time. Some problems are more interesting than others and this was one of the more interesting ones to solve. Hopefully it is worthwhile for you.

I have some questions about your solution. I couldn't understand how a LabeledLine is bound to Anchor? Both of them use something like independent coordinates.
I tried to implement it but didn't manage to do it completely. I have a graph that contains all of nodes and edges. Like this:




So I have to bind LabeledLine (as a Group) to coordinates of two AnchorNodes. And somehow draw its BoundLine and Label respectively. I managed to bind only BoundLine by adding it directly to mainPane's children.

But it didn't work with label. It seems I need your advice again if you have a time.
 
John Damien Smith
Ranch Hand
Posts: 299
15
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It's a slightly tricky problem, I'm not sure I'll be able to help you to solve your problem in exactly the way you wish if the sample code I provided isn't currently doing exactly what you wish (which is likely).
I'll try to answer some questions.

> I couldn't understand how a LabeledLine is bound to Anchor?

It's not really. The LabeledLine class is really just a helper class, it is isn't a node itself, that's why you can't directly add it to a scene graph. Instead, it aggregates two other nodes, (Label and Line) and internally, within it's constructor, establishes bindings that keep the label in sync with the line as you would expect. By this I mean, it binds the text of the label to the length of the line (to provide feedback to the user of the distance of the line), and it also establishes bindings based upon the angle of the line to ensure that that the text is never completely upside down and is printed at an appropriate angle near the mid-point of the line (that is accomplished through the help of the Distance and Angle internal classes in the LabeledLine). Binding the ends of the line to the anchor is not directly a function of the LabeledLine class, instead those bindings are established in the BoundLine class which binds the startX/startY/endX/endY properties for the line based upon start and end anchor positions. That way, when you drag the anchors around, the line start and end points move too and (due to the relationships setup in the LabeledLine class, so too does the associated distance label attached to the line). The idea with the LabeledLine graph is that you don't add it directly to the scene graph, instead you add the two nodes it manages (the Line and the Label) to the scene graph (as is done in the sample code I provided). You say you have a "LabeledLine (as a Group)" - don't do that, don't try to make LabeledLine itself a node, instead just add the nodes which the LabeledLine manages directly to your mainPane (the Label and the Line). You could supply an alternate implementation which treats the LabeledLine as an actual node (e.g. as a Control), but that is a bit more complicated and I have not done that in the sample here.
 
Alex Shykhman
Greenhorn
Posts: 6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, let's put out idea about making a node from LabeledLine. So, what we have?
Do you mean that in this code:

we can bind the ends of BoundLine to the Anchors' central coordinates from here:


If I got you right, I can just define Coordinate variables in the anchor (what if circles with their coordinates are just a view of the bigger AnchorNode? Is it acceptable?) and later just add lines... Let us assume we have a lot of Anchors. We can get their DoubleProperty coordinates. We choose two nodes and we want to create a connection. So we should pass to Connection's constructor these properties. And then what? How should we display this new connection properly?
 
John Damien Smith
Ranch Hand
Posts: 299
15
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
> Do you mean that in this code ... we can bind the ends of BoundLine to the Anchors' central coordinates from here

Yes.

> Coordinate variables in the anchor (what if circles with their coordinates are just a view of the bigger AnchorNode? Is it acceptable?) and later just add lines...

Yes, you could call these co-ordinates attachment points or anchor points. If you have a more complex node than a circle than you could associate multiple attachment points with a node (for example a rectangle where lines could be connected to any of the top, bottom, left or right sides of the rectangle). But I don't really know your use-case in detail, so I can't advise you exactly what to do here.

> And then what? How should we display this new connection properly?

The connection will be a line and a label, you can add them both to your scene.

Perhaps you might want to take a look at how connections work in an application such as giffly and (if that is what you want to achieve), study it in detail, then code up your program to mimic it's behavior (though don't expect this to be an easy task).
https://www.gliffy.com

You may want to consider using a commercial library to aid in your task:
https://www.yworks.com/products/yfiles-for-javafx


 
Alex Shykhman
Greenhorn
Posts: 6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I finally did it! Now, after many hours of debugging and trying to find out what all these X-Y-ended variables mean. I could not bind anything to my anchor and I didn't understand why. Later I just understood I used TranslateX to change Anchor's position. And all LabelLine children I've bound to LayoutX. Now I've changed it and it seems the model is working. I'll try to put out a link on Github soon.
 
John Damien Smith
Ranch Hand
Posts: 299
15
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yep, understanding how all of the layout stuff works can be tricky -> translateX/Y is different than layoutX/Y. Depending upon whether you use boundsInParent or boundsInLocal, the translate values can be included in calculating the bounds or not. There are some useful resources to help understand how it fits together:
* Node JavaDoc
* Interactive LayoutBounds Demo.
* Amy Fowler's presentation on JavaFX 2 layout


 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic