在已经缩放的节点中的枢轴点缩放 [英] Scale at pivot point in an already scaled node

查看:23
本文介绍了在已经缩放的节点中的枢轴点缩放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个带有可缩放/可平移画布的应用程序.

I'm trying to create an application with a zoomable/pannable canvas.

特点:

  • 在枢轴点用鼠标滚轮放大/缩小
  • 用鼠标左键在画布上拖动节点
  • 用鼠标右键拖动整个画布

只要您在比例 1 处开始缩放,枢轴点处的缩放就会起作用.将鼠标放在网格点上并滚动鼠标滚轮.轴心点将保留在您开始缩放的位置.

The zooming at the pivot point works as long as you start the zooming at scale 1. Position the mouse over a grid point and scroll the mouse wheel. The pivot point will remain where you started zooming.

问题:

当您放大时,将鼠标移动到另一个点并再次缩放,然后轴心点被移动并且在初始鼠标位置不再发生缩放.

When you zoom in, then move the mouse to another point and zoom again, then the pivot point is shifted and zooming isn't happening anymore at the initial mouse position.

示例:

代码如下:

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Scale;
import javafx.stage.Stage;

/**
 * The canvas which holds all of the nodes of the application.
 */
class PannableCanvas extends Pane {

    Scale scaleTransform;

    public PannableCanvas() {

        setPrefSize(600, 600);
        setStyle("-fx-background-color: lightgrey; -fx-border-color: blue;");

        // add scale transform
        scaleTransform = new Scale( 1.0, 1.0);
        getTransforms().add( scaleTransform);

        // logging
        addEventFilter(MouseEvent.MOUSE_PRESSED, event -> { 
            System.out.println( 
                    "canvas event: " + ( ((event.getSceneX() - getBoundsInParent().getMinX()) / getScale()) + ", scale: " + getScale())
                    );
            System.out.println( "canvas bounds: " + getBoundsInParent());   
                });

    }

    /**
     * Add a grid to the canvas, send it to back
     */
    public void addGrid() {

        double w = getBoundsInLocal().getWidth();
        double h = getBoundsInLocal().getHeight();

        // add grid
        Canvas grid = new Canvas(w, h);

        // don't catch mouse events
        grid.setMouseTransparent(true);

        GraphicsContext gc = grid.getGraphicsContext2D();

        gc.setStroke(Color.GRAY);
        gc.setLineWidth(1);

        // draw grid lines
        double offset = 50;
        for( double i=offset; i < w; i+=offset) {
            // vertical
            gc.strokeLine( i, 0, i, h);
            // horizontal
            gc.strokeLine( 0, i, w, i);
        }

        getChildren().add( grid);

        grid.toBack();
    }

    public Scale getScaleTransform() {
        return scaleTransform;
    }

    public double getScale() {
        return scaleTransform.getY();
    }

    /**
     * Set x/y scale
     * @param scale
     */
    public void setScale( double scale) {
        scaleTransform.setX(scale);
        scaleTransform.setY(scale);
    }

    /**
     * Set x/y pivot points
     * @param x
     * @param y
     */
    public void setPivot( double x, double y) {
        scaleTransform.setPivotX(x);
        scaleTransform.setPivotY(y);
    }
}


/**
 * Mouse drag context used for scene and nodes.
 */
class DragContext {

    double mouseAnchorX;
    double mouseAnchorY;

    double translateAnchorX;
    double translateAnchorY;

}

/**
 * Listeners for making the nodes draggable via left mouse button. Considers if parent is zoomed.
 */
class NodeGestures {

    private DragContext nodeDragContext = new DragContext();

    PannableCanvas canvas;

    public NodeGestures( PannableCanvas canvas) {
        this.canvas = canvas;

    }

    public EventHandler<MouseEvent> getOnMousePressedEventHandler() {
        return onMousePressedEventHandler;
    }

    public EventHandler<MouseEvent> getOnMouseDraggedEventHandler() {
        return onMouseDraggedEventHandler;
    }

