I am trying to implement a scrollable zoom pane. I started from this example:
JavaFx 8 - Scaling / zooming ScrollPane relative to mouse position. There is however one problem I have with this - the width of the lines and other objects is zoomed too, while I would like to achieve the effect that the features are dimensionless. Therefore I improved the solution with PointScalers from here: JavaFX How do I scale the coordinates of a Path without altering the line width? and managed to get the following result:
.
This looks fine, but the scene is not zoomed in a way that the point where I click remains in place during the transformation. Here is my code:
import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.VBox;
import java.util.List;
public class ZoomableScrollPane extends ScrollPane {
private final List<PointScaler> scalers;
private final Node targetNode, outerNode;
private final double zoomIntensity = 0.1;
private double scaleValue = 1.0;
public ZoomableScrollPane(SignFeaturesPresenter signGroupPresenter) {
super();
this.scalers = signGroupPresenter.getScalers();
this.targetNode = signGroupPresenter.getFeaturesGroup();
this.outerNode = outerNode(this.targetNode);
setContent(this.outerNode);
setPannable(true);
}
private Node outerNode(Node node) {
Node outerNode = centeredNode(node);
outerNode.setOnScroll(e -> {
e.consume();
onScroll(e.getTextDeltaY(), new Point2D(e.getX(), e.getY()));
});
return outerNode;
}
private Node centeredNode(Node node) {
VBox vBox = new VBox(node);
vBox.setAlignment(Pos.CENTER);
return vBox;
}
private void onScroll(double wheelDelta, Point2D mousePoint) {
Bounds outerBounds = outerNode.getLayoutBounds();
double zoomFactor = Math.exp(wheelDelta * zoomIntensity);
scaleValue = scaleValue * zoomFactor;
for (PointScaler scaler : scalers) {
scaler.setScale(scaleValue);
}
this.layout();
double newHvalue = mousePoint.getX()/outerBounds.getWidth();
double newVvalue = mousePoint.getY()/outerBounds.getHeight();
this.setHvalue(newHvalue);
this.setVvalue(newVvalue);
}
}
I understand why the equations for newHvalue
and newVvalue
are not correct, but I do not know how to correct them. I suppose I should use the position of the mouse in the viewport coordinate system, but I can see that the mouse position is in the outerNode
coordinate system, which extends the viewport many times. Also, I do not understand, what is the meaning of negative values for the minX, minY, maxX, maxY bounds returned by the method:
Bounds viewportBounds = getViewportBounds();
For example:
BoundingBox [minX:-3231.0, minY:-130.0, minZ:0.0, width:585.0, height:538.0, depth:0.0, maxX:-2646.0, maxY:408.0, maxZ:0.0]