Подтвердить что ты не робот

Внутренний div внутри внешнего вращающегося div не следует за мышью при перетаскивании с помощью jQuery UI

У меня есть внутренний div внутри внешнего div. Внутренний div перетаскивается, а внешний вращается на 40 градусов. Это тестовый пример. В реальном случае это может быть любой угол. Существует еще одна точка, называемая div, которая позиционируется так, как показано на рисунке. (Я из флеш-фона. В Flash, если я должен был перетащить внутренний div, он будет следовать за мышью, даже если он содержится внутри внешнего вращающегося div.) Но в HTML внутренний div не следует за мышью, как это видно от скрипки. Я хочу, чтобы div "point" точно следовал за мышью. Это возможно. Я пытался работать с использованием тригнометрии, но не мог заставить ее работать.

http://jsfiddle.net/bobbyfrancisjoseph/kB4ra/8/

4b9b3361

Ответ 1

Вот мой подход к этой проблеме.

http://jsfiddle.net/2X9sT/21/

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

В событии перетаскивания я преобразую смещение перетаскивания, чтобы отразить новые значения. Это делается вращением смещения вокруг внешнего центра div в противоположном направлении от угла поворота.

Я тестировал его и, похоже, работал в IE9, Firefox и Chrome.

Вы можете попробовать разные значения для угла, и он должен работать нормально.

Я также изменил HTML, чтобы можно было применить одну и ту же логику к нескольким div на странице.

Edit:

Я обновил script, чтобы учесть поведение сдерживания, а также каскадные вращения, как это предлагается в комментариях.

Я также устареваю с тем, что div outer перетаскивается внутри другого div. Сейчас он почти работает. Мне просто нужно иметь возможность обновить центр перетаскиваемого div, чтобы исправить поведение перетаскивания.

Попробуйте перетащить красный div.

http://jsfiddle.net/mohdali/kETcE/39/

Ответ 2

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

Прежде всего, вы должны понимать, что плагин вращения, который вы используете, применяет преобразование к вашему элементу (transform: rotate(30deg)), которое, в свою очередь, преобразуется в матрицу вашим браузером (matrix(0.8660254037844387, 0.49999999999999994, -0.49999999999999994, 0.8660254037844387, 0, 0)). Во-вторых, необходимо понять, что, вращая элемент, ось дочерних элементов вращается абсолютно и полностью с ним (после долгого поиска нет никакого реального трюка, чтобы обойти это, что имеет смысл), таким образом, единственное путь должен был вывести ребенка из родителя, как предлагают некоторые из других ответов, но я предполагаю, что это не вариант в вашем приложении.

Теперь, что нам нужно сделать, это отменить исходную матрицу родителя, которая является двухэтапным процессом. Сначала нам нужно найти матрицу, используя код в следующих строках:

var styles = window.getComputedStyle(el, null);

var matrix = styles.getPropertyValue("-webkit-transform") ||
             styles.getPropertyValue("-moz-transform") ||
             styles.getPropertyValue("-ms-transform") ||
             styles.getPropertyValue("-o-transform") ||
             styles.getPropertyValue("transform");

Далее матрица будет строкой, как показано выше, которую вам нужно будет анализировать для массива, с которым вы можете работать (для этого есть плагины jquery). Как только вы это сделаете, вам нужно будет взять обратную матрицу (которая сводится к rotate(-30deg) в вашем примере), которая может быть выполнена с использованием, например, this библиотека (или ваша математическая книга: P).

Наконец, вам нужно будет сделать обратное время матрицы (используйте ранее упомянутую матричную библиотеку) матрицу перевода (используйте этот инструмент, чтобы увидеть (переводы - движения вдоль оси x и y, немного похожие на левый и верхний части относительно позиционированного элемента, но аппаратное ускорение и часть свойства css матричного преобразования)), который даст вам новую матрицу, которую вы можете примените к вашему дочернему элементу, предоставляя вам перевод на той же оси, что и ваш родительский элемент.

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

О, и если вы сейчас думаете, что вспышка намного проще, поверьте, способ вращения оси в HTML/CSS имеет большой смысл и если вы хотите, чтобы поведение флеш-памяти использовало эту библиотеку.


1 Вот что делает Мохамед Али в своем ответе, например (функция transformOffset в его jsFiddle).


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

Ответ 3

Только для Webkit функция webkitConvertPointFromPageToNode обрабатывает отсутствующее поведение:

   var point = webkitConvertPointFromPageToNode(
       document.getElementById("outer"),
       new WebKitPoint(event.pageX, event.pageY)
   );

jsFiddle: http://jsfiddle.net/kB4ra/108/

Чтобы охватить другие браузеры, вы можете использовать метод, описанный в этом ответе StackOverflow: fooobar.com/questions/126727/...

function coords(event, element) {
  function a(width) {
    var l = 0, r = 200;
    while (r - l > 0.0001) {
      var mid = (r + l) / 2;
      var a = document.createElement('div');
      a.style.cssText = 'position: absolute;left:0;top:0;background: red;z-index: 1000;';
      a.style[width ? 'width' : 'height'] = mid.toFixed(3) + '%';
      a.style[width ? 'height' : 'width'] = '100%';
      element.appendChild(a);
      var x = document.elementFromPoint(event.clientX, event.clientY);
      element.removeChild(a);
      if (x === a) {
        r = mid;
      } else {
        if (r === 200) {
          return null;
        }
        l = mid;
      }
    }
    return mid;
  }
    var l = a(true),
        r = a(false);
    return (l && r) ? {
        x: l,
        y: r
    } : null;
}

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

jsFiddle: http://jsfiddle.net/kB4ra/122/

Это можно расширить, чтобы применить к #point, добавив событие mousemove:

$('#outer').mousemove(function(event){
   var point = convertCoordinates(event, $("#outer"));

    $("#point").css({left: point.x+1, top: point.y+1});          
});

Обратите внимание, что я корректирую x и y координаты #point на 1px, чтобы предотвратить его прямо под мышью; если бы я этого не сделал, тогда он блокировал бы перетаскивание #inner. Альтернативным решением было бы добавить обработчики к #point, которые обнаруживают события мыши и передают их в зависимости от того, какой элемент находится непосредственно под #point (и stopPropagation, чтобы они не запускались дважды на больших элементах страницы).

jsFiddle: http://jsfiddle.net/kB4ra/123/

Ответ 4

Мне кажется, что если вы не вращаете div, div точно следует за мышью. Это может быть проблемой с плагином. Можете ли вы правильно имитировать функцию перетаскивания?

Ответ 5

В основном это будет делать то, что вам нужно, хотя оно не работает. Свяжите обработчик события перехвата, перехватите объект ui и измените его, чтобы использовать смещение X и Y родительского элемента. Все X, Y, верхние, левые и т.д. Находятся в этих объектах. Я постараюсь сделать вам лучший пример когда-нибудь, когда сегодня я получаю немного больше времени. Удачи!

http://jsfiddle.net/kB4ra/107/

Ответ 6

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