Search code examples
amcharts

How to download multiple am4charts with layout in one PDF file?


I want to export multiple am4charts with layout in one PDF like it was in V3 https://www.amcharts.com/docs/v3/tutorials/exporting-pdf-with-multiple-charts-and-related-info/


Solution

  • Please follow the new tutorial how to generate a multi-content PDF.

    You can add another chart as extraSprites from version 4.2.0 as in:

    chart.exporting.extraSprites.push(chart2);
    

    Check more about how to add an extra element here.

    Previous Recommendation

    I recommend you to check the answer for this issue: https://github.com/amcharts/amcharts4/issues/743

    amCharts uses PDFMake to generate PDFs, which allows you to assemble PDF as you whish.

    Please check a simpler example how your code could look like:

    // Use this method to call the export functionality
    let exportCharts = async (charts) => {
    
        // Map chats to images
        let images = await Promise.all(charts.map(async (chart) => {
    
            return await new Promise((resolve, reject) => {
    
                let getImage = () => {
                    resolve(chart.exporting.getImage('png'));
                }
    
                // Get the image if the chart is ready
                if (chart.isReady())
                    getImage();
                // Get the image when the chart is ready
                else
                    chart.events.on('ready', () => getImage());
                });
            }));
    
            // Begin PDF layout
            const layout = {
                content: []
            };
    
            // Add charts
            layout.content = images.map((image) => {
    
            return {
                image: image,
                fit: [523, 300]
            };
        });
    
        // Finally, download our PDF
        charts[0].exporting.pdfmake.then(function(pdfMake) {
            pdfMake.createPdf(layout).download("amcharts4.pdf");
        });
    }
    
    // Call exports with all the charts you want exported
    exportCharts([chart1, chart2]);
    

    /**
     * ---------------------------------------
     * This demo was created using amCharts 4.
     * 
     * For more information visit:
     * https://www.amcharts.com/
     * 
     * Documentation is available at:
     * https://www.amcharts.com/docs/v4/
     * ---------------------------------------
     */
    
    // Themes begin
    am4core.useTheme(am4themes_animated);
    // Themes end
      
    // Create chart instance
    var chart1 = am4core.create('chart-1', am4charts.XYChart3D);
    
    // Add data
    chart1.data = [{
      "country": "USA",
      "visits": 4025
    }, {
      "country": "China",
      "visits": 1882
    }, {
      "country": "Japan",
      "visits": 1809
    }, {
      "country": "Germany",
      "visits": 1322
    }, {
      "country": "UK",
      "visits": 1122
    }, {
      "country": "France",
      "visits": 1114
    }, {
      "country": "India",
      "visits": 984
    }, {
      "country": "Spain",
      "visits": 711
    }, {
      "country": "Netherlands",
      "visits": 665
    }, {
      "country": "Russia",
      "visits": 580
    }, {
      "country": "South Korea",
      "visits": 443
    }, {
      "country": "Canada",
      "visits": 441
    }, {
      "country": "Brazil",
      "visits": 395
    }, {
      "country": "Italy",
      "visits": 386
    }, {
      "country": "Australia",
      "visits": 384
    }, {
      "country": "Taiwan",
      "visits": 338
    }, {
      "country": "Poland",
      "visits": 328
    }];
    
    // Create axes
    let categoryAxis = chart1.xAxes.push(new am4charts.CategoryAxis());
    categoryAxis.dataFields.category = "country";
    categoryAxis.renderer.labels.template.rotation = 270;
    categoryAxis.renderer.labels.template.hideOversized = false;
    categoryAxis.renderer.minGridDistance = 20;
    categoryAxis.renderer.labels.template.horizontalCenter = "right";
    categoryAxis.renderer.labels.template.verticalCenter = "middle";
    categoryAxis.tooltip.label.rotation = 270;
    categoryAxis.tooltip.label.horizontalCenter = "right";
    categoryAxis.tooltip.label.verticalCenter = "middle";
    
    let valueAxis = chart1.yAxes.push(new am4charts.ValueAxis());
    valueAxis.title.text = "Countries";
    valueAxis.title.fontWeight = "bold";
    
    // Create series
    var series = chart1.series.push(new am4charts.ColumnSeries3D());
    series.dataFields.valueY = "visits";
    series.dataFields.categoryX = "country";
    series.name = "Visits";
    series.tooltipText = "{categoryX}: [bold]{valueY}[/]";
    series.columns.template.fillOpacity = .8;
    
    var columnTemplate = series.columns.template;
    columnTemplate.strokeWidth = 2;
    columnTemplate.strokeOpacity = 1;
    columnTemplate.stroke = am4core.color("#FFFFFF");
    
    columnTemplate.adapter.add("fill", (fill, target) => {
      return chart1.colors.getIndex(target.dataItem.index);
    })
    
    columnTemplate.adapter.add("stroke", (stroke, target) => {
      return chart1.colors.getIndex(target.dataItem.index);
    })
    
    chart1.cursor = new am4charts.XYCursor();
    chart1.cursor.lineX.strokeOpacity = 0;
    chart1.cursor.lineY.strokeOpacity = 0;
    
    // Create chart instance
    var chart2 = am4core.create('chart-2', am4charts.PieChart);
    
    // Add data
    chart2.data = [ {
      "country": "Lithuania",
      "litres": 501.9
    }, {
      "country": "Czech Republic",
      "litres": 301.9
    }, {
      "country": "Ireland",
      "litres": 201.1
    }, {
      "country": "Germany",
      "litres": 165.8
    }, {
      "country": "Australia",
      "litres": 139.9
    }, {
      "country": "Austria",
      "litres": 128.3
    }, {
      "country": "UK",
      "litres": 99
    }, {
      "country": "Belgium",
      "litres": 60
    }, {
      "country": "The Netherlands",
      "litres": 50
    } ];
    
    // Add and configure Series
    var pieSeries = chart2.series.push(new am4charts.PieSeries());
    pieSeries.dataFields.value = "litres";
    pieSeries.dataFields.category = "country";
    pieSeries.slices.template.stroke = am4core.color("#fff");
    pieSeries.slices.template.strokeWidth = 2;
    pieSeries.slices.template.strokeOpacity = 1;
    
    // This creates initial animation
    pieSeries.hiddenState.properties.opacity = 1;
    pieSeries.hiddenState.properties.endAngle = -90;
    pieSeries.hiddenState.properties.startAngle = -90;
    
    // Disable labels
    pieSeries.labels.template.disabled = true;
    pieSeries.ticks.template.disabled = true;
    
    // Use this method to call the export functionality
    let exportCharts = async (charts) => {
    
      // Map chats to images
      let images = await Promise.all(charts.map(async (chart) => {
    
        return await new Promise((resolve, reject) => {
    
          let getImage = () => {
            resolve(chart.exporting.getImage('png'));
          }
    
          // Get the image if the chart is ready
          if (chart.isReady())
            getImage();
          // Get the image when the chart is ready
          else
            chart.events.on('ready', () => getImage());
        });
      }));
    
      // Begin PDF layout
      const layout = {
        content: []
      };
    
      // Add charts
      layout.content = images.map((image) => {
    
        return {
          image: image,
          fit: [523, 300]
        };
      });
    
      // Finally, download our PDF
      charts[0].exporting.pdfmake.then(function(pdfMake) {
        pdfMake.createPdf(layout).download("amcharts4.pdf");
      });
    }
    
    document.getElementById('print-to-pdf').addEventListener('click', () => {
    
      // Call exports with all the charts you want exported
      exportCharts([chart1, chart2]);
      
    });
    .ui.segment {
      padding: 0;
    }
    
    body > .ui.container {
      margin-top: 3em;
      margin-bottom: 4em;
    }
    
    body > .ui.container > .ui.segment {
      height: 36em;
    }
    <link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css" rel="stylesheet"/>
    <script src="https://www.amcharts.com/lib/4/core.js"></script>
    <script src="https://www.amcharts.com/lib/4/charts.js"></script>
    <script src="https://www.amcharts.com/lib/4/themes/animated.js"></script>
    
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/viewportAction.min.js"></script>
    
    <div class="ui container">
    
      <button id="print-to-pdf" class="ui blue button">Print</button>
      
      <div id="chart-1" class="ui segment">
        <div class="ui active loader"></div>
      </div>
      
      <div id="chart-2" class="ui segment">
        <div class="ui active loader"></div>
      </div>
      
    </div>