Search code examples
user-interfacejavafxdraggable

JavaFX draggable background - alternative to using a camera?


I am trying to implement a navigational feature for an editor I am working on, that would allow you to move around in the window by dragging on the background - basically like you can move around in Open Maps.

My current approach is to move a scene-camera around via DragEvent-Listeners on the scene, in which the displayed objects are children to the root Group.

However, I am wondering whether there is another way to implement this that would not require the use of a camera.


Solution

  • The following works as a simple test:

    import javafx.application.Application;
    import javafx.geometry.Point2D;
    import javafx.scene.Scene;
    import javafx.scene.layout.Pane;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.Circle;
    import javafx.stage.Stage;
    
    public class InfinitePanning extends Application {
    
        @Override
        public void start(Stage primaryStage) {
            Pane drawingPane = new Pane();
            drawingPane.setStyle("-fx-background-color: white;");
            Scene scene = new Scene(drawingPane, 800, 800, Color.WHITE);
    
            scene.setOnScroll(e -> {
                drawingPane.setTranslateX(drawingPane.getTranslateX() + e.getDeltaX());
                drawingPane.setTranslateY(drawingPane.getTranslateY() + e.getDeltaY());
            });
            scene.setOnMouseClicked(e -> {
                if (e.getClickCount() == 2) {
                    Point2D center = drawingPane.sceneToLocal(new Point2D(e.getX(), e.getY()));
                    Circle c = new Circle(center.getX(), center.getY(), 25, Color.CORNFLOWERBLUE);
                    drawingPane.getChildren().add(c);
                }
            });
            Circle c = new Circle(50, 50, 25, Color.CORNFLOWERBLUE);
            drawingPane.getChildren().add(c);
    
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    Double-click to add a new circle, scroll with the mouse (scroll button/wheel or scroll gesture on a trackpad) to move around.

    There are some subtleties here. The pane is initially sized to fit the scene; as you scroll around the mouse will be outside the bounds of the pane. If you double-click outside the bounds of the pane (so you add a new node whose parameters are outside the bounds), then the pane expands at that point to include the new child.