2012-03-10 5 views
19

d3.js를 사용하여 svg에서 세계지도를 렌더링합니다 (기능에 대해 https://github.com/johan/world.geo.json/blob/master/countries.geo.json 사용). Backbone View에서 렌더링 로직을 캡슐화하고 있습니다. 보기를 렌더링하고 DOM에 첨부하면 생성 된 HTML을 볼 때 SVG 마크 업이 올바르게 생성되지만 브라우저에는 아무 것도 표시되지 않습니다. 이것은 Backbone.View에서 캡슐화하지 않을 때 훌륭하게 렌더링됩니다.SVG가 백본보기로 올바르게 렌더링되지 않습니다.

/** 
* 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(); 

가 여기에 작동하는 코드이다 나는 또한 생성 된 SVG 마크 업의 스크린 샷을 첨부했습니다

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

Backbone.View

사용하지 않고, 다음은 Backbone.view를 사용하여 내 코드입니다. 어떤 생각이 잘못 될 수 있습니까?

/** 
* 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; 
} 

답변

26

문제는 "SVG"요소는 네임 스페이스를 필요로한다는 것이다 : -

enter image description here

편집 여기에 요청에 따라,이 문제를 해결 결국 재정의 메이크업 방법입니다. D3가 자동으로이 작업을 수행합니다. "svg"요소를 추가하면 네임 스페이스 "http://www.w3.org/2000/svg"이 사용됩니다. 자세한 내용은 src/core/ns.js을 참조하십시오. 불행히도 백본은 네임 스페이스 요소를 지원하지 않는 것으로 보입니다. view.make 메소드를 변경하려고합니다. 그런 다음 적절한 네임 스페이스를 설정하기 위해 view에 namespaceURI 속성이 필요하거나 HTML5 파서와의 일관성을 위해 SVG 요소에 대해 자동으로 수행하면됩니다.

어쨌든 간단한 문제는 DIV 요소에 SVG를 래핑 한 다음 D3을 사용하여 SVG 요소를 만드는 것입니다. 다음과 같이

+0

감사에서 http://jsfiddle.net/nocircleno/QsEp2/ ! 나는 내 생각에 'make'를 무력화 시켰고 createElement 대신 'http://www.w3.org/2000/svg'와 함께 createElementNS를 사용했다. 지침을 감사하십시오. –

+1

@rr : 어딘가에 방법을 게시 할 수 있습니까? –

+0

@PierreSpring :이 백본의 최신 버전과의 관련성에 대해서는 잘 모름. –

4

당신은 간단하게 초기화 기능에 뷰의 요소를 설정할 수 있습니다 :

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] 
     ); 
    } 
); 

이 explicite되는 장점이 있습니다.

+1

여기 백본 제작자가 언급 한 내용은 다음과 같습니다. https://github.com/documentcloud/backbone/pull/1357 –

+1

div를 만들 필요는 없습니다. setElement (document. createElementNS ('http://www.w3.org/2000/svg','svg'))'괜찮습니다. –

3

확인이 밖으로 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); 
    } 
} 
}); 
관련 문제