Wednesday, March 7, 2012

JavaFX 2.0: Transition along dynamic path


package javafx_path;

import javafx.animation.PathTransition;
import javafx.animation.PathTransitionBuilder;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.stage.Stage;
import javafx.util.Duration;

/**
 *
 * @web java-buddy.blogspot.com
 */
public class JavaFX_Path extends Application {
    
    PathTransition pathTransition;
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
    
    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("java-buddy.blogspot.com");
        Group root = new Group();
        Scene scene = new Scene(root, 400, 300, Color.WHITE);
        
        final Image image1 = new Image(getClass().getResourceAsStream("duke_44x80.png"));
        final ImageView imageView = new ImageView();
        imageView.setImage(image1);
        
        final Path path = new Path();
        path.setStrokeWidth(1);
        path.setStroke(Color.BLACK);
        
        //Mouse button pressed - clear path and start from the current X, Y.
        scene.onMousePressedProperty().set(new EventHandler<MouseEvent>(){

            @Override
            public void handle(MouseEvent event) {
                path.getElements().clear();
                path.getElements().add(new MoveTo(event.getX(), event.getY()));
            }
        });

        //Mouse dragged - add current point.
        scene.onMouseDraggedProperty().set(new EventHandler<MouseEvent>(){

            @Override
            public void handle(MouseEvent event) {
                path.getElements().add(new LineTo(event.getX(), event.getY()));
            }
        });
                
        //Mouse button released,  finish path.
        scene.onMouseReleasedProperty().set(new EventHandler<MouseEvent>(){

            @Override
            public void handle(MouseEvent event) {
                pathTransition = PathTransitionBuilder.create()
                        .node(imageView)
                        .path(path)
                        .duration(Duration.millis(5000))
                        .orientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT)
                        .cycleCount(1)
                        .build();

                pathTransition.play();
            }
        });

        root.getChildren().add(imageView);
        root.getChildren().add(path);
        primaryStage.setScene(scene);
        primaryStage.show();

    }
}


