Przeciąganie i zmiana rozmiaru elementów CSS

Jeśli na przykład ustawimy atrybut -vendor-transform: rotate(40deg) css na prostokącie <div>, nagłe przeciąganie i zmiana rozmiaru staje się bardzo dziwne i wadliwe.

Oto przykład z prostym jQueryUI: http://jsfiddle.net/Ja4dY/1/

Zauważysz, że jeśli przeciągniesz lub zmienisz rozmiar prostokąta po przekształceniu, przeskoczy on w górę lub w dół, a kursor nie pozostanie we właściwym miejscu. W moim prawdziwym kodzie używam niestandardowego kodu do zmiany rozmiaru i przeciągania, jednak napotkałem te same problemy.

Oczywiście "problem" polega na tym, że kierunek elementu ulegnie zmianie. Więc lewa może być prawa, Góra dostaje dół i coś inbetween, a kod Javascript nadal obsługuje każdy kierunek tak, jak to byłoby , a nie przekształcone.

Więc pytanie: Jak możemy zrekompensować / obrócone Elementy ?

Wszelkie dobre zasoby / książki / blogi są również bardzo mile widziane.

Author: Qiau, 2012-08-17

7 answers

Można uzyskać bieżącą macierz transformacji, która jest zastosowana do elementu za pomocą getComputedStyle (). Za jego pomocą można przekształcić bieżącą pozycję myszy na jej pozycję w przekształconej przestrzeni i sprawdzić, czy zdarzenia kliknięcia/przeciągnięcia znajdują się w granicach elementu i/lub narożnikach. Dobre zasoby dla to:

Http://www.useragentman.com/blog/2011/01/07/css3-matrix-transform-for-the-mathematically-challenged/

Http://www.eleqtriq.com/2010/05/css-3d-matrix-transformations/

BTW, jak doświadczasz, to nie jest trywialne dla kodu. Musieliśmy to zrobić dla Sencha Animator, a to była bestia.

 14
Author: Michael Mullany,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-21 05:15:47

Problem polega na tym, że funkcje, które sprawiają, że elementy są przeciągalne, używając jQuery UI lub nie, opierają się w dużej mierze na natywnej funkcji getBoundingClientRect(), aby ustalić pozycję elementu itp.

Podczas stosowania CSS3 przekształca, podobnie jak rotacja, wartości getBoundingClientRect() lub równoważnej funkcji jQuery offset() używanej w jQuery UI nie działają już zgodnie z oczekiwaniami, a pozycja wskaźnika myszy jest pomieszana, Ponieważ rozmiar elementu nagle się myli po jego obróceniu.

To napraw to musisz dodać jakąś funkcję pomocnika, która ponownie oblicza wartości, a dostępna jest dla tego łatka małpy, która działa z przeciągalnym interfejsem jQuery.

Trudno cokolwiek powiedzieć o tym, jak sprawić, by ta sama łatka działała dla kodu niestandardowego, ale prawdopodobnie będziesz musiał ją jakoś zintegrować z niestandardową funkcją, a to będzie wymagało trochę kodowania z twojej strony, a jeszcze trudniej wymyślić coś, co działa jako funkcja pomocnicza po wyjęciu z pudełka dla kodu niestandardowego. nie widać, i należy pamiętać, że jest to raczej związane z wykonywaniem tych obliczeń, patrz poniższy kod:

