user7554125
user7554125

Reputation:

how to animate arcs in Javafx

I'm working on a simple app and it features a pie chart. My goal is that if a user hovers their mouse over any section of the chart, it will expand and present more information. In my program, the chart is made of 3 arcs. Here's my code.

 import javafx.scene.Group; //Maybe too many imports, I just use em all
 import javafx.scene.Scene; //because I'm lazy
 import javafx.stage.Stage;
 import javafx.util.Duration;
 import javafx.scene.paint.Color; 
 import javafx.scene.shape.Arc; 
 import javafx.scene.shape.Rectangle;
 import javafx.event.EventHandler;
 import javafx.event.ActionEvent;
 import javafx.event.Event;
 import javafx.application.Application; 
 import javafx.scene.shape.*;
 import javafx.scene.shape.Line;
 import javafx.scene.text.Text;
 import javafx.scene.text.Font;
 import javafx.scene.text.FontWeight;
 import javafx.scene.input.MouseEvent;
 import javafx.animation.ScaleTransition;
 import java.lang.Thread;

public class AnimatingDemo extends Application{
    public static void main(String[] args) {
        launch(args);
    }
    @Override
    public void start(Stage stage) {
      //create 3 arc variables
      Arc arc1 = new Arc();
      Arc arc2 = new Arc();
      Arc arc3 = new Arc();
          //set up arc1 in place and to right color
      arc1.setFill(Color.rgb(35,25,43,1.0));
      arc1.setCenterX(250);
      arc1.setCenterY(250);
      arc1.setRadiusX(100.0f);
      arc1.setRadiusY(100.0f);
      arc1.setStartAngle(315);
      arc1.setLength(-90);
      arc1.setType(ArcType.ROUND);
      //set up and color arc2
      arc2.setFill(Color.rgb(39,70,144,1.0));
      arc2.setCenterX(250);
      arc2.setCenterY(250);
      arc2.setRadiusX(100.0f);
      arc2.setRadiusY(100.0f);
      arc2.setStartAngle(90);
      arc2.setLength(-135);
      arc2.setType(ArcType.ROUND);
      //set up and color arc3
      arc3.setFill(Color.rgb(54,65,86,1.0));
      arc3.setCenterX(250);
      arc3.setCenterY(250);
      arc3.setRadiusX(100.0f);
      arc3.setRadiusY(100.0f);
      arc3.setStartAngle(225);
      arc3.setLength(-135);
      arc3.setType(ArcType.ROUND);

      //create root group
      Group root = new Group();
      //set up window
      //add nodes to root
      root.getChildren().addAll(arc1,arc2,arc3);
      Scene scene = new Scene(root, 500,500);
      stage.setTitle("Testing arc animation");
      stage.setScene(scene);
      stage.show();
    }
}

This is just a sample I made so I can recreate the problem, but it gets the point across. I did research about various methods of animation in Javafx. The animation class seemed most viable, so I tried it in my program. I used the following code:

  arc1.addEventFilter(MouseEvent.MOUSE_PRESSED, new   EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent mouseEvent) {
            ScaleTransition st = new ScaleTransition(Duration.millis(1500),arc1);
            st.setByX(0.3);
            st.setByY(0.3);
            st.setCycleCount(1);
            st.setAutoReverse(false);
            st.play();

        }
  });

I repeated it 3 times for each arc but that's redundant here.

Anyway, the result is that both ends of the arc scale, so the pi chart looks messy and isn't centered anymore, also the scaling increases depending on the size of the arc so it's inconsistent.

I then decided to move onto a more basic method, using thread.sleep().

  arc1.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent mouseEvent) {
            for(int a = 0; a < 10; a++) {
                try {
                    arc1.setRadiusX(arc1.getRadiusX() + 1);
                    arc1.setRadiusY(arc1.getRadiusY() + 1);
                    Thread.sleep(100);
                }
                catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
  });

this doesn't work either, the circle just instantly expands by the given amount of units I wanted (instantly).

So my question is, what can I do? Is there a method to prevent the skewing in the animation class? Can I make the thread.sleep animation fluent in some way? Any advice helps, thank you for your time!

P.S. If it needs more comments let me know

Upvotes: 1

Views: 1040

Answers (1)

Hypnic Jerk
Hypnic Jerk

Reputation: 1192

I'm not sure this is exactly what you are looking for, since you went with Arc's instead of a proper PieChart, but I used the PieChart class and did everything you did and it works out just fine.

Here I took the PieChart.Data class and made three separate ones just for testing.

I added an EventFilter by calling .getNode() on the PieChart.Data variable, and then just pasted your method you supplied above.

Again, I assume there was a reason you used Arc instead of PieChart, but I got it to work this way.

@Override
    public void start(Stage stage) {
        ObservableList<PieChart.Data> data = FXCollections.observableArrayList();
        PieChart pieChart = new PieChart(data);
        PieChart.Data one = new PieChart.Data("one", 50.0);
        PieChart.Data two = new PieChart.Data("two", 33.0);
        PieChart.Data three = new PieChart.Data("three", 17.0);
        data.addAll(one, two, three);
        one.getNode().addEventFilter(MouseEvent.MOUSE_PRESSED, mouseEvent -> {
            ScaleTransition st = new ScaleTransition(Duration.millis(1500),one.getNode());
            st.setByX(0.3);
            st.setByY(0.3);
            st.setCycleCount(1);
            st.setAutoReverse(false);
            st.play();

        });
        two.getNode().addEventFilter(MouseEvent.MOUSE_PRESSED, mouseEvent -> {
            ScaleTransition st = new ScaleTransition(Duration.millis(1500),two.getNode());
            st.setByX(0.3);
            st.setByY(0.3);
            st.setCycleCount(1);
            st.setAutoReverse(false);
            st.play();

        });
        three.getNode().addEventFilter(MouseEvent.MOUSE_PRESSED, mouseEvent -> {
            ScaleTransition st = new ScaleTransition(Duration.millis(1500),three.getNode());
            st.setByX(0.3);
            st.setByY(0.3);
            st.setCycleCount(1);
            st.setAutoReverse(false);
            st.play();

        });

        //create root group
        Group root = new Group();
        //set up window
        //add nodes to root
        root.getChildren().addAll(pieChart);
        Scene scene = new Scene(root, 500,500);
        stage.setTitle("Testing arc animation");
        stage.setScene(scene);
        stage.show();
    }

Upvotes: 1

Related Questions