圆圈边缘的箭头

时间:2015-12-01 13:21:58

标签: java javafx javafx-8

在下面的JavaFX代码中,输出两个顶点(圆圈),其中有一条从源到目标的有向边(线和箭头)。但是,箭头始终是圆的中心。我希望箭头在拖动时始终指向圆的边缘。

主类(TestArrow.java):

import java.util.ArrayList;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.stage.Stage;

public class TestArrow extends Application
{
    int startX = 20,
    startY = 20,
    endX = 200,
    endY = 200;

    ArrayList<ArrowSecond> arrows = new ArrayList<>();

    @Override
    public void start(Stage primaryStage)
    {
        AnchorPane root = new AnchorPane();

        Line line = new Line(startX, startY, endX, endY);
        line.setStrokeWidth(3);
        line.setStroke(Color.BLACK);

        AnchorSecond start = new AnchorSecond(Color.BLACK, line.startXProperty(), line.startYProperty(), this);
        AnchorSecond end = new AnchorSecond(Color.BLACK, line.endXProperty(), line.endYProperty(), this);

        double[] points = {0.0, 10.0, -10.0, -10.0, 10.0, -10.0};

        arrows.add(new ArrowSecond(points, line));

        root.getChildren().addAll(arrows);
        root.getChildren().addAll(line, start, end);

        primaryStage.setScene(new Scene(root, 500, 500));
        primaryStage.show();
    }

    public ArrayList<ArrowSecond> getArrows(){
        return arrows;
    }

    public static void main(String[] args){
        launch(args);
    }
}

箭头类(ArrowSecond.java):

import javafx.scene.shape.Line;
import javafx.scene.shape.Polygon;

public class ArrowSecond extends Polygon
{
    private Line line;

    public ArrowSecond(double[] points, Line line)
    {
        super(points);
        this.line = line;
        initialize();
    }

    private void initialize()
    {
        double angle = Math.atan2(line.getEndY() - line.getStartY(), line.getEndX() - line.getStartX()) * 180 / 3.14;

        setRotate(angle - 90);
        setTranslateX(line.getStartX());
        setTranslateY(line.getStartY());
        setTranslateX(line.getEndX());
        setTranslateY(line.getEndY());
    }

    public void update(){
        initialize();
    }
}

顶点类(AnchorSecond.java):

import javafx.beans.property.DoubleProperty;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.StrokeType;

public class AnchorSecond extends Circle
{
    private double x, y;
    TestArrow app;

    public AnchorSecond(Color color, DoubleProperty xx, DoubleProperty yy, TestArrow app)
    {
        //      x point     y point     radius
        super(xx.get(), yy.get(), 12);

        this.app = app;

        setFill(color.deriveColor(1, 1, 1, 0.5));
        setStroke(color);
        setStrokeWidth(2);
        setStrokeType(StrokeType.OUTSIDE);

        xx.bind(centerXProperty());
        yy.bind(centerYProperty());     

        setOnMousePressed(new EventHandler<MouseEvent>(){
            @Override
            public void handle(MouseEvent mouseEvent)
            {
                x = getCenterX() - mouseEvent.getX();
                y = getCenterY() - mouseEvent.getY();
            }
        });

        setOnMouseDragged(new EventHandler<MouseEvent>(){
            @Override
            public void handle(MouseEvent event)
            {               
                setCenterX(event.getSceneX() - x);
                setCenterY(event.getSceneY() - y);

                //  update arrow positions when circles are dragged
                for(ArrowSecond arrow : app.getArrows())
                    arrow.update();
            }
        });
    }
}

1 个答案:

答案 0 :(得分:2)

这是我的解决方案:

我从结束X中减去并根据节点的半径结束Y坐标。数学很简单 - 我只是从斜边减去比例。

TestArrow类:

public class TestArrow extends Application {
int startX = 20, startY = 20, endX = 200, endY = 200;

ArrayList<ArrowSecond> arrows = new ArrayList<>();

@Override
public void start(Stage primaryStage)
{
    double radius = 12;
    AnchorPane root = new AnchorPane();

    Line line = new Line(startX, startY, endX, endY);
    line.setStrokeWidth(3);
    line.setStroke(Color.BLACK);

    AnchorSecond start = new AnchorSecond(Color.BLACK, line.startXProperty(), line.startYProperty(), radius, this);
    AnchorSecond end = new AnchorSecond(Color.BLACK, line.endXProperty(), line.endYProperty(), radius, this);

    double[] points = {0.0, 10.0, -10.0, -10.0, 10.0, -10.0};

    arrows.add(new ArrowSecond(points, line, radius));

    root.getChildren().addAll(arrows);
    root.getChildren().addAll(start, end, line);

    primaryStage.setScene(new Scene(root, 500, 500));
    primaryStage.show();
}

public ArrayList<ArrowSecond> getArrows(){
    return arrows;
}

public static void main(String[] args){
    launch(args);
}
}

ArrowSecond类:

public class ArrowSecond extends Polygon {
private Line line;
double radius;

public ArrowSecond(double[] points, Line line, double AnchorRadius) {
    super(points);
    this.line = line;
    this.radius = AnchorRadius * 2;
    initialize();

}

private void initialize() {
    double angle = Math.atan2(line.getEndY() - line.getStartY(), line.getEndX() - line.getStartX()) * 180 / 3.14;

    double height = line.getEndY() - line.getStartY();
    double width = line.getEndX() - line.getStartX();
    double length = Math.sqrt(Math.pow(height, 2) + Math.pow(width, 2));

    double subtractWidth = radius * width / length;
    double subtractHeight = radius * height / length;

    setRotate(angle - 90);
    setTranslateX(line.getStartX());
    setTranslateY(line.getStartY());
    setTranslateX(line.getEndX() - subtractWidth);
    setTranslateY(line.getEndY() - subtractHeight);
}

public void update(){
    initialize();
}
}

AnchorSecond类:

public class AnchorSecond extends Circle {
private double x, y;
TestArrow app;

public AnchorSecond(Color color, DoubleProperty xx, DoubleProperty yy, double radius, TestArrow app) {
    //      x point     y point     radius
    super(xx.get(), yy.get(), radius);

    this.app = app;

    setFill(color.deriveColor(1, 1, 1, 0.5));
    setStroke(color);
    setStrokeWidth(2);
    setStrokeType(StrokeType.OUTSIDE);

    xx.bind(centerXProperty());
    yy.bind(centerYProperty());     

    setOnMousePressed(new EventHandler<MouseEvent>(){
        @Override
        public void handle(MouseEvent mouseEvent)
        {
            x = getCenterX() - mouseEvent.getX();
            y = getCenterY() - mouseEvent.getY();
        }
    });

    setOnMouseDragged(new EventHandler<MouseEvent>(){
        @Override
        public void handle(MouseEvent event)
        {               
            setCenterX(event.getSceneX() - x);
            setCenterY(event.getSceneY() - y);

            //  update arrow positions when circles are dragged
            for(ArrowSecond arrow : app.getArrows())
                arrow.update();
        }
    });
}
}

抱歉格式错误 - 第一次回答SO问题