function monkeyPatch_mouseStart() {
     var oldFn = $.ui.draggable.prototype._mouseStart ;
     $.ui.draggable.prototype._mouseStart = function(event) {

            var o = this.options;

           function getViewOffset(node) {
              var x = 0, y = 0, win = node.ownerDocument.defaultView || window;
              if (node) addOffset(node);
              return { left: x, top: y };

              function getStyle(node) {
                return node.currentStyle || // IE
                       win.getComputedStyle(node, '');
              }

              function addOffset(node) {
                var p = node.offsetParent, style, X, Y;
                x += parseInt(node.offsetLeft, 10) || 0;
                y += parseInt(node.offsetTop, 10) || 0;

                if (p) {
                  x -= parseInt(p.scrollLeft, 10) || 0;
                  y -= parseInt(p.scrollTop, 10) || 0;

                  if (p.nodeType == 1) {
                    var parentStyle = getStyle(p)
                      , localName   = p.localName
                      , parent      = node.parentNode;
                    if (parentStyle.position != 'static') {
                      x += parseInt(parentStyle.borderLeftWidth, 10) || 0;
                      y += parseInt(parentStyle.borderTopWidth, 10) || 0;

                      if (localName == 'TABLE') {
                        x += parseInt(parentStyle.paddingLeft, 10) || 0;
                        y += parseInt(parentStyle.paddingTop, 10) || 0;
                      }
                      else if (localName == 'BODY') {
                        style = getStyle(node);
                        x += parseInt(style.marginLeft, 10) || 0;
                        y += parseInt(style.marginTop, 10) || 0;
                      }
                    }
                    else if (localName == 'BODY') {
                      x += parseInt(parentStyle.borderLeftWidth, 10) || 0;
                      y += parseInt(parentStyle.borderTopWidth, 10) || 0;
                    }

                    while (p != parent) {
                      x -= parseInt(parent.scrollLeft, 10) || 0;
                      y -= parseInt(parent.scrollTop, 10) || 0;
                      parent = parent.parentNode;
                    }
                    addOffset(p);
                  }
                }
                else {
                  if (node.localName == 'BODY') {
                    style = getStyle(node);
                    x += parseInt(style.borderLeftWidth, 10) || 0;
                    y += parseInt(style.borderTopWidth, 10) || 0;

                    var htmlStyle = getStyle(node.parentNode);
                    x -= parseInt(htmlStyle.paddingLeft, 10) || 0;
                    y -= parseInt(htmlStyle.paddingTop, 10) || 0;
                  }

                  if ((X = node.scrollLeft)) x += parseInt(X, 10) || 0;
                  if ((Y = node.scrollTop))  y += parseInt(Y, 10) || 0;
                }
              }
            }

                this.helper = this._createHelper(event);
                this._cacheHelperProportions();

                if($.ui.ddmanager)
                    $.ui.ddmanager.current = this;

                this._cacheMargins();

                this.cssPosition = this.helper.css("position");
                this.scrollParent = this.helper.scrollParent();

            this.offset = this.positionAbs = getViewOffset(this.element[0]);
                this.offset = {
                    top: this.offset.top - this.margins.top,
                    left: this.offset.left - this.margins.left
                };

                $.extend(this.offset, {
                    click: {
                        left: event.pageX - this.offset.left,
                        top: event.pageY - this.offset.top
                    },
                    parent: this._getParentOffset(),
                    relative: this._getRelativeOffset()
                });

                this.originalPosition = this.position = this._generatePosition(event);
                this.originalPageX = event.pageX;
                this.originalPageY = event.pageY;

                (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));

                if(o.containment)
                    this._setContainment();

                if(this._trigger("start", event) === false) {
                    this._clear();
                    return false;
                }

                this._cacheHelperProportions();

                if ($.ui.ddmanager && !o.dropBehaviour)
                    $.ui.ddmanager.prepareOffsets(this, event);

                this.helper.addClass("ui-draggable-dragging");
                this._mouseDrag(event, true);

                if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event);
                return true;
     };
 }
monkeyPatch_mouseStart();

A oto FIDDLE pokazuje, że działa zgodnie z oczekiwaniami z jQuery UI ' s draggable i resizeable !

 7
Author: adeneo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-20 20:40:37

Znalazłem to... To działa przykład Plus informacje, demo i link do pobrania.

Jquery-ui-rotation-using-css-transform -> live-demo

Korzysta z własnych bibliotek, ale jeśli jesteś zainteresowany tematem, możesz przeczytać i dowiedzieć się, jak go zdobyć.

Zdrówko i powodzenia.

Gmo.-

Btw, sieć jest po rosyjsku, ale z tłumaczem google można sobie poradzić; -)

 5
Author: gmo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-20 07:12:07

