I have a problem with zooming using javaFX and zooming. The items are wrapped in a group which is then scaled by the ZoomUtil. One node is animated to show the weird effect resulting: The Rectangles should stay within their original place and not constantly move around the frame.
I have no idea what causes this behaviour and tried many different transform settings and such but were not successful.
public class Test extends Application {
@Override
public void start(Stage primaryStage) {
List<Rectangle> rectangles = new ArrayList<>(5);
Color color = new Color(random(), random(), random(), 1);
Rectangle r = new Rectangle(200, 140,color);
r.relocate(-500,-500);
rectangles.add(r);
r = new Rectangle(200,140,color);
r.relocate(500, -500);
rectangles.add(r);
r = new Rectangle(200,140,color);
r.relocate(500, 500);
rectangles.add(r);
r = new Rectangle(200,140,color);
r.relocate(0, 0);
rectangles.add(r);
r = new Rectangle(200,140,color);
r.relocate(-500, 500);
rectangles.add(r);
Timeline timeline = new Timeline();
Node circle = r;
timeline.getKeyFrames().addAll(
new KeyFrame(Duration.seconds(10), // set start position at 0
new KeyValue(circle.translateXProperty(), random() * 8000),
new KeyValue(circle.translateYProperty(), random() * 6000)
),
new KeyFrame(new Duration(80000), // set end position at 40s
new KeyValue(circle.translateXProperty(), random() * 8000),
new KeyValue(circle.translateYProperty(), random() * 6000)
)
);
Group group = new Group();
group.setManaged(false);
group.getChildren().addAll(rectangles);
StackPane pane = new StackPane();
pane.setPrefWidth(500);
pane.setPrefHeight(500);
Scene scene = new Scene(pane);
pane.getChildren().add(group);
pane.setOnScroll(event -> ZoomUtil.zoom(group, event));
primaryStage.setScene(scene);
primaryStage.setWidth(500);
primaryStage.setHeight(500);
primaryStage.show();
timeline.play();
}
}
.
public class ZoomUtil {
/** Allow to zoom/scale any node with pivot at scene (x,y) coordinates.
*
* @param node
* @param x
* @param y
*/
public static void zoom(Node node, double factor, double x, double y) {
double oldScale = node.getScaleX();
double scale = oldScale * factor;
if (scale < 0.05) scale = 0.05;
if (scale > 50) scale = 50;
node.setScaleX(scale);
node.setScaleY(scale);
double f = (scale / oldScale) - 1;
/* Move view by translational difference */
Bounds bounds = node.localToScene(node.getBoundsInLocal());
double dx = (x - (bounds.getWidth() / 2 + bounds.getMinX()));
double dy = (y - (bounds.getHeight() / 2 + bounds.getMinY()));
node.setTranslateX(node.getTranslateX() - f * dx);
node.setTranslateY(node.getTranslateY() - f * dy);
}
public static void zoom(Node node, ScrollEvent event) {
zoom(node, Math.pow(1.002, event.getDeltaY()), event.getSceneX(), event.getSceneY());
}
public static void zoom(Node node, ZoomEvent event) {
zoom(node, event.getZoomFactor(), event.getSceneX(), event.getSceneY());
}
}