Reputation: 740
I am trying to get around 8-12 circles rotate in a circle behind each other.
Here is the code I am trying
import javafx.animation.PathTransition;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Cirlces extends Application {
@Override
public void start(final Stage stage) throws Exception {
final Group group = new Group();
final Scene scene = new Scene(group, 500, 500, Color.WHITE);
stage.setScene(scene);
stage.setTitle("Circles");
stage.show();
final Circle circle = new Circle(20, 20, 15);
circle.setFill(Color.DARKRED);
Circle path = new Circle(250,250,200);
path.setFill(Color.WHITE);
group.getChildren().add(path);
group.getChildren().add(circle);
final PathTransition pathTransition = new PathTransition();
pathTransition.setDuration(Duration.seconds(2.0));
pathTransition.setDelay(Duration.ZERO);
pathTransition.setPath(path);
pathTransition.setNode(circle);
pathTransition
.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT);
pathTransition.setCycleCount(Timeline.INDEFINITE);
//pathTransition.setAutoReverse(true);
pathTransition.play();
}
public static void main(final String[] arguments) {
Application.launch(arguments);
}
}
On compiling and executing this code, I get a circle which goes on a circular path. But after each rotation, there is a slight delay before the next rotation starts, even though I have set the delay to zero.
So using this code, when I create multiple circles on the path (I take a different path for each circle, so it looks like they are on the same path and start each individual from a later time phase using playFrom()
to synchronize their position), it gets really messy.
What I want is, multiple circles moving on a circular path uniformly, but that slight delay makes it look very bad.
So my questions are
What can I do to remove that delay? Would constructing the path in a different way help? Is there any way to remove that delay?
The rotation of the circle starts from 3'o clock position on the path, is there any way to change the initial position of the node on the path?
Can I add multiple nodes to the same path? Say 5 circle nodes to the path, with different initial positions.
Upvotes: 1
Views: 2170
Reputation: 159416
You can use multiple path transitions (one per node), with the starting time of each transition offset by the distance along the path that you want a node to start at (using jumpTo
).
This is a (simplified) variation on the solution to: "How to write text along a Bezier Curve?". The solution will work for nodes traveling along an arbitrary path, not just nodes traveling in a circle.
import javafx.animation.*;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
import javafx.util.Duration;
public class CirclePathTransitions extends Application {
private static final int NUM_NODES = 5;
private static final double W = 200;
private static final double H = 200;
private static final double NODE_SIZE = H / 8.0;
@Override
public void start(final Stage stage) throws Exception {
Pane content = new Pane();
content.setMinSize(Pane.USE_PREF_SIZE, Pane.USE_PREF_SIZE);
content.setPrefSize(W, H);
content.setMaxSize(Pane.USE_PREF_SIZE, Pane.USE_PREF_SIZE);
content.setStyle("-fx-background-color: coral;");
Shape path = new Circle(W/2, H/2, H * 3 / 8.0 - NODE_SIZE);
content.getChildren().add(new Circle(W/2, H/2, H * 3 / 8.0 - NODE_SIZE, Color.PALEGREEN));
for (int i = 0; i < NUM_NODES; i++) {
Node node = new Circle(NODE_SIZE / 2, Color.MIDNIGHTBLUE);
content.getChildren().add(node);
final Transition transition = createPathTransition(path, node);
transition.jumpTo(Duration.seconds(10).multiply(i * 1.0 / NUM_NODES));
transition.play();
}
stage.setScene(new Scene(new StackPane(content), W, H, Color.ALICEBLUE));
stage.show();
}
private PathTransition createPathTransition(Shape shape, Node node) {
final PathTransition transition = new PathTransition(
Duration.seconds(10),
shape,
node
);
transition.setAutoReverse(false);
transition.setCycleCount(PathTransition.INDEFINITE);
transition.setInterpolator(Interpolator.LINEAR);
return transition;
}
public static void main(String[] args) throws Exception {
launch(args);
}
}
Upvotes: 3
Reputation: 209418
pathTransition.setInterpolator(Interpolator.LINEAR);
path.setRotate(-90);
PathTransition
. You can achieve a similar effect using a Timeline
and binding a rotation for each circle to a property you "animate" with the timeline:-
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;
public class CircleTransitions extends Application {
@Override
public void start(final Stage stage) throws Exception {
final Group group = new Group();
final Scene scene = new Scene(group, 500, 500, Color.WHITE);
stage.setScene(scene);
stage.setTitle("Circles");
stage.show();
Circle path = new Circle(250,250,200);
path.setFill(Color.WHITE);
DoubleProperty angle = new SimpleDoubleProperty();
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(2), new KeyValue(angle, 360)));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
group.getChildren().add(path);
for (int i=0; i<5; i++) {
Circle circle = new Circle(250, 450, 15);
circle.setFill(Color.DARKRED);
Rotate rotate = new Rotate(0, 250, 250);
circle.getTransforms().add(rotate);
rotate.angleProperty().bind(angle.add(360.0 * i / 5));
group.getChildren().add(circle);
}
}
public static void main(final String[] arguments) {
Application.launch(arguments);
}
}
Upvotes: 4