    private EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {

        public void handle(MouseEvent event) {

            // left mouse button => dragging
            if( !event.isPrimaryButtonDown())
                return;

            nodeDragContext.mouseAnchorX = event.getSceneX();
            nodeDragContext.mouseAnchorY = event.getSceneY();

            Node node = (Node) event.getSource();

            nodeDragContext.translateAnchorX = node.getTranslateX();
            nodeDragContext.translateAnchorY = node.getTranslateY();

        }

    };

    private EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
        public void handle(MouseEvent event) {

            // left mouse button => dragging
            if( !event.isPrimaryButtonDown())
                return;

            double scale = canvas.getScale();

            Node node = (Node) event.getSource();

            node.setTranslateX(nodeDragContext.translateAnchorX + (( event.getSceneX() - nodeDragContext.mouseAnchorX) / scale));
            node.setTranslateY(nodeDragContext.translateAnchorY + (( event.getSceneY() - nodeDragContext.mouseAnchorY) / scale));

            event.consume();

        }
    };
}

/**
 * Listeners for making the scene's canvas draggable and zoomable
 */
class SceneGestures {

    private static final double MAX_SCALE = 10.0d;
    private static final double MIN_SCALE = .1d;

    private DragContext sceneDragContext = new DragContext();

    PannableCanvas canvas;

    public SceneGestures( PannableCanvas canvas) {
        this.canvas = canvas;
    }

    public EventHandler<MouseEvent> getOnMousePressedEventHandler() {
        return onMousePressedEventHandler;
    }

    public EventHandler<MouseEvent> getOnMouseDraggedEventHandler() {
        return onMouseDraggedEventHandler;
    }

    public EventHandler<ScrollEvent> getOnScrollEventHandler() {
        return onScrollEventHandler;
    }

    private EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {

        public void handle(MouseEvent event) {

            // right mouse button => panning
            if( !event.isSecondaryButtonDown())
                return;

            sceneDragContext.mouseAnchorX = event.getSceneX();
            sceneDragContext.mouseAnchorY = event.getSceneY();

            sceneDragContext.translateAnchorX = canvas.getTranslateX();
            sceneDragContext.translateAnchorY = canvas.getTranslateY();

        }

    };

    private EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
        public void handle(MouseEvent event) {

            // right mouse button => panning
            if( !event.isSecondaryButtonDown())
                return;

            canvas.setTranslateX(sceneDragContext.translateAnchorX + event.getSceneX() - sceneDragContext.mouseAnchorX);
            canvas.setTranslateY(sceneDragContext.translateAnchorY + event.getSceneY() - sceneDragContext.mouseAnchorY);

            event.consume();
        }
    };

    /**
     * Mouse wheel handler: zoom to pivot point
     */
    private EventHandler<ScrollEvent> onScrollEventHandler = new EventHandler<ScrollEvent>() {

        @Override
        public void handle(ScrollEvent event) {

            double delta = 1;

            double scale = canvas.getScale(); // currently we only use Y, same value is used for X
            double oldScale = scale;

            if (event.getDeltaY() < 0)
                scale -= delta;
            else
                scale += delta;

            if (scale <= MIN_SCALE) {
                scale = MIN_SCALE;
            } else if (scale >= MAX_SCALE) {
                scale = MAX_SCALE;
            }

            // pivot value must be untransformed, i. e. without scaling
            canvas.setPivot( 
                    ((event.getSceneX() - canvas.getBoundsInParent().getMinX()) / oldScale),
                    ((event.getSceneY() - canvas.getBoundsInParent().getMinY()) / oldScale)
                    );

            canvas.setScale( scale);

            System.out.println( "new pivot x: " + canvas.scaleTransform.getPivotX() + "/" + canvas.scaleTransform.getPivotY() + ", new scale: " + scale);
            System.out.println( "bounds: " + canvas.getBoundsInParent());       

            event.consume();

        }

    };


}

/**
 * An application with a zoomable and pannable canvas.
 */
public class ScrollApplication extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {

        Group group = new Group();

        // create canvas
        PannableCanvas canvas = new PannableCanvas();

        // we don't want the canvas on the top/left in this example => just
        // translate it a bit
        canvas.setTranslateX(100);
        canvas.setTranslateY(100);

        // create sample nodes which can be dragged
        NodeGestures nodeGestures = new NodeGestures( canvas);

        Label label1 = new Label("Draggable node 1");
        label1.setTranslateX(10);
        label1.setTranslateY(10);
        label1.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
        label1.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());

        Label label2 = new Label("Draggable node 2");
        label2.setTranslateX(100);
        label2.setTranslateY(100);
        label2.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
        label2.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());

        Label label3 = new Label("Draggable node 3");
        label3.setTranslateX(200);
        label3.setTranslateY(200);
        label3.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
        label3.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());

        Circle circle1 = new Circle( 300, 300, 50);
        circle1.setStroke(Color.ORANGE);
        circle1.setFill(Color.ORANGE.deriveColor(1, 1, 1, 0.5));
        circle1.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
        circle1.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());

        Rectangle rect1 = new Rectangle(100,100);
        rect1.setTranslateX(450);
        rect1.setTranslateY(450);
        rect1.setStroke(Color.BLUE);
        rect1.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.5));
        rect1.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
        rect1.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());

        canvas.getChildren().addAll(label1, label2, label3, circle1, rect1);

        group.getChildren().add(canvas);

        // create scene which can be dragged and zoomed
        Scene scene = new Scene(group, 1024, 768);

        SceneGestures sceneGestures = new SceneGestures(canvas);
        scene.addEventFilter( MouseEvent.MOUSE_PRESSED, sceneGestures.getOnMousePressedEventHandler());
        scene.addEventFilter( MouseEvent.MOUSE_DRAGGED, sceneGestures.getOnMouseDraggedEventHandler());
        scene.addEventFilter( ScrollEvent.ANY, sceneGestures.getOnScrollEventHandler());

        stage.setScene(scene);
        stage.show();

        canvas.addGrid();

    }
}

显然枢轴点计算有问题,但我无法弄清楚它是什么以及如何修复它.

It's obviously something wrong with the pivot point calculation, but I can't figure out what it is and how to fix it.

非常感谢!

推荐答案

首先,我建议不要以线性步长进行缩放,而是通过因子来平滑缩放:

First I would recommend to not scale in linear steps but by factors to smooth the scaling:

           double delta = 1.2;
           if (event.getDeltaY() < 0)
                scale /= delta;
            else
                scale *= delta;

...而且有点霸道,我推荐大括号作为一种很好的风格;-) :

... and to be somehow bossy, I recommend curly brackets as a good style ;-) :

               double delta = 1.2;
               if (event.getDeltaY() < 0) {
                    scale /= delta;
               } else {
                    scale *= delta;
               }

...并使用鼠标滚动值以获得更好的质量:

... and to use the mouse scroll value for even better quality:

               double delta = 1.2;
               if (event.getDeltaY() < 0) {
                    scale /= Math.pow(delta, -event.getDeltaY()/20);
               } else {
                    scale *= Math.pow(delta, event.getDeltaY()/20);
               }

...这最终与:

               scale *= Math.pow(1.01, event.getDeltaY());

第二,我建议使用画布平移和缩放属性而不是转换:

Second I recomend to use the canvas translate and scale properties instead of a Transformation:

public class ZoomApplication extends Application {
    static public class PannableCanvas extends Pane {

        DoubleProperty myScale = new SimpleDoubleProperty(1.0);

        public PannableCanvas() {

            setPrefSize(600, 600);
            setStyle("-fx-background-color: lightgrey; -fx-border-color: blue;");

            // add scale transform
            scaleXProperty().bind(myScale);
            scaleYProperty().bind(myScale);

            // logging
            addEventFilter(MouseEvent.MOUSE_PRESSED, event -> { 
                System.out.println( 
                        "canvas event: " + ( ((event.getSceneX() - getBoundsInParent().getMinX()) / getScale()) + ", scale: " + getScale())
                        );
                System.out.println( "canvas bounds: " + getBoundsInParent());   
            });

        }

        /**
         * Add a grid to the canvas, send it to back
         */
        public void addGrid() {

            double w = getBoundsInLocal().getWidth();
            double h = getBoundsInLocal().getHeight();

            // add grid
            Canvas grid = new Canvas(w, h);

            // don't catch mouse events
            grid.setMouseTransparent(true);

            GraphicsContext gc = grid.getGraphicsContext2D();

            gc.setStroke(Color.GRAY);
            gc.setLineWidth(1);

            // draw grid lines
            double offset = 50;
            for( double i=offset; i < w; i+=offset) {
                // vertical
                gc.strokeLine( i, 0, i, h);
                // horizontal
                gc.strokeLine( 0, i, w, i);
            }

            getChildren().add( grid);

            grid.toBack();
        }

