Javascript 拖航及;调整CSS转换元素的大小
例如,如果我们在矩形上设置了一个Javascript 拖航及;调整CSS转换元素的大小,javascript,jquery,css,transform,Javascript,Jquery,Css,Transform,例如,如果我们在矩形上设置了一个-vendor transform:rotate(40deg)css属性,那么突然之间拖动和调整大小就会变得非常奇怪和有缺陷 下面是一个简单jQueryUI的示例: 您会注意到,如果在变换时拖动或调整该矩形的大小,它将向上或向下跳跃,光标将不会保持在正确的位置。在我的真实代码中,我使用自定义代码来调整大小和拖动,但是我遇到了相同的问题 当然,问题是元素的方向会改变。所以左可以是右,上可以是下,中间有些东西,Javascript代码仍然处理每个方向,因为它不会被转换
-vendor transform:rotate(40deg)
css属性,那么突然之间拖动和调整大小就会变得非常奇怪和有缺陷
下面是一个简单jQueryUI的示例:
您会注意到,如果在变换时拖动或调整该矩形的大小,它将向上或向下跳跃,光标将不会保持在正确的位置。在我的真实代码中,我使用自定义代码来调整大小和拖动,但是我遇到了相同的问题
当然,问题是元素的方向会改变。所以左可以是右,上可以是下,中间有些东西,Javascript代码仍然处理每个方向,因为它不会被转换
因此,问题是:我们如何补偿变换/旋转的元素?
任何好的资源/书籍/博客都是非常受欢迎的。如果我们覆盖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});
});
更新小提琴:
可以使用getComputedStyle()获取应用于元素的当前转换矩阵。可以使用此选项将当前鼠标位置转换为其在转换空间中的位置,并查看单击/拖动事件是否位于图元边界和/或角点内。这方面的良好资源:
顺便说一句,正如您所经历的那样,这对于代码来说是非常重要的。我们必须为Sencha动画师做这件事,那是一头野兽。我发现了这个。。。这是一个工作的例子加上信息,演示和下载链接 -> 他使用自己的图书馆,但如果你对这门学科感兴趣,你可以阅读并了解他是如何得到它的 干杯,祝你好运 转基因生物-
顺便说一句,网络是俄语的,但是你可以用俄语来管理;-) 您当时说您对JQuery解决方案不感兴趣
- 一个解决办法是 我建议您编写自己的拖动和调整大小功能。你可以 处理旋转对象的大小调整和拖动,以添加其顶部和左侧的正弦和余弦
- 另一个解决办法是 您可以使用Raphael JS之类的库来创建要转换的对象, 拖动并调整大小。Raphael JS使用svg
- 另一个解决办法是 如果您不想使用Raphael JS这样的库,可以直接将SVG与JQuery结合使用
现在希望这些帮助。问题是,使元素可拖动的函数,无论是否使用jQuery UI,都严重依赖本机的
getBoundingClientRect()
函数来确定元素的位置等
当应用CSS3变换(如旋转)时,jQuery UI中使用的getBoundingClientRect()
或等价jQueryoffset()
函数的值不再像预期的那样工作,并且鼠标指针的位置变得混乱,因为旋转后元素的大小突然错误
要修复它,您需要添加某种帮助函数来重新计算值,并且有一个猴子补丁可用于此,它与jqueryui的draggable一起工作
很难说如何使同一个补丁对自定义代码起作用,但您可能必须以某种方式将其集成到自定义函数中,这将需要您进行一些编码,而且更难想出一些可以作为自定义代码的辅助函数的东西,请注意,进行这些计算相当复杂,请参见下面的代码:
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();
这是一个显示它与jQueryUI的可拖动和可调整大小一样工作的示例 实际上,这似乎是jQuery中的一个bug。一个简单的解决方法是:用容器
div
包围可调整大小的div
。将.draggable()
设置为外部div
,将.resizeable()
设置为内部div
。这似乎在Ubuntu上运行的Chromium中运行良好
我给外部的
div上色,让您了解引擎盖下发生了什么。这不是jQuery中的bug。根本不支持它。若您检查jQueryUI源代码,就会发现它并没有使用转换矩阵来计算转换后的对象和页面之间的差异
您的示例,以及可能每个JQUIDrag实现都会遇到这个问题,因为JQUI源代码中有两个方法(jquery.UI.draggable.js文件v1.8.23的314行左右)。计算的偏移量和偏移量的变化无关,因为旋转是在图元的中心进行的
你必须计算出那是什么变化。这是一个快速而肮脏的解决办法。其思想是检查转换元素的边界框中的差异
在这里检查样品
忽略前两个旋转的部分,它们只是为了最小化代码行。第三个涉及坐标系的平移,用于计算差分。执行平移后,它将向左和向上偏移(注意,它是过滤器中的第一个)
如果要避免前两个旋转过滤器,可以使用二维旋转公式生成代码:
x'=x cos f-y sin f
y'=y cos f+x sin f
其中f是旋转角度,但它不是那么简单,还包括更多代码行,您必须计算原始边界框的对角线角度,因为您需要x和y坐标与x轴(正部分)比较的左上角的初始角度。然后计算x-x'和y-y'的变化。但我预测一些有变化迹象的问题,编码/调试将比现在花费更多的时间。对此我很抱歉,但我相信你在阅读完这篇文章后会明白该怎么办。看来,这并非只有你一个人。这里有一个jquery错误:@JohnKoerner:的确如此。但我对jQuery(UI)解决方案并不特别感兴趣。