Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8210238

☂ Animations do not play backwards properly

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P3 P3
    • tbd
    • jfx11, 9, 10
    • javafx

      The docs for Animation#play [1] specify:

      To play an Animation backwards from the end:
      animation.setRate(negative rate);
      animation.jumpTo(overall duration of animation);
      animation.play();

      But this does not play the same animation from the end.

      Consider an animation that translates a node from 0 to 10:
      Playing will translate the node from 0 to 10. Then doing the above will translate the node from 20 to 10, and not from 10 to 0.

      Additionally, pausing the animation, setting rate = -1 and playing causes the animation to jump to the end.

      [1] https://docs.oracle.com/javase/10/docs/api/javafx/animation/Animation.html#play()

      --- Reproducer code ---


      import javafx.animation.Animation;
      import javafx.animation.Interpolator;
      import javafx.animation.PauseTransition;
      import javafx.animation.TranslateTransition;
      import javafx.application.Application;
      import javafx.geometry.Insets;
      import javafx.geometry.Orientation;
      import javafx.scene.Node;
      import javafx.scene.Scene;
      import javafx.scene.control.Button;
      import javafx.scene.control.Label;
      import javafx.scene.control.Separator;
      import javafx.scene.layout.HBox;
      import javafx.scene.layout.Pane;
      import javafx.scene.layout.VBox;
      import javafx.scene.paint.Color;
      import javafx.scene.shape.Circle;
      import javafx.stage.Stage;
      import javafx.util.Duration;

      public class AnimTest extends Application {

          @Override
          public void start(Stage stage) throws Exception {
              var circle = new Circle(5, Color.BLUE);
              var translateBy = new TranslateTransition(Duration.seconds(2), circle);
              translateBy.setInterpolator(Interpolator.LINEAR);
              translateBy.setFromX(0);
              translateBy.setFromY(0);
              translateBy.setByX(100);
              translateBy.setByY(100);
              VBox byPane = setup(translateBy, circle);
              byPane.getChildren().add(0, new Label("By"));

              var circle2 = new Circle(5, Color.BLUE);
              var translateTo = new TranslateTransition(Duration.seconds(2), circle2);
              translateTo.setInterpolator(Interpolator.LINEAR);
              translateTo.setFromX(0);
              translateTo.setFromY(0);
              translateTo.setToX(100);
              translateTo.setToY(100);
      // translateTo.setAutoReverse(true);
      // translateTo.setCycleCount(4);
              VBox toPane = setup(translateTo, circle2);
              toPane.getChildren().add(0, new Label("To"));
      // translateTo.statusProperty().addListener((obs, ov, nv) -> System.out.println("status: " + ov + " -> " + nv));
              translateTo.getCuePoints().put("A", null);

              var root = new HBox(10, byPane, new Separator(Orientation.VERTICAL), toPane);
              root.setPadding(new Insets(10));
              stage.setScene(new Scene(root));
              stage.show();
          }

          private VBox setup(Animation translate, Node node) {
              var play = new Button("Play");
              play.setOnAction(e -> translate.play());

              var pause = new Button("Pause");
              pause.setOnAction(e -> translate.pause());

              var stop = new Button("Stop");
              stop.setOnAction(e -> translate.stop());

              var pauseTransition = new PauseTransition(Duration.millis(1));
              pauseTransition.setOnFinished(e -> translate.pause());
              var playPause = new Button("Play and pause");
              playPause.setOnAction(e -> {
                  translate.play();
                  pauseTransition.play();
              });

              var jumpToStart = new Button("Jump to start");
              jumpToStart.setOnAction(e -> translate.jumpTo("start"));

              var jumpToEnd = new Button("Jump to end");
              jumpToEnd.setOnAction(e -> translate.jumpTo("end"));

              var rateP1 = new Button("rate=0.2");
              rateP1.setOnAction(e -> translate.setRate(0.2));

              var rateM1 = new Button("rate=-0.2");
              rateM1.setOnAction(e -> translate.setRate(-0.2));
              
              var rate0 = new Button("rate=0");
              rate0.setOnAction(e -> translate.setRate(0));

              var jump500 = new Button("jump to 500");
              jump500.setOnAction(e -> translate.jumpTo(Duration.millis(500)));

              var pane = new Pane(node);
              pane.setPrefSize(400, 300);

              var curTime = new Label();
              curTime.textProperty().bind(translate.currentTimeProperty().asString());

              var rate = new Label();
              rate.textProperty().bind(translate.rateProperty().asString());
              
              var curRate = new Label();
              curRate.textProperty().bind(translate.currentRateProperty().asString());

              var curState = new Label();
              curState.textProperty().bind(translate.statusProperty().asString());

              var controls = new VBox(5,
                      new HBox(5, play, pause, stop, playPause, curState),
                      new HBox(5, jumpToStart, jumpToEnd, jump500, curTime),
                      new HBox(5, rateP1, rateM1, rate0, rate, curRate));
              var root = new VBox(10, pane, controls);
              return root;
          }

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

            nlisker Nir Lisker
            nlisker Nir Lisker
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: