拖拽&调整CSS转换元素的大小

时间:2012-08-17 14:45:38

标签: javascript jquery css css3 transform

例如,如果我们在矩形-vendor-transform: rotate(40deg)上设置<div> css属性,则所有突然拖动和调整大小都会变得非常奇怪和有缺陷。

以下是一个简单的jQueryUI示例:http://jsfiddle.net/Ja4dY/1/

您会注意到,如果您在转换时拖动或调整该矩形的大小,它将向上或向下跳跃,并且光标将不会保留在正确的位置。在我的实际代码中,我使用自定义代码来调整大小和拖动,但是我遇到了同样的问题。

当然,“问题”是元素的方向会发生变化。所以左边可以是正确的,顶部是底部的,中间的东西和Javascript代码仍然处理每个方向,因为它将转换。

所以,问题是:我们如何补偿转换 / 旋转的元素?

任何好的资源/书籍/博客也非常受欢迎。

7 个答案:

答案 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!

    For more information about Raphael JS

  • 另一个解决方案是;

    如果您不想使用像Raphael JS这样的库,可以直接将SVG与JQuery一起使用

    For more information about SVG

现在不能写更多细节,我明天会扩展这个解决方案。

现在希望这些帮助。

答案 6 :(得分:0)

这确实是jQuery中的一个错误。一个简单的解决方法是:使用容器div包围可调整大小的div。将.draggable()设置为外部div,将.resizable()设置为内部div。这似乎在运行在Ubuntu上的Chromium中运行良好。 See Fiddle

我为外部div着色,让您了解幕后发生的事情。