Перетаскивание элементов на масштабируемом div

Я пробовал использовать встроенный jQuery, и я пробовал использовать пользовательские функции перетаскивания безрезультатно. У обоих есть свои уважаемые проблемы, и я постараюсь выделить их обоих.

в основном, я пытаюсь разрешить перетаскивание элемента, который находится в масштабированном контейнере div. Работают следующие методы ОК на масштабируемом элементе, который меньше, чем вокруг 2. Но если вы подниметесь выше этого, мы увидим некоторые проблемы.

любая помощь будет оцененный. Спасибо, что уделили мне время.

HTML-код

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

метод 1 (функция перетаскивания Jquery)

Я пробовал функцию jQuery draggable, как вы можете видеть в этом jsfiddle пример.

проблемы, которые я нашел в этом примере, следующие:

  • самая большая проблема: сбрасываемый контейнер не изменяется при его масштабировании. Поэтому, если элемент перетаскивается над частью масштабированного контейнера, который не является частью его исходного размера, он потерпит неудачу.
  • когда вы нажимаете, чтобы перетащить 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-пользовательская функция перетаскивания

Я пробовал использовать пользовательскую функцию перетаскивания, но она непригодна для использования после 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) {});

3 ответов


вот несколько моих выводов, чтобы убедиться, что перетаскивание масштабированного контейнера работает для способ один. Единственное предостережение - убедиться, что у вас есть var percent как масштабированный процент, объявленный до любого из этих действий.

во-первых, используйте этот код в верхней части вашего javascript. Это поможет убедиться, что область droppable работает с саклированным контейнером.

$.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 }); }

аналогичная проблема описана здесь: jQuery-css "transform:scale" влияет".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 также здесь.


вот пример простого перетаскивания с масштабированием, однако, в prue 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>