1

Here I have multiple charts from highcharts,These charts can be multiple which is coming dynamically,here for reference I have shown only 2.I need to download the content of some div as well as all highcharts in the page.I can able to do it with jspdf plugin,but when it comes multiple charts I am not able to get how to download it.I have updated the working code in the plunker http://plnkr.co/edit/Z3hJcC8pgzZxXPLWpfBw?p=preview ,here is my code below. Other libraries can be found on above url.

html

 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
     <script src="jspdf.debug.js"></script>
     <script src="https://code.highcharts.com/highcharts.js"></script>
    <script src="https://code.highcharts.com/modules/series-label.js"></script>
    <script src="https://code.highcharts.com/modules/exporting.js"></script>
    <script src="https://code.highcharts.com/modules/export-data.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>
      <script src="https://github.com/devongovett/pdfkit/releases/download/v0.6.2/pdfkit.js"></script>
      <script src="rgbcolor.js"></script>
      <script src="canvg.js"></script>
      <script src="script.js"></script>
    </head>

    <body>
      <input type="button" onclick="chartWithContentDownload()" value="download" /> Please click on this button to get chart with html content on pdf

      <div class="white-back row" style="padding: 1.5rem;" id="tvgMainCnt">
        <div id="top-content">
          <div>
            <div>
              logo
            </div>
            </div>
          <div style="margin-top: 1rem;">
            <p>
              Dear members,
            </p>
          </div>
          <div>
            Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book
          </div>
          <br />
          <div style="margin-top: 1rem;">
            <p>
              Download of chart with html content should work with multiple chart.
            </p>
          </div>
        </div>
        <div id="middle-content">
          <div id="testchart"></div>
          <div id="testchart2"></div>
        </div>
        <div id="bottom-content">
          <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. </p>
        </div>
      </div>

script.js

$(document).ready(function(){
   Highcharts.chart('testchart', {

    title: {
        text: 'Solar Employment Growth by Sector, 2010-2016'
    },

    subtitle: {
        text: 'Source: thesolarfoundation.com'
    },

    yAxis: {
        title: {
            text: 'Number of Employees'
        }
    },
    legend: {
        layout: 'vertical',
        align: 'right',
        verticalAlign: 'middle'
    },

    plotOptions: {
        series: {
            label: {
                connectorAllowed: false
            },
            pointStart: 2010
        }
    },

    series: [{
        name: 'Installation',
        data: [43934, 52503, 57177, 69658, 97031, 119931, 137133, 154175]
    }, {
        name: 'Manufacturing',
        data: [24916, 24064, 29742, 29851, 32490, 30282, 38121, 40434]
    }, {
        name: 'Sales & Distribution',
        data: [11744, 17722, 16005, 19771, 20185, 24377, 32147, 39387]
    }, {
        name: 'Project Development',
        data: [null, null, 7988, 12169, 15112, 22452, 34400, 34227]
    }, {
        name: 'Other',
        data: [12908, 5948, 8105, 11248, 8989, 11816, 18274, 18111]
    }],

    responsive: {
        rules: [{
            condition: {
                maxWidth: 500
            },
            chartOptions: {
                legend: {
                    layout: 'horizontal',
                    align: 'center',
                    verticalAlign: 'bottom'
                }
            }
        }]
    }

});
  Highcharts.chart('testchart2', {

    title: {
        text: 'Solar Employment Growth by Sector, 2010-2016'
    },

    subtitle: {
        text: 'Source: thesolarfoundation.com'
    },

    yAxis: {
        title: {
            text: 'Number of Employees'
        }
    },
    legend: {
        layout: 'vertical',
        align: 'right',
        verticalAlign: 'middle'
    },

    plotOptions: {
        series: {
            label: {
                connectorAllowed: false
            },
            pointStart: 2010
        }
    },

    series: [{
        name: 'Installation',
        data: [43934, 52503, 57177, 69658, 97031, 119931, 137133, 154175]
    }, {
        name: 'Manufacturing',
        data: [24916, 24064, 29742, 29851, 32490, 30282, 38121, 40434]
    }, {
        name: 'Sales & Distribution',
        data: [11744, 17722, 16005, 19771, 20185, 24377, 32147, 39387]
    }, {
        name: 'Project Development',
        data: [null, null, 7988, 12169, 15112, 22452, 34400, 34227]
    }, {
        name: 'Other',
        data: [12908, 5948, 8105, 11248, 8989, 11816, 18274, 18111]
    }],

    responsive: {
        rules: [{
            condition: {
                maxWidth: 500
            },
            chartOptions: {
                legend: {
                    layout: 'horizontal',
                    align: 'center',
                    verticalAlign: 'bottom'
                }
            }
        }]
    }

});
  });
   function chartWithContentDownload() {
    var doc = new jsPDF('portrait', 'pt', 'a4', true);
    var elementHandler = {
      '#ignorePDF': function(element, renderer) {
        return true;
      }
    };

    var source = document.getElementById("top-content");
    doc.fromHTML(source, 15, 15, {
      'width': 560,
      'elementHandlers': elementHandler
    });

    var svg = document.querySelector('svg');
    var canvas = document.createElement('canvas');
    var canvasIE = document.createElement('canvas');
    var context = canvas.getContext('2d');
    var DOMURL = window.URL || window.webkitURL || window;
    var data1 = (new XMLSerializer()).serializeToString(svg);
    canvg(canvas, data1);
    var svgBlob = new Blob([data1], {
      type: 'image/svg+xml;charset=utf-8'
    });

    var url = DOMURL.createObjectURL(svgBlob);

    var img = new Image();
    img.onload = function() {
      context.canvas.width = $('#testchart').find('svg').width();
      console.log(context.canvas.width)
      context.canvas.height = $('#testchart').find('svg').height();

      context.drawImage(img, 0, 0);
      // freeing up the memory as image is drawn to canvas
      DOMURL.revokeObjectURL(url);

      var dataUrl;
                        if (isIEBrowser()) { // Check of IE browser 
                            var svg = $('#testchart').highcharts().container.innerHTML;
                            canvg(canvasIE, svg);
                            dataUrl = canvasIE.toDataURL('image/JPEG');
                        }
                        else{
                            dataUrl = canvas.toDataURL('image/jpeg');
                        }
      doc.addImage(dataUrl, 'JPEG', 20, 300, 560, 350);

      var bottomContent = document.getElementById("bottom-content");
      doc.fromHTML(bottomContent, 15, 650, {
        'width': 560,
        'elementHandlers': elementHandler
      });

      setTimeout(function() {
        doc.save('TestChart.pdf');
      }, 2000);
    };
    img.src = url;

  };
  function isIEBrowser(){
                    var ieBrowser;
                    var ua = window.navigator.userAgent;
                    var msie = ua.indexOf("MSIE ");

                    if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)) // Internet Explorer
                    {
                      ieBrowser = true;
                    }
                    else  //Other browser
                    {
                      console.log('Other Browser');
                        ieBrowser = false;
                    }

                    return ieBrowser;
                };
