¿Cómo puedo hacer que los elementos SVG que se arrastran en Chrome con jQuery funcionen sin obtener compensaciones? (Firefox está bien)

Estoy tratando de escribir algún código que permita arrastrar elementos SVG. Esto es bastante fácil con jQuery, jQuery UI y jQuery SVG, y funciona bien en Firefox, pero en Chrome cuando arrastro el elemento SVG, aparentemente se agrega un desplazamiento a sus coordenadas. No puedo ver nada que esté haciendo mal, o descubrir cualquier error conocido en esta área.

He construido un pequeño ejemplo que ilustra el problema:

  Foo       $(function() { var svgOnLoad = function () { var svg = $('#canvas').svg('get'); $('#piece') .draggable() .bind('drag', function (event, ui) { // Update transform manually, since top/left style props don't work on SVG var t = event.target.transform.baseVal; if (t.numberOfItems == 0) { t.appendItem(svg.root().createSVGTransform()); } t.getItem(0).setTranslate(ui.position.left, ui.position.top); }); } $('#canvas').svg({loadURL: "foo.svg", onLoad: svgOnLoad}); });    

donde foo.svg es solo:

     

Una versión en línea se puede encontrar en:

http://jsfiddle.net/rrthomas/v477X/2/

El problema es que no estás empezando en la posición 0, 0 del canvas de svg. Puede lograr el resultado deseado restando los atributos x e y del objeto. Cuando calcula su arrastre manual, está reubicando todo el elemento svg, no solo el rectángulo.

Consulte aquí: http://jsfiddle.net/v477X/6/

NOTA: Los diferentes navegadores parecen devolver diferentes objetos para el elemento que está intentando traducir. Esta solución funciona en los navegadores webkit. En este punto, parece que tienes 2 opciones. Modifique su selector para elegir el mismo elemento, (específicamente la línea t.getItem (0)), o determine en qué navegador está viendo actualmente el usuario, y agregue la compensación si es webkit. Personalmente, me gustaría ir con este último, ya que de esa manera solo puede establecer una variable y verificarla.

Consulte aquí cómo detectar el motor del navegador: ¿Cómo detectar si un navegador utiliza Chrome con jQuery?

Parece que hay un error en jQueryUI aquí: en los navegadores que no son de Webkit, el objeto ui.position utiliza coordenadas absolutas, mientras que en otros navegadores es un desplazamiento de ui.originalPosition. No sé cuál es la correcta; El error es que el comportamiento es inconsistente. He presentado un informe de error en:

http://bugs.jqueryui.com/ticket/8335

Por lo tanto, la solución es almacenar las coordenadas originales del elemento de nivel superior y establecer la coordenada en (ui.position – ui.originalPosition + origCoords) al configurar la transformación de traducción en los navegadores Webkit. (La respuesta de Jlange usa los atributos x e y del rect utilizado en mi ejemplo mínimo, que funciona bien allí, pero no funciona con objetos más complejos, lo que a) no puede tener atributos x e y (por ejemplo, si el elemento de nivel superior es El elemento ag) yb) donde las coordenadas devueltas no parecen ser las del elemento de nivel superior de todos modos (me temo que no sé por qué).

 var svgOnLoad = function () { var svg = $('#canvas').svg('get');   $('#piece')     .draggable() .on({ dragstart: function (event, ui) { var tlist = this.transform.baseVal;           if (tlist.numberOfItems == 0) {             tlist.appendItem(svg.root().createSVGTransform());           }           var tm = tlist.getItem(0).matrix;           var pos = {left: tm.e, top: tm.f};           $.data(this, 'originalPosition', pos);         },         drag: function (event, ui) {           // Update transform manually, since top/left style props don't work on SVG           var tlist = this.transform.baseVal; var CTM = this.getCTM(); var p = svg.root().createSVGPoint(); px = ui.position.left + CTM.e; py = ui.position.top + CTM.f; if ($.browser.webkit) { // Webkit gets SVG-relative coords, not offset from element var origPos = $.data(this, 'originalPosition'); px -= ui.originalPosition.left - origPos.left; py -= ui.originalPosition.top - origPos.top; } p = p.matrixTransform(CTM.inverse()); tlist.getItem(0).setTranslate(px, py);         }}); }; $('#canvas').svg({onLoad: svgOnLoad}); 

Versión en vivo en: http://jsfiddle.net/rrthomas/v477X/

Recientemente pasé un par de días tratando este problema y encontré una solución que funcionó bastante bien para mí. Definitivamente es un hack y no funcionará en todas las situaciones.

Este enlace tiene una excelente descripción de cómo resolver el problema en general, y esa es definitivamente la solución “mejor”. Sin embargo, quería seguir usando la excelente API de Draggable de JQuery.

Puedes ver una rápida maqueta de lo que hice en un violín aquí . La idea clave es usar un div de proxy que mantienes flotando exactamente sobre el elemento svg que deseas arrastrar. Luego, cambia las coordenadas x e y del elemento svg a medida que arrastra el proxy div. Algo como esto:

 $('#proxy').on('drag', function(e) { t = $('#background'); prox = $('#proxy'); t.attr('x', t.attr('x')*1 + prox.css('left').slice(0,-2)*1 - prox.data('position').left) .attr('y', t.attr('y')*1 + prox.css('top').slice(0,-2)*1 - prox.data('position').top); prox.data('position',{top : prox.css('top').slice(0,-2)*1, left: prox.css('left').slice(0,-2)*1} ); }); 

En mi caso, el elemento SVG que quería arrastrar siempre llenaría un cierto cuadrado en la pantalla, por lo que fue muy fácil colocar el div proxy sobre el objective. En otras situaciones podría ser mucho más difícil. Tampoco es demasiado difícil usar la opción de “contención” para asegurarse de que no arrastre el fondo fuera del marco … solo es necesario realizar un análisis matemático cuidadoso y tiene que restablecer la contención entre cada arrastre.

utilizar esta:

   Foo        

Tengo un problema similar. Descubrí que, por alguna razón, Chrome convierte los atributos de transformación en propiedades de estilo CSS. Así que crea un estilo CSS, el motor CSS ajusta las coordenadas, luego el motor SVG intenta aplicar la transformación: traducir. Los dos entonces interfieren el uno con el otro.

El CSS parece tener prioridad. Aquí hay un codepen que muestra esto.
http://codepen.io/dax006/pen/ONNWXv

Mi teoría es que cuando Chrome está actualizando el estilo CSS, está siendo destruido y recreado constantemente, y en ocasiones, entre estos momentos, el SVG se cuela en una transformación: translate (). Chrome luego toma el nuevo valor de transformación y lo aplica al CSS, y ahora su transformación no funcionará correctamente porque el CSS está en el camino.

En teoría, la transformación: traducción debe destruirse exactamente en el mismo momento en que se crea el CSS, pero no lo es. Simplemente inspeccione el elemento y verá tanto la existencia de un estilo CSS que cambia las coordenadas como un atributo de transformación.

  

Asegúrese de revisar este artículo y los enlaces en la parte inferior. https://css-tricks.com/svg-animation-on-css-transforms/