2010-07-20 15 views
34

Ho lavorato con un documento HTML5 con SVG in linea e animazione javascript.Selettore jQuery + SVG Incompatibile?

Mi piacerebbe avere una finestra pop-up quando l'utente fa clic ovunque, e vorrei che la scatola scomparisse quando l'utente fa clic da qualche parte che non è la scatola. Questo significa che non posso usare $(window).click(), che funziona.

Ho provato a selezionare gli SVG in alto dando loro nomi di classe e utilizzando $(".svgclassname").click(), ma questo non sembra funzionare. Né seleziona singoli con $("#svgname").click().

Qual è il problema?

(Se si sostituisce $(".eyesvg") con $(window), una scatola blu appare vicino al cursore quando l'utente fa clic in qualsiasi punto della finestra.)

risposta

64

Ciò accade perché la specifica SVG DOM differisce molto dal DOM HTML.

SVG DOM è un dialetto diverso e alcune proprietà hanno lo stesso nome ma significano cose diverse. Ad esempio, per ottenere il className di un elemento SVG, si utilizza:

svg.className.baseVal 

I properites colpiti da questa sta

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

Queste proprietà animate sono le strutture, con baseVal tenendo lo stesso valore che aveva trovare in HTML DOM e animatedVal tenendo non sono sicuro di cosa.

SVG DOM è anche privo di alcune librerie di proprietà, ad esempio innerHTML.

Ciò interrompe jQuery in molti modi, tutto ciò che dipende dalle proprietà precedenti non riesce.

In generale, SVG DOM e HTML DOM non si combinano molto bene. Lavorano insieme quel tanto che basta per attirarti, e poi le cose scoppiano in silenzio, e un altro angelo perde le ali.

ho scritto un po 'di estensione jQuery che avvolge elementi SVG per farle sembrare più simile a 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); 

Si crea un wrapper per oggetti SVG che li fa apparire come HTML DOM a jQuery. L'ho usato con jQuery-UI per rendere i miei elementi SVG trascinabili.

La mancanza di interoperabilità DOM tra HTML e SVG è un disastro totale. Tutte le librerie di utilità dolce scritte per HTML devono essere reinventate per SVG.

+7

Ehi, Aleksander, grazie per questo suggerimento! Lo snippet ci ha portato molto lontano, ma non ha funzionato in Firefox 15 a causa di un errore generato durante l'utilizzo dell'ereditarietà del prototipo direttamente con un elemento SVG DOM. Lo abbiamo modificato per funzionare in Firefox e lo stiamo usando con successo. Il codice è qui: http://github.com/RedBrainLabs/jquery.wrap-svg –

+0

Basta caricare lo script in Safari 8.0 Ho ricevuto un errore: "SyntaxError: le istruzioni della funzione devono avere un nome." (svg.js, riga 1). Ho messo lo script in un file js separato, svg.js, e ho provato a caricarlo prima e dopo il file jQuery. Stesso errore in entrambi i casi. –

+0

Sembra fantastico, ma come deve essere usato? – kris

3

a volte non capisco ... ma in realtà non funziona con il selettore di classe. Se usi id $ ("# mysvg") o l'elemento $ ("svg") funziona! Strano ....

E funziona solo quando si sposta lo script onClick dall'intestazione al corpo dopo l'elemento svg! jquery può solo associare l'onclick quando l'elemento è dichiarato prima dell'associazione.

+0

Aha! Funziona favolosamente.Nonostante il problema di jQuery con il selettore di classe, sono sicuro che sarò in grado di selezionare più ID. Grazie! – thure

+9

Nota che puoi selezionare gli elementi SVG per classe usando '$ ('* [class ~ =" eyesvg "]')' ([l'attributo contiene il selettore di parole] (http://api.jquery.com/attribute-contains -word selettore /)). – Phrogz

3

u possibile utilizzare jquery-svg plug-in, come un fascino:

<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>