2012-03-10 33 views
19

Tôi đang sử dụng d3.js để hiển thị bản đồ thế giới bằng svg (sử dụng https://github.com/johan/world.geo.json/blob/master/countries.geo.json cho các đối tượng địa lý). Tôi đang đóng gói logic hiển thị trong dạng xem xương sống. Khi tôi hiển thị chế độ xem và đính kèm nó vào DOM, không có gì hiển thị trong trình duyệt của tôi, mặc dù đánh dấu SVG được tạo chính xác khi xem HTML được tạo. Điều này làm cho tốt khi không đóng gói trong một Backbone.View. Dưới đây là mã của tôi sử dụng Backbone.view:SVG không hiển thị đúng như chế độ xem xương sống

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

Dưới đây là đoạn code mà làm việc, mà không sử dụng 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); 

Tôi cũng kèm theo một ảnh chụp màn hình của đánh dấu SVG tạo ra. Bất kỳ ý tưởng gì có thể xảy ra ở đây?

enter image description here

Edit - Đây là làm cho ghi đè phương pháp mà kết thúc giải quyết này, theo yêu cầu:

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

Trả lời

26

Vấn đề là các yếu tố "svg" đòi hỏi một không gian tên. D3 thực hiện điều này cho bạn một cách tự động; khi bạn nối thêm phần tử "svg", nó sử dụng không gian tên "http://www.w3.org/2000/svg". Để biết chi tiết, xem src/core/ns.js. Xương sống, không may, không xuất hiện để hỗ trợ các yếu tố không gian tên. Bạn muốn thay đổi phương thức view.make. Sau đó, bạn cần một thuộc tính namespaceURI trên khung nhìn của bạn để đặt không gian tên thích hợp hoặc chỉ tự động làm điều đó cho các phần tử SVG để nhất quán với trình phân tích cú pháp HTML5.

Ở mức độ nào đó, cách khắc phục đơn giản cho vấn đề của bạn là bao bọc SVG của bạn trong phần tử DIV, sau đó sử dụng D3 để tạo phần tử SVG.

+0

Cảm ơn! Tôi overrode 'làm' trong quan điểm của tôi và sử dụng createElementNS với 'http://www.w3.org/2000/svg' thay vì createElement và điều đó dường như làm các trick. Đánh giá cao hướng dẫn. –

+1

@rr: bạn có thể đăng phương thức tạo của mình ở đâu đó không? –

+0

@PierreSpring: Xong, không chắc chắn về mức độ liên quan của phiên bản này với các phiên bản Backbone mới hơn, tôi vẫn chưa theo kịp. –

4

Bạn chỉ có thể thiết lập các phần tử của cái nhìn trong hàm khởi tạo như sau:

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

này có lợi thế là explicite.

+1

Đây là những gì được đề cập bởi các tác giả xương sống ở đây: https://github.com/documentcloud/backbone/pull/1357 –

+1

Bạn không cần phải tạo một div mặc dù, 'setElement (tài liệu. createElementNS ('http://www.w3.org/2000/svg','svg')) 'là tốt. –

3

Kiểm tra này ra http://jsfiddle.net/nocircleno/QsEp2/ từ 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); 
    } 
} 
}); 
Các vấn đề liên quan