pdfmake icon indicating copy to clipboard operation
pdfmake copied to clipboard

PDF Charts

Open zacnewnham opened this issue 7 years ago • 11 comments

I am using pdfmake and I am trying to include graphs into the PDF output. The charts need to be created by using variables. I'm trying to create a bar chart, pie chart and line charts. Is there a solution for this?

zacnewnham avatar Aug 09 '16 10:08 zacnewnham

+1

sharvesh avatar Sep 08 '16 03:09 sharvesh

What kind of of chart did you use? I used https://jtblin.github.io/angular-chart.js/ and it worked fine. Did you convert your graphs into .toDataURL() ?

This is my code for getting my graph:

var canvas = $(".container #bar").get(0);
var dataURL = canvas.toDataURL();

generatePDF (dataURL);

For me ,the first thing to do is to try getting your chart like this: console.log($(".container #bar").get(0).toDataURL()); If you see a very long line, try to get it, and open it on another tab, if nothing has been shown, then try it on another class/id where the chart is. I can't explain further since I just did trial and error on getting the chart data.

eldesgonzales avatar Jan 20 '17 08:01 eldesgonzales

I don't know if it can help, but I have charts in SVG format : I convert them in png and then I can include them as image in the pdf. As the conversion is asynchronous, one must just take care to use a Promise.

bhericher avatar Feb 03 '17 09:02 bhericher

I think the solution for this would be to add support for SVG paths like PDFKit. Something like:

content = [{
	canvas: [
		{
			type: 'svg'
			path: 'M 0,20 L 100,160 Q 130,200 150,120 C 190,-40 200,200 300,150 L 400,90'
		}
	]
}];

... then you could use virtually any chart library you want.

Here's an example of how you might draw a pie chart with Paths.js:

let pie = require('paths-js/pie')

var content = [{
    canvas: []
 }];

var chart = pie({
  data: [
    {
      name: 'Italy',
      population: 59859996
    }, {
      name: 'Mexico',
      population: 118395054
    }, {
      name: 'France',
      population: 65806000
    }, {
      name: 'Argentina',
      population: 40117096
    }, {
      name: 'Japan',
      population: 127290000
    }
  ],
  accessor: function(x) {
    return x.population;
  },
  compute: {
    color: function(i) {
      return chartColors[i];
    }
  },
  center: [20, 15],
  r: 30,
  R: 50
});

chart.curves.forEach( function(curve, index) {
    content[0].canvas[index] = {
      type: 'svg',
      path: curve.sector.path.print()
    };
});
    
    console.log(content)
/*
[ { canvas: 
     [ { type: 'svg',
         path: 'M 20 -35 A 50 50 0 0 1 59.599813 -15.526297 L 43.759888 -3.315778 A 30 30 0 0 0 20 -15 Z ' },
       { type: 'svg',
         path: 'M 59.599813 -15.526297 A 50 50 0 0 1 40.370176 60.662412 L 32.222106 42.397447 A 30 30 0 0 0 43.759888 -3.315778 Z ' },
       { type: 'svg',
         path: 'M 40.370176 60.662412 A 50 50 0 0 1 -7.620771 56.678448 L 3.427537 40.007069 A 30 30 0 0 0 32.222106 42.397447 Z ' },
       { type: 'svg',
         path: 'M -7.620771 56.678448 A 50 50 0 0 1 -26.562961 33.217867 L -7.937776 25.93072 A 30 30 0 0 0 3.427537 40.007069 Z ' },
       { type: 'svg',
         path: 'M -26.562961 33.217867 A 50 50 0 0 1 20 -35 L 20 -15 A 30 30 0 0 0 -7.937776 25.93072 Z ' } ] } ]
*/

jwerre avatar May 22 '17 23:05 jwerre

Added experimental path vector type with svg syntax support by commit https://github.com/bpampuch/pdfmake/commit/46ee6b440bd57f4a096e9f52eca49a4d5d32aff0.

Example of usage:

var dd = {
	content: [
		{
			canvas: [
				{
					type: 'path',
					d: 'M 0,20 L 100,160 Q 130,200 150,120 C 190,-40 200,200 300,150 L 400,90',
					dash: {length: 5},
					// lineWidth: 10,
					lineColor: 'blue',
				},
			 ]
		}
	]
}

liborm85 avatar May 27 '17 06:05 liborm85

Do you think it would be worth setting up a native chart implementation? Something like this:

{
    chart: 'pie',
    data: [10, 20, 30, 40],
    colors: ['red', 'green', 'blue', 'black'],
    position: [X, Y],
    size: [W, H]
}

I'd be happy to contribute and set this up the following:

  • Pie/Donut charts
  • Bar/Column charts
  • Line charts
  • Radar charts

jwerre avatar Jan 26 '19 00:01 jwerre

Well after 4 years of the opening of this topic, I would be happy just for a simple line chart .

mcanyucel avatar Feb 07 '20 13:02 mcanyucel

+1 charts would be an amazing addition

drummerjolev avatar Mar 01 '21 11:03 drummerjolev

I've had success using echarts Build a chart and then use the dataURL with an {image} field

const getChartDataUrl = ( option, w, h ) => new Promise(done => {
    const canvas = document.createElement('canvas')
    canvas.width = w || 600
    canvas.height = h || 200

    const chart = echarts.init(canvas)
    chart.setOption(option)
    chart.on('finished', () => done( chart.getDataURL() ))
})
//Returns a data url (promise): "data:image/png;base64,..."

https://echarts.apache.org/handbook/en/basics/release-note/5-3-0/#server-side-rendering-with-zero-dependencies

codeion avatar May 23 '22 18:05 codeion

Hi, I would like to add another option which worked for me (server-side):

  • Define the chart parameters within the document definition
  • Process the chart parameters (server-side) by a charting library.
  • Working directly with SVG is better than converting/transcoding to raster images, unfortunately there are few options that do this without an "html container", VEGA suited better for my needs, but the options I found are: - chartis-svg - VEGA a visualization grammar
  • Replace chart definition with the resulting SVG string - you will have to deal with the resulting promises if you have multiple charts per document

It is worth noting that client-side libraries are easier to find, I worked with Plotly which also renders SVG charts which can be placed directly in the document definition.

UPDATE: I found Apache ECharts for js, and I am using it cause it is very simple its use and supports SVG rendering.

jaguarxii avatar Jul 15 '22 17:07 jaguarxii