4 comments:

  1. Hi,
    I have integrated your code with the XyChart plot and zoom: by right mouse button click and drag perform free hand draw, while with left mouse button click and drag perform Zoom In on selected area.

    My problem is about zoom on freehand draw it always get translated. Try to draw somewhere around a corner.

    How can I solve it ?


    (Part 1)

    ReplyDelete
  2. public class Zoom extends Application {

    Path path;//Add path for freehand
    BorderPane pane;
    Rectangle rect;
    SimpleDoubleProperty rectinitX = new SimpleDoubleProperty();
    SimpleDoubleProperty rectinitY = new SimpleDoubleProperty();
    SimpleDoubleProperty rectX = new SimpleDoubleProperty();
    SimpleDoubleProperty rectY = new SimpleDoubleProperty();

    double initXLowerBound = 0, initXUpperBound = 0, initYLowerBound = 0, initYUpperBound = 0;
    @Override
    public void start(Stage stage) {
    stage.setTitle("Lines plot");
    final NumberAxis xAxis = new NumberAxis(1, 12, 1);
    final NumberAxis yAxis = new NumberAxis(0.53000, 0.53910, 0.0005);

    yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) {

    @Override
    public String toString(Number object) {
    return String.format("%7.5f", object);
    }
    });

    final LineChart lineChart = new LineChart(xAxis, yAxis);

    lineChart.setCreateSymbols(false);
    lineChart.setAlternativeRowFillVisible(false);
    lineChart.setAnimated(true);

    XYChart.Series series1 = new XYChart.Series();
    series1.getData().add(new XYChart.Data(1, 0.53185));
    series1.getData().add(new XYChart.Data(2, 0.532235));
    series1.getData().add(new XYChart.Data(3, 0.53234));
    series1.getData().add(new XYChart.Data(4, 0.538765));
    series1.getData().add(new XYChart.Data(5, 0.53442));
    series1.getData().add(new XYChart.Data(6, 0.534658));
    series1.getData().add(new XYChart.Data(7, 0.53023));
    series1.getData().add(new XYChart.Data(8, 0.53001));
    series1.getData().add(new XYChart.Data(9, 0.53589));
    series1.getData().add(new XYChart.Data(10, 0.53476));
    series1.getData().add(new XYChart.Data(11, 0.530123));
    series1.getData().add(new XYChart.Data(12, 0.53035));


    pane = new BorderPane();
    pane.setCenter(lineChart);
    Scene scene = new Scene(pane, 800, 600);
    lineChart.getData().addAll(series1);

    initXLowerBound = ((NumberAxis) lineChart.getXAxis()).getLowerBound();
    initXUpperBound = ((NumberAxis) lineChart.getXAxis()).getUpperBound();
    initYLowerBound = ((NumberAxis) lineChart.getYAxis()).getLowerBound();
    initYUpperBound = ((NumberAxis) lineChart.getYAxis()).getUpperBound();

    stage.setScene(scene);

    path = new Path();
    path.setStrokeWidth(1);
    path.setStroke(Color.BLACK);

    scene.setOnMouseClicked(mouseHandler);
    scene.setOnMouseDragged(mouseHandler);
    scene.setOnMouseEntered(mouseHandler);
    scene.setOnMouseExited(mouseHandler);
    scene.setOnMouseMoved(mouseHandler);
    scene.setOnMousePressed(mouseHandler);
    scene.setOnMouseReleased(mouseHandler);

    pane.getChildren().add(path);

    rect = new Rectangle();
    rect.setFill(Color.web("blue", 0.1));
    rect.setStroke(Color.BLUE);
    rect.setStrokeDashOffset(50);

    rect.widthProperty().bind(rectX.subtract(rectinitX));
    rect.heightProperty().bind(rectY.subtract(rectinitY));
    pane.getChildren().add(rect);

    stage.show();
    }


    (Part 2)

    ReplyDelete
  3. EventHandler mouseHandler = new EventHandler() {
    @Override
    public void handle(MouseEvent mouseEvent) {
    if (mouseEvent.getButton() == MouseButton.PRIMARY)
    {if (mouseEvent.getEventType() == MouseEvent.MOUSE_PRESSED) {
    rect.setX(mouseEvent.getX());
    rect.setY(mouseEvent.getY());
    rectinitX.set(mouseEvent.getX());
    rectinitY.set(mouseEvent.getY());
    } else if (mouseEvent.getEventType() == MouseEvent.MOUSE_DRAGGED) {
    rectX.set(mouseEvent.getX());
    rectY.set(mouseEvent.getY());
    } else if (mouseEvent.getEventType() == MouseEvent.MOUSE_RELEASED) {
    if ((rectinitX.get() >= rectX.get())&&(rectinitY.get() >= rectY.get()))
    {
    LineChart lineChart = (LineChart) pane.getCenter();
    ((NumberAxis)lineChart.getXAxis()).setLowerBound(initXLowerBound);
    ((NumberAxis)lineChart.getXAxis()).setUpperBound(initXUpperBound);
    ((NumberAxis)lineChart.getYAxis()).setLowerBound(initYLowerBound);
    ((NumberAxis) lineChart.getYAxis()).setUpperBound(initYUpperBound);

    ZoomFreeHand(path, 1.0, 1.0, 0, 0);

    }
    else
    {
    //Zoom In

    double Tgap = 0;
    double newLowerBound, newUpperBound, axisShift;
    double xScaleFactor, yScaleFactor;
    double xaxisShift, yaxisShift;

    LineChart lineChart = (LineChart) pane.getCenter();

    // Zoom in Y-axis by changing bound range.
    NumberAxis yAxis = (NumberAxis) lineChart.getYAxis();
    Tgap = yAxis.getHeight()/(yAxis.getUpperBound() - yAxis.getLowerBound());
    axisShift = getSceneShiftY(yAxis);
    yaxisShift = axisShift;

    newUpperBound = yAxis.getUpperBound() - ((rectinitY.get() - axisShift) / Tgap);
    newLowerBound = yAxis.getUpperBound() - (( rectY.get() - axisShift) / Tgap);


    if (newUpperBound > yAxis.getUpperBound())
    newUpperBound = yAxis.getUpperBound();

    yScaleFactor = (yAxis.getUpperBound() - yAxis.getLowerBound())/(newUpperBound - newLowerBound);
    yAxis.setLowerBound(newLowerBound);
    yAxis.setUpperBound(newUpperBound);


    NumberAxis xAxis = (NumberAxis) lineChart.getXAxis();

    Tgap = xAxis.getWidth()/(xAxis.getUpperBound() - xAxis.getLowerBound());
    axisShift = getSceneShiftX(xAxis);
    xaxisShift = axisShift;
    newLowerBound = ((rectinitX.get() - axisShift) / Tgap) + xAxis.getLowerBound();
    newUpperBound = ((rectX.get() - axisShift) / Tgap) + xAxis.getLowerBound();

    if (newUpperBound > xAxis.getUpperBound())
    newUpperBound = xAxis.getUpperBound();

    xScaleFactor = (xAxis.getUpperBound() - xAxis.getLowerBound())/(newUpperBound - newLowerBound);
    xAxis.setLowerBound( newLowerBound );
    xAxis.setUpperBound( newUpperBound );

    ZoomFreeHand(path, xScaleFactor, yScaleFactor, xaxisShift, yaxisShift);
    }
    // Hide the rectangle
    rectX.set(0);
    rectY.set(0);
    }
    }
    else if (mouseEvent.getButton() == MouseButton.SECONDARY) //free hand graphics
    {
    if(mouseEvent.getEventType() == MouseEvent.MOUSE_PRESSED){
    path.getElements().clear();
    path.getElements().add(new MoveTo(mouseEvent.getX(), mouseEvent.getY()));
    }
    else if(mouseEvent.getEventType()==MouseEvent.MOUSE_DRAGGED){
    path.getElements().add(new LineTo(mouseEvent.getX(), mouseEvent.getY()));
    }
    }
    }
    };



    (Part 3/4)

    ReplyDelete
  4. private static double getSceneShiftX(Node node) {
    double shift = 0;
    do {
    shift += node.getLayoutX();
    node = node.getParent();
    } while (node != null);
    return shift;
    }
    private static double getSceneShiftY(Node node) {
    double shift = 0;
    do {
    shift += node.getLayoutY();
    node = node.getParent();
    } while (node != null);
    return shift;
    }
    private static void ZoomFreeHand(Path path, double xScaleFactor, double yScaleFactor, double xaxisShift, double yaxisShift) {

    double layX, layY;

    layX = path.getLayoutX();
    layY = path.getLayoutY();
    path.setScaleX(xScaleFactor);
    path.setScaleY(yScaleFactor);
    path.setTranslateX(xaxisShift);
    path.setTranslateY(yaxisShift);
    }
    public static void main(String[] args) {
    launch(args);
    }
    }

    (part 4/4)

    ReplyDelete