javascript-拖动CSS转换元素并调整其大小

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

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

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

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

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

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

jAndy asked 2020-08-09T00:08:44Z
7个解决方案
14 votes

您可以使用getComputedStyle()获得应用于元素的当前转换矩阵。 您可以使用它来将当前鼠标位置转换为它在转换空间中的位置,并查看单击/拖动事件是否在元素边界和/或角内。 好的资源:

[HTTP://呜呜呜.user agent man.com/blog/2011/01/07/CSS3-matrix-transform-佛如-他和-mathematically-challenged/]

[HTTP://呜呜呜.饿了其他日期.com/2010/05/CSS-3的-matrix-transformations/]

顺便说一句,正如您所经历的那样,这对于代码来说并非易事。 我们必须为Sencha Animator做这件事,那真是野兽。

Michael Mullany answered 2020-08-09T00:09:03Z
7 votes

问题在于使元素可拖动的函数(无论是否使用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可以正常工作!

adeneo answered 2020-08-09T00:09:42Z
5 votes

我发现了...这是一个工作示例,还提供信息,演示和下载链接。

jQuery的UI旋转使用CSS转换->现场演示

他使用自己的图书馆,但是,如果您对该主题感兴趣,可以阅读和学习他的用法。

欢呼,祝你好运。

Gmo.-

两者之间,网络为俄语,但使用Google翻译,您可以管理;-)

gmo answered 2020-08-09T00:10:24Z
2 votes

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

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

您必须计算出那是什么变化。 这是解决方法,既快速又肮脏。 这个想法是要检查变换后的元素的边界框有什么区别。

在此处检查示例[http://jsfiddle.net/mjaric/9Nqrh/]

忽略前两次旋转的零件,只是为了最大程度地减少代码行。 第三部分涉及转换坐标系以计算出的差异。 执行翻译后,它将向左和向左偏移(请注意,它是过滤器中的第一个)。

如果要避免使用前两个旋转滤镜,则可以使用2D旋转公式编写代码:

x'= x cos f-y sin f

y'= y cos f + x sin f

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

Milan Jaric answered 2020-08-09T00:11:21Z
1 votes

如果我们重写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/]

John Koerner answered 2020-08-09T00:11:50Z
0 votes

您说您那时对JQuery解决方案不感兴趣,

  • 一种解决方案是;

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

  • 另一个解决方案是;

    您可以使用Raphael JS之类的库来创建要转换的对象,拖动并调整大小。 Raphael JS使用svg!

    有关Raphael JS的更多信息

  • 另一个解决方案是;

    如果您不想使用Raphael JS之类的库,则可以直接将SVG与JQuery一起使用

    有关SVG的更多信息

现在无法编写更多详细信息,我明天将扩展此解决方案。

希望这些帮助暂时。

totten answered 2020-08-09T00:12:54Z
0 votes

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

我为外部div上色,以使您了解引擎盖下正在发生的事情。

Jasper de Vries answered 2020-08-09T00:13:19Z
translate from https://stackoverflow.com:/questions/12007971/dragging-resizing-css-transformed-elements