Goutte précise pour élément déplaçable sur div redimensionné

LE PROBLÈME

J’ai un problème mineur en faisant glisser des éléments sur un conteneur div évolutif.

Une fois que l’élément est réellement dans le conteneur, les éléments se déplacent bien et fonctionnent comme ils sont censés le faire.

Les éléments plus grands qui sont déplacés sur le conteneur évolutif ne posent pas trop de problèmes.

Mais lorsque des éléments plus petits sont glissés, vous pouvez voir que la souris n’est plus attachée à cet élément et lorsqu’elle est lâchée, elle tombe un peu à l’endroit où elle est supposée tomber.

J’essaie de trouver une solution pour que ma souris rest sur l’élément et qu’elle tombe là où elle est supposée tomber.

J’ai résolu des problèmes petit à petit et vous pouvez voir ci-dessous mais c’est la dernière pièce du puzzle qui me rend fou. Si quelqu’un a le temps de donner un coup de main, cela serait grandement apprécié.

Voici un codepen – cliquez et faites glisser les deux éléments bleus sur le conteneur blanc pour l’essayer

Codepen

Vue plein écran

GIF court en action


Cela aidera à s’assurer que la zone de repository fonctionne avec un conteneur à l’échelle.

$.ui.ddmanager.prepareOffsets = function(t, event) { var i, j, m = $.ui.ddmanager.droppables[t.options.scope] || [], type = event ? event.type : null, list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack(); droppablesLoop: for (i = 0; i < m.length; i++) { if (m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0], (t.currentItem || t.element)))) { continue; } for (j = 0; j < list.length; j++) { if (list[j] === m[i].element[0]) { m[i].proportions().height = 0; continue droppablesLoop; } } m[i].visible = m[i].element.css("display") !== "none"; if (!m[i].visible) { continue; } if (type === "mousedown") { m[i]._activate.call(m[i], event); } m[i].offset = m[i].element.offset(); m[i].proportions({ width: m[i].element[0].offsetWidth * percent, height: m[i].element[0].offsetHeight * percent }); } }; 

Activer l’élément pour qu’il soit redimensionnable sur un conteneur mis à l’échelle

 function resizeFix(event, ui) { var changeWidth = ui.size.width - ui.originalSize.width, newWidth = ui.originalSize.width + changeWidth / percent, changeHeight = ui.size.height - ui.originalSize.height, newHeight = ui.originalSize.height + changeHeight / percent; ui.size.width = newWidth; ui.size.height = newHeight; } 

Fait en sorte que le glisser fonctionne sur un conteneur à l’échelle

 function dragFix(event, ui) { var containmentArea = $("#documentPage_"+ui.helper.parent().parent().attr('id').replace(/^(\w+)_/, "")), contWidth = containmentArea.width(), contHeight = containmentArea.height(); ui.position.left = Math.max(0, Math.min(ui.position.left / percent , contWidth - ui.helper.width())); ui.position.top = Math.max(0, Math.min(ui.position.top / percent, contHeight- ui.helper.height())); } 