carreankush
  • 621
  • 2
  • 9
  • 32

1 Answers1

1

The first issue here is that the code is just handling one chart / image. The approach should include a loop or multi-processing of various elements.

I've managed to edit your code and this is my result: http://plnkr.co/edit/qRT4dqJDMU8mTSocL3tb?p=preview

var elements = [$('#testchart'), $('#testchart2')];

  for (let i in elements) {

      var svg = document.querySelector('svg');
      var canvas = document.createElement('canvas');
      var canvasIE = document.createElement('canvas');
      var context = canvas.getContext('2d');

      var data1 = (new XMLSerializer()).serializeToString(svg);
      canvg(canvas, data1);
      var svgBlob = new Blob([data1], {
        type: 'image/svg+xml;charset=utf-8'
      });

      var url = DOMURL.createObjectURL(svgBlob);

      var img = new Image();
      img.onload = function() {
        context.canvas.width = elements[i].find('svg').width();
        context.canvas.height = elements[i].find('svg').height();

        context.drawImage(img, 0, 0);
        // freeing up the memory as image is drawn to canvas
        DOMURL.revokeObjectURL(url);

        var dataUrl;
        if (isIEBrowser()) { // Check of IE browser 
          var svg = $(elements[i]).highcharts().container.innerHTML;
          canvg(canvasIE, svg);
          dataUrl = canvasIE.toDataURL('image/JPEG');
        } else {
          dataUrl = canvas.toDataURL('image/jpeg');
        }
        doc.addPage();
        doc.addImage(dataUrl, 'JPEG', 20, 20, 560, 350);

      };
      img.src = url;
    }

 var bottomContent = document.getElementById("bottom-content");
  doc.fromHTML(bottomContent, 15, 650, {
    'width': 560,
    'elementHandlers': elementHandler
  });
  setTimeout(function() {
    doc.save('TestChart.pdf');
  }, 2000);

A PDF with 3 pages including both charts plus the additional contents. Give format, clean ups and edit as you may need. Hope it helps.

Jose Cordero
  • 526
  • 5
  • 15
  • Thanks for your answer,but here chart is coming out of header and footer in the pdf.It should come between header and footer as like as html – carreankush Nov 02 '18 at 03:48
  • Duplicate of: https://stackoverflow.com/questions/53075908/jspdf-is-not-able-to-capture-the-div-content-properly-for-highcharts-to-download. – Wojciech Chmiel Nov 02 '18 at 09:01
  • That duplicate code is totally different,Can you please help me on how to format, even the position is correct chart is coming below the content, it not coming similar to html – carreankush Nov 02 '18 at 13:44
  • @carreankush I've just managed to include both charts. To making it work for your needs, first try using global variables instead of fixed ones. Just test around adding element's height and width to your positionX, positionY global variables. Same as you already have, but without constant ones. This way, you can add new elements between them if needed. – Jose Cordero Nov 02 '18 at 18:59
  • yes I have changed and updated the code in my plunker as far as possible – carreankush Nov 02 '18 at 19:44
  • I have one more issue that this code is showing error message 'elements[i].find is not a function' when I used with jquery,onclick.I have updated here http://plnkr.co/edit/Z3hJcC8pgzZxXPLWpfBw?p=preview ,For my need I have to use it with jquery in my project,Can you please help me on it – carreankush Nov 04 '18 at 06:19
  • Here one more issue in your plunker that same chart is downloading..it always downloading the top chart number of times – carreankush Nov 06 '18 at 03:40