Reputation: 11
I'm supposed to generate a report based on a JSON document with this structure:
tables:
[
{
<some descriptors of the dataset>,
series:
[
key: ...,
values:
[
{ label: ..., value: ... },
...
]
]
},
...
]
There can be an arbitrary number of tables in the JSON array, with arbitrary series. Of course, each series holds the same set of values with different values. For each table, I have to draw a table with the given data and a multi-bar chart. I chose NVD3.js as my chart library.
Since I'm not very experienced with JavaScript, I decided to play it safe and follow the NVD3.js examples to the letter, and generate the divs and objects I need in the most archaic and stupid way possible. As soon as I feel more comfortable in JS I will implement templates and such. Here's a shortened version of my JavaScript code. I know it's horrible, so please don't judge me.
var report_data = <stupid way of getting data, will use AJAX later>;
var my_div = document.getElementById('show-report');
report_data.tables.forEach(
function(table)
{
var newDiv = document.createElement('div');
newDiv.id = 'report_' + table.name;
var newHeader = document.createElement('h1');
newHeader.textContent = table.name;
newDiv.appendChild(newHeader);
// Generate style element for chart
var newStyle = document.createElement('style');
newStyle.textContent = '#' + table.name + '_chart svg {height: 500px;}';
newDiv.appendChild(newStyle);
// Generate <div><svg /></div> where chart will be placed
var chartDiv = document.createElement('div');
chartDiv.id = table.name + '_chart';
var svgEl = document.createElement('svg');
chartDiv.appendChild(svgEl);
newDiv.appendChild(chartDiv);
// Here I write the table and append it to the main div. Omitted because of intense shame.
my_div.appendChild(newDiv);
//Draw chart
nv.addGraph(
function()
{
var chart = nv.models.multiBarHorizontalChart()
.x(function(d) { return d.label })
.y(function(d) { return d.value })
.margin({top: 30, right: 20, bottom: 50, left: 175})
.tooltips(true)
.showControls(true);
chart.yAxis
.tickFormat(d3.format(',.2f'));
d3.select('#'+ table.name +'_chart svg')
.datum(table.series)
.transition().duration(250)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
}
);
}
);
So, the code is bad, but it works... sort of. Here's the thing: it tries to draw each chart and put it in its div, but each chart just shows in plain text with no style. See this Imgur album. If I "hardcode" a div with the name of one of my tables, it draws the chart without a hitch inside it. To me, it looks like the newly-created divs aren't applying the NVD3.js CSS file. I don't even know if that's possible, since I know even less about CSS than JavaScript.
Has anyone tried something like this or does anyone know what could be causing that behavior?
Upvotes: 1
Views: 1173
Reputation: 41671
I just ran into this issue, and after looking around on GitHub I found the problem.
you cant create SVG elements using document.createElement, you have to use document.createElementNS and specify the xml namespace for SVG, or just use d3´s append method: d3.select(...).append("svg")
My problem was specifically involved jQuery, which resulted in me generating the SVG element using:
var $svg = d3.select($jqElement[0]).append("svg")
For non-jQuery users, regular DOM elements can be passed into d3.select
. In the example, $jqElement[0]
is called to get the DOM version of the jQuery object.
Upvotes: 5