11

I am using SVG.toDataURL() to export c3js charts to png images. Exporting the charts to png works properly.

In case of the line charts, they are not rendered properly. e.g.

  1. The x and y axis width is increased.
  2. Lines are not proper, instead of the lines it shows dark black regions.

enter image description here

enter image description here

jsfiddle

Below is the code to export png

 function exportImageAsPNG(){
        var svgElements = $("#chart").find('svg');
        var svg ;
        svgElements.each(function() {
            svg = this;
        });
        var img = document.getElementById("fromcanvas");
        svg.toDataURL("image/png", {
            callback: function(data) {
                img.setAttribute("src", data)
            }
        })
    }

Same thing happens when I use the canvag library.

var $container = $('#chart'),
content = $container.html().trim(),
canvas = document.getElementById('svg-canvas');

// Draw svg on canvas
canvg(canvas, content);

// Change img be SVG representation
var theImage = canvas.toDataURL('image/png');

$("#hiddenPng").attr('href', theImage);
$("#hiddenPng span").trigger("click");
ajm
  • 12,863
  • 58
  • 163
  • 234

3 Answers3

16

The issue is that the exporter function only considers inline CSS styles when performing the export. In other words, the exporter is losing track of C3's css settings, thus your graph will look like this fellow's right before it exports

https://github.com/c3js/c3/issues/356

Most importantly, the black triangles are caused by the fill property of some specific .c3 elements. c3.css sets these to none by default, but your exporter doesn't know that.

See:

highlight-graph

And, if you manually turn off the fill property from c3.min.css...

enter image description here

You'll want to somehow set the fill CSS property of those specific elements as inline CSS (as in ) before exporting

Here's a quick, plainJS fix for this, add these lines between genChart(); and exportImageAsPNG(); as shown to fix your problem.

    genChart();
    var nodeList = document.getElementById('chart').querySelector('svg').querySelectorAll('.c3-chart path');
    var nodeList2 = document.getElementById('chart').querySelector('svg').querySelectorAll('.c3-axis path');
    var nodeList3 = document.getElementById('chart').querySelector('svg').querySelectorAll('.c3 line');
    var line_graph = Array.from(nodeList);
    var x_and_y = Array.from(nodeList2).concat(Array.from(nodeList3));
    line_graph.forEach(function(element){
        element.style.fill = "none";
    })
    x_and_y.forEach(function(element){
        element.style.fill = "none";
        element.style.stroke = "black";
    })
    exportImageAsPNG();

JSFiddle: https://jsfiddle.net/vtange/vajs3cmf/

clean

vtange
  • 649
  • 1
  • 5
  • 10
  • I've been struggling with exporting c3.js for quite a while and your answer pointed me in the right direction. Thank you! – ffflabs Feb 13 '17 at 21:18
  • Great! The only working solution for C3.js SVG to PNG that properly works. – Davidson Lima Nov 14 '17 at 18:47
  • thankyou @vtange the above solution works well for line chart also there was a issue with same after **genChart function** graph legend 's color changes to the color which is used in the code `element.style.stroke = "black";` any how i fixed the same But there are other issues with exporting other charts of c3 Is there any alternative solution for exporting svg to png/or other image format – Srinivas Feb 01 '18 at 09:41
  • @vtange This answer was very helpful. One thing needed here is, when i export svg (which has horizontal lines) to image, the horizontal lines are not showing in the exported one. – Pitchiah Natarajan Jul 17 '18 at 10:27
  • Thanks.. life saver! – Neha May 19 '21 at 13:57
4

Maybe a little bit late, but I hope this solution helps future devs:

  • the validated solution above didn't work for me with Barchart and others
  • so, base on the same principle, here's what I did to make the export work with every chart type. Here are some example:

enter image description here enter image description here enter image description here

Assume we have this in html, and the chart is already generated with c3:

<div id="chartID" class="chart-content"></div>

Then, in our JS, this is export function :

function exportChartToPng(chartID){
//fix weird back fill
d3.select('#'+chartID).selectAll("path").attr("fill", "none");
//fix no axes
d3.select('#'+chartID).selectAll("path.domain").attr("stroke", "black");
//fix no tick
d3.select('#'+chartID).selectAll(".tick line").attr("stroke", "black");
var svgElement = $('#'+chartID).find('svg')[0];
saveSvgAsPng(svgElement, chartID+'.png');
}

Note : the saveSvgAsPng tools is from https://github.com/exupero/saveSvgAsPng

user2342558
  • 5,567
  • 5
  • 33
  • 54
4givN
  • 2,936
  • 2
  • 22
  • 51
1

For anyone who keeps getting this issue, I got this maybe can help you...

var nodeList    = $('svg .c3-chart path.c3-shape.c3-shape.c3-line');
var fillArea    = Array.from(nodeList);

fillArea.forEach(function(element){
  element.style.fill = "none";
})