        public double getScale() {
            return myScale.get();
        }

        /**
         * Set x/y scale
         * @param myScale
         */
        public void setScale( double scale) {
            myScale.set(scale);
        }

        /**
         * Set x/y pivot points
         * @param x
         * @param y
         */
        public void setPivot( double x, double y) {
            setTranslateX(getTranslateX()-x);
            setTranslateY(getTranslateY()-y);
        }
    }


    /**
     * Mouse drag context used for scene and nodes.
     */
    class DragContext {

        double mouseAnchorX;
        double mouseAnchorY;

        double translateAnchorX;
        double translateAnchorY;

    }

    /**
     * Listeners for making the nodes draggable via left mouse button. Considers if parent is zoomed.
     */
    class NodeGestures {

        private DragContext nodeDragContext = new DragContext();

        PannableCanvas canvas;

        public NodeGestures( PannableCanvas canvas) {
            this.canvas = canvas;

        }

        public EventHandler<MouseEvent> getOnMousePressedEventHandler() {
            return onMousePressedEventHandler;
        }

        public EventHandler<MouseEvent> getOnMouseDraggedEventHandler() {
            return onMouseDraggedEventHandler;
        }

        private EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {

            public void handle(MouseEvent event) {

                // left mouse button => dragging
                if( !event.isPrimaryButtonDown())
                    return;

                nodeDragContext.mouseAnchorX = event.getSceneX();
                nodeDragContext.mouseAnchorY = event.getSceneY();

                Node node = (Node) event.getSource();

                nodeDragContext.translateAnchorX = node.getTranslateX();
                nodeDragContext.translateAnchorY = node.getTranslateY();

            }

        };

