>我在外部div中有一个内部div。内部div 可拖动,外部div 旋转 40 度。这是一个测试用例。在实际情况下,它可以是任何角度。还有另一个称为点的div,其位置如图所示。(我来自闪光背景。在 Flash 中,如果我拖动内部div,即使它包含在外部旋转的div 中,它也会跟随鼠标。但是在 HTML 中,内部div 不会跟随鼠标,因为它可以从小提琴中看到。我希望div "点"完全跟随鼠标。这可能吗。我试图使用三角函数来工作,但无法让它工作。
http://jsfiddle.net/bobbyfrancisjoseph/kB4ra/8/
这是我解决这个问题的方法。
http://jsfiddle.net/2X9sT/21/
我把点放在旋转的div 之外。这样我就可以放心,拖动事件将产生正常行为(不会向奇怪的方向跳跃)。我使用可拖动处理程序将点附加到鼠标光标。
在拖动事件中,我转换拖动偏移量以反映新值。这是通过围绕外部div 中心的偏移量沿与旋转角度相反的方向旋转来完成的。
我测试了它,它似乎可以在IE9,Firefox和Chrome中工作。
您可以尝试不同的角度值,它应该可以正常工作。
我还修改了 HTML,以便可以将相同的逻辑应用于页面中的多个div。
编辑:
我更新了脚本以考虑包含行为以及评论中建议的级联旋转。
我也在使outer
div 可拖动到另一个div 中。现在它几乎在工作。我只需要能够更新拖动div 的中心即可修复拖动行为。
尝试拖动红色div。
http://jsfiddle.net/mohdali/kETcE/39/
在工作,所以我不能为你做这项工作,但我可以解释解决问题的最简洁方法背后的数学(可能不是最简单的解决方案,但与其他一些黑客不同,一旦你实现它,它就会更加灵活)。
首先,您必须意识到您正在使用的旋转插件正在对您的元素(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)
),例如可以使用此库(或您的数学书:P)来完成。
最后,您需要执行逆矩阵时间(使用我之前提到的矩阵库)一个翻译矩阵(使用此工具找出它们的外观(平移是沿 x 和 y 轴的运动,有点像相对定位元素上的左和顶部,但硬件加速和矩阵转换 css 属性的一部分))这将为您提供一个新矩阵,您可以将其应用于您的子元素在与父元素相同的轴上为您提供平移。
现在,你可以通过使用 left
、top
和手动三角函数1 来大大简化这一点,仅用于特定的旋转(完全绕过对逆矩阵甚至矩阵的全部需求),但这有一个明显的缺点,即它仅适用于正常旋转,并且需要根据它使用的每种特定情况进行更改。
哦,如果你现在认为flash要容易得多,相信我,轴在HTML/CSS中的旋转方式很有意义,如果你想要像flash一样的行为,请使用这个库。
1 这就是穆罕默德·阿里在他的答案中所做的,例如(他的jsFiddle中的transformOffset
函数)。
免责声明,自从我做这些事情以来已经有一段时间了,我对矩阵的理解从来都不是很好,所以如果你看到任何错误,请指出/修复它们。
仅对于 Webkit,webkitConvertPointFromPageToNode
函数处理缺失的行为:
var point = webkitConvertPointFromPageToNode(
document.getElementById("outer"),
new WebKitPoint(event.pageX, event.pageY)
);
js小提琴: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;
}
这样做的缺点是当鼠标在目标元素之外时不起作用,但是应该可以将其覆盖的区域扩展任意量(尽管很难保证无论多大,它都会覆盖整个窗口)。
js小提琴:http://jsfiddle.net/kB4ra/122/
这可以通过添加鼠标移动事件来扩展到应用于 #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/
,如果你不旋转div,div就会完全跟随鼠标。这可能是插件的问题。也许您可以相应地模拟可拖动功能?
这基本上可以满足您的需求,尽管它有问题。绑定拖动事件处理程序,截获 ui 对象并将其修改为使用父元素的偏移量 X 和 Y。所有的X,Y,顶部,左侧等都在这些对象中。我会尽量给你一个更好的例子,今天当我有更多的时间的时候。祝你好运!
http://jsfiddle.net/kB4ra/107/
你的jquery库的问题,或者你可以通过分配内部div和外部div的z顺序值来检查这一点,确保你给内部div提供更高的数字。