# Thread: Repositioning components based on mouse position

1. Member
Join Date
Jun 2011
Posts
19
Rep Power
0

## Repositioning components based on mouse position

Hello, I am implementing a zoom feature for a JPanel that is populated with many smaller JPanels.
The premise is: when the user spins the mouse scroll wheel the "zoomPercent" is increased/decreased and then all the child components are resized based on their "defaultSize" and the new "zoomPercent" value. This all works fine. Now the problem I've run into is how to get the child components to relocate towards the mouse pointer based on the "zoomPercent" to give the illusion of zooming. I believe the Trig involved requires the use of the AAA Similar Triangle Theorem but I can't quite figure it out. What I have right now \/ is giving me odd results. When I scroll the mouse wheel forward the elements seem to move towards the mouse pointer, but they don't move away from the pointer when I scroll backwards on the scroll wheel. Eventually, after scrolling forwards and backwards a few times the child components will all be perfectly overlapped and jump to the mouse pointer's position when I try scrolling. Any guidance?

Java Code:
```private int zoomPercent = 100;

public void mouseWheelMoved(MouseWheelEvent e)
{
int oldZoomPercent = Math.max(1, zoomPercent);
int notches = -e.getWheelRotation();
int increment = 50;
zoomPercent += increment * notches;
zoomPercent = Math.max(0, zoomPercent);

//mouse position
int x = e.getX();
int y = e.getY();

for (Node node: nodes)
{
int newWidth = node.defaultWidth * zoomPercent / 100;
int newHeight = node.defaultHeight * zoomPercent / 100;
node.setSize(newWidth, newHeight);

int nodeX = node.getLocation().x;
int nodeY = node.getLocation().y;

int dx = Math.abs(x - nodeX);
int dy = Math.abs(y - nodeY);

//distance between component and mouse pointer
double hyp = Math.sqrt(dx * dx + dy * dy);

//angle of hypotenuse
double angle = Math.asin(dy / hyp);

//new hypotenuse length
double newHyp = hyp * zoomPercent / oldZoomPercent;

//horizontal component of hypotenuse
double sin = Math.sin(angle);
//vertical component of hypotenuse
double cos = Math.cos(angle);

//change in horizontal component
dx = (int) Math.abs(sin * newHyp - sin * hyp);
//change in vertical component
dy = (int) Math.abs(cos * newHyp - cos * hyp);

int finalX, finalY = 0;

if (nodeX > x) {
finalX = x + dx;
} else {
finalX = x - dx;
}

if (nodeY > y) {
finalY = y + dy;
} else {
finalY = y - dy;
}

node.setLocation(finalX, finalY);
}
validate();
}```

2. Moderator
Join Date
Feb 2009
Location
New Zealand
Posts
4,712
Rep Power
14
If you want to perform an enlargement whose center is at the mouse position, I'm not sure I would bother with the angle.

* Find nodeX-x, the x-distance to the node. (Don't Math.abs() it because the sign is important)
* Multiply this "delta" by the scale factor
* Add the result back to x to get the new x-position of the node
* Repeat for y

3. Member
Join Date
Jun 2011
Posts
19
Rep Power
0
Originally Posted by pbrockway2
If you want to perform an enlargement whose center is at the mouse position, I'm not sure I would bother with the angle.

* Find nodeX-x, the x-distance to the node. (Don't Math.abs() it because the sign is important)
* Multiply this "delta" by the scale factor
* Add the result back to x to get the new x-position of the node
* Repeat for y
Very much appreciated. This was my first inclination but I made errors in other places and assumed my approach was incorrect.
Well now it works wonderfully! The zoom effect is perfect. Now there's just one little hick-up. If I zoom out so far that the nodes actually disappear
when I zoom back in and they reappear they are all occupying the same exact position and hence, are overlapping.
Java Code:
```public void mouseWheelMoved(MouseWheelEvent e)
{
double oldZoomPercent = Math.max(1, zoomPercent);
int notches = -e.getWheelRotation();
int increment = 50;
zoomPercent += increment * notches;
zoomPercent = Math.max(0, zoomPercent);

//mouse position
int x = e.getX();
int y = e.getY();

for (Node node: nodes)
{
int newWidth = (int) (node.defaultWidth * zoomPercent / 100);
int newHeight = (int) (node.defaultHeight * zoomPercent / 100);
node.setSize(newWidth, newHeight);

int nodeX = node.getLocation().x;
int nodeY = node.getLocation().y;

int dx = (int) ((nodeX - x) * zoomPercent / oldZoomPercent);
int dy = (int) ((nodeY - y) * zoomPercent / oldZoomPercent);

node.setLocation(x + dx, y + dy);
}
validate();
}```
edit: dx seems to get stuck at 0 once the nodes disappear. When they reappear dx is still at 0...
Last edited by robbie.26; 06-21-2011 at 03:42 AM.

4. Looks like the usual integer math 'problem'. I think you'll have to maintain a pair of double variables for the 'last computed location' of the node. I would also declare dx and dy as double, and cast the final incremented value in setLocation.
Java Code:
``` // x, dx, y, dy are of type double
// x and y are retained, possibly as custom fields of 'node'
x += dx;
y += dy;
node.setLocation((int) x, (int) y);```
db

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts
•