Wednesday, October 30, 2013

How to Download charts to PDF formate


It gives many problem to export any html or div to pdf  when it content charts because many  pdf converter library do not support chart container and not able to convert that chart or html div to pdf.

        Here I am going to sort out these problem.
These blog show you how to download Charts like google charts and others, to pdf formate at client side.

Here we use three script or technique:

1. First of all we draw charts at html div as we done in previous blog.
2. Then we convert that chart to Image(canvas) using google api (canvg.js) .
3. Convert whole html page to canvas using html2canvas library.
4.download that canvas (as image) to pdf formate using jspdf librar.

//Import html2canvas and jspdf library to you local folder.

//<Script That help to achieve our goal>

1. //script of charts that you use as google api that we use in previous blog.

//convert chart to Image(canvas) used to invoke canvg(); method

<script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/canvg.js"></script>

//convert html page to canvas using html2canvas library

<script type="text/javascript" src="../js/html2canvas.js"></script>

//Now export canvas to pdf using jspdf library.

<script type="text/javascript" src="/oltapp/js/FileSaver.js"></script>
<script type="text/javascript" src="/oltapp/js/jspdf.js"></script>
<script type="text/javascript" src="/oltapp/js/jspdf.plugin.addimage.js"></script>

Note: we do not need to import all js of jspdf .

lets take an example to fully understand.

Example code:
 <html>
<head>
<script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/canvg.js"></script>
<script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/rgbcolor.js"></script>
<script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/StackBlur.js"></script>
<script type="text/javascript" src="../js/html2canvas.js"></script>
<script type="text/javascript" src="../js/FileSaver.js"></script>
<script type="text/javascript" src="../js/jspdf.js"></script>
<script type="text/javascript" src="../js/jspdf.plugin.addimage.js"></script> 



<script type="text/javascript">

