I'm a beginner in JavaFX, and I'm working on a project where I'm using four Bezier curves to draw a circle. My goal is to eventually achieve a "wobbly" effect by allowing the curves to be deformed when the user drags them. To accomplish this, I want to add a feature that restores the original state of the circle when the user releases the mouse click (EDIT) performing an animation that makes the curve move to its initial path, which I stored in the "initialPath" list.
While I have chosen to use JavaFX for this project, I am aware that it may not be the best tool for the job... I'm just trying to explore JavaFX's capabilities and would appreciate any guidance or tips on how to implement this functionality. Thank you for your help.
I tried working with Timeline and Keyframes' interpolation, I can't seem to find any other question on this exact topic and I'm finding it hard to grasp. This is the state of my code at the moment:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.PathElement;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class BezierCurves extends Application {
private double dragStartX;
private double dragStartY;
private List<Path> initialPaths = new ArrayList<>();
private Pane pane;
public Path drawCurve(double[] moveTo, double[] coordinates, int color) {
Path path = new Path();
switch (color) {
case 0 -> path.setStroke(Color.RED);
case 1 -> path.setStroke(Color.BLUE);
case 2 -> path.setStroke(Color.GREEN);
case 3 -> path.setStroke(Color.ORANGE);
default -> path.setStroke(Color.BLACK);
}
path.setStrokeWidth(2);
path.setFill(null);
MoveTo moveTo1 = new MoveTo(moveTo[0], moveTo[1]);
CubicCurveTo curveTo1 = new CubicCurveTo(coordinates[0],
coordinates[1],
coordinates[2],
coordinates[3],
coordinates[4],
coordinates[5]);
path.getElements().addAll(moveTo1, curveTo1);
return path;
}
@Override
public void start(Stage primaryStage) {
pane = new Pane();
Scene scene = new Scene(pane, 400, 400);
double centerX = 200, centerY = 200, radius = 100, kappa = 0.5522848;
Path path1 = drawCurve(new double[]{centerX, centerY - radius},
new double[]{centerX + radius * kappa,
centerY - radius,
centerX + radius,
centerY - radius * kappa,
centerX + radius, centerY}, 0);
path1.setOnMousePressed(this::handleMousePressed);
path1.setOnMouseDragged(this::handleMouseDragged);
path1.setOnMouseReleased(this::handleMouseReleased);
Path path2 = drawCurve(new double[]{centerX + radius, centerY},
new double[]{centerX + radius,
centerY + radius * kappa,
centerX + radius * kappa,
centerY + radius, centerX,
centerY + radius}, 1);
path2.setOnMousePressed(this::handleMousePressed);
path2.setOnMouseDragged(this::handleMouseDragged);
path2.setOnMouseReleased(this::handleMouseReleased);
Path path3 = drawCurve(new double[]{centerX, centerY + radius},
new double[]{centerX - radius * kappa,
centerY + radius,
centerX - radius,
centerY + radius * kappa,
centerX - radius, centerY}, 2);
path3.setOnMousePressed(this::handleMousePressed);
path3.setOnMouseDragged(this::handleMouseDragged);
path3.setOnMouseReleased(this::handleMouseReleased);
Path path4 = drawCurve(new double[]{centerX - radius, centerY},
new double[]{centerX - radius,
centerY - radius * kappa,
centerX - radius * kappa,
centerY - radius,
centerX,
centerY - radius}, 3);
path4.setOnMousePressed(this::handleMousePressed);
path4.setOnMouseDragged(this::handleMouseDragged);
path4.setOnMouseReleased(this::handleMouseReleased);
initialPaths.addAll(Arrays.asList(path1, path2, path3, path4));
pane.getChildren().addAll(path1, path2, path3, path4);
primaryStage.setScene(scene);
primaryStage.show();
}
private void handleMousePressed(MouseEvent event) {
dragStartX = event.getX();
dragStartY = event.getY();
}
private void handleMouseDragged(MouseEvent event) {
double offsetX = event.getX() - dragStartX;
double offsetY = event.getY() - dragStartY;
Path path = (Path) event.getSource();
for (PathElement element : path.getElements()) {
if (element instanceof CubicCurveTo curve) {
curve.setControlX1(curve.getControlX1() + offsetX * 0.02);
curve.setControlY1(curve.getControlY1() + offsetY * 0.02);
curve.setControlX2(curve.getControlX2() + offsetX * 0.02);
curve.setControlY2(curve.getControlY2() + offsetY * 0.02);
}
}
}
private void handleMouseReleased(MouseEvent event) {
// TODO
}
public static void main(String[] args) {
launch(args);
}
}