2012-11-12 8 views
12

Mam tablicę zagnieżdżonych struktur JSON gdzie one różnej głębokości i nie ten sam zestaw kluczy wszędzie:Rekursywnie (lub iteracyjnie) utworzyć zagnieżdżoną tabelę html za pomocą 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 
      } 
     ] 
    } 
] 

chciałem użyć D3, aby uczynić to jako zagnieżdżone tabele html. Na przykład kolumna przyjaciół będzie zawierała tabele z nazwą i wynagrodzeniem znajomych osoby wymienionej w wierszu. Czasami jedna z tych tabel będzie miała inny poziom tabeli podrzędnej.

Wyobrażam sobie, że sposobem na to jest rekurencyjne tworzenie tabel. Napisałem program w języku Python, który przyjmuje taką strukturę JSON i renderuje tabele w tabelach, a najprostszym sposobem jest rekurencyjnie. Widzę w dokumentacji d3.js, że można zadzwonić pod numer .each(), ale jestem pewien, że tego potrzebuję, po prostu potrzebuję trochę przyspieszenia (https://github.com/mbostock/d3/wiki/Selections#wiki-each).

Czy istnieje dobry sposób na zrobienie tego w D3? Znalazłem ten świetny przykład renderowania macierzy danych 2d jako tabeli Creating a table linked to a csv file. Dzięki temu samouczkowi udało mi się uzyskać najwyższy zewnętrzny poziom tej struktury danych renderowanej jako tabela, ale utknąłem na tym, jak w razie potrzeby przechodzić w poziomy rekursywnie, ponieważ teraz po prostu pokazują się jako "Obiekt" w tabeli. ponieważ nie traktuję ich inaczej niż normalne łańcuchy i liczby.

Również znalazłem to inne pytanie/odpowiedź, które jest podobne do mojego pytania, ale naprawdę nie rozumiem javascriptu na tyle dobrze, aby zobaczyć, gdzie/jak przebiega rekursja i readaptować rozwiązanie do moich potrzeb: How do I process data that is nested multiple levels in D3?. Każda rada lub wskazówki do tutoriali rekurencyjnie lub iteracyjnie przetwarzających zagnieżdżone drzewa, takie jak struktury danych JSON w D3, byłyby mile widziane!

Odpowiedz

18

Funkcja rekursywna prawdopodobnie byłaby dobrym podejściem. Zobacz kod poniżej dla jednej możliwej implementacji (zakładając, że twoje dane są przechowywane w jdata). Zobacz komentarze w kodzie jakiegoś wyjaśnienia i zobaczyć ten GIST dla wersji na żywo: 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

IT zawiera niedozwolone znaki w pliku JavaScript! Czy naprawdę muszę zamienić te zmienne w prawie 8000 linii? naprawdę? wtf – msqar

+3

@msqar - nie, po prostu musisz określić, że jest to UTF-8: zobacz https://github.com/mbostock/d3/wiki/Upgrading-to-3.0. Potrzebujesz tagu doctype, tagu , a twój skrypt musi być dołączony w następujący sposób: dja

+0

Wygląda świetnie. A co z tablicą tablic? @nautat – bumpkin

Powiązane problemy