images 3wschool javascript jquery css3 webkit

javascript - 3wschool - Webkit y jQuery draggable jumping



flex-wrap (8)

@ecmanaut: Gran solución. Gracias por tus esfuerzos. Para ayudar a otros, convertí tu solución en un parche de mono. Copie el código a continuación en un archivo. Incluya el archivo después de cargar jquery-ui.js de la siguiente manera:

<script src="javascripts/jquery/jquery.js"></script> <script src="javascripts/jquery/jquery-ui.js"></script> <!-- the file containing the monkey-patch to draggable --> <script src="javascripts/jquery/patch_draggable.js"></script>

Aquí está el código para copiar / pegar en patch_draggable.js:

function monkeyPatch_mouseStart() { // don''t really need this, but in case I did, I could store it and chain 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; } } } //Create and append the visible helper this.helper = this._createHelper(event); //Cache the helper size this._cacheHelperProportions(); //If ddmanager is used for droppables, set the global draggable if($.ui.ddmanager) $.ui.ddmanager.current = this; /* * - Position generation - * This block generates everything position related - it''s the core of draggables. */ //Cache the margins of the original element this._cacheMargins(); //Store the helper''s css position this.cssPosition = this.helper.css("position"); this.scrollParent = this.helper.scrollParent(); //The element''s absolute position on the page minus margins 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: { //Where the click happened, relative to the element left: event.pageX - this.offset.left, top: event.pageY - this.offset.top }, parent: this._getParentOffset(), relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper }); //Generate the original position this.originalPosition = this.position = this._generatePosition(event); this.originalPageX = event.pageX; this.originalPageY = event.pageY; //Adjust the mouse offset relative to the helper if ''cursorAt'' is supplied (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); //Set a containment if given in the options if(o.containment) this._setContainment(); //Trigger event + callbacks if(this._trigger("start", event) === false) { this._clear(); return false; } //Recache the helper size this._cacheHelperProportions(); //Prepare the droppable offsets if ($.ui.ddmanager && !o.dropBehaviour) $.ui.ddmanager.prepareOffsets(this, event); this.helper.addClass("ui-draggable-dragging"); //JWL: Hier vindt de jump plaats this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event); return true; }; } monkeyPatch_mouseStart();

Como experimento, creé algunos div y los giré usando CSS3.

.items { position: absolute; cursor: pointer; background: #FFC400; -moz-box-shadow: 0px 0px 2px #E39900; -webkit-box-shadow: 1px 1px 2px #E39900; box-shadow: 0px 0px 2px #E39900; -moz-border-radius: 2px; -webkit-border-radius: 2px; border-radius: 2px; }

Luego los diseñé al azar y los hice arrastrables a través de jQuery.

$(''.items'').each(function() { $(this).css({ top: (80 * Math.random()) + ''%'', left: (80 * Math.random()) + ''%'', width: (100 + 200 * Math.random()) + ''px'', height: (10 + 10 * Math.random()) + ''px'', ''-moz-transform'': ''rotate('' + (180 * Math.random()) + ''deg)'', ''-o-transform'': ''rotate('' + (180 * Math.random()) + ''deg)'', ''-webkit-transform'': ''rotate('' + (180 * Math.random()) + ''deg)'', }); }); $(''.items'').draggable();

El arrastre funciona, pero estoy notando un salto repentino mientras arrastro los divs solo en navegadores webkit, mientras que todo está bien en Firefox.

Si elimino la posición: estilo absoluto , el ''salto'' es aún peor. Pensé que tal vez había una diferencia en el origen de la transformación entre webkit y gecko, pero ambos están en el centro del elemento de forma predeterminada.

Ya he buscado, pero solo obtuve resultados sobre barras de desplazamiento o listas ordenables.

Aquí hay una demostración funcional de mi problema. Intenta verlo en Safari / Chrome y Firefox. http://jsbin.com/ucehu/

¿Es esto un error dentro de webkit o cómo los navegadores rinden webkit?


David Wick tiene razón sobre la dirección general anterior, pero calcular las coordenadas correctas es mucho más complicado que eso. Aquí hay un parche para monos más preciso, basado en el código Firebug con licencia de MIT, que debería funcionar en muchas más situaciones donde tienes un DOM complejo:

En lugar de reemplazar:

//The element''s absolute position on the page minus margins this.offset = this.positionAbs = this.element.offset();

con el menos hacky (asegúrese de obtener todo, tendrá que desplazarse):

//The element''s absolute position on the page minus margins this.offset = this.positionAbs = getViewOffset(this.element[0]); 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; } } }

Es una pena que el DOM no exponga estos cálculos de forma nativa.


Debe establecer el contenedor principal del elemento arrastrable en "posición: relativa".


Dibujo una imagen para indicar el desplazamiento después de rotar en diferentes navegadores como la respuesta de @David Wick.

Este es el código que se debe corregir si no desea parchar o modificar jquery.ui.draggable.js

$(document).ready(function () { var recoupLeft, recoupTop; $(''#box'').draggable({ start: function (event, ui) { var left = parseInt($(this).css(''left''),10); left = isNaN(left) ? 0 : left; var top = parseInt($(this).css(''top''),10); top = isNaN(top) ? 0 : top; recoupLeft = left - ui.position.left; recoupTop = top - ui.position.top; }, drag: function (event, ui) { ui.position.left += recoupLeft; ui.position.top += recoupTop; } }); });

o puedes ver la demo


Esto es el resultado de la dependencia del draggable de la función jquery offset() y del uso de offset() de la función js nativa getBoundingClientRect() . En última instancia, se trata de un problema con el núcleo de jquery que no compensa las incoherencias asociadas con getBoundingClientRect() . La versión de Firefox de getBoundingClientRect() ignora las transformaciones css3 (rotación) mientras que cromo / safari (webkit) no lo hace.

here hay una ilustración del problema.

Una solución hacky:

reemplace lo siguiente en jquery.ui.draggable.js

//The element''s absolute position on the page minus margins this.offset = this.positionAbs = this.element.offset();

con

//The element''s absolute position on the page minus margins this.offset = this.positionAbs = { top: this.element[0].offsetTop, left: this.element[0].offsetLeft };

y finalmente una versión monopatched de tu jsbin .


Prefiero esta solución ya que conserva el controlador original
Elimina la transformación y luego la restaura

$(document).ready(function(){ // backup original handler var _mouseStart = $.ui.draggable.prototype._mouseStart; $.ui.draggable.prototype._mouseStart = function(event) { //remove the transform var transform = this.element.css(''transform''); this.element.css(''transform'', ''none''); // call original handler var result = _mouseStart.call(this, event); //restore the transform this.element.css(''transform'', transform); return result; }; });

demo (comenzada desde @Liao San-Kai jsbin)


Usé muchas de las soluciones para que el arrastre funcionara correctamente. PERO, todavía reaccionó mal a una zona de caída (como si no hubiera sido rotada). La solución realmente es usar un contenedor principal que esté posicionado de manera relativa.

Esto me ahorró muchísimo tiempo.

<div id="drawarea"> <div class="rect-container h"> <div class="rect"></div> </div> </div> .rect-container { position:relative; }

Solución completa aquí (no es de mi parte): http://jsfiddle.net/Sp6qa/2/

También investigué mucho. Y es así, jQuery no tiene planes de cambiar ese comportamiento actual en el futuro. Todos los tickets enviados sobre ese tema se cerraron. Por lo tanto, empiece con tener contenedores padres que estén en posición relativa. Funciona como un encanto y debe ser a prueba de futuro.


la respuesta de David Wick fue muy útil ... gracias ... aquí codifiqué la misma solución para el cambio de tamaño, porque tiene el mismo problema:

busque lo siguiente en jquery.ui.resizable.js

var o = this.options, iniPos = this.element.position(), el = this.element;

y reemplazar con:

var o = this.options, iniPos = {top:this.element[0].offsetTop,left:this.element[0].offsetLeft}, el = this.element;