2014-04-26 14 views
6

Sono interessato alla creazione di un SVG composito mediante la composizione di elementi grafici riutilizzabili racchiusi all'interno delle direttive Angular.js. Per esempio potrei avere:AngularJS: elementi SVG di transizione nelle direttive

<div ng-app="svgApp"> 
    <canvas> 
    <drawing ng-repeat="i in [1,2,3]" cy="{{i * 40}}"></drawing> 
    </canvas> 
</div> 

dove sto definendo i seguenti direttive:

.directive('canvas', function() { 
    return { 
     template: '<svg height=200 width=100 ng-transclude></svg>', 
     restrict: 'E', 
     replace: true, 
     transclude: true 
    }; 
    }) 

    .directive('drawing', function() { 
    return { 
     template: '<circle cx=50 r=15></circle>', 
     restrict: 'E', 
     replace: true 
    }; 
    }) 

Il problema è che gli elementi SVG non sembrano ottenere transclusa correttamente. Un indizio sembra essere here, in another StackOverflow question che questo è principalmente dovuto al fatto che i nodi SVG non vengono creati correttamente all'interno di Angular.js.

Dopo aver frugato ulteriormente, ho trovato this solution, which involves using a helper function per sostituire gli elementi DOM rilevanti con nodi SVG correttamente creato, a la:

.value('createSVGNode', function(name, element, settings) { 
     var namespace = 'http://www.w3.org/2000/svg'; 
     var node = document.createElementNS(namespace, name); 
     for (var attribute in settings) { 
     var value = settings[attribute]; 
     if (value !== null && !attribute.match(/\$/) && (typeof value !== 'string' || value !== '')) { 
      node.setAttribute(attribute, value); 
     } 
     } 
     return node; 
    }); 

Tuttavia, sembrava auspicabile che avrei bisogno di utilizzare questo ovunque, e io volevo mantenere la soluzione alternativa al bug il più possibile, finché non è stata corretta.

La mia domanda è se la seguente sarebbe una soluzione ragionevole:

angular.forEach(['circle', ...], function (svgElem) { 

    svgModule 

    .directive(svgElem, function (createSVGNode) { 
     return { 
     restrict: 'E', 
     link: function(scope, element, attrs) { 
      var node = createSVGNode(svgElem, element, attrs); 
      angular.element(node).append(element[0].childNodes); 
      element.replaceWith(node); 
     } 
     }; 
    }); 

}); 

E questo funziona in Plunker!

È valido per me ridefinire le direttive degli elementi SVG esistenti in questo modo?

risposta

5

Quanto sopra è un approccio possibile se non è possibile spostare il codice fino al suggerimento di sviluppo attivo di AngularJS 1.3 in cui il problema degli elementi di inclusione di un diverso spazio dei nomi (come SVG o MathML) è resolved.

Il collegamento Plunker mostra come aggiornare il codice con la correzione. La chiave è l'aggiunta di una nuova chiave "templateNamespace" nell'oggetto definizione direttiva:

.directive('svgInternal', function() { 
    return { 
     templateNamespace: 'svg', 
     template: '<g><rect height="25" width="25" /><text x="30" y="20">Hello, World</text></g>', 
     restrict: 'E', 
     replace: true 
    }; 
    }) 

dove il codice seguente dimostra la direttiva SVG-tipo in uso:

<svg height="30"> 
    <svg-internal></svg-internal> 
    </svg> 

Edit: " type "è stato modificato in" templateNamespace "da 1.3.beta.19.

+1

Grazie per la risposta. Sto avendo problemi con il tuo plunkr, 'Frammento di SVG incorporato in un contenitore di svg (FIXED)' e 'SVG in transclusione (FIXED) 'non mostra lo svg rect. – apairet

+1

OK, 'type' è stato rinominato' templateNamespace' vedi http://plnkr.co/edit/IgXMeZ6vNHPLxZOs0Sbu – apairet

+0

Pre 1.3, avvolgere il modello in ''. Gli elementi SVG possono essere nidificati. –

Problemi correlati