Jquery перетаскивается с проблемой масштабирования

Я работаю над страницей, в которой все ее содержимое масштабируется с помощью масштабирования. Проблема в том, что когда я перетаскиваю что-то на странице, перетаскиваемый элемент получает неправильную позицию, которая кажется относительно величины масштабирования.

Чтобы решить эту проблему, я попытался немного посчитать положение перетаскиваемого компонента, но кажется, что даже если он визуально исправлен, «истинное» положение не пересчитывается.

вот код, чтобы объяснить лучше:

var zoom = Math.round((parseFloat($("body").css("zoom")) / 100)*10)/10;

var x = $(this).data('draggable').position;
$(this).data('draggable').position.left = Math.round(x.left/zoom);
$(this).data('draggable').position.top = Math.round(x.top/zoom);

Любая помощь будет принята с благодарностью


person Manuel    schedule 28.05.2010    source источник
comment
Для дальнейшего использования - если кто-то когда-либо столкнется с той же проблемой - аналогичный вопрос + рабочий ответ можно найти здесь.   -  person ptriek    schedule 23.12.2011


Ответы (4)


Потребовалось много времени и усилий, чтобы исправить это, но, наконец, у меня есть решение, которое работает.

Это решение работает как для Firefox, так и для IE. #canvas — это div, содержащий перетаскиваемый элемент. Обратите внимание, что мы должны убедиться, что элементы остаются внутри холста вручную.

Это также работает, если холст имеет другой уровень масштабирования, чем остальная часть страницы.

var pointerX;
var pointerY;
$(c).draggable({
  start : function(evt, ui) {
    pointerY = (evt.pageY - $('#canvas').offset().top) / zoom - parseInt($(evt.target).css('top'));
    pointerX = (evt.pageX - $('#canvas').offset().left) / zoom - parseInt($(evt.target).css('left'));
  },
  drag : function(evt, ui) {
    var canvasTop = $('#canvas').offset().top;
    var canvasLeft = $('#canvas').offset().left;
    var canvasHeight = $('#canvas').height();
    var canvasWidth = $('#canvas').width();

    // Fix for zoom
    ui.position.top = Math.round((evt.pageY - canvasTop) / zoom - pointerY); 
    ui.position.left = Math.round((evt.pageX - canvasLeft) / zoom - pointerX); 

    // Check if element is outside canvas
    if (ui.position.left < 0) ui.position.left = 0;
    if (ui.position.left + $(this).width() > canvasWidth) ui.position.left = canvasWidth - $(this).width();  
    if (ui.position.top < 0) ui.position.top = 0;
    if (ui.position.top + $(this).height() > canvasHeight) ui.position.top = canvasHeight - $(this).height();  

    // Finally, make sure offset aligns with position
    ui.offset.top = Math.round(ui.position.top + canvasTop);
    ui.offset.left = Math.round(ui.position.left + canvasLeft);
  }
});
person torke1    schedule 10.03.2011
comment
можете ли вы предоставить ссылку JSFiddle, которая работает? мы были бы признательны за вопрос 8605439 - person Janus Troelsen; 22.12.2011
comment
У меня та же проблема. Увеличение в процентах или фактическое значение? - person Ricardo Peres; 27.02.2013
comment
Давно я этого не делал, но, глядя на код, это должно быть (плавающее) значение, где 1,0 - это 100% масштабирование. Попробуйте! - person torke1; 20.03.2013
comment
Отлично, это тоже решило мою проблему. Единственное, после прокрутки перетаскиваемый элемент каким-то образом перемещается вверх. - person Pramesh Bajracharya; 23.07.2019
comment
Для будущих читателей попробуйте сначала ответить @Yusuf Demirag (он где-то внизу), так как это работает и с прокруткой. (и тоже коротко) - person Pramesh Bajracharya; 23.07.2019

Если CSS Zoom выполняется специально для тела html, есть очень простое решение, но оно требует изменения исходного кода. Некоторым это не подходит, но я все равно опубликую решение здесь.

Таким образом, функция перетаскивания пользовательского интерфейса jQuery определяет положение мыши с помощью метода, называемого _generatePosition. Проблема в том, что он не принимает во внимание масштаб (ох), поэтому нам просто нужно разделить его результат на уровень масштабирования, и все будет работать.

