Thursday, May 24, 2012

ZoomAnimator to specific location in Visual Library.

I totally wanted Visual Library in Netbeans to zoom in all nicely animated, so cue ZoomAnimator. Except that the damned thing zooms to the upper left corner. There's no choice in it, that's where it starts going. Which seemed rather odd. I mean the library files had MouseCenteredZoomAction and that zooms to a specific location (the mouse). So I tried to role up my own class and found it really odd. It kept messing up, being off here and there along the edges and not going where I told it to to go. So I looked up MouseCenteredZoomAction Source and found what it was doing. Then I fixed my class and quickly realized why it wasn't being consistent. The view.scrollRectToVisible depends on the current state of the view window. You cannot easily predict where the view window will be after the zoom. Which is why the MouseCenteredZoomAction class sets the zoom, forces it to validate the scene, and then checks for the window data. Thankfully that's pretty much identical to preTick and postTick in the Zoom Animator Listener class, and to straddle that with the pre and post ticks commands is rather easy.

You likely don't care about this, it's all greek to you (rare, likely imaginary, reader of this blog). But, mark my words. Somebody is going to google and find this and love the hell out of it. It will make their day.


You can ensure it zooms to a specific location by giving it a rectangle similar to the view field.

    protected void zoomrange(Rectangle rectangle) {
        Rectangle viewBounds = getView().getVisibleRect();
        double zoomw = (float) viewBounds.width / rectangle.width;
        double zoomh = (float) viewBounds.height / rectangle.height;
        double zoom = min(zoomw, zoomh);
        Rectangle normaled = new Rectangle(rectangle.x, rectangle.y, (int)(viewBounds.width / zoom), (int)(viewBounds.height / zoom));
        getSceneAnimator().animateZoomFactor(zoom);
        getSceneAnimator().getZoomAnimator().addAnimatorListener(new FocusZoomAnimatorListener(this, normaled));
    }


import java.awt.Point;
import java.awt.Rectangle;
import javax.swing.JComponent;
import org.netbeans.api.visual.animator.AnimatorEvent;
import org.netbeans.api.visual.animator.AnimatorListener;
import org.netbeans.api.visual.widget.Scene;
import org.netbeans.api.visual.widget.Widget;

/**
 * @author Tat
 */
public class FocusZoomAnimatorListener implements AnimatorListener {

    private Point point;
    private Rectangle rectangle,viewRect;
    private Point center;
    private Point mouseLocation;
    private JComponent view;
    private Scene scene;
    private Widget widget;
   

    public FocusZoomAnimatorListener(Widget widget, Point point) {
        this.widget = widget;
        this.point = point;
        scene = widget.getScene();
        view = scene.getView();
    }
   
    public FocusZoomAnimatorListener(Widget widget, Rectangle rectangle) {
        this.widget = widget;
        this.rectangle = rectangle;
        scene = widget.getScene();
        view = scene.getView();
    }

    @Override
    public void animatorStarted(AnimatorEvent ae) {
    }

    @Override
    public void animatorReset(AnimatorEvent ae) {
    }

    @Override
    public void animatorFinished(AnimatorEvent ae) {
    }

    @Override
    public void animatorPreTick(AnimatorEvent ae) {
        if (point != null) {
            viewRect = view.getVisibleRect();
            center = widget.convertLocalToScene(point);
            mouseLocation = scene.convertSceneToView(center);
        }
    }

    @Override
    public void animatorPostTick(AnimatorEvent ae) {
        if (point != null) {
            center = scene.convertSceneToView(center);
            view.scrollRectToVisible(new Rectangle(
                    center.x - (mouseLocation.x - viewRect.x),
                    center.y - (mouseLocation.y - viewRect.y),
                    viewRect.width,
                    viewRect.height));
        } else {
            viewRect = scene.convertSceneToView(rectangle);
            view.scrollRectToVisible(viewRect);
        }
    }
}