To nie jest błąd w jQuery. Po prostu nie jest obsługiwany. Jeśli sprawdzisz kod źródłowy jQuery UI, przekonasz się, że nie używa macierzy transformacji do obliczania różnicy między przekształconym obiektem a stroną.

Twój przykład i prawdopodobnie każda implementacja JQ UI drag cierpią z powodu tego problemu przyczyny 2 metod w kodzie źródłowym JQ UI (około 314 linii jquery.ui.do ciągnięcia.plik js v1.8. 23). Obliczonego offsetu nie ma znaczenia zmiana offsetu, ponieważ obrót odbywa się nad środek żywiołu.

Musisz obliczyć, co to za Zmiana. Oto obejście, szybkie i brudne. Chodzi o to, aby sprawdzić, jaka jest różnica w obwiedni przekształconego elementu.

Sprawdź próbkę tutaj http://jsfiddle.net/mjaric/9Nqrh/

Ignoruj część z dwoma pierwszymi obrotami, są one po prostu zrobione, aby zminimalizować linie kodu. Trzeci polega na tłumaczeniu układu współrzędnych dla obliczonej różnicy. Przesunie się w lewo i w górę po wykonaniu tłumaczenia (zauważ, że jest pierwszy w filtrze).

Jeśli chcesz uniknąć pierwszych dwóch filtrów rotacji, możesz zrobić kod używając formuły do rotacji 2D:

X ' = x cos f-y sin F

Y' = Y cos f + X sin f

Gdzie f to kąt obrotu, ale nie jest to takie proste i zawiera również więcej linii kodu, gdzie musisz obliczyć, jaki jest kąt przekątnej oryginalnej obwiedni, ponieważ potrzebujesz początkowego kąta lewego górnego rogu, który X i y są porównywane do osi x (część dodatnia). Następnie Oblicz zmianę w x - x 'i y-y'. Ale przewiduję pewne problemy z oznaką zmiany i kodowanie/debugowanie zajęłoby więcej czasu, niż mam teraz. Przepraszam za to, ale jestem pewien, że można dowiedzieć się, co zrobić po przeczytaniu tego postu.

 2
Author: Milan Jaric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-24 00:00:52

Lepiej będzie, jeśli nadpiszemy kursor:

$("#foo").mousedown(function (e) { 
    var x = e.pageX - this.offsetLeft;
    var y = e.pageY - this.offsetTop;
    console.log(x);
    $("#foo").draggable("option", "cursorAt", {left: x, top:y});
});

Aktualizacja: http://jsfiddle.net/johnkoer/Ja4dY/8/

 1
Author: John Koerner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-17 15:08:31

Powiedziałeś, że nie jesteś zainteresowany rozwiązaniami JQuery wtedy,

  • Jednym rozwiązaniem jest;

    Zalecam napisanie własnych funkcji przeciągania i zmiany rozmiaru. Możesz obsługa zmiany rozmiaru i przeciągania na obracanych obiektach, aby dodać ich górną i lewą sinus i cosinus tego stopnia.

  • Innym rozwiązaniem jest;

    Możesz używać bibliotek takich jak Raphael JS do tworzenia obiektów do transformacji, przeciągnij i zmień rozmiar. Raphael JS używa svg!

    Więcej informacji o Raphaelu JS

  • Jeszcze innym rozwiązaniem jest;

    Jeśli nie chcesz używać biblioteki jak Raphael JS, możesz bezpośrednio użyć SVG z JQuery

    Więcej informacji o SVG

Nie mogę teraz napisać więcej szczegółów, jutro rozbuduję To rozwiązanie.

Mam nadzieję, że na razie pomogą.

 0
Author: totten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-20 09:25:58

To rzeczywiście wydaje się być błąd w jQuery. Łatwo obejść to: otoczyć zmienny div kontenerem div. Ustaw {[2] } do zewnętrznego div i .resizable() do wewnętrznego div. Wydaje się, że działa to dobrze w Chromium działającym na Ubuntu. Patrz Fiddle .

Pokolorowałem zewnętrzną div, aby dać ci wyobrażenie, co dzieje się pod maską.

 0
Author: Jasper de Vries,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-23 17:09:00