Итак, поверните это:

    return {
        top: (

            // The absolute mouse position
            pageY -

            // Click offset (relative to the element)
            this.offset.click.top -

            // Only for relative positioned nodes: Relative offset from element to offset parent
            this.offset.relative.top -

            // The offsetParent's offset without borders (offset + border)
            this.offset.parent.top +
            ( this.cssPosition === "fixed" ?
                -this.offset.scroll.top :
                ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
        )/ ,
        left: (

            // The absolute mouse position
            pageX -

            // Click offset (relative to the element)
            this.offset.click.left -

            // Only for relative positioned nodes: Relative offset from element to offset parent
            this.offset.relative.left -

            // The offsetParent's offset without borders (offset + border)
            this.offset.parent.left +
            ( this.cssPosition === "fixed" ?
                -this.offset.scroll.left :
                ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
        )
    };

in

    var zoomLevel = parseFloat($('body').css("zoom") || "1.0");

    return {
        top: (

            // The absolute mouse position
            pageY -

            // Click offset (relative to the element)
            this.offset.click.top -

            // Only for relative positioned nodes: Relative offset from element to offset parent
            this.offset.relative.top -

            // The offsetParent's offset without borders (offset + border)
            this.offset.parent.top +
            ( this.cssPosition === "fixed" ?
                -this.offset.scroll.top :
                ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
        ) / zoomLevel,
        left: (

            // The absolute mouse position
            pageX -

            // Click offset (relative to the element)
            this.offset.click.left -

            // Only for relative positioned nodes: Relative offset from element to offset parent
            this.offset.relative.left -

            // The offsetParent's offset without borders (offset + border)
            this.offset.parent.left +
            ( this.cssPosition === "fixed" ?
                -this.offset.scroll.left :
                ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
        ) / zoomLevel
    };

Это все. Я предлагаю сохранить его под определенным именем, чтобы было легко распознать, что он был изменен. Например: jquery-ui.ZOOMFIX.js

Я использовал файл jquery-ui.js из следующего пакета: https://jqueryui.com/resources/download/jquery-ui-1.12.1.zip

person kragovip    schedule 10.03.2018
comment
Как этот ответ относится к вопросу? - person sg7; 10.03.2018
comment
@ sg7 OP запрашивает решение для перетаскивания с неправильным позиционированием с помощью пользовательского интерфейса jQuery. Мой ответ предлагает решение для исправления плохо позиционированного перетаскивания с помощью пользовательского интерфейса jQuery. Поскольку мой ответ отвечает на вопрос, я считаю его достаточно актуальным. - person kragovip; 10.03.2018

Учитываете ли вы положение прокрутки, поля и отступы? Такие как:

x.left + 
parseInt($(this).css('margin-left')) + 
parseInt($(this).css('padding-left')) + 
parseInt($(this).parent().scrollLeft());

x.top + 
parseInt($(this).css('margin-top')) + 
parseInt($(this).css('padding-top')) + 
parseInt($(this).parent().scrollTop());

Затем настроить значение масштабирования по мере необходимости?

person Matthew Callis    schedule 10.06.2010
comment
расчет хороший, возвращаемое значение для offset().top неверно, если масштаб не равен 1,0 - person Mladen Janjetovic; 10.01.2014

Я боролся с этим несколько часов. У меня была сетка, в которой я начал с масштабирования, установив размер шрифта (125% и т. д. в контейнере). Это работало хорошо, пока я не наткнулся на изображения, которые не масштабировались с сеткой.

Думал, что вместо этого я буду использовать зум, и это сработало блестяще. Затем я понял, что draggable/droppable не масштабируется с ним, хм .. Потратил несколько часов, пытаясь уничтожить и повторно инициализировать объекты jqueryUI, но ничего не получилось.

Затем, наконец, я понял, что могу использовать комбинацию размера шрифта для масштабирования сетки и масштабирования css для изображений. Теперь все работает, и я могу перетаскивать тот же экземпляр jQueryUI.

Надеюсь, этот подход поможет кому-то еще. :-)

person Stefan Lindberg    schedule 03.10.2014