1

I'm connecting two nodes by a line. I can drag a line from the circle from one node to the circle of another by drag and drop a CubicCurve.

My Nodes look like this:

enter image description here

My problem is, that after I drop my CubicCurve and it sets the start and end points, the 'Anchor' points are height/2 and width/2 of my DragNode. But I want them to be in the center of my circles (left or right of my Nodes).

My current bindEnds()-Function, where I link the Curves to the Center of my DragNode (AnchorPane):

public void bindEnds (DragNode source, DragNode target) {

    cubicCurve.startXProperty().bind(
    Bindings.add(source.layoutXProperty(), (source.getWidth() / 2.0)));

    cubicCurve.startYProperty().bind(
    Bindings.add(source.layoutYProperty(), (source.getWidth() / 2.0)));

    cubicCurve.endXProperty().bind(
    Bindings.add(target.layoutXProperty(), (target.getWidth() / 2.0)));

    cubicCurve.endYProperty().bind(
    Bindings.add(target.layoutYProperty(), (target.getWidth() / 2.0)));

    source.registerLink (getId());
    target.registerLink (getId());       
}

I'm thinking about to change my bindEnds()-Function to something like this, where I have my nodes and also their child circles and their centers, where I want to bind my linking curves:

       public void bindEnds (DragNode source, DragNode target, Circle c1, Circle c2) {

    source.getChildren().add(c1);
    target.getChildren().add(c2);


    cubicCurve.startXProperty().bind(
    Bindings.add(source.layoutXProperty(), (c1.getLayoutX())));

    cubicCurve.startYProperty().bind(
    Bindings.add(source.layoutYProperty(), (c1.getLayoutY())));

    cubicCurve.endXProperty().bind(
    Bindings.add(target.layoutXProperty(), (c2.getLayoutX())));

    cubicCurve.endYProperty().bind(
    Bindings.add(target.layoutYProperty(), (c2.getLayoutY())));

    source.registerLink (getId());
    target.registerLink (getId());
} 

and in my Window ControllerClass:

