在缩放的div上拖动元素

11

我尝试使用jQuery内置的可拖动功能以及自定义拖动函数,但都没有成功。两种方法都有各自的问题,我将尝试概述一下。

基本上,我想允许拖动一个在缩放div容器上的元素。以下方法在小于约2的缩放元素上工作得还可以。但是如果你超过这个值,我们会遇到一些问题。

如果有任何帮助,将不胜感激。感谢您花时间阅读。

HTML

<div id="container">
    <div id="dragme">Hi</div>
</div>

方法一(Jquery可拖动函数)

如您在这个jsfiddle示例中所见,我已经尝试过jquery draggable函数。

这个例子中我发现以下问题:

  • 最大问题:当容器被缩放时,可放置的容器不会改变大小。因此,如果元素被拖到缩放后的容器的原始大小之外的部分,它将失败。
  • 当您单击并拖动一个div时,它会向鼠标光标的方向跳跃一小段距离,不是一个无缝的拖动。

JS代码:

var percent = 2.5;

$("#dragme").draggable({
    zIndex: 3000,
    appendTo: 'body',
    helper: function (e, ui) {
        var draggable_element = $(this),
            width = draggable_element.css('width'),
            height = draggable_element.css('height'),
            text = draggable_element.text(),
            fontsize = draggable_element.css('font-size'),
            textalign = draggable_element.css('font-size');
        return $('<div id="' + draggable_element.id + '" name="' + draggable_element.attr('name') + '" class="text">' + text + '</div>').css({
            'position': 'absolute',
                'text-align': textalign,
                'background-color': "red",
                'font-size': fontsize,
                'line-height': height,
                'width': width,
                'height': height,
                'transform': 'scale(' + percent + ')',
                '-moz-transform': 'scale(' + percent + ')',
                '-webkit-transform': 'scale(' + percent + ')',
                '-ms-transform': 'scale(' + percent + ')'
        });
    },
    start: function (e, ui) {
        $(this).hide();
    },
    stop: function (e, ui) {
        $(this).show();
    }
});

$("#container").droppable({
    drop: function (event, ui) {
        var formBg = $(this),
            x = ui.offset.left,
            y = ui.offset.top,
            drag_type = ui.draggable.attr('id');

        var element_top = (y - formBg.offset().top - $(ui.draggable).height() * (percent - 1) / 2) / percent,
            element_left = (x - formBg.offset().left - $(ui.draggable).width() * (percent - 1) / 2) / percent;

        $(ui.draggable).css({
            'top': element_top,
                'left': element_left
        });

    }
});

方法二 - 自定义拖动函数

我尝试使用自定义拖动函数,但在缩放到大约 2 后它就无法使用了。

  • jsfiddle 上的 scale(2) - 看起来可拖动的 div 元素正在抽搐。
  • jsfiddle 上的 scale(2.5) - 当你尝试拖动它时,这个可拖动的 div 元素会飞走。

JS

(function ($) {
    $.fn.drags = function (opt) {

        opt = $.extend({
            handle: "",
            cursor: "move"
        }, opt);

        if (opt.handle === "") {
            var $el = this;
        } else {
            var $parent = this;
            var $el = this.find(opt.handle);
        }

        return $el.css('cursor', opt.cursor).on("mousedown", function (e) {
            if (opt.handle === "") {
                var $drag = $(this).addClass('draggable');
            } else {
                $(this).addClass('active-handle')
                var $drag = $parent.addClass('draggable');
            }

            var
            drg_h = $drag.outerHeight(),
                drg_w = $drag.outerWidth(),
                pos_y = $drag.offset().top + drg_h - e.pageY,
                pos_x = $drag.offset().left + drg_w - e.pageX;

            follow = function (e) {
                $drag.offset({
                    top: e.pageY + pos_y - drg_h,
                    left: e.pageX + pos_x - drg_w
                })
            };

            $(window).on("mousemove", follow).on("mouseup", function () {
                $drag.removeClass('draggable');
                $(window).off("mousemove", follow);
            });

            e.preventDefault(); // disable selection

        }).on("mouseup", function () {
            if (opt.handle === "") {
                $(this).removeClass('draggable');
            } else {
                $(this).removeClass('active-handle');
                $parent.removeClass('draggable');
            }
        });

    }
})(jQuery);

$("#dragme").drags({}, function (e) {});

你是想要创建一个自定义的拖拽函数吗?jQuery-UI已经有了一个可拖拽的函数。 - Da Rod
我用几个不同的比例输入测试了你的代码。似乎当它达到1.75左右时,就像你所说的那样开始闪烁和跳动。低于这个值的一切都看起来很正常。 - Da Rod
我顺便更新了你的JSFiddle,这样你就可以跟踪位置和大小了。我会尝试一些其他的方法,但我认为这可能是一个与浏览器相关的问题。 - Da Rod
请检查此答案:http://stackoverflow.com/questions/19787104/draggable-element-gets-dropped-onto-multiple-droppable-areas-if-the-droppable-ar - Nishit Maheta
3个回答

