JavaFx animating a path with a shape
I am working on a project with a feature of animating a path with a line. So when I press a button, a line goes through all the circles in the canvas. But I see that there is a slight difference in my path and the strokeline. It doesnt go through the circles. Please kindly advice thank you.
This is my code:
import java.util.ArrayList;
import java.util.Random;
import javafx.animation.Animation;
import javafx.animation.PathTransition;
import javafx.animation.PathTransition.OrientationType;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class PathVisualization extends Application {
private static double SCENE_WIDTH = 1000;
private static double SCENE_HEIGHT = 500;
private Canvas canvas;
private GraphicsContext gc;
private Button clear;
private Animation animation;
private ArrayList<Circle> num;
@Override
public void start(Stage primaryStage) throws Exception {
BorderPane bp = new BorderPane();
Pane root = new Pane();
root.setMaxSize(800,500);
// path = new Path();
canvas = new Canvas(SCENE_WIDTH,SCENE_HEIGHT);
TextField no = new TextField();
Button add = new Button("Add Circle");
Button playAnimation = new Button("Play");
clear = new Button("Clear");
Button pause = new Button("Pause");
VBox control = new VBox();
control.getChildren().add(no);
control.getChildren().add(add);
control.getChildren().add(playAnimation);
control.getChildren().add(clear);
control.getChildren().add(pause);
root.getChildren().add(canvas);
bp.setCenter(root);
bp.setLeft(control);
num = new ArrayList<Circle>();
clear.setOnMouseClicked(event->{
num.clear();
gc.clearRect(0, 0, gc.getCanvas().getWidth(), gc.getCanvas().getHeight());
root.getChildren().clear();
root.getChildren().add(canvas);
});
add.setOnMouseClicked(event->{
int cirNum = Integer.parseInt(no.getText());
Random rand = new Random();
for (int j=0;j<cirNum;j++) {
int x = rand.nextInt((int)root.getMaxWidth()-1);
int y = rand.nextInt((int)root.getMaxHeight()-1);
Circle circle = new Circle(x,y,10);
num.add(circle);
root.getChildren().add(circle);
}
//Heuristic Change
Path path = new Path();
path.setStroke(Color.RED);
path.getElements().add(new MoveTo(num.get(0).getCenterX(),num.get(0).getCenterY()));
path.setStrokeWidth(1);
for (int i=0;i<num.size();i++) {
try {
path.getElements().addAll(new LineTo(num.get(i).getCenterX(),num.get(i).getCenterY()));
}catch(IndexOutOfBoundsException e) {
path.getElements().addAll(new LineTo(num.get(0).getCenterX(),num.get(0).getCenterY()));
}
}
root.getChildren().addAll(path);
//create animation
animation = createPathAnimation(path, Duration.seconds(num.size()/4));
});
playAnimation.setOnMouseClicked(e ->{
animation.play();
});
pause.setOnMouseClicked(e->{
animation.pause();
});
primaryStage.setScene(new Scene(bp, SCENE_WIDTH, SCENE_HEIGHT));
primaryStage.show();
}
private Animation createPathAnimation(Path path, Duration duration) {
gc = canvas.getGraphicsContext2D();
// move a node along a path. we want its position
Circle pen = new Circle(0,0,0);
// create path transition
PathTransition pathTransition = new PathTransition(duration, path, pen);
pathTransition.currentTimeProperty().addListener( new ChangeListener<Duration>() {
Location oldLocation = null;
/**
* Draw a line from the old location to the new location
*/
@Override
public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
// skip starting at 0/0
if( oldValue == Duration.ZERO)
return;
// get current location
double x = pen.getTranslateX();
double y = pen.getTranslateY();
// initialize the location
if( oldLocation == null) {
oldLocation = new Location();
oldLocation.x = x;
oldLocation.y = y;
return;
}
// draw line
gc.setStroke(Color.GREENYELLOW);
gc.setLineWidth(5);
gc.strokeLine(oldLocation.x, oldLocation.y, x, y);
// update old location with current one
oldLocation.x = x;
oldLocation.y = y;
}
});
pathTransition.setOrientation(OrientationType.ORTHOGONAL_TO_TANGENT);
return pathTransition;
}
public static class Location {
double x;
double y;
}
public static void main(String args) {
launch(args);
}
}
This is the issue. At certain corners, the strokeline does not go through the circle and makes a weird cut.
enter image description here
javafx path graphicscontext
add a comment |
I am working on a project with a feature of animating a path with a line. So when I press a button, a line goes through all the circles in the canvas. But I see that there is a slight difference in my path and the strokeline. It doesnt go through the circles. Please kindly advice thank you.
This is my code:
import java.util.ArrayList;
import java.util.Random;
import javafx.animation.Animation;
import javafx.animation.PathTransition;
import javafx.animation.PathTransition.OrientationType;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class PathVisualization extends Application {
private static double SCENE_WIDTH = 1000;
private static double SCENE_HEIGHT = 500;
private Canvas canvas;
private GraphicsContext gc;
private Button clear;
private Animation animation;
private ArrayList<Circle> num;
@Override
public void start(Stage primaryStage) throws Exception {
BorderPane bp = new BorderPane();
Pane root = new Pane();
root.setMaxSize(800,500);
// path = new Path();
canvas = new Canvas(SCENE_WIDTH,SCENE_HEIGHT);
TextField no = new TextField();
Button add = new Button("Add Circle");
Button playAnimation = new Button("Play");
clear = new Button("Clear");
Button pause = new Button("Pause");
VBox control = new VBox();
control.getChildren().add(no);
control.getChildren().add(add);
control.getChildren().add(playAnimation);
control.getChildren().add(clear);
control.getChildren().add(pause);
root.getChildren().add(canvas);
bp.setCenter(root);
bp.setLeft(control);
num = new ArrayList<Circle>();
clear.setOnMouseClicked(event->{
num.clear();
gc.clearRect(0, 0, gc.getCanvas().getWidth(), gc.getCanvas().getHeight());
root.getChildren().clear();
root.getChildren().add(canvas);
});
add.setOnMouseClicked(event->{
int cirNum = Integer.parseInt(no.getText());
Random rand = new Random();
for (int j=0;j<cirNum;j++) {
int x = rand.nextInt((int)root.getMaxWidth()-1);
int y = rand.nextInt((int)root.getMaxHeight()-1);
Circle circle = new Circle(x,y,10);
num.add(circle);
root.getChildren().add(circle);
}
//Heuristic Change
Path path = new Path();
path.setStroke(Color.RED);
path.getElements().add(new MoveTo(num.get(0).getCenterX(),num.get(0).getCenterY()));
path.setStrokeWidth(1);
for (int i=0;i<num.size();i++) {
try {
path.getElements().addAll(new LineTo(num.get(i).getCenterX(),num.get(i).getCenterY()));
}catch(IndexOutOfBoundsException e) {
path.getElements().addAll(new LineTo(num.get(0).getCenterX(),num.get(0).getCenterY()));
}
}
root.getChildren().addAll(path);
//create animation
animation = createPathAnimation(path, Duration.seconds(num.size()/4));
});
playAnimation.setOnMouseClicked(e ->{
animation.play();
});
pause.setOnMouseClicked(e->{
animation.pause();
});
primaryStage.setScene(new Scene(bp, SCENE_WIDTH, SCENE_HEIGHT));
primaryStage.show();
}
private Animation createPathAnimation(Path path, Duration duration) {
gc = canvas.getGraphicsContext2D();
// move a node along a path. we want its position
Circle pen = new Circle(0,0,0);
// create path transition
PathTransition pathTransition = new PathTransition(duration, path, pen);
pathTransition.currentTimeProperty().addListener( new ChangeListener<Duration>() {
Location oldLocation = null;
/**
* Draw a line from the old location to the new location
*/
@Override
public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
// skip starting at 0/0
if( oldValue == Duration.ZERO)
return;
// get current location
double x = pen.getTranslateX();
double y = pen.getTranslateY();
// initialize the location
if( oldLocation == null) {
oldLocation = new Location();
oldLocation.x = x;
oldLocation.y = y;
return;
}
// draw line
gc.setStroke(Color.GREENYELLOW);
gc.setLineWidth(5);
gc.strokeLine(oldLocation.x, oldLocation.y, x, y);
// update old location with current one
oldLocation.x = x;
oldLocation.y = y;
}
});
pathTransition.setOrientation(OrientationType.ORTHOGONAL_TO_TANGENT);
return pathTransition;
}
public static class Location {
double x;
double y;
}
public static void main(String args) {
launch(args);
}
}
This is the issue. At certain corners, the strokeline does not go through the circle and makes a weird cut.
enter image description here
javafx path graphicscontext
Unable to reproduce. Does it happen consistently or frequently on your side?
– Jai
Nov 21 at 6:41
not consistently, but happens often to notice it. It is too obvious on a big screen.
– Selva
Nov 21 at 13:39
add a comment |
I am working on a project with a feature of animating a path with a line. So when I press a button, a line goes through all the circles in the canvas. But I see that there is a slight difference in my path and the strokeline. It doesnt go through the circles. Please kindly advice thank you.
This is my code:
import java.util.ArrayList;
import java.util.Random;
import javafx.animation.Animation;
import javafx.animation.PathTransition;
import javafx.animation.PathTransition.OrientationType;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class PathVisualization extends Application {
private static double SCENE_WIDTH = 1000;
private static double SCENE_HEIGHT = 500;
private Canvas canvas;
private GraphicsContext gc;
private Button clear;
private Animation animation;
private ArrayList<Circle> num;
@Override
public void start(Stage primaryStage) throws Exception {
BorderPane bp = new BorderPane();
Pane root = new Pane();
root.setMaxSize(800,500);
// path = new Path();
canvas = new Canvas(SCENE_WIDTH,SCENE_HEIGHT);
TextField no = new TextField();
Button add = new Button("Add Circle");
Button playAnimation = new Button("Play");
clear = new Button("Clear");
Button pause = new Button("Pause");
VBox control = new VBox();
control.getChildren().add(no);
control.getChildren().add(add);
control.getChildren().add(playAnimation);
control.getChildren().add(clear);
control.getChildren().add(pause);
root.getChildren().add(canvas);
bp.setCenter(root);
bp.setLeft(control);
num = new ArrayList<Circle>();
clear.setOnMouseClicked(event->{
num.clear();
gc.clearRect(0, 0, gc.getCanvas().getWidth(), gc.getCanvas().getHeight());
root.getChildren().clear();
root.getChildren().add(canvas);
});
add.setOnMouseClicked(event->{
int cirNum = Integer.parseInt(no.getText());
Random rand = new Random();
for (int j=0;j<cirNum;j++) {
int x = rand.nextInt((int)root.getMaxWidth()-1);
int y = rand.nextInt((int)root.getMaxHeight()-1);
Circle circle = new Circle(x,y,10);
num.add(circle);
root.getChildren().add(circle);
}
//Heuristic Change
Path path = new Path();
path.setStroke(Color.RED);
path.getElements().add(new MoveTo(num.get(0).getCenterX(),num.get(0).getCenterY()));
path.setStrokeWidth(1);
for (int i=0;i<num.size();i++) {
try {
path.getElements().addAll(new LineTo(num.get(i).getCenterX(),num.get(i).getCenterY()));
}catch(IndexOutOfBoundsException e) {
path.getElements().addAll(new LineTo(num.get(0).getCenterX(),num.get(0).getCenterY()));
}
}
root.getChildren().addAll(path);
//create animation
animation = createPathAnimation(path, Duration.seconds(num.size()/4));
});
playAnimation.setOnMouseClicked(e ->{
animation.play();
});
pause.setOnMouseClicked(e->{
animation.pause();
});
primaryStage.setScene(new Scene(bp, SCENE_WIDTH, SCENE_HEIGHT));
primaryStage.show();
}
private Animation createPathAnimation(Path path, Duration duration) {
gc = canvas.getGraphicsContext2D();
// move a node along a path. we want its position
Circle pen = new Circle(0,0,0);
// create path transition
PathTransition pathTransition = new PathTransition(duration, path, pen);
pathTransition.currentTimeProperty().addListener( new ChangeListener<Duration>() {
Location oldLocation = null;
/**
* Draw a line from the old location to the new location
*/
@Override
public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
// skip starting at 0/0
if( oldValue == Duration.ZERO)
return;
// get current location
double x = pen.getTranslateX();
double y = pen.getTranslateY();
// initialize the location
if( oldLocation == null) {
oldLocation = new Location();
oldLocation.x = x;
oldLocation.y = y;
return;
}
// draw line
gc.setStroke(Color.GREENYELLOW);
gc.setLineWidth(5);
gc.strokeLine(oldLocation.x, oldLocation.y, x, y);
// update old location with current one
oldLocation.x = x;
oldLocation.y = y;
}
});
pathTransition.setOrientation(OrientationType.ORTHOGONAL_TO_TANGENT);
return pathTransition;
}
public static class Location {
double x;
double y;
}
public static void main(String args) {
launch(args);
}
}
This is the issue. At certain corners, the strokeline does not go through the circle and makes a weird cut.
enter image description here
javafx path graphicscontext
I am working on a project with a feature of animating a path with a line. So when I press a button, a line goes through all the circles in the canvas. But I see that there is a slight difference in my path and the strokeline. It doesnt go through the circles. Please kindly advice thank you.
This is my code:
import java.util.ArrayList;
import java.util.Random;
import javafx.animation.Animation;
import javafx.animation.PathTransition;
import javafx.animation.PathTransition.OrientationType;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class PathVisualization extends Application {
private static double SCENE_WIDTH = 1000;
private static double SCENE_HEIGHT = 500;
private Canvas canvas;
private GraphicsContext gc;
private Button clear;
private Animation animation;
private ArrayList<Circle> num;
@Override
public void start(Stage primaryStage) throws Exception {
BorderPane bp = new BorderPane();
Pane root = new Pane();
root.setMaxSize(800,500);
// path = new Path();
canvas = new Canvas(SCENE_WIDTH,SCENE_HEIGHT);
TextField no = new TextField();
Button add = new Button("Add Circle");
Button playAnimation = new Button("Play");
clear = new Button("Clear");
Button pause = new Button("Pause");
VBox control = new VBox();
control.getChildren().add(no);
control.getChildren().add(add);
control.getChildren().add(playAnimation);
control.getChildren().add(clear);
control.getChildren().add(pause);
root.getChildren().add(canvas);
bp.setCenter(root);
bp.setLeft(control);
num = new ArrayList<Circle>();
clear.setOnMouseClicked(event->{
num.clear();
gc.clearRect(0, 0, gc.getCanvas().getWidth(), gc.getCanvas().getHeight());
root.getChildren().clear();
root.getChildren().add(canvas);
});
add.setOnMouseClicked(event->{
int cirNum = Integer.parseInt(no.getText());
Random rand = new Random();
for (int j=0;j<cirNum;j++) {
int x = rand.nextInt((int)root.getMaxWidth()-1);
int y = rand.nextInt((int)root.getMaxHeight()-1);
Circle circle = new Circle(x,y,10);
num.add(circle);
root.getChildren().add(circle);
}
//Heuristic Change
Path path = new Path();
path.setStroke(Color.RED);
path.getElements().add(new MoveTo(num.get(0).getCenterX(),num.get(0).getCenterY()));
path.setStrokeWidth(1);
for (int i=0;i<num.size();i++) {
try {
path.getElements().addAll(new LineTo(num.get(i).getCenterX(),num.get(i).getCenterY()));
}catch(IndexOutOfBoundsException e) {
path.getElements().addAll(new LineTo(num.get(0).getCenterX(),num.get(0).getCenterY()));
}
}
root.getChildren().addAll(path);
//create animation
animation = createPathAnimation(path, Duration.seconds(num.size()/4));
});
playAnimation.setOnMouseClicked(e ->{
animation.play();
});
pause.setOnMouseClicked(e->{
animation.pause();
});
primaryStage.setScene(new Scene(bp, SCENE_WIDTH, SCENE_HEIGHT));
primaryStage.show();
}
private Animation createPathAnimation(Path path, Duration duration) {
gc = canvas.getGraphicsContext2D();
// move a node along a path. we want its position
Circle pen = new Circle(0,0,0);
// create path transition
PathTransition pathTransition = new PathTransition(duration, path, pen);
pathTransition.currentTimeProperty().addListener( new ChangeListener<Duration>() {
Location oldLocation = null;
/**
* Draw a line from the old location to the new location
*/
@Override
public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
// skip starting at 0/0
if( oldValue == Duration.ZERO)
return;
// get current location
double x = pen.getTranslateX();
double y = pen.getTranslateY();
// initialize the location
if( oldLocation == null) {
oldLocation = new Location();
oldLocation.x = x;
oldLocation.y = y;
return;
}
// draw line
gc.setStroke(Color.GREENYELLOW);
gc.setLineWidth(5);
gc.strokeLine(oldLocation.x, oldLocation.y, x, y);
// update old location with current one
oldLocation.x = x;
oldLocation.y = y;
}
});
pathTransition.setOrientation(OrientationType.ORTHOGONAL_TO_TANGENT);
return pathTransition;
}
public static class Location {
double x;
double y;
}
public static void main(String args) {
launch(args);
}
}
This is the issue. At certain corners, the strokeline does not go through the circle and makes a weird cut.
enter image description here
javafx path graphicscontext
javafx path graphicscontext
asked Nov 20 at 20:05
Selva
61
61
Unable to reproduce. Does it happen consistently or frequently on your side?
– Jai
Nov 21 at 6:41
not consistently, but happens often to notice it. It is too obvious on a big screen.
– Selva
Nov 21 at 13:39
add a comment |
Unable to reproduce. Does it happen consistently or frequently on your side?
– Jai
Nov 21 at 6:41
not consistently, but happens often to notice it. It is too obvious on a big screen.
– Selva
Nov 21 at 13:39
Unable to reproduce. Does it happen consistently or frequently on your side?
– Jai
Nov 21 at 6:41
Unable to reproduce. Does it happen consistently or frequently on your side?
– Jai
Nov 21 at 6:41
not consistently, but happens often to notice it. It is too obvious on a big screen.
– Selva
Nov 21 at 13:39
not consistently, but happens often to notice it. It is too obvious on a big screen.
– Selva
Nov 21 at 13:39
add a comment |
1 Answer
1
active
oldest
votes
I couldn't reproduce it originally, but after more tries I managed to reproduce it. It looks like this is due to latency.
As far as I know (I'm not an expert in animations), animations (including PathTransition
) use a timer internally, and each tick is generally equivalent to JavaFX scene graph pulse duration. This means that animations are updated at 60 times per second maximum. When a pulse happens, the PathTransition
calculates the new translate values based on the elapsed time on the timer. So what happens here is that the calculated translate values are quite far apart between two particular pulses. In general, the more things you try to do on the JavaFX Application Thread, the more likely this would happen.
If you are trying to draw a tracing line based on the animation, there is no way you could avoid this latency. However, you could avoid the problem of the drawn path cutting corners, by breaking it up into multiple animations. Each animation would move in a straight line, and each of your tracing line is guaranteed to start from the start and end at the ending point.
I tried this and it works:
// Heuristic Change
// Path path = new Path();
// path.setStroke(Color.RED);
// path.getElements().add(new MoveTo(num.get(0).getCenterX(), num.get(0).getCenterY()));
// path.setStrokeWidth(1);
// for (int i = 0; i < num.size(); i++) {
// try {
// path.getElements().addAll(new LineTo(num.get(i).getCenterX(), num.get(i).getCenterY()));
// }
// catch (IndexOutOfBoundsException e) {
// path.getElements().addAll(new LineTo(num.get(0).getCenterX(), num.get(0).getCenterY()));
// }
// }
List<Path> paths = new ArrayList<>();
for (int i = 0; i < num.size() - 1; i++) {
Circle current = num.get(i);
Circle next = num.get(i + 1);
Path path = new Path();
path.setStroke(Color.RED);
path.getElements().addAll(new MoveTo(current.getCenterX(), current.getCenterY()),
new LineTo(next.getCenterX(), next.getCenterY()));
path.setStrokeWidth(1);
paths.add(path);
}
// root.getChildren().addAll(path);
root.getChildren().addAll(paths);
Circle pen = new Circle();
// create animation
// animation = createPathAnimation(path, Duration.seconds(num.size()/4));
animation = createPathAnimation(paths, Duration.millis(200), pen);
And...
private Animation createPathAnimation(List<Path> paths, Duration duration, Circle pen) {
SequentialTransition seq = new SequentialTransition();
// ...
for (Path path : paths) {
// The same PathTransition stuff you had
seq.getChildren().add(pathTransition);
}
return seq;
}
The only thing that changed is that the speed changes at each segment of the full path. If you want to keep that constant, you have to apply Pythagoras' theorem to find the distance, and adjust the duration accordingly.
Thanks, will give it a go and update asap!
– Selva
Nov 21 at 13:38
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53400733%2fjavafx-animating-a-path-with-a-shape%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
I couldn't reproduce it originally, but after more tries I managed to reproduce it. It looks like this is due to latency.
As far as I know (I'm not an expert in animations), animations (including PathTransition
) use a timer internally, and each tick is generally equivalent to JavaFX scene graph pulse duration. This means that animations are updated at 60 times per second maximum. When a pulse happens, the PathTransition
calculates the new translate values based on the elapsed time on the timer. So what happens here is that the calculated translate values are quite far apart between two particular pulses. In general, the more things you try to do on the JavaFX Application Thread, the more likely this would happen.
If you are trying to draw a tracing line based on the animation, there is no way you could avoid this latency. However, you could avoid the problem of the drawn path cutting corners, by breaking it up into multiple animations. Each animation would move in a straight line, and each of your tracing line is guaranteed to start from the start and end at the ending point.
I tried this and it works:
// Heuristic Change
// Path path = new Path();
// path.setStroke(Color.RED);
// path.getElements().add(new MoveTo(num.get(0).getCenterX(), num.get(0).getCenterY()));
// path.setStrokeWidth(1);
// for (int i = 0; i < num.size(); i++) {
// try {
// path.getElements().addAll(new LineTo(num.get(i).getCenterX(), num.get(i).getCenterY()));
// }
// catch (IndexOutOfBoundsException e) {
// path.getElements().addAll(new LineTo(num.get(0).getCenterX(), num.get(0).getCenterY()));
// }
// }
List<Path> paths = new ArrayList<>();
for (int i = 0; i < num.size() - 1; i++) {
Circle current = num.get(i);
Circle next = num.get(i + 1);
Path path = new Path();
path.setStroke(Color.RED);
path.getElements().addAll(new MoveTo(current.getCenterX(), current.getCenterY()),
new LineTo(next.getCenterX(), next.getCenterY()));
path.setStrokeWidth(1);
paths.add(path);
}
// root.getChildren().addAll(path);
root.getChildren().addAll(paths);
Circle pen = new Circle();
// create animation
// animation = createPathAnimation(path, Duration.seconds(num.size()/4));
animation = createPathAnimation(paths, Duration.millis(200), pen);
And...
private Animation createPathAnimation(List<Path> paths, Duration duration, Circle pen) {
SequentialTransition seq = new SequentialTransition();
// ...
for (Path path : paths) {
// The same PathTransition stuff you had
seq.getChildren().add(pathTransition);
}
return seq;
}
The only thing that changed is that the speed changes at each segment of the full path. If you want to keep that constant, you have to apply Pythagoras' theorem to find the distance, and adjust the duration accordingly.
Thanks, will give it a go and update asap!
– Selva
Nov 21 at 13:38
add a comment |
I couldn't reproduce it originally, but after more tries I managed to reproduce it. It looks like this is due to latency.
As far as I know (I'm not an expert in animations), animations (including PathTransition
) use a timer internally, and each tick is generally equivalent to JavaFX scene graph pulse duration. This means that animations are updated at 60 times per second maximum. When a pulse happens, the PathTransition
calculates the new translate values based on the elapsed time on the timer. So what happens here is that the calculated translate values are quite far apart between two particular pulses. In general, the more things you try to do on the JavaFX Application Thread, the more likely this would happen.
If you are trying to draw a tracing line based on the animation, there is no way you could avoid this latency. However, you could avoid the problem of the drawn path cutting corners, by breaking it up into multiple animations. Each animation would move in a straight line, and each of your tracing line is guaranteed to start from the start and end at the ending point.
I tried this and it works:
// Heuristic Change
// Path path = new Path();
// path.setStroke(Color.RED);
// path.getElements().add(new MoveTo(num.get(0).getCenterX(), num.get(0).getCenterY()));
// path.setStrokeWidth(1);
// for (int i = 0; i < num.size(); i++) {
// try {
// path.getElements().addAll(new LineTo(num.get(i).getCenterX(), num.get(i).getCenterY()));
// }
// catch (IndexOutOfBoundsException e) {
// path.getElements().addAll(new LineTo(num.get(0).getCenterX(), num.get(0).getCenterY()));
// }
// }
List<Path> paths = new ArrayList<>();
for (int i = 0; i < num.size() - 1; i++) {
Circle current = num.get(i);
Circle next = num.get(i + 1);
Path path = new Path();
path.setStroke(Color.RED);
path.getElements().addAll(new MoveTo(current.getCenterX(), current.getCenterY()),
new LineTo(next.getCenterX(), next.getCenterY()));
path.setStrokeWidth(1);
paths.add(path);
}
// root.getChildren().addAll(path);
root.getChildren().addAll(paths);
Circle pen = new Circle();
// create animation
// animation = createPathAnimation(path, Duration.seconds(num.size()/4));
animation = createPathAnimation(paths, Duration.millis(200), pen);
And...
private Animation createPathAnimation(List<Path> paths, Duration duration, Circle pen) {
SequentialTransition seq = new SequentialTransition();
// ...
for (Path path : paths) {
// The same PathTransition stuff you had
seq.getChildren().add(pathTransition);
}
return seq;
}
The only thing that changed is that the speed changes at each segment of the full path. If you want to keep that constant, you have to apply Pythagoras' theorem to find the distance, and adjust the duration accordingly.
Thanks, will give it a go and update asap!
– Selva
Nov 21 at 13:38
add a comment |
I couldn't reproduce it originally, but after more tries I managed to reproduce it. It looks like this is due to latency.
As far as I know (I'm not an expert in animations), animations (including PathTransition
) use a timer internally, and each tick is generally equivalent to JavaFX scene graph pulse duration. This means that animations are updated at 60 times per second maximum. When a pulse happens, the PathTransition
calculates the new translate values based on the elapsed time on the timer. So what happens here is that the calculated translate values are quite far apart between two particular pulses. In general, the more things you try to do on the JavaFX Application Thread, the more likely this would happen.
If you are trying to draw a tracing line based on the animation, there is no way you could avoid this latency. However, you could avoid the problem of the drawn path cutting corners, by breaking it up into multiple animations. Each animation would move in a straight line, and each of your tracing line is guaranteed to start from the start and end at the ending point.
I tried this and it works:
// Heuristic Change
// Path path = new Path();
// path.setStroke(Color.RED);
// path.getElements().add(new MoveTo(num.get(0).getCenterX(), num.get(0).getCenterY()));
// path.setStrokeWidth(1);
// for (int i = 0; i < num.size(); i++) {
// try {
// path.getElements().addAll(new LineTo(num.get(i).getCenterX(), num.get(i).getCenterY()));
// }
// catch (IndexOutOfBoundsException e) {
// path.getElements().addAll(new LineTo(num.get(0).getCenterX(), num.get(0).getCenterY()));
// }
// }
List<Path> paths = new ArrayList<>();
for (int i = 0; i < num.size() - 1; i++) {
Circle current = num.get(i);
Circle next = num.get(i + 1);
Path path = new Path();
path.setStroke(Color.RED);
path.getElements().addAll(new MoveTo(current.getCenterX(), current.getCenterY()),
new LineTo(next.getCenterX(), next.getCenterY()));
path.setStrokeWidth(1);
paths.add(path);
}
// root.getChildren().addAll(path);
root.getChildren().addAll(paths);
Circle pen = new Circle();
// create animation
// animation = createPathAnimation(path, Duration.seconds(num.size()/4));
animation = createPathAnimation(paths, Duration.millis(200), pen);
And...
private Animation createPathAnimation(List<Path> paths, Duration duration, Circle pen) {
SequentialTransition seq = new SequentialTransition();
// ...
for (Path path : paths) {
// The same PathTransition stuff you had
seq.getChildren().add(pathTransition);
}
return seq;
}
The only thing that changed is that the speed changes at each segment of the full path. If you want to keep that constant, you have to apply Pythagoras' theorem to find the distance, and adjust the duration accordingly.
I couldn't reproduce it originally, but after more tries I managed to reproduce it. It looks like this is due to latency.
As far as I know (I'm not an expert in animations), animations (including PathTransition
) use a timer internally, and each tick is generally equivalent to JavaFX scene graph pulse duration. This means that animations are updated at 60 times per second maximum. When a pulse happens, the PathTransition
calculates the new translate values based on the elapsed time on the timer. So what happens here is that the calculated translate values are quite far apart between two particular pulses. In general, the more things you try to do on the JavaFX Application Thread, the more likely this would happen.
If you are trying to draw a tracing line based on the animation, there is no way you could avoid this latency. However, you could avoid the problem of the drawn path cutting corners, by breaking it up into multiple animations. Each animation would move in a straight line, and each of your tracing line is guaranteed to start from the start and end at the ending point.
I tried this and it works:
// Heuristic Change
// Path path = new Path();
// path.setStroke(Color.RED);
// path.getElements().add(new MoveTo(num.get(0).getCenterX(), num.get(0).getCenterY()));
// path.setStrokeWidth(1);
// for (int i = 0; i < num.size(); i++) {
// try {
// path.getElements().addAll(new LineTo(num.get(i).getCenterX(), num.get(i).getCenterY()));
// }
// catch (IndexOutOfBoundsException e) {
// path.getElements().addAll(new LineTo(num.get(0).getCenterX(), num.get(0).getCenterY()));
// }
// }
List<Path> paths = new ArrayList<>();
for (int i = 0; i < num.size() - 1; i++) {
Circle current = num.get(i);
Circle next = num.get(i + 1);
Path path = new Path();
path.setStroke(Color.RED);
path.getElements().addAll(new MoveTo(current.getCenterX(), current.getCenterY()),
new LineTo(next.getCenterX(), next.getCenterY()));
path.setStrokeWidth(1);
paths.add(path);
}
// root.getChildren().addAll(path);
root.getChildren().addAll(paths);
Circle pen = new Circle();
// create animation
// animation = createPathAnimation(path, Duration.seconds(num.size()/4));
animation = createPathAnimation(paths, Duration.millis(200), pen);
And...
private Animation createPathAnimation(List<Path> paths, Duration duration, Circle pen) {
SequentialTransition seq = new SequentialTransition();
// ...
for (Path path : paths) {
// The same PathTransition stuff you had
seq.getChildren().add(pathTransition);
}
return seq;
}
The only thing that changed is that the speed changes at each segment of the full path. If you want to keep that constant, you have to apply Pythagoras' theorem to find the distance, and adjust the duration accordingly.
answered Nov 21 at 9:34
Jai
5,66411131
5,66411131
Thanks, will give it a go and update asap!
– Selva
Nov 21 at 13:38
add a comment |
Thanks, will give it a go and update asap!
– Selva
Nov 21 at 13:38
Thanks, will give it a go and update asap!
– Selva
Nov 21 at 13:38
Thanks, will give it a go and update asap!
– Selva
Nov 21 at 13:38
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53400733%2fjavafx-animating-a-path-with-a-shape%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Unable to reproduce. Does it happen consistently or frequently on your side?
– Jai
Nov 21 at 6:41
not consistently, but happens often to notice it. It is too obvious on a big screen.
– Selva
Nov 21 at 13:39