function export_PDF(chartContainer, imgContainer) {

         //main Div Hide
              var el = document.getElementById( 'chart_Container' );
             el.parentNode.removeChild( el );  

        //Chart to Image

          var doc = chartContainer.ownerDocument;
          var img = doc.createElement('img');
          img.src = getImgData(chartContainer);

          while (imgContainer.firstChild) {
               imgContainer.removeChild(imgContainer.firstChild);
           }

             imgContainer.appendChild(img);

      //Pdf Creation

                   var divElements = document.getElementById('expotPdfDiv).innerHTML;
                                         //Get the HTML of whole page
                                         var oldPage = document.body.innerHTML;

                                         //Reset the page's HTML with div's HTML only
                                         document.body.innerHTML =
                                           "<html><head><title></title></head><body>" +
                                           divElements + "</body>";

//convert whole html page to canvas
 
                             html2canvas(document.body, {
                                     onrendered: function(canvas) {
                                       
  // canvas is the final rendered <canvas> element
                                        
 var myImage = canvas.toDataURL("image/JPEG").slice('data:image/jpeg;base64,'.length);
                                        
 // Convert the data to binary form
                                         myImage = atob(myImage)

//new object of jspdf and save image to pdf.

                                         var doc = new jsPDF();
                                         doc.addImage(myImage, 'JPEG', 0, 0, 200,200);
                                          doc.save('pdfName.pdf');
                                      

                                     }
                                 });


}

function getImgData(chartContainer)
  {


     var chartArea = chartContainer.getElementsByTagName('svg')[0].parentNode;
     var svg = chartArea.innerHTML;
     var doc = chartContainer.ownerDocument;
     var canvas = doc.createElement('canvas');
     canvas.setAttribute('width', chartArea.offsetWidth);
     canvas.setAttribute('height', chartArea.offsetHeight);


     canvas.setAttribute(
         'style',
         'position: absolute; ' +
         'top: ' + (-chartArea.offsetHeight * 2) + 'px;' +
         'left: ' + (-chartArea.offsetWidth * 2) + 'px;');
     doc.body.appendChild(canvas);
     canvg(canvas, svg);

     var imgData = canvas.toDataURL("image/JPEG");
    var data = canvas.toDataURL('image/JPEG').slice('data:image/JPEG;base64,'.length);
             
// Convert the data to binary form
             data = atob(data)


     canvas.parentNode.removeChild(canvas);



     return imgData;
  }

</script>

</head>

<body>
 <div id="expotPdfDiv">
<div id="chart_Container" >
----
---        //Here is script for making chart at chart_Container div.
---

</div>

 <div id="chart_image"></div>  //div where chart image genrate

 <button  Onclick=" export_PDF(document.getElementById('chart_Container'), document.getElementById('chart_image')); " > Download PDF</button>

</div>

</body>

</html>



26 comments:

  1. Hi Sachin,

    Came here via your reply on the Google forums. Your solution is just what I'm looking for.

    I can't seem to get it working though. I've tried to apply your solution to a default graph, see: http://www.dannyoosterveer.nl/test_canvas2pdf/canvas2pdf.html

    Though I get this error:

    ----- error in canvg.js
    TypeError: Illegal constructor.

    var color = new RGBColor(this.value);
    -----

    Can you see what I'm doing wrong? And/or do you have a live demo?

    ReplyDelete
    Replies
    1. hey Danny ,

      I see your page,and trying to solve your problem as soon as possible .

      and thanks to comment .

      Delete
    2. Hi Sachin,

      That's great, thanks in advance!

      Delete
    3. Hey Danny,

      Add extra java script for canvas .

      http://canvg.googlecode.com/svn/trunk/rgbcolor.js
      http://canvg.googlecode.com/svn/trunk/StackBlur.js

      Try this,and let me know. Is it working or not.

      Delete
  2. Hi Sachin,

    Thanks for your reply.

    I've added the two javascripts. It gets passed the RGBcolor error now.

    Unfortunately, there's another error that pops up:

    ---------------------
    InvalidCharacterError: String contains an invalid character

    myImage = atob(myImage)
    ---------------------

    ReplyDelete
  3. hey Danny,

    just paste that code in line 91 to 97 .and set pdf formate according to you

    var myImage = canvas.toDataURL("image/JPEG").slice('data:image/jpeg;base64,'.length);

    myImage = atob(myImage)

    ReplyDelete
    Replies
    1. you having space in line 93
      var myImage = canvas.toDataURL("image/JPEG").slice('data:image /jpeg;base64,'.length);
      thats why you got error. I think it is working this time.

      Delete
    2. Ah, must have been some copy paste error, I missed that, my bad.

      I was just able to generate a PDF, hurray!

      Any idea why the dimensions are screwed up? (see http://www.dannyoosterveer.nl/test_canvas2pdf/pdfName.pdf)

      Delete
    3. Great man now you generated pdf ,
      and for improve your pdf graphics check jspdf library . :)

      Delete
  4. http://jsfiddle.net/spurgeom/je3Fy/ here's a working solution

    ReplyDelete
  5. Hai Sachin Nahar it is working for single Google chart.but not for multiple charts that i binded dynamically. How can i display multiple charts in pdf format plz reply

    ReplyDelete
    Replies
    1. yes we can use it for multiple charts also ..convert all charts to canvas .

      Delete
    2. Can you please give us the workable solution for multiple charts also?

      Delete
  6. Yes. Is there a way to add another chart to the pdf?

    ReplyDelete
  7. hi Sachin this is working only for svg tag of google chart,is there way to working for whole chartContener and one thing is not working in touch device ,so please tell me is ther any way by which we can do this..

    ReplyDelete
  8. Hi Sachin, I am using your example to create pdf for my google chat where i am using ajax and json. Everything working fine in Firefox browser, but not working in IE9.
    I am getting 'undefined' for chartContainer.getElementsByTagName('svg')[0] in the getImgData(chartContainer) function. I have added all the js libraries that you have mentioned above.
    Do you know if i am missing something?

    ReplyDelete
  9. Hi Sachin,

    Can you please give me workable solution for exporting multiple charts into pdf?

    Thanks in advance

    ReplyDelete
  10. I am facing the same issue. Exporting multiple charts on dashboard to pdf. Any help plz.
    Thank you.

    ReplyDelete
  11. Hi Sachin,

    I am getting an error, "Cannot read property 'parentNode' of null" on the following line(Line no. 18):
    el.parentNode.removeChild( el );

    Can you please help me in resolving this issue?

    Thanks in advance,
    Shashank

    ReplyDelete
  12. i hv tried the sample code bt getting error Cannot read property 'parentNode' of undefined

    ReplyDelete
  13. Hi sachin,
    i want to also add datatable of the chart with chart and download pdf of both div together can u help plz.

    ReplyDelete
  14. Hi sachin,
    sample code is running perfectly one time,on downloading d copy of the page 2nd time getting error,Uncaught TypeError: Cannot read property 'parentNode' of null plz,help

    ReplyDelete
  15. Hi Sachin

    Thank you

    If I have a URL, www.anysite.com and I want to export the contents of that site to a PDF,
    Is it possible with jsPDF?

    Thank you

    ReplyDelete
  16. Hi Sachin

    Thank you

    If I have a URL, www.anysite.com and I want to export the contents of that site to a PDF,
    Is it possible with jsPDF?

    Thank you

    ReplyDelete
  17. Hi Sachin

    Thank you

    If I have a URL, www.anysite.com and I want to export the contents of that site to a PDF,
    Is it possible with jsPDF?

    Thank you

    ReplyDelete