Mofified so recursion is stopped on arrays of strings and not objects eg [ "f1", "f2" ] will be a single cell containing f1,f2 and so JSON objects are stringified in a cell
-
-
Save ululh/60781dd62905ec22da44fdf268654875 to your computer and use it in GitHub Desktop.
Nested tables from json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style type="text/css"> | |
table { | |
font-family: "Helvetica", "Lucida Sans", "Lucida Sans Unicode", "Luxi Sans", Tahoma, sans-serif; | |
box-shadow: 1px 1px 10px rgba(0,0,0,0.5); | |
border-collapse: collapse; | |
border-spacing: 0; | |
} | |
table { | |
margin: auto; | |
} | |
table, td, th { | |
padding: 7px; | |
text-align: center; | |
border: 1px solid rgb(8,48,107); | |
} | |
th { | |
background-color: rgb(8,81,156); | |
color: white; | |
} | |
</style> | |
<body> | |
<script src="http://d3js.org/d3.v3.js"></script> | |
<script> | |
jdata = [ | |
{ | |
"name":"bob", | |
"address" : { "city" : "dijon", "street" : "rue des fleurs" }, | |
"salary":13000, | |
"friends":[ | |
{ | |
"name": "sarah", | |
"salary":10000 | |
}, | |
{ | |
"name": "bill", | |
"salary":5000 | |
} | |
] | |
}, | |
{ | |
"name":"marge", | |
"address" : [ "barcelona","ramblas" ], | |
"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 | |
} | |
] | |
} | |
]; | |
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 or if it's an array without filed names eg [ "v1", "v2" ] | |
// if data is an object call JSON stringify | |
tds.filter(function(d) { return (!(d instanceof Array) || !(d[0] instanceof Object) || !(typeof d == "object")); }) | |
.text(function(d) { return d; }); | |
tds.filter(function(d) { return ((!(d instanceof Array) && !(d[0] instanceof Object)) && typeof d == "object") }) | |
.text(function(d) { return(JSON.stringify(d)); }); | |
// fill with a new table if data is an Array | |
tds.filter(function(d) { return (d instanceof Array && d[0] instanceof Object ); }) | |
.append("table") | |
.call(recurse); | |
}); | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment