1

I have several D3 charts, one a basic Heat Map and the others things like Donut Chart or Bar Chart. The Pie, Donut and Bar charts will all show in a PDF when using wkhtmltopdf, but my Heat Map will not. I cannot understand why not.

Here is a working Bar Chart (note, I am passing data to the chart through a Django Template):

        <div id="duelChart"></div>
        <script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
        <script>   
                var data = [
                    { "name": "Stat 5", "value": {{ stat.duel_defensive_won|default:0 }}, },
                    { "name": "Stat 4", "value": {{ stat.duel_offensive_won|default:0 }}, },
                    { "name": "Stat 3", "value": {{ stat.aerial_duels_won|default:0 }}, },
                    { "name": "Stat 2", "value": {{ stat.ground_duels_won|default:0 }}, },
                    { "name": "Stat 1", "value": {{ stat.duel_won|default:0 }}, },];

                var margin = { top: 15, right: 25, bottom: 15, left: 60 };           
                var width = 400 - margin.left - margin.right,
                    height = 250 ;
                var svg = d3.select("#duelChart").append("svg")
                    .attr("width", width + margin.left + margin.right)
                    .attr("height", height + margin.top + margin.bottom)
                    .append("g")
                    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

                var x = d3.scale.linear()
                    .range([0, width])
                    .domain([0, d3.max(data, function (d) {
                        return d.value;
                    })]);

                var y = d3.scale.ordinal()
                    .rangeRoundBands([height, 0], .1)
                    .domain(data.map(function (d) {
                        return d.name;
                    }));

                //make y axis to show bar names
                var yAxis = d3.svg.axis()
                    .scale(y)
                    //no tick marks
                    .tickSize(0)
                    .orient("left");

                var gy = svg.append("g")
                    //.attr("class", "y axis")
                    //.call(yAxis)

                var bars = svg.selectAll(".bar")
                    .data(data)
                    .enter()
                    .append("g")

                //append rects
                bars.append("rect")
                    .attr("class", "bar")
                    .attr("y", function (d) {
                        return y(d.name);
                    })
                    .attr("height", y.rangeBand())
                    .attr("x", 0)
                    .attr("width", function (d) {
                        return x(d.value);
                    });

                //add a value label on the left of each bar
                bars.append("text")
                    .attr("class", "label")
                    //y position of the label is halfway down the bar
                    .attr("y", function (d) {
                        return y(d.name) + y.rangeBand() / 2 + 4;
                    })
                    //x position is 3 pixels to the right of the bar
                    //.attr("x", function (d) {
                    //    return x(d.value) + 3;
                    //})
                    .style('fill', 'white')
                    .text(function (d) {
                        return d.name;
                    });

            </script>

Here is the not working (simple) Heat Map:

<div id="heatMap" style="margin-left:12px"></div>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
                    <script>
                        data = [];
                        {% for column in heatmap.gridData %}
                        {% for row in column %}
                        data.push({ "week": {{ forloop.counter0 }} , "day" : {{ forloop.parentloop.counter0 }}, "value": {{ row }} }, );
                        {% endfor %}
                        {% endfor %}
                        var colorDomain = d3.extent(data, function (d) {
                            return d.value;
                        });


                        var colorScale = d3.scale.linear()
                            .domain(colorDomain)
                            .range(["lightblue", "blue"]);

                        var svg = d3.select("#heatMap")
                            .append("svg")
                            .attr("width", 835)
                            .attr("height", 535)                                
                            .append("g")
                            .attr("transform", "translate(" + 0 + "," + 0 + ")");

                        var rectangles = svg.selectAll("rect")
                            .data(data)
                            .enter()
                            .append("g");

                        rectangles
                            .append('rect')
                            .attr("x", function (d) {
                                return d.day * 41;

                            })
                            .attr("y", function (d) {
                                return d.week * 41;
                            })
                            .attr("width", 42)
                            .attr("height", 41).
                            style("fill", function (d) {
                                return colorScale(d.value);
                            });    
                    </script>

This Heat Map renders exactly as I would expect in the browser window, but when I try and send it to a PDF using django-wkhtmltopdf, the image doesn't come in.

Please note <script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script> is actually within the <head> ... </head> at the top of the html file but I included within the local script to show I had included it. Both charts, along with many others are in the same html page. The Heat Map is the only one not rendering in wkhtmltopdf.

Any help explaining why it is not rendering (and how to fix) would be very much appreciated

HenryM
  • 5,557
  • 7
  • 49
  • 105
  • 1
    in the heatmap you attach the `rect`'s to the `svg`, in the bar graph there is a `g` with a transform and a `g` for each rect+text. – rioV8 Aug 19 '18 at 16:42
  • @rioV8 - Thanks; I've amended the script as shown in the question (so the question has been edited) and it still isn't working - can you advise if I've done it correctly? – HenryM Aug 19 '18 at 17:11
  • the other diff I see is the fill color of the heatmap rect's. Are the bar chart rects all black? What if you place a bar chart in the location of the heat map? Maybe the location on the page is the problem or what is in the neighbor hood. – rioV8 Aug 19 '18 at 17:20
  • Just confirmed I can render the bar charts where I am trying to render the heatMap – HenryM Aug 19 '18 at 17:28
  • can you try adding delay ? I mean once the page is loaded, wait for a few seconds and then convert it to pdf – kawadhiya21 Aug 19 '18 at 17:29
  • `javascript-delay` already set at 2000 – HenryM Aug 19 '18 at 17:30
  • I have used the command line v0.12.5, created a HTML file with both charts, and converted to pdf, both are visible – rioV8 Aug 19 '18 at 18:33
  • I'm using `wkhtmltopdf 0.12.4 (with patched qt)` and it isn't working from the command line – HenryM Aug 20 '18 at 06:53
  • do you use the result DOM or does `wkhtmltopdf` need to run the javascript (d3+your code)? – rioV8 Aug 20 '18 at 11:27
  • `wkhtmltopdf` runs the javascript – HenryM Aug 20 '18 at 11:43
  • did you find the problem that causes this issue ? – zahma Dec 26 '18 at 10:23
  • No. We removed the heatmap with a plan of reviewing later – HenryM Dec 27 '18 at 11:07

0 Answers0