patternjavascriptMinor
Moving circles along a ray to eliminate location check
Viewed 0 times
raycircleseliminatemovingalongchecklocation
Problem
I have a function that moves circles out of the way of an expanding circle. It moves them along a ray from the center of the expanding circle through the center of the circle to move. This allows all surrounding circles to move without overlapping.
Here's a diagram to better explain this:
I expand the size of the red circle from 100px to 200px. I want to move all the blue circles out of the way by half the difference ( (200-100)/2 = 50px, in this example ) along the gray line (with the gray line being different for each blue circle).
jsFiddle
Mathematically, I'm sure there is a better way to do this, but I got this way working, and it's fine (although I'm not opposed hearing better solutions). But the one part I don't like about this function are the two lines:
What bugs me is that I'm having to do th
Here's a diagram to better explain this:
I expand the size of the red circle from 100px to 200px. I want to move all the blue circles out of the way by half the difference ( (200-100)/2 = 50px, in this example ) along the gray line (with the gray line being different for each blue circle).
jsFiddle
$this.siblings( ".circle" ).each( function() {
var $this = $( this ),
circle = $this.data(),
circleX = circle.left + circle.radius,
circleY = circle.top + circle.radius,
a = Math.abs( hoveredY - circleY ),
b = Math.abs( hoveredX - circleX ),
c = Math.sqrt( ( a*a ) + ( b*b ) ),
A = Math.acos( b / c ),
C = 90 * ( Math.PI / 180 ),
B = C - A,
sinA = Math.sin( A ),
sinB = Math.sin( B ),
sinC = Math.sin( C ),
newc = c + ( expand / 2 ),
newa = ( newc * sinA ) / sinC,
newb = ( newc * sinB ) / sinC,
newX = hoveredX + ( hoveredX > circleX ? -newb : newb ),
newY = hoveredY + ( hoveredY > circleY ? -newa : newa ),
left = newX - circle.radius,
top = newY - circle.radius;
$this.animate( {
"left": left,
"top": top
}, 75 );
});hoveredX and hoveredY are the left and top coordinates of the red circle and expand is how much the red circle is expanding in pixels.Mathematically, I'm sure there is a better way to do this, but I got this way working, and it's fine (although I'm not opposed hearing better solutions). But the one part I don't like about this function are the two lines:
newX = hoveredX + ( hoveredX > circleX ? -newb : newb ),
newY = hoveredY + ( hoveredY > circleY ? -newa : newa ),What bugs me is that I'm having to do th
Solution
I had two thoughts. One was ... You really only need an angle and a distance. The distance is the amount you expand and the angle can be derived from the x/y coordinates.
http://jsfiddle.net/uLu7v/38/
first you calculate the angle:
Then you calculate the distance they move:
then use jQuery's built in animate
Tada!
Edit:- A couple of improvements in the code not supplied in the question:
In
In
Makes it cleaner but not a real improvement otherwise, more of a preference.
In
http://jsfiddle.net/uLu7v/38/
first you calculate the angle:
var angle = Math.atan2(hoveredY - circleY, hoveredX - circleX);Then you calculate the distance they move:
var topMove = ((expand /2 ) * Math.sin(angle)); // sin for Y
var leftMove = ((expand /2 ) * Math.cos(angle)); // cos for Xthen use jQuery's built in animate
+=:$this.animate( {
"left": "-=" + leftMove + "px",
"top": "-=" + topMove + "px"
}, 75 );Tada!
Edit:- A couple of improvements in the code not supplied in the question:
In
function inCircle() change the return statement to return (mouseDistance <= radius); Using the ternary operator to return a boolean? ... I'm sure it used to return some other values right?In
$( ".circle" ).click( :if(!$( this ).data( "clicked" ) && inCircle( $( this ), event.pageX, event.pageY ) ) {
$( this ).data( "clicked", true );
setLocations( this, 200, event );
} else {
resetLocations();
$( this ).data( "clicked", false );
};Makes it cleaner but not a real improvement otherwise, more of a preference.
In
function setLocations() your circle parameter conflicts with the local circle variable. I would change the parameter to circleElement.Code Snippets
var angle = Math.atan2(hoveredY - circleY, hoveredX - circleX);var topMove = ((expand /2 ) * Math.sin(angle)); // sin for Y
var leftMove = ((expand /2 ) * Math.cos(angle)); // cos for X$this.animate( {
"left": "-=" + leftMove + "px",
"top": "-=" + topMove + "px"
}, 75 );if(!$( this ).data( "clicked" ) && inCircle( $( this ), event.pageX, event.pageY ) ) {
$( this ).data( "clicked", true );
setLocations( this, 200, event );
} else {
resetLocations();
$( this ).data( "clicked", false );
};Context
StackExchange Code Review Q#6807, answer score: 3
Revisions (0)
No revisions yet.