46

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

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

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

好吧,“问题”当然是元素的方向会改变。所以左可以是右,上到下,中间有一些东西,Javascript代码仍然处理每个方向,因为它不会被转换

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

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

4

7 回答 7

16

您可以使用 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 做这件事,它是一头野兽。

于 2012-08-18T00:27:16.533 回答
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 的可拖动和可调整大小按预期工作!

于 2012-08-20T20:40:37.737 回答
5

我找到了这个......这是一个工作示例加上信息、演示和下载链接。

jquery-ui-rotation-using-css-transform -> live-demo

他使用他自己的图书馆,但如果你对这个主题感兴趣,你可以阅读并了解他是如何获得它的。

欢呼,祝你好运。

转基因-

顺便说一句,网络是俄语的,但你可以用谷歌翻译来管理 ;-)

于 2012-08-20T07:12:07.887 回答
3

它不是 jQuery 中的错误。只是不支持。如果您检查 jQuery UI 源代码,您会发现它不使用转换矩阵来计算转换后的对象和页面之间的差异。

您的示例以及可能每个 jQ UI 拖动实现都因 JQ UI 源代码中的 2 个方法(大约 314 行 jquery.ui.draggable.js 文件 v1.8.23 )而受到此问题的影响。计算的偏移量与偏移量的变化无关,因为旋转是在元素中心完成的。

你必须计算出什么是变化。这是解决方法,快速而肮脏。这个想法是检查转换元素的边界框有什么不同。

在此处查看示例http://jsfiddle.net/mjaric/9Nqrh/

忽略前两次旋转的部分,它们只是为了最小化代码行。第三涉及计算差异的坐标系转换。执行平移后,它将向左和向上偏移(注意它在过滤器中首先)。

如果您想避免前两个旋转过滤器,您可以使用 2D 旋转公式编写代码:

x' = x cos f - y sin f

y' = y cos f + x sin f

其中 f 是旋转角度,但它不是那么简单,还包含更多代码行,您必须计算原始边界框的对角线角度,因为您需要 x 和 y 坐标与 x 进行比较的左上角的初始角度轴(正部分)。然后计算 xx' 和 yy' 的变化。但我预测一些与变化迹象有关的问题,编码/调试将需要比我现在更多的时间。抱歉,但我相信您在阅读这篇文章后可以弄清楚该怎么做。

于 2012-08-24T00:00:52.390 回答
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/

​</p>

于 2012-08-17T15:08:31.807 回答
0

你说你对 JQuery 解决方案不感兴趣,

  • 一种解决方案是;

    我建议您编写自己的拖动和调整大小功能。您可以处理旋转对象的大小调整和拖动,以将其顶部和左侧添加该度数的正弦和余弦。

  • 另一种解决方案是;

    您可以使用 Raphael JS 等库来创建对象以进行变换、拖动和调整大小。Raphael JS 使用 svg!

    有关 Raphael JS 的更多信息

  • 另一个解决方案是;

    如果不想使用 Raphael JS 之类的库,可以直接使用 SVG 和 JQuery

    有关 SVG 的更多信息

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

现在希望这些帮助。

于 2012-08-20T09:25:58.973 回答
0

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

我已经为外部着色div,让您了解引擎盖下发生的事情。

于 2012-08-23T17:09:00.043 回答