This discussion is archived
1 Reply Latest reply: Mar 17, 2013 3:37 PM by James_D RSS

extend size of a shape through a path

997363 Newbie
Currently Being Moderated
Hi there i'm trying to extend the size of an arrow (which is a Polygon actually) through a path. I implemented an animation that an arrow can follow the path from a start point to the end point.However, the thing i wanna do is this arrow should leave tracks behind of it while it followes the path or in other words the rectangle part of arrow would extend until the head of arrow reaches end of the path. Here is my simple code which an arrow can follow the path.
Rectangle rect1 = new Rectangle(71, 64, 31, 21);
        Rectangle rect2 = new Rectangle(158, 64, 35, 21);
        
        rect1.setFill(Color.YELLOW);
        rect2.setFill(Color.YELLOW);
        
        rect1.setVisible(true);
        rect2.setVisible(true);
        
        root.getChildren().add(rect1);
        root.getChildren().add(rect2);
        
        Path path = new Path();
        
        MoveTo moveTo = new MoveTo();
        
        moveTo.setX( rect1.getX()+ (rect1.getWidth()/2) );
        moveTo.setY( rect1.getY()+ (rect1.getHeight()/2) );
        
        QuadCurveTo quadCurveTo = new QuadCurveTo(); 
       
        quadCurveTo.setX( rect2.getX()+(rect2.getWidth()/2) );
        quadCurveTo.setY( rect2.getY()+(rect2.getHeight()/2) );
        quadCurveTo.setControlX( ( rect1.getX()+rect2.getX() ) /2 );
        quadCurveTo.setControlY( ( rect1.getY()-50) );
        
        path.getElements().add(moveTo);
        path.getElements().add(quadCurveTo);
        path.setStrokeWidth(3); 
        path.setStroke(Color.BLACK);
        path.setMouseTransparent(true);
        path.setVisible(true);
        
        final Polygon arrow = new Polygon();
        
        arrow.getPoints().addAll(new Double[] {50.0,50.0,70.0,50.0,70.0,42.0,82.0,54.0,70.0,66.0,70.0,58.0,50.0,58.0});
        arrow.setFill(Color.GREEN);
        arrow.setMouseTransparent(true);
        
        PathTransition pathTransition = new PathTransition();
        
        pathTransition.setDuration(Duration.millis(750));
        pathTransition.setPath(path);
        pathTransition.setNode(arrow);
        pathTransition.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT);
        pathTransition.setCycleCount(Timeline.INDEFINITE);
        pathTransition.setAutoReverse(true);
        pathTransition.play();
        
        root.getChildren().add(path);
        root.getChildren().add(arrow);
Edited by: 994360 on 17.Mar.2013 06:13

