43 votes

Faire glisser et redimensionner des éléments transformés CSS

Si par exemple, nous avons créé un -vendor-transform: rotate(40deg) attribut css sur un rectangle <div>,, tout d'un coup en faisant glisser et redimensionner devient très bizarre et vicié.

Voici un exemple avec un simple jQueryUI: http://jsfiddle.net/Ja4dY/1/

Vous remarquerez que si vous déplacez ou redimensionnez un rectangle lorsqu'il est transformé, il saute vers le haut ou vers le bas et le curseur ne restera pas dans l'endroit correct. Dans mon code, je suis en utilisant un code personnalisé pour le redimensionnement et la faisant glisser, toutefois, j'ai rencontré les mêmes problèmes.

Eh bien, bien sûr, le "problème" est que la direction d'un Élément de changement. Donc, de gauche à droite, haut devient le bas et quelque chose entre les deux et le code Javascript encore des poignées de chaque direction, comme il le serait pas transformé.

Donc, la question: Comment peut-on compenser transformer / rotation des Éléments ?

Tout bon des ressources / livres / les blogs sont également les bienvenus.

14voto

Michael Mullany Points 9020

Vous pouvez obtenir la transformation actuelle de la matrice qui est appliquée à un élément en utilisant getComputedStyle(). Vous pouvez l'utiliser pour transformer la position actuelle de la souris à sa position dans le transformé de l'espace et de voir si le cliquer/glisser les événements sont à l'intérieur de l'élément de délimitation et/ou des coins. De bonnes ressources pour ceci:

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, que vous êtes en train de vivre, c'est non-trivial de code. Nous avons eu à le faire pour le Sencha Animator, et c'était une bête.

7voto

adeneo Points 135949

Le problème est que les fonctions qui en font des éléments déplaçables, soit à l'aide de jQuery UI ou non, s'appuie fortement sur le natif getBoundingClientRect() fonction pour comprendre la position de l'élément etc.

Lors de l'application de CSS3 transforme, comme la rotation, les valeurs de getBoundingClientRect() ou le equalent jQuery offset() fonction utilisée dans l'INTERFACE utilisateur de jQuery ne fonctionne plus comme prévu, et la position du pointeur de la souris se foiré parce que la taille de l'élément est soudainement mal, après il a été tourné.

Pour corriger cela, vous devez ajouter une sorte de fonction d'assistance qui recalcule les valeurs, et il y a un singe correctif disponible pour ce qui fonctionne avec jQuery UI est déplaçable.

Il est difficile de dire quelque chose sur la façon de faire le même patch de travail pour le code personnalisé, mais vous aurez probablement à l'intégrer dans votre fonction personnalisée d'une certaine manière, et il faudra un peu de codage de votre part, et il est encore plus difficile de trouver quelque chose qui fonctionne comme une fonction d'aide de la boîte de code personnalisé l'on n'a pas vu, et être conscient que c'est plutôt à faire ces calculs, voir le code ci-dessous :

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();

Et voici un VIOLON montrant qu'il fonctionne comme prévu avec jQuery UI déplaçables et redimensionnables !

5voto

gmo Points 2156

J'ai trouvé ce... C'est un exemple de travail plus d'infos, de démonstration et le lien de téléchargement.

jquery-ui-rotation-aide-css-transformer -> live-démo

Il utilise sa propre bibliothèque, mais si vous êtes intéressés par le sujet, vous pouvez lire et d'apprendre comment il l'obtenir.

a bientôt et bonne chance.

Les ogm.-

Btw, le web est en russe, mais avec google translate vous pouvez gérer ;-)

2voto

Milan Jaric Points 3039

Il n'est pas un bug en jQuery. Simplement, il n'est pas pris en charge. Si vous cochez jQuery UI code source vous permettra de comprendre qu'il ne veut pas utiliser la matrice de transformation à calculer la différence entre l'objet transformé et page.

Votre exemple, et sans doute tous les jQ INTERFACE utilisateur de faire glisser la mise en œuvre souffrent de ce problème cause de 2 méthodes de JQ INTERFACE utilisateur code source (environ 314 ligne de jquery.ui.draggable.js fichier v1.8.23 ). Calculé décalage n'a pas d'importance sur le changement de décalage depuis la rotation se fait sur le centre de l'élément.

Vous devez calculer ce qui est de ce changement. Ici est la solution, rapide et sale. L'idée est de vérifier quelle est la différence dans la boîte englobante de l'transformée élément.

Vérifier exemple ici http://jsfiddle.net/mjaric/9Nqrh/

Ignorer une partie avec les deux premières rotations, ils sont juste fait pour minimiser les lignes de code. Troisième implique la traduction de système de coordonnées pour la différence calculée. Il va compenser en haut et à gauche après la traduction est effectuée (remarque c'est d'abord dans le filtre).

Si vous voulez éviter les deux premiers de rotation des filtres, Vous pourriez faire le code à l'aide de la formule de rotation 2D:

x' = x cos f - y sin f

y' = y cos f + x sin f

où f est l'angle de rotation, mais il n'est pas simple et comprend également plus de lignes de code où vous devez calculer quel est l'angle de champ diagonal de l'origine de la boîte englobante, car vous avez besoin initial de l'angle du coin supérieur gauche, x et y coordonnées sont la comparant à l'axe des x (partie positive). Calculez ensuite le modifier dans x-x' et y-y'. Mais je suis prédire quelques problèmes avec le signe du changement et de codage/débogage prendrait plus de temps alors que j'ai droit. Désolé cause de ça, mais je suis sûr que vous pouvez comprendre ce qu'il faut faire après la lecture de ce post.

1voto

John Koerner Points 17899

Cela semble mieux si nous remplaçons le curseurAt:

 $("#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});
});
 

Violon mis à jour: http://jsfiddle.net/johnkoer/Ja4dY/8/

Un séjour sans faille

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X