title: Retain relative mouse position while resizing a JPanel in a JScrollPane
body: <p>I'm resizing a JPanel inside of a JScrollPane, and I want to make sure that the point on the JPanel where my mouse is currently located retains its position with respect to the JScrollPane after the resize (like Google maps does when you zoom in/out).</p>
  
  <p>I find the mouse position on the JPanel, which lets me deal with the viewport being at various positions.  I multiply it by the zoom factor so I know where the point will be after scaling.  I then subtract the position of the mouse on the ScrollPane so that I know where the point was with respect to the viewable area.  I'm doing something wrong however, and I just can't see what.</p>
  
  <p>Example Code:</p>
  
  <pre><code>import java.awt.BorderLayout;
  import java.awt.Dimension;
  import java.awt.Point;
  import java.awt.event.MouseWheelEvent;
  import java.awt.event.MouseWheelListener;
  
  import javax.swing.JFrame;
  import javax.swing.JPanel;
  import javax.swing.JScrollPane;
  import javax.swing.SwingUtilities;
  
  
  public class Test 
  {
      public static void main(String[] in)
      {
          javax.swing.SwingUtilities.invokeLater(new Runnable() {
              public void run() {
                  new Test();
              }
          });
      }
  
      public Test()
      {
          final JFrame frame = new JFrame();
          final ScalablePanel child = new ScalablePanel();
  
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.setLayout(new BorderLayout());
          frame.add(child, BorderLayout.CENTER);
          frame.pack();
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
      }
  }
  
  class ScalablePanel
  extends JScrollPane
  implements MouseWheelListener
  {
      final double ZOOM_IN_FACTOR = 1.1;
      final double ZOOM_OUT_FACTOR = 0.9;
      final JPanel zoomPanel = new JPanel();
  
      public ScalablePanel()
      {
          final javax.swing.JLabel marker = new javax.swing.JLabel("Testing the mouse position on zoom");
          marker.setHorizontalAlignment(javax.swing.JLabel.CENTER);
  
          zoomPanel.setLayout(new BorderLayout());
          zoomPanel.add(marker,BorderLayout.CENTER);
  
          getViewport().setView(zoomPanel);
          setPreferredSize(new Dimension(300,300));
          addMouseWheelListener(this);
      }
  
      public void mouseWheelMoved(final MouseWheelEvent e) 
      {
          if (e.isControlDown())
          {
              if (e.getWheelRotation() &lt; 0)
                  zoomIn(e);
              else
                  zoomOut(e);
              e.consume();
          }
      }
  
      public void zoomIn(final MouseWheelEvent e)
      {
          // Get the mouse position with respect to the zoomPanel
          final Point pointOnZoomPanel = SwingUtilities.convertPoint(
                  e.getComponent(), e.getPoint(), zoomPanel);
  
          // Resize panel
          final Dimension currSize = zoomPanel.getSize();
          zoomPanel.setPreferredSize(
                  new Dimension(
                          (int)(currSize.width * ZOOM_IN_FACTOR),
                          (int)(currSize.height * ZOOM_IN_FACTOR) ));
  
          // Find out where our point on the zoom panel is now that we've resized it
          final Point newViewPos = new Point();
          newViewPos.x = (int)(ZOOM_IN_FACTOR * pointOnZoomPanel.x - e.getPoint().x);
          newViewPos.y = (int)(ZOOM_IN_FACTOR * pointOnZoomPanel.y - e.getPoint().y);
          // Move the viewport to the new position to keep the area our mouse was in the same spot
          getViewport().setViewPosition(newViewPos);
  
          zoomPanel.revalidate();
      }
  
      public void zoomOut(final MouseWheelEvent e)
      {
          // Get the mouse position with respect to the zoomPanel
          final Point pointOnZoomPanel = SwingUtilities.convertPoint(
                  e.getComponent(), e.getPoint(), zoomPanel);
  
          // Resize panel
          final Dimension currSize = zoomPanel.getSize();
          zoomPanel.setPreferredSize(
                  new Dimension(
                          (int)(currSize.width * ZOOM_OUT_FACTOR),
                          (int)(currSize.height * ZOOM_OUT_FACTOR) ));
  
          // Find out where our point on the zoom panel is now that we've resized it
          final Point newViewPos = new Point();
          newViewPos.x = (int)(ZOOM_OUT_FACTOR * pointOnZoomPanel.x - e.getPoint().x);
          newViewPos.y = (int)(ZOOM_OUT_FACTOR * pointOnZoomPanel.y - e.getPoint().y);
          // Move the viewport to the new position to keep the area our mouse was in the same spot
          getViewport().setViewPosition(newViewPos);
  
          zoomPanel.revalidate();
      }
  }
  </code></pre>