SVG ne fonctionne pas correctement comme vue arrière

J'utilise d3.js pour rendre une carte du monde dans svg (en utilisant https://github.com/johan/world.geo.json/blob/master/countries.geo.json pour les fonctionnalités). J'encapsule la logique de rendu dans une vue Backbone. Lorsque je rends la vue et je la joigne au DOM, rien ne s'affiche dans mon navigateur, bien que le balisage SVG soit correctement généré en regardant le HTML généré. Cela rend la fonction correcte lorsqu'elle ne s'inscrit pas dans un Backbone.View. Voici mon code utilisant Backbone.view:

/** * SVG Map view */ var MapView = Backbone.View.extend({ tagName: 'svg', translationOffset: [480, 500], zoomLevel: 1000, /** * Sets up the map projector and svg path generator */ initialize: function() { this.projector = d3.geo.mercator(); this.path = d3.geo.path().projection(this.projector); this.projector.translate(this.translationOffset); this.projector.scale(this.zoomLevel); }, /** * Renders the map using the supplied features collection */ render: function() { d3.select(this.el) .selectAll('path') .data(this.options.featureCollection.features) .enter().append('path') .attr('d', this.path); }, /** * Updates the zoom level */ zoom: function(level) { this.projector.scale(this.zoomLevel = level); }, /** * Updates the translation offset */ pan: function(x, y) { this.projector.translate([ this.translationOffset[0] += x, this.translationOffset[1] += y ]); }, /** * Refreshes the map */ refresh: function() { d3.select(this.el) .selectAll('path') .attr('d', this.path); } }); var map = new MapView({featureCollection: countryFeatureCollection}); map.$el.appendTo('body'); map.render(); 

Voici le code qui fonctionne, sans utiliser Backbone.View

 var projector = d3.geo.mercator(), path = d3.geo.path().projection(projector), countries = d3.select('body').append('svg'), zoomLevel = 1000; coords = [480, 500]; projector.translate(coords); projector.scale(zoomLevel); countries.selectAll('path') .data(countryFeatureCollection.features) .enter().append('path') .attr('d', path); 

J'ai également attaché une capture d'écran du balisage SVG généré. Une idée de ce qui pourrait se passer mal ici?

Entrez la description de l'image ici

Edit – Voici la méthode de création surchargée qui a fini par résoudre ceci, par demande:

 /** * Custom make method needed as backbone does not support creation of * namespaced HTML elements. */ make: function(tagName, attributes, content) { var el = document.createElementNS('http://www.w3.org/2000/svg', tagName); if (attributes) $(el).attr(attributes); if (content) $(el).html(content); return el; } 

Le problème est que l'élément "svg" nécessite un espace de noms. D3 le fait automatiquement pour votre compte; Lorsque vous ajoutez un élément "svg", il utilise l'espace de noms " http://www.w3.org/2000/svg ". Pour plus de détails, voir src / core / ns.js. L'épine dorsale, malheureusement, ne semble pas prendre en charge les éléments nommés sur les noms. Vous souhaitez modifier la méthode view.make . Ensuite, vous auriez besoin d'une propriété namespaceURI sur votre vue pour définir l'espace de noms approprié, ou simplement le faire automatiquement pour les éléments SVG pour la cohérence avec l'analyseur HTML5.

En tout cas, une solution simple pour votre problème consiste à envelopper votre SVG dans un élément DIV, puis à utiliser D3 pour créer l'élément SVG.

Vous pouvez simplement définir l'élément de la vue dans la fonction d'initialisation comme suit:

 Backbone.View.extend({ // This is only for informaiton. The node will // be raplaced in the initialize function. tagName: 'svg', initialize: function () { this.setElement( d3.select($('<div/>')[0]).append('svg')[0] ); } ); 

Cela a l'avantage d'être explicite.

Vérifiez ceci http://jsfiddle.net/nocircleno/QsEp2/ de http://nocircleno.com/blog/svg-with-backbone-js/

 Backbone.View.extend({ nameSpace: "http://www.w3.org/2000/svg", _ensureElement: function() { if (!this.el) { var attrs = _.extend({}, _.result(this, 'attributes')); if (this.id) attrs.id = _.result(this, 'id'); if (this.className) attrs['class'] = _.result(this, 'className'); var $el = $(window.document.createElementNS(_.result(this, 'nameSpace'), _.result(this, 'tagName'))).attr(attrs); this.setElement($el, false); } else { this.setElement(_.result(this, 'el'), false); } } });