2010-07-20 18 views
34

He estado trabajando con un documento HTML5 con SVG en línea y animación de JavaScript.jQuery Selector + SVG ¿Incompatible?

Me gustaría tener una ventana emergente cuando el usuario haga clic en cualquier lugar, y me gustaría que la caja se vaya cuando el usuario haga clic en algún lugar que no sea el cuadro. Esto significa que no puedo usar $(window).click(), que funciona.

He intentado seleccionar los SVG en la parte superior dándoles nombres de clase y usando $(".svgclassname").click(), pero parece que esto no funciona. Tampoco la selección de los individuales con $("#svgname").click().

¿Cuál es el problema?

(Si se sustituyen con $(".eyesvg")$(window), aparece un cuadro azul cerca del cursor cuando el usuario hace clic en cualquier lugar de la ventana.)

Respuesta

64

Esto ocurre porque la especificación SVG DOM difiere mucho de HTML DOM.

SVG DOM es un dialecto diferente, y algunas propiedades tienen los mismos nombres pero significan cosas diferentes. Por ejemplo, para obtener el className de un elemento SVG, que utilice:

svg.className.baseVal 

Los properites afectados por esto son

className is SVGAnimatedString 
height,width, x, y, offsetWidth, offsetHeight are SVGAnimatedLength 

Estas propiedades son animados estructuras, con baseVal sosteniendo el mismo valor que había encontrar en HTML DOM y animatedVal sosteniendo No estoy seguro de qué.

SVG DOM también le faltan algunas propiedades de las que dependen las bibliotecas, como innerHTML.

Esto rompe jQuery de muchas maneras, cualquier cosa que dependa de las propiedades anteriores falla.

En general, SV SV DOM y HTML DOM no se mezclan muy bien. Trabajan juntos lo suficiente para atraerte, y luego las cosas se rompen silenciosamente, y otro ángel pierde sus alas.

me escribió una pequeña extensión de jQuery que envuelve elementos SVG para que se vean más como HTML DOM

(function (jQuery){ 
    function svgWrapper(el) { 
     this._svgEl = el; 
     this.__proto__ = el; 
     Object.defineProperty(this, "className", { 
      get: function(){ return this._svgEl.className.baseVal; }, 
      set: function(value){ this._svgEl.className.baseVal = value; } 
     }); 
     Object.defineProperty(this, "width", { 
      get: function(){ return this._svgEl.width.baseVal.value; }, 
      set: function(value){ this._svgEl.width.baseVal.value = value; } 
     }); 
     Object.defineProperty(this, "height", { 
      get: function(){ return this._svgEl.height.baseVal.value; }, 
      set: function(value){ this._svgEl.height.baseVal.value = value; } 
     }); 
     Object.defineProperty(this, "x", { 
      get: function(){ return this._svgEl.x.baseVal.value; }, 
      set: function(value){ this._svgEl.x.baseVal.value = value; } 
     }); 
     Object.defineProperty(this, "y", { 
      get: function(){ return this._svgEl.y.baseVal.value; }, 
      set: function(value){ this._svgEl.y.baseVal.value = value; } 
     }); 
     Object.defineProperty(this, "offsetWidth", { 
      get: function(){ return this._svgEl.width.baseVal.value; }, 
      set: function(value){ this._svgEl.width.baseVal.value = value; } 
     }); 
     Object.defineProperty(this, "offsetHeight", { 
      get: function(){ return this._svgEl.height.baseVal.value; }, 
      set: function(value){ this._svgEl.height.baseVal.value = value; } 
     }); 
    }; 

    jQuery.fn.wrapSvg = function() { 
     return this.map(function(i, el) { 
      if (el.namespaceURI == "http://www.w3.org/2000/svg" && !('_svgEl' in el)) 
       return new svgWrapper(el); 
      else 
       return el; 
      }); 
     }; 
})(window.jQuery); 

Se crea una cobertura de los objetos SVG que hace que se vean como HTML DOM para jQuery. Lo he usado con jQuery-UI para hacer que mis elementos SVG sean desplegables.

La falta de interoperabilidad DOM entre HTML y SVG es un desastre total. Todas las bibliotecas de utilidad dulce escritas para HTML deben reinventarse para SVG.

+7

¡Hola Aleksander, gracias por esta sugerencia! El fragmento nos llevó bastante lejos, pero no funcionó en Firefox 15 debido a un error al usar la herencia de prototipos directamente con un elemento SVG DOM. Lo hemos modificado para que funcione en Firefox y lo estamos utilizando con éxito. El código está aquí: http://github.com/RedBrainLabs/jquery.wrap-svg –

+0

Simplemente cargando la secuencia de comandos en Safari 8.0 Obtuve un error: "SyntaxError: las instrucciones de la función deben tener un nombre". (svg.js, línea 1). Puse el script en un archivo js separado, svg.js, y traté de cargarlo antes y después del archivo jQuery. Mismo error en ambos casos. –

+0

Esto se ve genial, pero ¿cómo se supone que debe usarse? – kris

3

a veces no lo entiendo ... pero en realidad no funciona con el selector de clases Si usa el id $ ("# mysvg") o el elemento $ ("svg") ¡funciona! Extraño ...

¡Y solo funciona cuando mueves el script onClick del encabezado al cuerpo después del elemento svg! jquery solo puede enlazar el onclick cuando el elemento se declara antes del enlace.

+0

Aha! Eso funciona fabulosamente.A pesar del problema de jQuery con el selector de clases, estoy seguro de que solo podré seleccionar varios identificadores. ¡Gracias! – thure

+9

Tenga en cuenta que puede seleccionar elementos SVG por clase usando '$ ('* [class ~ =" eyesvg "]')' (el [atributo contiene selector de palabras]) (http://api.jquery.com/attribute-contains) -word-selector /)). – Phrogz

3

u puede utilizar jquery-svg plug-in, como un encanto:

<script> 
    //get svg object, like a jquery object 
    var svg = $("#cars").getSVG(); 
    //use jquery functions to do some thing 
    svg.find("g path:first-child()").attr('fill', color); 
</script>