2012-11-12 55 views
12

Tôi có một mảng của cấu trúc JSON lồng, nơi họ đã thay đổi sâu sắc và không phải là cùng một bộ chìa khóa ở khắp mọi nơi:đệ quy (hoặc lặp lại) tạo một bảng html lồng nhau với d3.js?

[ 
    { 
     "name":"bob", 
     "salary":10000, 
     "friends":[ 
      { 
       "name": "sarah", 
       "salary":10000 
      }, 
      { 
       "name": "bill", 
       "salary":5000 
      } 
     ] 
    }, 
    { 
     "name":"marge", 
     "salary":10000, 
     "friends":[ 
      { 
       "name": "rhonda", 
       "salary":10000 
      }, 
      { 
       "name": "mike", 
       "salary":5000, 
       "hobbies":[ 
        { 
         "name":"surfing", 
         "frequency":10 
        }, 
        { 
         "name":"surfing", 
         "frequency":15 
        } 
       ] 
      } 
     ] 
    }, 
    { 
     "name":"joe", 
     "salary":10000, 
     "friends":[ 
      { 
       "name": "harry", 
       "salary":10000 
      }, 
      { 
       "name": "sally", 
       "salary":5000 
      } 
     ] 
    } 
] 

Tôi muốn sử dụng D3 để render này bảng html như lồng nhau. Ví dụ cột bạn bè sẽ có bảng hiển thị tên và mức lương của bạn bè của cá nhân được tham chiếu trong hàng. Đôi khi một trong những bảng này sẽ có một cấp độ khác của một bảng phụ.

Tôi tưởng tượng cách để làm điều này là bằng cách đệ quy tạo bảng. Tôi đã viết một chương trình python mà có một cấu trúc JSON như thế này, và ám các bảng trong bảng, và cách dễ nhất để làm điều đó là đệ quy. Tôi thấy trên tài liệu d3.js có một điều .each() mà bạn có thể gọi, mà tôi chắc chắn là những gì tôi cần, tôi chỉ cần một chút tăng nhận được ở đó (https://github.com/mbostock/d3/wiki/Selections#wiki-each).

Vậy có cách nào tốt đẹp để thực hiện điều này trong D3? Tôi đã tìm thấy ví dụ tuyệt vời này để hiển thị ma trận dữ liệu 2d dưới dạng bảng Creating a table linked to a csv file. Với hướng dẫn đó, tôi có thể nhận được cấp độ ngoài cùng nhất của cấu trúc dữ liệu này được biểu hiện dưới dạng bảng, nhưng tôi bị kẹt về cách đi vào các cấp đệ quy khi cần thiết, lúc này chúng chỉ hiển thị dưới dạng "Đối tượng" trong bảng vì tôi không đối xử với họ khác với các chuỗi và số thường. Tôi cũng tìm thấy câu hỏi/câu trả lời tương tự như câu hỏi của tôi, nhưng tôi thực sự không hiểu rõ javascript đủ để xem nơi/cách thức đệ quy đang diễn ra và đọc giải pháp cho phù hợp với nhu cầu của tôi: How do I process data that is nested multiple levels in D3?. Bất kỳ lời khuyên hay chỉ dẫn nào để hướng dẫn về đệ quy hoặc lặp lại xử lý cây lồng nhau như cấu trúc dữ liệu JSON trong D3 sẽ được đánh giá cao!

Trả lời

18

Chức năng đệ quy có thể là cách tiếp cận tốt. Xem mã bên dưới để có thể triển khai (giả sử dữ liệu của bạn được lưu trữ trong jdata). Xem các nhận xét trong mã để xem giải thích và xem Gist này để có phiên bản trực tiếp: http://bl.ocks.org/4085017

d3.select("body").selectAll("table") 
    .data([jdata]) 
    .enter().append("table") 
    .call(recurse); 

function recurse(sel) { 
    // sel is a d3.selection of one or more empty tables 
    sel.each(function(d) { 
    // d is an array of objects 
    var colnames, 
     tds, 
     table = d3.select(this); 

    // obtain column names by gathering unique key names in all 1st level objects 
    // following method emulates a set by using the keys of a d3.map() 
    colnames = d              // array of objects 
     .reduce(function(p,c) { return p.concat(d3.keys(c)); }, []) // array with all keynames 
     .reduce(function(p,c) { return (p.set(c,0), p); }, d3.map()) // map with unique keynames as keys 
     .keys();              // array with unique keynames (arb. order) 

    // colnames array is in arbitrary order 
    // sort colnames here if required 

    // create header row using standard 1D data join and enter() 
    table.append("thead").append("tr").selectAll("th") 
     .data(colnames) 
     .enter().append("th") 
     .text(function(d) { return d; }); 

    // create the table cells by using nested 2D data join and enter() 
    // see also http://bost.ocks.org/mike/nest/ 
    tds = table.append("tbody").selectAll("tr") 
     .data(d)       // each row gets one object 
     .enter().append("tr").selectAll("td") 
     .data(function(d) {     // each cell gets one value 
      return colnames.map(function(k) { // for each colname (i.e. key) find the corresponding value 
      return d[k] || "";    // use empty string if key doesn't exist for that object 
      }); 
     }) 
     .enter().append("td"); 

    // cell contents depends on the data bound to the cell 
    // fill with text if data is not an Array 
    tds.filter(function(d) { return !(d instanceof Array); }) 
     .text(function(d) { return d; }); 
    // fill with a new table if data is an Array 
    tds.filter(function(d) { return (d instanceof Array); }) 
     .append("table") 
     .call(recurse); 
    });  
} 
+0

CNTT Chứa các ký tự không hợp lệ trong tệp javascript! tôi có thực sự cần phải thay thế các biến này trong gần 8000 dòng không? có thật không? wtf – msqar

+3

@msqar - không, bạn chỉ cần xác định rằng đó là UTF-8: xem https://github.com/mbostock/d3/wiki/Upgrading-to-3.0. Bạn cần một loại tài liệu, một thẻ và tập lệnh của bạn cần được bao gồm như sau: dja

+0

Có vẻ thú vị. Điều gì về mảng mảng? @nautat – bumpkin

Các vấn đề liên quan