Поменять перетаскиваемый элемент на курсор мыши при падении другого перетаскиваемого элемента

Я видел несколько вопросов о простой замене двух перетаскиваемых элементов при перетаскивании, но моя ситуация немного другая.

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

Нам бы ХОТЕЛОСЬ, чтобы при перетаскивании элемента сетки выполнялась обычная операция перетаскивания (назовите ее A), но когда элемент затем перетаскивается в желаемое место назначения (в котором уже есть другой элемент сетки, назовите его B). , то A должен занять место B, а затем B должен привязаться к курсору мыши, как если бы пользователь щелкнул и перетащил его. Это, очевидно, немного портит взаимодействие с мышью, потому что теперь у пользователя нет нажатых кнопок мыши, но он перетаскивает элемент, поэтому, чтобы освободить элемент, он либо щелкнет пустую ячейку, из которой пришел A, либо щелкнет другой элемент сетки C. , после чего B займет место C, а C теперь будет прикреплен к курсору мыши.

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

Чтобы было ясно, это своего рода диаграмма взаимодействия того, что я ищу:

Original Setup - ^ is mouse cursor
[A]  ^  [C]
[B]     [D]

Now click and drag on A. Result is:
[ ]^A   [C]
[B]     [D] 

Now drag over B and release. Result is:
[ ]     [C]
[A]^B   [D]

B is now acting as if it's being dragged, but mouse button is not held down. Move
cursor over C and click mouse button. Result is:
[ ]     [B] ^C
[A]     [D]

B has taken C's place, and C is now following the mouse cursor. Again, mouse 
button is not being held down. Move cursor over empty cell and click mouse 
button. Result is:
[C] ^   [B]
[A]     [D]

Now there is nothing attached to the mouse cursor.

person Isochronous    schedule 07.03.2014    source источник
comment
Прежде чем действительно попытаться реализовать это, я бы поспрашивал в ux.stackexchange.com (пользовательский интерфейс), поскольку я вижу это немного раздражающим, и вы можете запутать пользователей. Может им будет удобнее просто с регулярными свопами   -  person aleation    schedule 10.03.2014
comment
Спасибо, но взаимодействие уже прошло тестирование, и в любом случае это для обученной пользовательской базы - с правильной обратной связью и возможностями наши тестовые пользователи без труда разобрались в этом. Однако я ценю это предложение.   -  person Isochronous    schedule 10.03.2014
comment
Чтобы уточнить, это на самом деле игра в стиле скобок, где может быть 128 участников, расположенных в двух столбцах по 64 в каждой. Использование sortable исключено, потому что на самом деле существует много разных списков фиксированного размера, и переполнение одного списка вернет меня обратно в это место. Мы пробовали поменять местами, но поскольку на самом деле вы не можете увидеть все команды одновременно для большой сетки, пользователи запутались, когда обмен привел к исчезновению одной команды (поскольку она поменялась на позицию за пределами экрана). Поменять нечетное количество позиций тоже оказалось сложнее, чем хотелось бы нашим пользователям.   -  person Isochronous    schedule 11.03.2014


Ответы (2)


Что ж, поскольку никто даже не попытался ответить на мой вопрос, мне удалось найти довольно простой способ сделать это самостоятельно. Моим спасителем в данном случае оказались плагины jquery.simulate, jquery.simulate.ext и jquery.simulate.drag-n-drop. С их помощью легко имитировать конкретное событие в собственном браузере для набора элементов (или, в случае плагина drag-n-drop, для одного элемента). Это означает, что я мог просто использовать обратный вызов drop из jQueryUI droppable, чтобы выполнить то, что мне было нужно:

drop: function (e, ui) {
    var $targ = $(e.target);
    ui.draggable.detach().appendTo($targ).css({top: 0, left: 0});
    $targ.find('.ui-draggable .handle').simulate('drag', {});
}

Вот и все! Это все, что нужно. Вот скрипка, чтобы продемонстрировать решение в действии: http://jsfiddle.net/isochronous/mD8uM/

Обновление: оказалось, что обработка «отката» в перетаскиваемом режиме была на самом деле самой сложной частью. В итоге я создал свой собственный виджет, расширяющий $.ui.draggable для решения этой проблемы. Я обновил скрипку и добавил комментарии, чтобы объяснить, как все это работает, на всякий случай, если кому-то интересно.

person Isochronous    schedule 11.03.2014
comment
Хорошее решение - но все еще есть ошибка: возьмите Item1List1 с левой стороны - теперь перетащите его немного по центру между двумя списками - ваша мышь все еще находится над левым элементом, а элемент немного больше на правая сторона. Если вы отпустите сейчас, предмет поменяется местами с предметом справа. Если затем вы переместите курсор в недопустимое место, перетаскиваемый элемент также переместится вправо - два элемента в одном поле: -o - person Falco; 17.03.2014
comment
Спасибо за отчет об ошибке - я уже видел похожие проблемы, и это одна из причин, по которой я выбираю альтернативное решение, о котором я писал в другом ответе. - person Isochronous; 17.03.2014

Добавьте это как отдельный ответ, потому что это совершенно другой подход к проблеме.

После того, как я получил эту работу, я попытался добавить несколько других новых функций, например, применить класс is-swap к перетаскиваемому объекту, когда он зависает над непустым отбрасываемым объектом, и применить к нему класс is-drop, когда он зависает над пустым. Но поскольку наши отбрасываемые объекты расположены так близко друг к другу, обратные вызовы over и out будут сбиты с толку, когда станут over новым удаляемым объектом перед тем, как стать out предыдущим.

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

Прямо сейчас мой план состоит в том, чтобы создать виджет, который можно создать на каком-то элементе контейнера, и предоставить параметры, позволяющие потребителю виджета нацеливаться на желаемые элементы в виде перетаскиваемых и сбрасываемых элементов, а также просто использовать перетаскиваемые и отбрасываемые элементы в их «естественном» виде. " штат. Это позволит мне делать такие вещи, как проверять состояние одного сбрасываемого объекта из обратного вызова другого, и исправлять такие проблемы, как проблема синхронизации out и over, о которой я упоминал ранее.

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

Обновление: вот значительно упрощенная и более точная реализация с использованием этого подхода. http://jsfiddle.net/isochronous/BQyx2/

person Isochronous    schedule 15.03.2014