Get relative x and y div after rotation
So here's one which I wished I paid more attention in maths class for:
http://i.imgur.com/noKxg.jpg
I have a big container div and inside of this I have a few content divs which are rotated.
What I'm trying to do is animate between the child divs by moving the Main Div around in the viewport. This would be really easy if I was just doing it based upon simple x/y (top/left) calculations, however when there's rotation involved, my maths just breaks down.
I have tried a few things and haven't really cracked it.
Here's a simplified version of my results sort far, please feel free to fiddle:
http://jsfiddle.net/dXKJH/3/
I really can't figure this out!
[EDIT]
I'm going with this solution as a preference simply because I've already worked a way of making the rotate plugin work with MSIE6+.
Howver I have to say that although I follow all the math functions and they seem clean the results are not pixel perfect is this something to do with a PI calculation? It seems that the bigger and more spaced out i make the boxes the less likely they are to match up to the top left? Oddness.
Also can anyone remind me of what trig thing I need to do if the angle is more than 45 degress, I can't find a reference I remember this from maths class years ago when there were 4 quadrants or something... rr how i wish i paid more attention.. :-)
Thank you hugely for all the help so far!!
Well, this is how far I got... I made everything smaller so as to see better where the div
s end up, and also added scrollbars for this reason.
Important points:
Math.sin
/ Math.cos
require radians, not degrees (0, 0)
(this applies to both the main div
and the box div
s; first translate -width / 2
, -height / 2
, rotate, and then translate back) parseInt(x, 10)
to make sure you're using base 10 Final code: http://jsfiddle.net/pimvdb/dXKJH/10/. This solution needs hardcoded positions and rotations in HTML as well since .css
was having some quirks with rotated elements.
$("#div-1").rotate("-10deg");
$("#div-2").rotate("10deg");
$("#div-3").rotate("15deg");
$("#div-4").rotate("75deg");
$("#main").click(function() {
console.log($('body').scrollLeft(), $('body').scrollTop());
});
$("a").click(function(e){
goTo($(this).attr("id").substring(4,5));
return false;
});
function n(x) {
return parseInt(x, 10);
}
function sin(x) {
return Math.sin(x / 180 * Math.PI);
}
function cos(x) {
return Math.cos(x / 180 * Math.PI);
}
function rotate(x, y, a) {
var x2 = cos(a) * x - sin(a) * y;
var y2 = sin(a) * x + cos(a) * y;
return [x2, y2];
}
var offsets = [null,
[0,100,-10],
[100,200, 10],
[300,100, 15],
[400,100, 75]].map(function(v) {
if(!v) return v;
var rotated = rotate(-50, -50, v[2]);
rotated[0] += v[0] + 50;
rotated[1] += v[1] + 50;
return rotated.concat(v[2]);
});
function goTo(num){
var obj = $("#div-" + num);
var angle = -n(obj.rotate());
var pointX = offsets[num][0] - 500;
var pointY = offsets[num][1] - 500;
var rotated = rotate(pointX, pointY, angle);
var newX = rotated[0] + 500;
var newY = rotated[1] + 500;
$("#main").animate({rotate: angle + "deg"}, 1000);
$("body").animate({scrollLeft: newX,
scrollTop: newY}, 1000)
}
I'd like to suggest a different approach:
This may be easier and result in less complex (more maintainable) code. Note that the moves and rotates could be animated. Also, if you use translations instead of left/top styles this solution will be far more complicated due to the transform-origin changes.
It looks like you are trying to mimic Apple's iPhone website: http://www.apple.com/iphone/. I've emulated this technique here:
http://jsfiddle.net/Yw9SK/2/ (uses Webkit transitions)
This really doesn't require much math, don't over-engineer it. You just need to cancel the rotation of the child <div>
s and adjust for their width/height and offset from the container <div>
.
Here's how to do it:
container width: 500 height: 500 rotation: 0 top: 0 left: 0
child width: 90 height: 90 rotation: 120deg top: 330 left: 0
To ensure the rotation is correct, the container must get the negative rotation of the child:
child rotation: 120deg --> container rotation: -120deg
To have the child centered in the view, we need to subtract its width from the container width, divide by 2 (to keep it centered), and then subtract any offsets. The same thing happens for height:
Width Height
500 (container width) 500 (container height)
- 60 (child width) - 40 (child height)
---- ----
440 460
/ (divide by 2 / (divide by 2
2 to keep it centered) 2 to keep it centered)
---- ----
220 230
- 0 (subtract the left: offset) -330 (subtract the top: offset)
---- ----
220 translateX -100 translateY
Because the "stage" is centered on top of the container, the new transform will also be centered within the stage. (It's not much harder to make this happen for a rectangle compared to a square.) Thus our transform to be applied to the container <div>
is:
transform: rotate(-120eg) translateX(220px) translateY(-100px)
Rinse and repeat for the other child elements and transition through them accordingly.
This JSFiddle is just an example of how to accomplish this. It is not a very well-designed implantation. A more optimal solution would have a transition-delay or animation-delay (instead of setInterval) and then listen for the 'transitionEnd' or 'animationEnd' events.
I would definitely recommend NOT trying to calculate the new positions and rotations programmatically on the fly (although you can, and then you just have to get those values from the .style
property in JS). I would recommend having the translations/rotations you need pre-defined upfront (as seen in my example, though they should be in CSS) and simply apply them in correct order to the container. This will ensure the transitions are fast and smooth.
下一篇: 旋转后获取相对x和y div