JavaFx animating a path with a shape












1














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










share|improve this question






















  • 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
















1














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










share|improve this question






















  • 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














1












1








1







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










share|improve this question













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






share|improve this question













share|improve this question











share|improve this question




share|improve this question










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


















  • 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












1 Answer
1






active

oldest

votes


















0














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.






share|improve this answer





















  • Thanks, will give it a go and update asap!
    – Selva
    Nov 21 at 13:38











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
});


}
});














draft saved

draft discarded


















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









0














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.






share|improve this answer





















  • Thanks, will give it a go and update asap!
    – Selva
    Nov 21 at 13:38
















0














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.






share|improve this answer





















  • Thanks, will give it a go and update asap!
    – Selva
    Nov 21 at 13:38














0












0








0






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.






share|improve this answer












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.







share|improve this answer












share|improve this answer



share|improve this answer










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


















  • 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


















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

404 Error Contact Form 7 ajax form submitting

How to know if a Active Directory user can login interactively

TypeError: fit_transform() missing 1 required positional argument: 'X'