例如,如果我们在矩形-vendor-transform: rotate(40deg)
上设置<div>
css属性,则所有突然拖动和调整大小都会变得非常奇怪和有缺陷。
以下是一个简单的jQueryUI示例:http://jsfiddle.net/Ja4dY/1/
您会注意到,如果您在转换时拖动或调整该矩形的大小,它将向上或向下跳跃,并且光标将不会保留在正确的位置。在我的实际代码中,我使用自定义代码来调整大小和拖动,但是我遇到了同样的问题。
当然,“问题”是元素的方向会发生变化。所以左边可以是正确的,顶部是底部的,中间的东西和Javascript代码仍然处理每个方向,因为它将不转换。
所以,问题是:我们如何补偿转换 / 旋转的元素?
任何好的资源/书籍/博客也非常受欢迎。
答案 0 :(得分:14)
您可以使用getComputedStyle()获取应用于元素的当前变换矩阵。您可以使用它将当前鼠标位置转换为其在变换空间中的位置,并查看单击/拖动事件是否在元素边界和/或角落内。良好的资源:
http://www.useragentman.com/blog/2011/01/07/css3-matrix-transform-for-the-mathematically-challenged/
http://www.eleqtriq.com/2010/05/css-3d-matrix-transformations/
顺便说一下,正如您所经历的那样,这对代码来说并非易事。我们不得不为Sencha Animator做这件事,而且它是一头野兽。答案 1 :(得分:7)
问题在于,使用jQuery UI使元素可拖动的函数在很大程度上依赖于本机getBoundingClientRect()
函数来计算元素的位置等。
当应用CSS3变换(如旋转)时,jQuery UI中使用的getBoundingClientRect()
或等价jQuery offset()
函数的值不再按预期工作,并且鼠标指针的位置变得混乱,因为旋转后元素的大小突然出错。
要修复它,你需要添加一些重新计算值的辅助函数,并且有一个可用于jQuery UI的可拖动的猴子补丁。
很难说如何为自定义代码制作相同的补丁工作,但你可能不得不以某种方式将它集成到自定义函数中,而且你需要编写一些代码,而且更难提出了一些可以作为辅助功能的东西,用于自定义代码,但没有看到,并且要注意这涉及到进行这些计算,请参阅下面的代码:
function monkeyPatch_mouseStart() {
var oldFn = $.ui.draggable.prototype._mouseStart ;
$.ui.draggable.prototype._mouseStart = function(event) {
var o = this.options;
function getViewOffset(node) {
var x = 0, y = 0, win = node.ownerDocument.defaultView || window;
if (node) addOffset(node);
return { left: x, top: y };
function getStyle(node) {
return node.currentStyle || // IE
win.getComputedStyle(node, '');
}
function addOffset(node) {
var p = node.offsetParent, style, X, Y;
x += parseInt(node.offsetLeft, 10) || 0;
y += parseInt(node.offsetTop, 10) || 0;
if (p) {
x -= parseInt(p.scrollLeft, 10) || 0;
y -= parseInt(p.scrollTop, 10) || 0;
if (p.nodeType == 1) {
var parentStyle = getStyle(p)
, localName = p.localName
, parent = node.parentNode;
if (parentStyle.position != 'static') {
x += parseInt(parentStyle.borderLeftWidth, 10) || 0;
y += parseInt(parentStyle.borderTopWidth, 10) || 0;
if (localName == 'TABLE') {
x += parseInt(parentStyle.paddingLeft, 10) || 0;
y += parseInt(parentStyle.paddingTop, 10) || 0;
}
else if (localName == 'BODY') {
style = getStyle(node);
x += parseInt(style.marginLeft, 10) || 0;
y += parseInt(style.marginTop, 10) || 0;
}
}
else if (localName == 'BODY') {
x += parseInt(parentStyle.borderLeftWidth, 10) || 0;
y += parseInt(parentStyle.borderTopWidth, 10) || 0;
}
while (p != parent) {
x -= parseInt(parent.scrollLeft, 10) || 0;
y -= parseInt(parent.scrollTop, 10) || 0;
parent = parent.parentNode;
}
addOffset(p);
}
}
else {
if (node.localName == 'BODY') {
style = getStyle(node);
x += parseInt(style.borderLeftWidth, 10) || 0;
y += parseInt(style.borderTopWidth, 10) || 0;
var htmlStyle = getStyle(node.parentNode);
x -= parseInt(htmlStyle.paddingLeft, 10) || 0;
y -= parseInt(htmlStyle.paddingTop, 10) || 0;
}
if ((X = node.scrollLeft)) x += parseInt(X, 10) || 0;
if ((Y = node.scrollTop)) y += parseInt(Y, 10) || 0;
}
}
}
this.helper = this._createHelper(event);
this._cacheHelperProportions();
if($.ui.ddmanager)
$.ui.ddmanager.current = this;
this._cacheMargins();
this.cssPosition = this.helper.css("position");
this.scrollParent = this.helper.scrollParent();
this.offset = this.positionAbs = getViewOffset(this.element[0]);
this.offset = {
top: this.offset.top - this.margins.top,
left: this.offset.left - this.margins.left
};
$.extend(this.offset, {
click: {
left: event.pageX - this.offset.left,
top: event.pageY - this.offset.top
},
parent: this._getParentOffset(),
relative: this._getRelativeOffset()
});
this.originalPosition = this.position = this._generatePosition(event);
this.originalPageX = event.pageX;
this.originalPageY = event.pageY;
(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
if(o.containment)
this._setContainment();
if(this._trigger("start", event) === false) {
this._clear();
return false;
}
this._cacheHelperProportions();
if ($.ui.ddmanager && !o.dropBehaviour)
$.ui.ddmanager.prepareOffsets(this, event);
this.helper.addClass("ui-draggable-dragging");
this._mouseDrag(event, true);
if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event);
return true;
};
}
monkeyPatch_mouseStart();
这里有一个FIDDLE显示它正常工作,jQuery UI可拖动且可调整大小!
答案 2 :(得分:5)
我发现了这个...这是一个工作示例以及信息,演示和下载链接。
jquery-ui-rotation-using-css-transform - &gt; live-demo
他使用自己的图书馆,但如果你对这个主题感兴趣,你可以阅读并了解他是如何得到它的。
欢呼和祝你好运。GMO .-
顺便说一句,网络是俄语,但是google translate可以管理; - )
答案 3 :(得分:2)
这不是jQuery中的错误。只是它不受支持。如果你检查jQuery UI源代码,你会发现它没有使用变换矩阵来计算变换对象和页面之间的差异。
您的示例,可能每个jQ UI拖动实现都会遇到此问题导致JQ UI源代码中的2个方法(jquery.ui.draggable.js文件v1.8.23的314行)。由于在元素中心上进行旋转,因此计算的偏移与偏移的变化无关。
你必须计算出那个变化是什么。这是解决方法,快速而肮脏。我们的想法是检查转换元素的边界框有什么不同。
在此处检查示例http://jsfiddle.net/mjaric/9Nqrh/
忽略前两个旋转的部分,它们只是为了最小化代码行。第三个涉及用于计算差异的坐标系的平移。它将在执行转换后偏移左侧和顶部(注意它在滤波器中是第一个)。
如果您想避免前两个旋转滤镜,可以使用公式进行2D旋转:
X&#39; = x cos f - y sin f
ý&#39; = y cos f + x sin f
其中f是旋转角度,但它并不那么简单,还包括更多的代码行,你必须计算原始边界框的对角线角度,因为你需要左上角的初始角度x和y坐标与x轴(正面部分)进行比较。然后计算x-x&#39;的变化。和y-y&#39;。但我预测一些变化迹象和编码/调试的问题将花费更多的时间,而不是现在。很抱歉,但我确定你在阅读这篇文章后可以弄明白该怎么做。
答案 4 :(得分:1)
如果我们覆盖cursorAt:
,看起来会更好$("#foo").mousedown(function (e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
console.log(x);
$("#foo").draggable("option", "cursorAt", {left: x, top:y});
});
更新了小提琴:http://jsfiddle.net/johnkoer/Ja4dY/8/
答案 5 :(得分:0)
你说你对JQuery解决方案不感兴趣,
一个解决方案是;
我建议您编写自己的拖动和调整大小功能。您可以 处理旋转对象的大小调整和拖动,以使其顶部和左侧添加该度数的正弦和余弦。
另一个解决方案是;
您可以使用Raphael JS之类的库来创建要转换的对象, 拖动并调整大小。 Raphael JS使用svg!
另一个解决方案是;
如果您不想使用像Raphael JS这样的库,可以直接将SVG与JQuery一起使用
现在不能写更多细节,我明天会扩展这个解决方案。
现在希望这些帮助。
答案 6 :(得分:0)
这确实是jQuery中的一个错误。一个简单的解决方法是:使用容器div
包围可调整大小的div
。将.draggable()
设置为外部div
,将.resizable()
设置为内部div
。这似乎在运行在Ubuntu上的Chromium中运行良好。 See Fiddle
我为外部div
着色,让您了解幕后发生的事情。