Edited by: 994360 on 17.Mar.2013 10:22
  • 1. Re: extend size of a shape through a path
    James_D Guru
    Currently Being Moderated
    I don't know an easy way to do this.

    My approach would be:
    - Animate the head of the arrow directly using your path transition
    - Create a Path for the body of the arrow
    - Listen for changes in the translate x and y properties of the arrow head, and update the path for the arrow body in response.

    If you center the arrow head at (0,0) then the translate x and y will be the desired endpoints of the path. You'll need to do some geometry to figure the control point for the quadratic curve. I'm going to cheat here and figure the curve parameter from the currentTime of the animation; I think you probably need to do some more complex geometry to get the paths to match exactly (it has a little "bulge" near the end, which I think is due to the interpolation used for the animation).

    Obviously the calculation is dependent on the path you use, so it's not real flexible. There may be a better solution but I don't see it.
    import java.util.ArrayList;
    import java.util.List;
    
    import javafx.animation.Interpolator;
    import javafx.animation.PathTransition;
    import javafx.animation.Timeline;
    import javafx.application.Application;
    import javafx.beans.binding.IntegerBinding;
    import javafx.beans.property.IntegerProperty;
    import javafx.beans.property.SimpleIntegerProperty;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.scene.Scene;
    import javafx.scene.layout.Pane;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.MoveTo;
    import javafx.scene.shape.Path;
    import javafx.scene.shape.Polygon;
    import javafx.scene.shape.QuadCurve;
    import javafx.scene.shape.QuadCurveTo;
    import javafx.scene.shape.Rectangle;
    import javafx.stage.Stage;
    import javafx.util.Duration;
    
    public class TracingArrow extends Application {
    
         @Override
         public void start(Stage primaryStage) {
           final Pane root = new Pane();
           
           Rectangle rect1 = new Rectangle(71, 64, 31, 21);
        Rectangle rect2 = new Rectangle(158, 64, 35, 21);
        
        rect1.setFill(Color.YELLOW);
        rect2.setFill(Color.YELLOW);
        
        rect1.setVisible(true);
        rect2.setVisible(true);
        
        root.getChildren().add(rect1);
        root.getChildren().add(rect2);
        
        Path path = new Path();
        
        final MoveTo moveTo = new MoveTo();
        
        moveTo.setX( rect1.getX()+ (rect1.getWidth()/2) );
        moveTo.setY( rect1.getY()+ (rect1.getHeight()/2) );
        
        final QuadCurveTo quadCurveTo = new QuadCurveTo(); 
       
        quadCurveTo.setX( rect2.getX()+(rect2.getWidth()/2) );
        quadCurveTo.setY( rect2.getY()+(rect2.getHeight()/2) );
        quadCurveTo.setControlX( ( rect1.getX()+rect2.getX() ) /2 );
        quadCurveTo.setControlY( ( rect1.getY()-50) );
        
        path.getElements().add(moveTo);
        path.getElements().add(quadCurveTo);
        path.setStrokeWidth(3); 
        path.setStroke(Color.BLACK);
        path.setMouseTransparent(true);
        path.setVisible(true);
        
        final Polygon arrow = new Polygon();
        
        arrow.getPoints().addAll(-6.0, -12.0, 6.0, 0.0, -6.0, 12.0);
        arrow.setFill(Color.GREEN);
        arrow.setMouseTransparent(true);
        
        final PathTransition pathTransition = new PathTransition();
        
        pathTransition.setDuration(Duration.millis(750));
        pathTransition.setPath(path);
        pathTransition.setNode(arrow);
        pathTransition.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT);
        pathTransition.setCycleCount(Timeline.INDEFINITE);
        pathTransition.setAutoReverse(true);
        
        pathTransition.play();
        
        final Path arrowBody = new Path();
        arrowBody.getElements().add(moveTo);
        final QuadCurveTo arrowBodyQuadCurve = new QuadCurveTo();
        arrowBodyQuadCurve.setX(moveTo.getX());
        arrowBodyQuadCurve.setY(moveTo.getY());
        arrowBodyQuadCurve.setControlX(quadCurveTo.getControlX());
        arrowBodyQuadCurve.setControlY(quadCurveTo.getControlY());
        arrowBody.getElements().add(arrowBodyQuadCurve);
        arrow.translateXProperty().addListener(new ChangeListener<Number>() {
          @Override
          public void changed(ObservableValue<? extends Number> observable,
              Number oldValue, Number newValue) {
            arrowBodyQuadCurve.setX(arrow.getTranslateX());
            double t = pathTransition.getCurrentTime().toMillis() / pathTransition.getDuration().toMillis() ;
            arrowBodyQuadCurve.setControlX(t * quadCurveTo.getControlX() + (1-t) * moveTo.getX());
          }
        });
        arrow.translateYProperty().addListener(new ChangeListener<Number>() {
          @Override
          public void changed(ObservableValue<? extends Number> observable,
              Number oldValue, Number newValue) {
            arrowBodyQuadCurve.setY(arrow.getTranslateY());
            double t = pathTransition.getCurrentTime().toMillis() / pathTransition.getDuration().toMillis() ;
            arrowBodyQuadCurve.setControlY(t * quadCurveTo.getControlY() + (1-t) * moveTo.getY());
          }
        });
        arrowBody.setStrokeWidth(8);
        arrowBody.setStroke(Color.GREEN);
        
        root.getChildren().add(path);
        root.getChildren().add(arrow);
        root.getChildren().add(arrowBody);
        
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
         }
    
         public static void main(String[] args) {
              launch(args);
         }
    
    }

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points