private void buildDragHandlers() {
    this.setOnDragDone (new EventHandler <DragEvent> (){

        @Override
        public void handle (DragEvent event) {
            DragContainer container = (DragContainer) event.getDragboard().getContent(DragContainer.AddNode);
            container = (DragContainer) event.getDragboard().getContent(DragContainer.AddLink);  
            if (container != null) {
                String sourceId = container.getValue("source");
                String targetId = container.getValue("target");
                if (sourceId != null && targetId != null) {
                      NodeLink link = new NodeLink();
                      rightAnchor.getChildren().add(0,link);

                      DragNode source = null;
                      DragNode target = null;

                      for (Node n: rightAnchor.getChildren()) {                                             
                          if (n.getId() == null)
                              continue;                                             
                      if (n.getId().equals(sourceId)){
                          source = (DragNode) n;                      
                          }

                      if (n.getId().equals(targetId)){
                          target = (DragNode) n;                              
                          }
                      }                                         
                      if (source != null && target != null){
                          source.link(target);
                          link.bindEnds(source, target, c1, c2);                          
                      }
                  }

            }
        }
    });

In my DragNode controller class:

private ArrayList<Circle> circles = new ArrayList<Circle>();

private Circle getNearestCircle(DragNode source) {
    Circle nearestCircle = null;
    for (Circle circle : circles) {
        if (nearestCircle == null) {
            nearestCircle = circle;
        } else {
        }
    }
    return nearestCircle;
}

public void link (DragNode source) { 
    getNearestCircle(source).centerXProperty().bindBidirectional(source.getNearestCircle(this).centerXProperty());
    getNearestCircle(source).centerYProperty().bindBidirectional(source.getNearestCircle(this).centerYProperty());
}

I have to make it accessible to the Circles I use and also put them inside link.indEnds(source, target);

Can anyone help me?

Flippy
  • 202
  • 3
  • 12
  • I'm not exactly sure what you want help with but I'll try to help. Just make your circles class members of your `DragNode`. Then you can just do e.g. `target.getCircle()` to get the circle of the dragNode. Maybe you could even have a `target.getClosestCircle(source)` that will get the circle with the coordinates closest to the target circle. You'd typically want the link to end not in the middle of the circle but on the corner of it. I'm not sure if this is what your asking for, but if it is I can write an example. – Jonatan Stenbacka Nov 17 '16 at 13:29
  • added this to my DragNode class: `public void getCircle(DragNode node1, Circle circ1) { node1.getChildren().add(circ1); }`, but an example would be good, it is still not working sadly :/ – Flippy Nov 17 '16 at 13:48
  • I'm getting a NullPointerException with my edited code ... – Flippy Nov 17 '16 at 14:30
  • See related: [CubicCurve JavaFX](http://stackoverflow.com/questions/13056795/cubiccurve-javafx) and [JavaFX line/curve with arrow head](http://stackoverflow.com/questions/26702519/javafx-line-curve-with-arrow-head). I admit I didn't read your question in detail, so the linked question may or may not help you, it just seemed somewhat similar at first glance. – jewelsea Nov 17 '16 at 19:04
  • I think my main problem is how to correctly reference to my circle of my DragNode / getting the circles as child without getting NullPointerExceptions – Flippy Nov 17 '16 at 19:16
  • @jewelsea could you help me fixing my problem? I I have a mainController class for the window I create my custom nodes in, my custom nodes class where i load my nodes where my circles are on, and my nodelink class where i made the bindEnds function, to bind my nodelinks to the circles of my nodes. – Flippy Nov 18 '16 at 18:56
  • It is working now, used static for circle data. – Flippy Nov 18 '16 at 20:56

1 Answers1

1

Just make your circles class members of your DragNode. Then you can create a method e.g. target.getNearestCircle() to get the circle closest to the dragged node. The code below is more or less meta code, but I hope you get the idea:

DragNode:

public class DragNode {
    private ArrayList<Circle> circles = new ArrayList<Circle>

    private Circle getNearestCircle(DragNode source) {
        Circle nearestCircle = null;
        for (Circle circle : circles) {
            if (nearestCircle == null) {
                nearestCircle = circle;
            } else {
                // If this circle is closer to the target than the current nearest circle, set this circle as the nearestCircle.
            }
        }
        return nearestCircle;
    }

    public void link (DragNode source) {
        // Bind the x and y property of the target and source circle closest to each other.  
        getNearestCircle(source).xProperty.bindBidirectional(source.getNearestCircle(this).xProperty())
        getNearestCircle(source).yProperty.bindBidirectional(source.getNearestCircle(this).yProperty())
    }
}
Jonatan Stenbacka
  • 1,824
  • 2
  • 23
  • 48
  • Could you also please post an example of a code without the nearest functionality? – Flippy Nov 17 '16 at 14:06
  • Well you somehow have to know which one of the left and right node you want to bind your link to if you just drag your link to the `DragNode` and not to the circles themselves. Maybe you just want `DragNode` to have two members, `leftCircle` and `rightCircle`? Then you can just have methods like `linkToRightCircle(DragNode source). But you somehow need to keep track of which of the two circles in your source node and which of the two circles of your target node that you want to link with each other. – Jonatan Stenbacka Nov 17 '16 at 14:12
  • How do I call the getNearestCircle() inside my MainController? If I try it, I'm getting an error `the method getNearestCircle(DragNode) from the type DragNode is not visible ` – Flippy Nov 17 '16 at 14:23
  • This is because `getNearestCircle() is private. Just use the `link(DragNode source)` method and send in the node you want to link with this node. Then `link()` should connect the two nodes if you've implemented the methods correctly. Please not that my code example doesn't have the full functionality, I just wanted you to get the general idea. – Jonatan Stenbacka Nov 17 '16 at 14:30
  • Yea I know, I made some changes, what do you mean with xProperty? I can't use startXProperty. And should I call it like `source.link(source); target.link(target);`? – Flippy Nov 17 '16 at 14:34
  • `xProperty` was just some meta code. In reality you might need to use `layoutXProperty()` or something, I'm not entirely sure. And for your second question: Since I'm binding them bidirectionally in my example, you only need to call `source.link(target)` and both will be bound to each other. I will remove this answer and make a compilable example when and if I have the time. – Jonatan Stenbacka Nov 17 '16 at 14:57
  • uhm so where should i insert `source.link(target)`? inside my `buildDragHandlers();` ? – Flippy Nov 17 '16 at 15:25
  • I mean where inside my `buildDragHandlers();` – Flippy Nov 17 '16 at 15:35
  • Inside `if (source != null && target != null)` would be a good idea, since you have to have a valid target and source node to be able to connect them. – Jonatan Stenbacka Nov 18 '16 at 09:24
  • I think my main problem is inside the bindEnds() function, I make new Circles there which will be placed to 0/0 and I don't refer to my circles which i already created. I'll edit my post with the bindEnds function (Edit2) – Flippy Nov 18 '16 at 14:59
  • Should my function `bindEnds()` remain the same or should I change sth in there? – Flippy Nov 18 '16 at 18:34