        private EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
            public void handle(MouseEvent event) {

                // left mouse button => dragging
                if( !event.isPrimaryButtonDown())
                    return;

                double scale = canvas.getScale();

                Node node = (Node) event.getSource();

                node.setTranslateX(nodeDragContext.translateAnchorX + (( event.getSceneX() - nodeDragContext.mouseAnchorX) / scale));
                node.setTranslateY(nodeDragContext.translateAnchorY + (( event.getSceneY() - nodeDragContext.mouseAnchorY) / scale));

                event.consume();

            }
        };
    }

    /**
     * Listeners for making the scene's canvas draggable and zoomable
     */
    class SceneGestures {

        private static final double MAX_SCALE = 10.0d;
        private static final double MIN_SCALE = .1d;

        private DragContext sceneDragContext = new DragContext();

        PannableCanvas canvas;

        public SceneGestures( PannableCanvas canvas) {
            this.canvas = canvas;
        }

        public EventHandler<MouseEvent> getOnMousePressedEventHandler() {
            return onMousePressedEventHandler;
        }

        public EventHandler<MouseEvent> getOnMouseDraggedEventHandler() {
            return onMouseDraggedEventHandler;
        }

        public EventHandler<ScrollEvent> getOnScrollEventHandler() {
            return onScrollEventHandler;
        }

        private EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {

            public void handle(MouseEvent event) {

                // right mouse button => panning
                if( !event.isSecondaryButtonDown())
                    return;

                sceneDragContext.mouseAnchorX = event.getSceneX();
                sceneDragContext.mouseAnchorY = event.getSceneY();

                sceneDragContext.translateAnchorX = canvas.getTranslateX();
                sceneDragContext.translateAnchorY = canvas.getTranslateY();

            }

        };

        private EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
            public void handle(MouseEvent event) {

                // right mouse button => panning
                if( !event.isSecondaryButtonDown())
                    return;

                canvas.setTranslateX(sceneDragContext.translateAnchorX + event.getSceneX() - sceneDragContext.mouseAnchorX);
                canvas.setTranslateY(sceneDragContext.translateAnchorY + event.getSceneY() - sceneDragContext.mouseAnchorY);

                event.consume();
            }
        };

        /**
         * Mouse wheel handler: zoom to pivot point
         */
        private EventHandler<ScrollEvent> onScrollEventHandler = new EventHandler<ScrollEvent>() {

            @Override
            public void handle(ScrollEvent event) {


                double scale = canvas.getScale(); // currently we only use Y, same value is used for X
                double oldScale = scale;

                scale *= Math.pow(1.01, event.getDeltaY());

                if (scale <= MIN_SCALE) {
                    scale = MIN_SCALE;
                } else if (scale >= MAX_SCALE) {
                    scale = MAX_SCALE;
                }

                double f = (scale / oldScale)-1;

                double dx = (event.getSceneX() - (canvas.getBoundsInParent().getWidth()/2 + canvas.getBoundsInParent().getMinX()));
                double dy = (event.getSceneY() - (canvas.getBoundsInParent().getHeight()/2 + canvas.getBoundsInParent().getMinY()));


                canvas.setScale( scale);
                canvas.setPivot(f*dx, f*dy);

                event.consume();

            }

        };


    }

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {

        Group group = new Group();

        // create canvas
        PannableCanvas canvas = new PannableCanvas();

        // we don't want the canvas on the top/left in this example => just
        // translate it a bit
        canvas.setTranslateX(100);
        canvas.setTranslateY(100);

        // create sample nodes which can be dragged
        NodeGestures nodeGestures = new NodeGestures( canvas);

        Label label1 = new Label("Draggable node 1");
        label1.setTranslateX(10);
        label1.setTranslateY(10);
        label1.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
        label1.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());

        Label label2 = new Label("Draggable node 2");
        label2.setTranslateX(100);
        label2.setTranslateY(100);
        label2.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
        label2.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());

        Label label3 = new Label("Draggable node 3");
        label3.setTranslateX(200);
        label3.setTranslateY(200);
        label3.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
        label3.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());

        Circle circle1 = new Circle( 300, 300, 50);
        circle1.setStroke(Color.ORANGE);
        circle1.setFill(Color.ORANGE.deriveColor(1, 1, 1, 0.5));
        circle1.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
        circle1.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());

        Rectangle rect1 = new Rectangle(100,100);
        rect1.setTranslateX(450);
        rect1.setTranslateY(450);
        rect1.setStroke(Color.BLUE);
        rect1.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.5));
        rect1.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
        rect1.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());

        canvas.getChildren().addAll(label1, label2, label3, circle1, rect1);

        group.getChildren().add(canvas);

        // create scene which can be dragged and zoomed
        Scene scene = new Scene(group, 1024, 768);

        SceneGestures sceneGestures = new SceneGestures(canvas);
        scene.addEventFilter( MouseEvent.MOUSE_PRESSED, sceneGestures.getOnMousePressedEventHandler());
        scene.addEventFilter( MouseEvent.MOUSE_DRAGGED, sceneGestures.getOnMouseDraggedEventHandler());
        scene.addEventFilter( ScrollEvent.ANY, sceneGestures.getOnScrollEventHandler());

        stage.setScene(scene);
        stage.show();

        canvas.addGrid();

    }
}

在对缩放进行了一些思考后,我得出的结论是

After some thoughts about zoom, I came to the conclusion, that it would be a good idea to

  1. 编写一个独立的缩放助手方法来简化缩放功能
  2. 同样支持双指缩放手势

所以我写了下面的辅助方法:

So I wrote the following helper method:

/** Allow to zoom/scale any node with pivot at scene (x,y) coordinates.
 * 
 * @param node
 * @param delta
 * @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;
    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.01, event.getDeltaY()), event.getSceneX(), event.getSceneY());
}
public static void zoom(Node node, ZoomEvent event) {
    zoom(node, event.getZoomFactor(), event.getSceneX(), event.getSceneY());
}

允许我在任何节点上注册缩放功能,就像:

allowing me to register zoom function on any node as easy as:

    myView.setOnScroll(event -> GUITools.zoom(myView, event)); // mouse scroll wheel zoom
    myView.setOnZoom(event -> GUITools.zoom(myView, event)); // pinch to zoom

完成...

这篇关于在已经缩放的节点中的枢轴点缩放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