6
以下是我的发现,以确保在“第一种方法”中对缩放容器进行拖动。唯一要注意的是,在执行任何这些操作之前,请确保声明缩放百分比为 var percent
首先,在您的JavaScript文件顶部使用以下代码。这将有助于确保可投放区域与缩放容器配合使用。
$.ui.ddmanager.prepareOffsets = function( t, event ) { var i, j, m = $.ui.ddmanager.droppables[ t.options.scope ] || [], type = event ? event.type : null, list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack(); droppablesLoop: for ( i = 0; i < m.length; i++ ) { if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) { continue; } for ( j = 0; j < list.length; j++ ) { if ( list[ j ] === m[ i ].element[ 0 ] ) { m[ i ].proportions().height = 0; continue droppablesLoop; }  } m[ i ].visible = m[ i ].element.css( "display" ) !== "none"; if ( !m[ i ].visible ) { continue; } if ( type === "mousedown" ) { m[ i ]._activate.call( m[ i ], event ); } m[ i ].offset = m[ i ].element.offset(); m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth * percent, height: m[ i ].element[ 0 ].offsetHeight * percent }); } };

以下是一些必要的功能,用于修复拖动操作,使其在缩放的容器上正常工作。
function dragFix(event, ui) { var changeLeft = ui.position.left - ui.originalPosition.left, newLeft = ui.originalPosition.left + changeLeft / percent, changeTop = ui.position.top - ui.originalPosition.top, newTop = ui.originalPosition.top + changeTop / percent; ui.position.left = newLeft; ui.position.top = newTop; }

function startFix(event, ui) { ui.position.left = 0; ui.position.top = 0;  var element = $(this); }

如果您希望在缩放容器上启用元素可调整大小,则需要使用此选项。

function resizeFix(event, ui) { var changeWidth = ui.size.width - ui.originalSize.width, newWidth = ui.originalSize.width + changeWidth / percent, changeHeight = ui.size.height - ui.originalSize.height, newHeight = ui.originalSize.height + changeHeight / percent;  ui.size.width = newWidth; ui.size.height = newHeight; }

为了使元素可拖动,我使用以下函数。
$("ELEMENT").resizable({ minWidth: - ($(this).width()) * 10, minHeight: - ($(this).height()) * 10, resize: resizeFix, start: startFix });
$("ELEMENT").draggable({ cursor: "move", start: startFix, drag: dragFix }); }

这很完美。谢谢! - bryan

2

这里提到了一个类似的问题:jquery - css "transform:scale" affects '.offset()' of jquery

看起来问题是由于jQuery无法为缩放元素返回精确的大小,从而无法为元素设置正确的偏移值。

为了解决这个问题,他建议首先将比例设置为1并设置偏移量,然后再次重置比例值。

但是仅此还不足以解决此问题。由于在缩放时采用鼠标位置,因此位置值也应该除以比例值。

这是代码的修改版本:

  var scl = 2.5;
  var
    drg_h = $drag.outerHeight(),
    drg_w = $drag.outerWidth(),
    pos_y = $drag.offset().top/scl + drg_h - e.pageY/scl,
    pos_x = $drag.offset().left/scl + drg_w - e.pageX/scl;

  follow = function(e) {
    var size = {
      top:e.pageY/scl + pos_y - drg_h+scl*2,
      left:e.pageX/scl + pos_x - drg_w+scl*2
    };
      $drag.parent().css("transform","scale(1)");
      $drag.offset(size);
      $drag.parent().css("transform","scale("+scl+")");
  };

注意: 我只替换了transform标签的比例值,因为我正在使用Chrome。您也可以替换所有实例,或者您可以使用一个具有1个比例值的不同类。

JSFiddle也在这里


哇,这真是太棒了!感谢您的付出。我有一个类似的用例,一直在尝试让它在此类缩放环境下工作。我知道这不是本意的问题,但我想知道您是否介意看一下,并看看我能做些什么来使其在父级未被缩放的情况下工作。我稍微编辑了一下,它可以工作,但仍然会有一些瞬移的情况。 - bryan
似乎与边距和填充值有关,因为它们也被考虑在光标位置的计算中。为了进行快速检查,我添加了以下 CSS:body,.trimSpace,.formContainer,#formBox{margin:0px !important;padding:0px !important;},它运行得很好。这是fiddle - fatih
嗯,我想没有简单的解决办法。 - bryan

-1

这是一个简单的拖动和缩放示例,但是在纯DOM中实现。

<style>
#dragme {
    position:absolute;
    border:1px solid red;
    background:pink;
    left:10px;
    top:20px;
    width:100px;
    height:200px;
}
#container {
    transform: scale(2,2) translate(100px,100px);
    position:relative;
    border:1px solid green;
    background:grey;
    width:200px;
    height:300px;
}
</style>
<body>

<div id="container">
    <div id="dragme">Hi</div>
</div>


    <script>
    var dragme=document.getElementById("dragme");
    var container=document.getElementById("container");
    dragme.onmousedown=function Drag(e){
        this.ini_X = this.offsetLeft-e.clientX/2;
        this.ini_Y = this.offsetTop-e.clientY/2;
        container.onmousemove = move;
        container.onmouseup = release;
      return false;
    }
    function move(e){
        e.target.style.left = e.clientX/2 + e.target.ini_X + 'px';
        e.target.style.top = e.clientY/2 + e.target.ini_Y + 'px';
    }
    function release(){
        container.onmousemove=container.onmouseup=null;
}

    </script>
    </body>

从我的问题中,你可以看出这不是我寻找的答案,但即使如此,你也没有努力展示给我如何在一个可扩展的容器上实现这个。 - bryan
div元素在一个缩放因子为2的容器中进行移动,该容器在x和y坐标上进行了缩放。该示例在IE11、Firefox和Chrome中以任何比例都能正常工作。实际上,这非常简单,如果父级缩放比例为m,则拖动目标的移动(此处使用e.clientX进行测量)应该除以m。 - simonleung

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接