在使用jQuery UI拖动的情况下,外部旋转div内的内部div不会跟随鼠标

时间:2012-05-30 06:12:59

标签: javascript jquery html jquery-ui graphics

我在外部div中有一个内部div。内部div是可拖动的,外部旋转40度。这是一个测试用例。在实际情况中,它可以是任何角度。还有另一个叫做点的div,它的位置如图所示。 (我来自flash背景。在Flash中,如果我要拖动内部div,它将跟随鼠标,即使它包含在外部旋转div中。)但在HTML中,内部div不会跟随鼠标,因为它可以看到来自小提琴。我希望div'点'完全跟随鼠标。这可能吗。我尝试使用trignometry工作,但无法让它工作。

http://jsfiddle.net/bobbyfrancisjoseph/kB4ra/8/

6 个答案:

答案 0 :(得分:9)

以下是解决此问题的方法。

http://jsfiddle.net/2X9sT/21/

我把点放在旋转的div之外。这样我就可以确定拖拽事件会产生正常的行为(不会在奇怪的方向上跳跃)。我使用draggable处理程序将点附加到鼠标光标。

在拖动事件中,我转换拖动偏移以反映新值。这是通过在旋转角度的相反方向上围绕外部div中心旋转偏移来完成的。

我测试了它,它似乎在IE9,Firefox和Chrome中工作。

您可以尝试不同的角度值,它应该可以正常工作。

我还修改了HTML,因此可以将相同的逻辑应用于页面中的多个div。

修改

我更新了脚本以考虑包含行为以及注释中建议的级联旋转。

我也在使outer div在另一个div中可拖动时失效。现在它几乎正常工作。我只需要能够更新拖动div的中心来修复拖动行为。

尝试拖动红色div。

http://jsfiddle.net/mohdali/kETcE/39/

答案 1 :(得分:3)

我现在在工作,所以我不能为你做这份工作,但我可以解释最新解决问题的方法背后的数学(可能不是最简单的解决方案,但不像其他一些黑客一旦你实现它就很多更灵活。)

首先,您必须意识到您正在使用的旋转插件正在对您的元素(transform: rotate(30deg))应用转换,而转换又会被您的浏览器(matrix(0.8660254037844387, 0.49999999999999994, -0.49999999999999994, 0.8660254037844387, 0, 0))更改为矩阵。 其次,有必要了解通过旋转元素,子元素的轴完全旋转并完全旋转(在查找很长时间之后,没有任何真正的技巧可以绕过它,因此,唯一的方法是将孩子带出父母,因为其他一些答案建议,但我认为这不是你申请中的一个选项。

现在,我们需要做的是取消父母的原始矩阵,这是一个两步过程。首先,我们需要使用以下代码中的代码找到矩阵:

var styles = window.getComputedStyle(el, null);

var matrix = styles.getPropertyValue("-webkit-transform") ||
             styles.getPropertyValue("-moz-transform") ||
             styles.getPropertyValue("-ms-transform") ||
             styles.getPropertyValue("-o-transform") ||
             styles.getPropertyValue("transform");

接下来,矩阵将是一个如上所示的字符串,您需要将其解析为可以使用的数组(有jquery插件可以执行此操作)。完成后,您需要使用矩阵的倒数(在您的示例中可以归结为rotate(-30deg)),这可以使用例如this library(或您的数学书:P)来完成。

最后你需要做反矩阵时间(使用我前面提到的矩阵库)一个平移矩阵(使用this tool来计算出它们的外观(平移是沿着x和y轴的运动,a在相对定位的元素上有点像left和top,但是硬件加速并且矩阵变换css属性的一部分))这将为您提供一个新的矩阵,您可以将其应用于您的子元素,使您在与您的轴相同的轴上进行平移父元素。

现在,你可以通过lefttop和手动三角法 1 进行专门的旋转来大大简化这一过程(绕过对逆矩阵的整个需求甚至完全矩阵),但这有一个明显的缺点,它正常旋转工作,需要根据它使用的每个特定情况进行更改。

哦,如果你现在认为 flash 要容易得多,请相信我,在HTML / CSS中旋转轴的方式很有意义if you want flash like behavior use this library


1这就是Mohamed Ali在他的答案中所做的事情(his jsFiddle中的transformOffset函数)。


免责声明,我已经有一段时间了,因为我一直在做这些事情而且我对矩阵的理解从来都不是很好,所以如果你发现任何错误,请指出它们/解决它们。

答案 2 :(得分:2)

仅对于Webkit,webkitConvertPointFromPageToNode函数处理缺少的行为:

   var point = webkitConvertPointFromPageToNode(
       document.getElementById("outer"),
       new WebKitPoint(event.pageX, event.pageY)
   );

jsFiddle:http://jsfiddle.net/kB4ra/108/

要覆盖其他浏览器,您可以使用此StackOverflow答案中描述的方法:https://stackoverflow.com/a/6994825/638544

function coords(event, element) {
  function a(width) {
    var l = 0, r = 200;
    while (r - l > 0.0001) {
      var mid = (r + l) / 2;
      var a = document.createElement('div');
      a.style.cssText = 'position: absolute;left:0;top:0;background: red;z-index: 1000;';
      a.style[width ? 'width' : 'height'] = mid.toFixed(3) + '%';
      a.style[width ? 'height' : 'width'] = '100%';
      element.appendChild(a);
      var x = document.elementFromPoint(event.clientX, event.clientY);
      element.removeChild(a);
      if (x === a) {
        r = mid;
      } else {
        if (r === 200) {
          return null;
        }
        l = mid;
      }
    }
    return mid;
  }
    var l = a(true),
        r = a(false);
    return (l && r) ? {
        x: l,
        y: r
    } : null;
}

这样做的缺点是当鼠标位于目标元素之外时不能正常工作,但应该可以将它覆盖的区域扩展任意数量(尽管很难保证它覆盖整个窗口)无论多大)。

jsFiddle:http://jsfiddle.net/kB4ra/122/

这可以扩展为通过添加mousemove事件来应用于#point:

$('#outer').mousemove(function(event){
   var point = convertCoordinates(event, $("#outer"));

    $("#point").css({left: point.x+1, top: point.y+1});          
});

请注意,我将#point的x和y坐标调整为1px,以防止它直接位于鼠标下方;如果我不这样做,那么它会阻止拖动#inner。另一种解决方法是向#point添加处理程序以检测鼠标事件,并将它们传递给#point下面的任何元素(和stopPropagation,以便它们不会在较大的页面元素上运行两次)。

jsFiddle:http://jsfiddle.net/kB4ra/123/

答案 3 :(得分:0)

在我看来,如果你不旋转div,div就会紧跟鼠标。 这可能是插件的一个问题。你可以正确地模拟可拖动的功能吗?

答案 4 :(得分:0)

这基本上可以满足您的需求,尽管它有缺陷。绑定拖动事件处理程序,拦截ui对象并修改它以使用父元素的偏移量X和Y.所有X,Y,顶部,左侧等都在这些对象中。当我得到更多时间的时候,我会尽力让你有一个更好的例子。祝你好运!

http://jsfiddle.net/kB4ra/107/

答案 5 :(得分:-1)

可能是你的jquery库的问题,或者你可以通过分配内部div和外部div的z顺序值来检查这一点,确保你给内部div更高的数字。