旋转后获取相对于父级div的x和y坐标

7

以下是一道编程题,我希望在数学课上更加专注听讲:

http://i.imgur.com/noKxg.jpg

我有一个大容器div,里面有几个旋转的内容div。
我的目标是通过在视口中移动主Div来在子Div之间进行动画。如果只基于简单的x/y(top/left)计算,这将非常容易,但当涉及旋转时,我的数学就会崩溃。
我尝试过一些方法,但还没有真正解决它。
这是我迄今为止结果的简化版本,请随意调整:

http://jsfiddle.net/dXKJH/3/

我真的想不出来这个问题的答案!

[编辑]

我选择这个解决方案,因为我已经找到了一种方法让旋转插件与MSIE6+兼容。

但是我必须说,虽然我遵循所有数学函数并且它们看起来很干净,但结果并不完全精确。这是否与PI计算有关?似乎随着盒子变得更大和间隔更大,它们越不可能与左上角对齐?很奇怪。

还有,如果角度超过45度,有谁能提醒我需要做什么三角函数吗?我无法找到一个参考资料,我记得这是多年前在数学课上学到的,当时有四个象限或其他什么...唉,我希望我当时能更加注意.. :-)

非常感谢迄今为止的所有帮助!!


1
Math.sin/cos需要弧度而不是角度。 - pimvdb
3个回答

2

这是我所做到的...我将所有内容缩小,以便更好地查看div的位置,并为此添加了滚动条。

重要点:

  • Math.sin / Math.cos需要弧度制而非角度制
  • CSS围绕元素的中点旋转,而不是(0, 0)(这适用于主要的div和盒子div;首先将-width/2-height/2翻译,然后旋转,最后再翻译回来)
  • 使用parseInt(x,10)确保您正在使用基数10

最终代码:http://jsfiddle.net/pimvdb/dXKJH/10/。由于.css在旋转元素时存在一些问题,因此此解决方案还需要在HTML中硬编码位置和旋转。

$("#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)
}

1

看起来你想要模仿苹果的iPhone网站: http://www.apple.com/iphone/。我在这里模拟了这个技巧:

http://jsfiddle.net/Yw9SK/2/ (使用Webkit转换)

这并不需要太多的数学知识,不要过度设计。你只需要取消子<div>的旋转,并调整它们的宽度/高度和与容器<div>的偏移量。

这是如何做到的:

container width: 500  height: 500  rotation: 0       top: 0    left: 0
child     width: 90   height: 90   rotation: 120deg  top: 330  left: 0


  1. 为确保旋转正确,容器必须获得子元素的负旋转:

    子元素旋转:120度  --> 容器旋转:-120度
    
  2. 为使子元素在视图中居中,我们需要从容器宽度中减去其宽度,除以2(保持居中),然后再减去任何偏移量。高度也是同样的道理:

    宽度                                   高度
     500    (容器宽度)                 500    (容器高度)
    - 60    (子元素宽度)                - 40    (子元素高度)
    ----                                     ----
     440                                      460
       /    (除以2                        /    (除以2
       2     保持居中)               2     保持居中)
    ----                                     ----
     220                                      230
    -  0    (减去左侧偏移量)      -330    (减去顶部偏移量)
    ----                                     ----
     220    translateX                       -100    translateY
    


因为“stage”位于容器顶部中心,所以新的变换也将在“stage”内居中显示。(相对于正方形而言,这对矩形来说并不难实现。)因此,我们要应用于容器<div>的变换是:

transform: rotate(-120eg) translateX(220px) translateY(-100px)

对于其他子元素,重复以上步骤并相应地进行过渡。


这个JSFiddle只是一个实现的例子,它并不是一个非常好的实现。更优化的解决方案应该有一个transition-delay或animation-delay(而不是setInterval),然后监听'transitionEnd'或'animationEnd'事件。

我强烈建议不要尝试在程序运行时动态计算新的位置和旋转角度(虽然你可以,在JS中从.style属性获取这些值)。我建议预先定义需要的平移/旋转(如我的示例所示,但它们应该在CSS中),然后按正确的顺序将它们应用于容器。这将确保过渡快速而平滑。


谢谢,是的,类似但不是这个 iPhone 的东西,更像是这种导航:http://www.zeitgeistbot.com/ - Alex
喜欢使用 WebKit 转换效果,这可能是未来的趋势,但我需要它具有尽可能的跨兼容性。 - Alex
检查页面的代码,他们实际上正在使用jQuery的浏览器特定变换 :) 他们还将所有正确的X/Y位置保留在数组中,并在单击指定链接后应用它们... 正如我的示例所演示的那样。 - skyline3000

1

我想提出一种不同的方法:

  1. 从起始状态移动到 div-2(使用 left/top 样式重新定位 Main Div)
  2. 将 Main Div 的 transform-origin 设置为视图中心(也是 div-2 的中心)
  3. 将 Main Div 旋转与 div-2 相反的角度(div-2 应正确居中)
  4. 将 Main Div 旋转回 0 度。
  5. 移动到 div-3
  6. 将 Main Div 的 transform-origin 设置为视图中心(也是 div-3 的中心)
  7. 将 Main Div 旋转与 div-3 相反的角度(div-3 应正确居中)
  8. 重复上述步骤

这可能更容易,结果会产生较少复杂(更易维护)的代码。请注意,移动和旋转可以进行动画处理。此外,如果您使用翻译而不是 left/top 样式,则由于 transform-origin 更改,此解决方案将变得更加复杂。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接