Friday 15 February 2013

JavaFX Pan & Zoom

These notes are based around putting objects into a normal Pane object and not, for example, a ScrollPane where the rules for finding the centre point to pivot a scale around are a bit odd!

JavaFX gives amazing controls over panning and zooming.  For example to pan a pane you can simply use

    pane.setTranslateX(10);
    pane.setTranslateY(10);

This will set the translate.  If you want to move an object more from its currently panned position use

    pane.setTranslateX(pane.getTranslateX() + ...);
    pane.setTranslateY(pane.getTranslateY() + ...);

Zooming is very similar, to double the size around the centre point of the pane,

    pane.setScaleX(2);
    pane.setScaleY(2);

Putting these together is fine and works well.  However, you would normally want to zoom around the centre point of the screen rather than the centre point of the pane, particularly if the pane has been panned first. To do a zoom around a particular point you can use the Scale transformation provided as standard.

    Scale scale = new Scale();
    scale.setPivotX(pivotX);
    scale.setPivotY(pivotY);
    scale.setX(zoomFactorX);
    scale.setY(zoomFactorY);
    pane.getTransforms().add(scale);

The pivotX, pivotY point here is the point around which the scale takes place.  How, the problem comes to calculate the pivot point.  You can do this fairly easily using the position of the pane in the parent.

    Bounds bip = pane.boundsInParent().get();
    double pivotX = (screenWidth / 2 - bip.getMinX()) / scaleX;
    double pivotY = (screenHeight / 2 - bip.getMinY()) / scaleY;

    Scale scale = new Scale()
    ...

    scaleX *= zoomFactorX;
    scaleY *= zoomFactorY;

Where scaleX and scaleY are the current scaling.  You can keep track of the current scale easily enough by adjusting it after each zoom (as above) or you can get the current width / height from the bounds object and calculate the zoom from the original size.

For consistency, you can now use a transform to do the translation as well.  This makes no difference to the scaling and pivot calculation as the boundsInParent will still be the same whichever way the translation is done.

    Translate translate = new Translate(panX, panY);
    pane.getTransforms().add(translate);

No comments:

Post a Comment