在已缩放节点中的枢轴点处缩放
Posted
技术标签:
【中文标题】在已缩放节点中的枢轴点处缩放【英文标题】:Scale at pivot point in an already scaled node 【发布时间】:2015-02-06 00:35:51 【问题描述】:我正在尝试使用可缩放/可平移的画布创建应用程序。
特点:
在枢轴点使用鼠标滚轮放大/缩小 用鼠标左键在画布上拖动节点 用鼠标右键拖动整个画布只要您以比例 1 开始缩放,轴点处的缩放就会起作用。将鼠标放在网格点上并滚动鼠标滚轮。枢轴点将保留在您开始缩放的位置。
问题:
当您放大,然后将鼠标移动到另一个点并再次缩放时,轴心点会移动,并且在初始鼠标位置不再发生缩放。
示例:
代码如下:
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();
支点计算显然有问题,但我不知道它是什么以及如何解决它。
非常感谢!
【问题讨论】:
另见variation。 【参考方案1】:首先,我建议不要以线性步骤进行缩放,而是通过因素来平滑缩放:
double delta = 1.2;
if (event.getDeltaY() < 0)
scale /= delta;
else
scale *= delta;
...为了有点专横,我推荐大括号作为一种很好的风格;-) :
double delta = 1.2;
if (event.getDeltaY() < 0)
scale /= delta;
else
scale *= delta;
...并使用鼠标滚动值获得更好的质量:
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());
其次,我建议使用画布平移和缩放属性而不是转换:
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();
在对缩放进行了一些思考后,我得出结论,这是一个好主意
-
编写一个独立的缩放辅助方法来简化缩放功能
以同样的方法也支持捏拉缩放手势
于是我写了如下辅助方法:
/** 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());
允许我在任何节点上注册缩放功能,如下所示:
myView.setOnScroll(event -> GUITools.zoom(myView, event)); // mouse scroll wheel zoom
myView.setOnZoom(event -> GUITools.zoom(myView, event)); // pinch to zoom
完成了……
【讨论】:
非常感谢您的快速解决方案。它按预期工作:-) 非常感谢您的更新。我一定会用的。 似乎增量在很大程度上取决于鼠标滚轮设置。我有e。 G。非常高分辨率的屏幕,因此鼠标滚轮滚动值很高。当我使用您的代码并缩小时,我立即得到一个 ~100x100 像素的窗格。所以我想必须考虑使用 getDeltaX() 和 getDeltaY() 的乘数或使用固定的增量。 是的,这是可能的......我也会考虑不直接使用普通的鼠标滚轮(滚动 Y),因为它已经具有当前视图的 Y 移动语义(例如使用两个手指滑动以在平板电脑上的 X、Y 方向滚动)...也许 1.003 的基数可能会更好,而不是 1.01,以便在缩放速度上更加保守。【参考方案2】:我改变了你的 SceneGestures 类,所以现在可以工作了。
class SceneGestures
private double oldx;
private double oldy;
double ttx=0;
double tty=0;
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;
if (oldx==0)
ttx=event.getSceneX() ;
tty=event.getSceneY() ;
else
if (oldx!=event.getSceneX())
ttx=((event.getSceneX()+oldx)/2) ;
if (oldy!=event.getSceneY())
tty=((event.getSceneY()+oldy)/2);
// pivot value must be untransformed, i. e. without scaling
canvas.setPivot(
((ttx- canvas.getBoundsInParent().getMinX()) / oldScale),
((tty- canvas.getBoundsInParent().getMinY()) / oldScale)
);
// if (oldx==0)
oldx=event.getSceneX();
oldy=event.getSceneY();
//
//try
// Robot rbt=new Robot();
// rbt.mouseMove(512, 384);
// catch (AWTException ex)
// System.out.println(ex.getMessage());
//
canvas.setScale( scale);
System.out.println( "new pivot x: " + canvas.scaleTransform.getPivotX() + "/" + canvas.scaleTransform.getPivotY() + ", new scale: " + scale);
System.out.println( "bounds: " + canvas.getBoundsInParent());
System.out.println( "old: " + oldx+" "+oldy);
System.out.println( "tt: " + ttx+" "+tty);
event.consume();
;
【讨论】:
放大到圆形、平移到矩形并继续放大时不起作用。Jens-Peter 的解决方案有效。但我仍然要感谢你的努力:-)【参考方案3】:在 FX8 中你可以做到
final Affine accumulatedScales = new Affine();
chart.getTransforms().add(accumulatedScales);
chart.setOnScroll(new EventHandler<ScrollEvent>()
@Override public void handle(ScrollEvent event)
accumulatedScales.appendScale(scaleFactor, scaleFactor, event.getX(), event.getY());
);
你就完成了
【讨论】:
它不起作用。当我G。将鼠标光标悬停在圆心上,当我使用滚轮时,圆会移动。【参考方案4】:通过这种方法,您可以通过变换、旋转的节点放大位置。
public static void zoom(Node node, double factor, ScrollEvent event)
double oldScale = node.getScaleX();
double scale = oldScale*factor;
if (scale < MIN_ZOOM) scale = MIN_ZOOM;
if (scale > MAX_ZOOM) scale = MAX_ZOOM;
double x = event.getX();
double y = event.getY();
Point2D p0 = node.localToScene(x, y);
node.setScaleX(scale);
node.setScaleY(scale);
Point2D p1 = node.localToScene(x, y);
double deltaX = p1.getX() - p0.getX();
double deltaY = p1.getY() - p0.getY();
node.setTranslateX(node.getTranslateX() - deltaX);
node.setTranslateY(node.getTranslateY() - deltaY);
【讨论】:
以上是关于在已缩放节点中的枢轴点处缩放的主要内容,如果未能解决你的问题,请参考以下文章