Créer un élément déplaçable que je peux glisser sur la boîte.

 .directive('draggableTypes', function() { return { ressortingct:'A', link: function(scope, element, attrs) { element.draggable({ zIndex:3000, appendTo: 'body', helper: function(e, ui){ var formBox = angular.element($("#formBox")); percent = formBox.width() / scope.templateData.pdf_width; if(element.attr('id') == 'textbox_item') return $('
New Text Box.
').css({ 'transform': 'scale(' + percent + ')', '-moz-transform': 'scale(' + percent + ')', '-webkit-transform': 'scale(' + percent + ')', '-ms-transform': 'scale(' + percent + ')'}); if(element.attr('id') == 'sm_textbox_item') return $('
').css({ 'transform': 'scale(' + percent + ')', '-moz-transform': 'scale(' + percent + ')', '-webkit-transform': 'scale(' + percent + ')', '-ms-transform': 'scale(' + percent + ')'}); } }); } }; })

Créez des éléments déplaçables / redimensionnables qui peuvent déjà se trouver dans la zone et appliquez le correctif glisser / redimensionner à ces éléments.

 .directive('textboxDraggable', function() { return { ressortingct:'A', link: function(scope, element, attrs) { element.draggable({ cursor: "move", drag: dragFix, start: function(event, ui) { var activeId = element.attr('id'); scope.activeElement.id = activeId; scope.activeElement.name = scope.templateItems[activeId].info.name; scope.$apply(); } }); element.resizable({ minWidth: 25, minHeight: 25, resize: resizeFix, stop: function( event, ui ) { var activeId = element.attr('id'); scope.activeElement.duplicateName = false; scope.activeElement.id = activeId; scope.activeElement.name = scope.templateItems[activeId].info.name; scope.templateItems[activeId]['style']['width'] = element.css('width'); scope.templateItems[activeId]['style']['height'] = element.css('height'); scope.$apply(); } }) } }; }) 

Que se passe-t-il lorsqu’un object est déposé?

 .directive('droppable', function($comstack) { return { ressortingct: 'A', link: function(scope,element,attrs){ element.droppable({ drop:function(event,ui) { var draggable = angular.element(ui.draggable), draggable_parent = draggable.parent().parent(), drag_type = draggable.attr('id'), documentBg = element, x = ui.offset.left, y = ui.offset.top, element_top = (y - documentBg.offset().top - draggable.height() * (percent - 1) / 2) / percent, element_left = (x - documentBg.offset().left - draggable.width() * (percent - 1) / 2) / percent, timestamp = new Date().getTime(); //just get the document page of where the mouse is if its a new element if(draggable_parent.attr('id') == 'template_builder_box_container' || draggable_parent.attr('id') == 'template_builder_container') var documentPage = documentBg.parent().parent().attr('id').replace(/^(\w+)_/, ""); //if you are dragging an element that was already on the page, get parent of draggable and not parent of where mouse is else var documentPage = draggable_parent.parent().parent().attr('id').replace(/^(\w+)_/, ""); if(drag_type == "textbox_item") { scope.activeElement.id = scope.templateItems.push({ info: {'page': documentPage,'name': 'textbox_'+timestamp, 'type': 'text'}, style: {'text-align':'left','font-size':'14px','top':element_top+'px','left':element_left+'px', 'width':'200px', 'height':'20px'} }) - 1; scope.activeElement.name = 'textbox_'+timestamp; } else if(drag_type == "sm_textbox_item") { scope.activeElement.id = scope.templateItems.push({ info: {'page': documentPage,'name': '', 'type': 'text'}, style: {'text-align':'left','font-size':'14px','top':element_top+'px','left':element_left+'px', 'width':'5px', 'height':'5px'} }) - 1; scope.activeElement.name = 'textbox_'+timestamp; } else { scope.templateItems[scope.activeElement.id]['style']['top'] = draggable.css('top'); scope.templateItems[scope.activeElement.id]['style']['left'] = draggable.css('left'); } scope.$apply(); } }); } }; }) 

last but not least, mon contrôleur

 .controller('testing', function($scope, $rootScope, $state, $stateParams) { $scope.templateItems = []; $scope.activeElement = { id: undefined, name: undefined }; $scope.templateData = {"id":"12345", "max_pages":1,"pdf_width":385,"pdf_height":800}; $scope.clickElement = function(index) { $scope.activeElement = { id: index, name: $scope.templateItems[index].info.name } } }); 

Voici la base de mon HTML

 
{{ item.info.name }}

    Pour la position du curseur pendant le glissement, voir cette réponse: Positionner le curseur au centre pour ui.helper dans la méthode jquery-ui draggable

    Fondamentalement, vous pouvez contrôler la position du curseur de l’instance, ce qui permet d’avoir quelque chose de plus dynamic que le curseurAt . Comme ça:

     start: function(event, ui){ $(this).draggable('instance').offset.click = { left: Math.floor(ui.helper.width() / 2), top: Math.floor(ui.helper.height() / 2) } }, 

    Ensuite, sur le drop , vous devez prendre en compte la transformation, mais vous pouvez simplifier en utilisant les coordonnées auxiliaires au lieu du draggable . Comme ça:

     element_top = (ui.helper.offset().top / percent) - (documentBg.offset().top / percent); element_left = (ui.helper.offset().left / percent) - (documentBg.offset().left / percent); 

    Résultat: https://codepen.io/anon/pen/jamLBq

    On dirait que ce qui fait paraître cela étrange est le suivant:

    Tout d’abord, le petit div est stylé comme display: block . Cela signifie que même si le div semble petit, cet élément s’étend à son conteneur entier.

    Deuxièmement, une fois que vous affichez le carré déplacé sur l’écran de gauche, la relation entre le curseur de la souris et l’ensemble de l’élément est centrée techniquement, mais vous réduisez la taille de l’élément original et sa largeur et sa hauteur diminuent. , le résultat est rendu avec la nouvelle largeur et hauteur en partant du coin supérieur gauche du div original. (Si vous stylisez le petit bouton à display: inline , vous pouvez voir ce que je veux dire. Essayez de le saisir dans le coin supérieur gauche et essayez le plus à droite. Vous verrez que le premier semble correct mais le dernier est éteint) .

    Donc, mes suggestions sont les suivantes:

    1. Faire apparaître les éléments du draggabble display: inline
    2. Faites en sorte que l’élément glissé sur l’écran gauche affiche la hauteur et la largeur exactes de l’élément d’origine sur l’écran de droite.

    J’espère que cela pourra aider!

    J’ai fourré votre codepen et joué avec.

    Regardez-la ICI et voyez si cela vous aide à trouver le “bug”.

    Pour votre script draggable , j’ai modifié le code en ajoutant margin-left et margin-right :

     if(element.attr('id') == 'sm_textbox_item') { /* the small draggable box */ var el = { pos: element.offset(), // position of the small box height: element.outerHeight() + 20, left: 0 } var deduct = $('#formBox').innerWidth() - 20; // width of the element that's left of small box's container el.left = el.pos.left - deduct; return $('
    ') .css({ 'margin-left': el.left + 'px', 'margin-top': el.pos.top - el.height + 'px', 'transform': 'scale(' + percent + ')', '-moz-transform': 'scale(' + percent + ')', '-webkit-transform': 'scale(' + percent + ')', '-ms-transform': 'scale(' + percent + ')' }); }

    Ensuite, pour votre script de droppable , j’ai modifié la formule pour element_top et element_left :

     // old formula element_top = (y - documentBg.offset().top - draggable.height() * (percent - 1) / 2) / percent element_left = (x - documentBg.offset().left - draggable.width() * (percent - 1) / 2) / percent // new formula element_top = (y - documentBg.offset().top) / (percent * 0.915) element_left = (x - documentBg.offset().left) / (percent * 0.915) 

    Cela donne un résultat “presque” précis, mais vous pourrez peut-être le peaufiner pour le peaufiner. J’espère que cela t’aides.

    Pour attacher des éléments avec le curseur pendant le glissement, il vous suffit d’utiliser

     cursorAt: { top: 6, left: -100 } 

    Et un petit changement dans les parameters haut et gauche de “sm_textbox_item”.

     top: (y - documentBg.offset().top) / (percent) + "px", left: (x - documentBg.offset().left) / (percent) + "px", 

    Pour la grande case, un ajustement des éléments haut et gauche est nécessaire (mise à jour du stylo).

    top: element_top-3, left: element_left+6.49,

    J’ai fourré votre stylo et fait quelques changements. Je sais que ce n’est pas une solution parfaite, j’essaie aussi de la résoudre petit à petit. Vous pouvez le vérifier ici

    @ITWitch a raison, il doit y avoir un bug dans draggable() . margin: 0 auto; style margin: 0 auto; dans #sm_textbox_item est la source du problème.

    Essayez d’append ceci aux options déplaçables dans votre directive draggableType pour corriger la position:

    cursorAt: {left: -parseInt(window.getComputedStyle(element[0],null,null)['margin-left'])},

    Ce problème se produit lorsque vous ajoutez une transform au style d’un élément, puis que vous le faites glisser. Il faudra se débrouiller sans se transform pour obtenir un résultat parfait. J’ai passé 2 jours à déboguer jusqu’à ce que je le découvre et je ne voulais pas que quelqu’un d’autre passe par cette douleur.