☝️Small business or a startup? See if you qualify for our special offer.
+
List of all demos

React Pivot Table with amCharts

Flexmonster Pivot Table & Charts gently integrates with amCharts — a JavaScript library for interactive data visualization with a great choice of interactive charts.

This React dashboard example is built on some Kaggle data about the Cheese industry.

With our specially written connector for amCharts, your visualizations will become even more interactive: just change the slice on the pivot or filter the data, and see your charts immediately transform!

Overall Cheese Interest by Month

Creating React dashboards with amCharts and Flexmonster Pivot Table is easy and engaging: choose from a wide range of modern and bright charts and present your data most favourably.

Total Cheese Interest by Country

Icons made by Freepik from www.flaticon.com

Configure the React pivot grid with the data you need and instantly submit all the information to interactive charts: you will quickly identify all extremes and detect crucial points.

Feta Interest by Month
Feta Interest by Country

  • .js
  • .css
  • index.html
import React, { Component } from "react";
import * as FlexmonsterReact from "react-flexmonster";

// Importing Flexmonster Connector for amCharts
import "flexmonster/lib/flexmonster.amcharts.js";

// amCharts imports
import * as am5 from "@amcharts/amcharts5";
import * as am5xy from "@amcharts/amcharts5/xy";
import * as am5percent from "@amcharts/amcharts5/percent";
import * as am5map from "@amcharts/amcharts5/map";
import am5geodata_worldHigh from "@amcharts/amcharts5-geodata/worldHigh";
import am5themes_Animated from "@amcharts/amcharts5/themes/Animated";
import am5themes_Responsive from "@amcharts/amcharts5/themes/Responsive";

class PivotTableDemo extends Component {

  constructor(props) {
    super(props);
    this.myRef = React.createRef();
    this.chartColors = [
      am5.color("#4CBF8B"),
      am5.color("#FFCD4C"),
      am5.color("#E8734C"),
      am5.color("#9875E3"),
      am5.color("#4C9EFF"),
      am5.color("#8ACFC3"),
      am5.color("#CD97E6"),
      am5.color("#F1D34C"),
      am5.color("#65D2E7"),
    ];
    this.cheeseColors = [am5.color("#FFE268"), am5.color("#FFCD4C"), am5.color("#FFB037")];
  }

  render() {
    return (
      <div className="App">
        <h1 className="page-title">Integrating with amCharts</h1>

        <div className="description-blocks first-description-block">
          <p>
            Extend Flexmonster’s visualization functionality by integrating with the amCharts
            library:{" "}
            <a href="https://www.flexmonster.com/doc/integration-with-amcharts/?r=rm_react" target="_blank" rel="noopener noreferrer" className="title-link">
              Integration with amCharts
            </a>
            .
          </p>
        </div>

        <FlexmonsterReact.Pivot
          ref={this.myRef}
          toolbar={true}
          height={440}
          componentFolder="https://cdn.flexmonster.com/"
          report={{
            dataSource: {
              type: "json",
              filename: "data/demos/amcharts-demo-data.json",
              mapping: {
                Date: {
                  type: "date",
                },
                Country: {
                  type: "string",
                },
                id: {
                  type: "string",
                },
                CountryCode: {
                  type: "property",
                  hierarchy: "Country",
                },
                Feta: {
                  type: "number",
                },
                Mozzarella: {
                  type: "number",
                },
                "Parmigiano-Reggiano": {
                  type: "number",
                },
              },
            },
            slice: {
              rows: [
                {
                  uniqueName: "Date.Month",
                  filter: {
                    exclude: [
                      "date.month.[december]",
                      "date.month.[november]",
                      "date.month.[october]",
                    ],
                  },
                },
                {
                  uniqueName: "[Measures]",
                },
              ],
              columns: [
                {
                  uniqueName: "Country",
                },
              ],
              measures: [
                {
                  uniqueName: "Feta",
                  aggregation: "sum",
                  grandTotalCaption: "Feta",
                },
                {
                  uniqueName: "Mozzarella",
                  aggregation: "sum",
                  grandTotalCaption: "Mozzarella",
                },
                {
                  uniqueName: "Parmigiano-Reggiano",
                  aggregation: "sum",
                  grandTotalCaption: "Parmigiano-Reggiano",
                },
                {
                  uniqueName: "Fetas",
                  formula: 'sum("Feta")',
                  caption: "value",
                  active: false,
                },
              ],
            },
            options: {
              grid: {
                showHeaders: false,
                showGrandTotals: "rows",
              },
              showAggregationLabels: false,
            },
          }}
          licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key"
          reportcomplete={this.reportComplete}
          customizeCell={this.customizeCell}
        />
        <div className="demo-box">
          <div className="demo-title">
            Overall Cheese Interest by Month
          </div>
          <div id="amcharts-stacked-container" className="chart-container"></div>
        </div>
        <div className="demo-box">
          <div className="demo-title">
            Total Cheese Interest by Country
          </div>
          <div id="amcharts-pictorial-container" className="chart-container"></div>
          <div>
            Icons made by{" "}
            <a href="https://www.freepik.com" title="Freepik">
              Freepik
            </a>{" "}
            from{" "}
            <a href="https://www.flaticon.com/" title="Flaticon">
              www.flaticon.com
            </a>
          </div>
        </div>
        <div className="demo-box">
          <div className="demo-title">
            Feta Interest by Month
          </div>
          <div id="amcharts-pie-container" className="chart-container"></div>
        </div>

        <div className="demo-box no-text-before no-text-after">
          <div className="demo-title">
            Feta Interest by Country
          </div>
          <div id="amcharts-map-container" className="chart-container"></div>
        </div>
      </div>
    );
  }

  reportComplete = () => {
    this.myRef.current.flexmonster.off(this.reportComplete);
    this.createStackedChart();
    this.createPictorialChart();
    this.createPieChart();
    this.createMapChart();
  };

  createStackedChart = () => {
    this.myRef.current.flexmonster.amcharts.getData(
      {},
      this.drawStackedChart,
      this.updateStackedChart
    );
  };

  drawStackedChart = (chartData, rawData) => {
    this.stackedChartRoot = am5.Root.new("amcharts-stacked-container");

    //Set themes
    this.stackedChartRoot.setThemes([am5themes_Animated.new(this.stackedChartRoot)]);

    let stackedChart = this.stackedChartRoot.container.children.push(
      am5xy.XYChart.new(this.stackedChartRoot, {})
    );
    stackedChart.get("colors").set("colors", this.chartColors);
    // Craete Y-axis
    var valueAxis = stackedChart.yAxes.push(
      am5xy.ValueAxis.new(this.stackedChartRoot, {
        renderer: am5xy.AxisRendererY.new(this.stackedChartRoot, {}),
        tooltip: am5.Tooltip.new(this.stackedChartRoot, {
          truncate: true,
          maxWidth: 200,
          tooltipText: "{category}",
        }),
      })
    );

    valueAxis.children.unshift(
      am5.Label.new(this.stackedChartRoot, {
        rotation: -90,
        text: "Queries",
        y: am5.p50,
        centerX: am5.p50,
      })
    );

    // Create X-Axis
    var categoryAxis = stackedChart.xAxes.push(
      am5xy.CategoryAxis.new(this.stackedChartRoot, {
        renderer: am5xy.AxisRendererX.new(this.stackedChartRoot, {
          minGridDistance: 20,
        }),
        categoryField: this.myRef.current.flexmonster.amcharts.getCategoryName(rawData),
        tooltip: am5.Tooltip.new(this.stackedChartRoot, {
          truncate: true,
          maxWidth: 200,
          tooltipText: "{category}",
        }),
      })
    );

    //Get xRendeder for axis configurations
    let xRenderer = categoryAxis.get("renderer");

    xRenderer.grid.template.setAll({
      location: 0,
    });

    const maxWidth = 200;

    xRenderer.labels.template.setAll({
      truncate: true,
      maxWidth: maxWidth,
      tooltipText: "{category}",
    });

    categoryAxis.events.on("boundschanged", function (ev) {
      let axis = ev.target;
      let cellWidth =
        axis.innerWidth() / (axis.getPrivate("endIndex") - axis.getPrivate("startIndex"));
      if (cellWidth < maxWidth) {
        xRenderer.labels.template.setAll({
          rotation: -45,
          horizontalCenter: "right",
          verticalCenter: "middle",
        });
      } else {
        xRenderer.labels.template.setAll({
          rotation: 0,
          horizontalCenter: "middle",
          verticalCenter: "top",
        });
      }
    });

    categoryAxis.data.setAll(chartData.data);

    for (let i = 0; i < this.myRef.current.flexmonster.amcharts.getNumberOfMeasures(rawData); i++) {
      // Create series
      let series = stackedChart.series.push(
        am5xy.ColumnSeries.new(this.stackedChartRoot, {
          xAxis: categoryAxis,
          yAxis: valueAxis,
          categoryXField: this.myRef.current.flexmonster.amcharts.getCategoryName(rawData),
          valueYField: this.myRef.current.flexmonster.amcharts.getMeasureNameByIndex(rawData, i),
          name: this.myRef.current.flexmonster.amcharts
            .getMeasureNameByIndex(rawData, i)
            .split(" ")
            .pop(),
          stacked: true,
        })
      );

      series.columns.template.setAll({
        tooltipText: "{name}, {categoryX}: {valueY}",
      });

      series.data.setAll(chartData.data);
    }
    stackedChart.set("cursor", am5xy.XYCursor.new(this.stackedChartRoot, {}));
  };

  updateStackedChart = (chartData, rawData) => {
    this.stackedChartRoot.dispose();
    this.drawStackedChart(chartData, rawData);
  };

  createPictorialChart = () => {
    this.myRef.current.flexmonster.amcharts.getData(
      {
        slice: {
          rows: [
            {
              uniqueName: "Country",
            },
            {
              uniqueName: "[Measures]",
            },
          ],
          measures: [
            {
              uniqueName: "Fetas",
              formula: 'sum("Feta")',
              caption: "value",
            },
          ],
        },
      },
      this.drawPictorialChart,
      this.updatePictorialChart
    );
  };

  drawPictorialChart = (chartData, rawData) => {
    let iconPathValue = window.iconPath();

    // Create chart instance
    this.pictorialChartRoot = am5.Root.new("amcharts-pictorial-container");
    let pictorialChart = this.pictorialChartRoot.container.children.push(
      am5percent.SlicedChart.new(this.pictorialChartRoot, {
        layout: this.pictorialChartRoot.horizontalLayout,
      })
    );

    //Set themes
    this.stackedChartRoot.setThemes([am5themes_Animated.new(this.stackedChartRoot)]);

    //Create series
    let series = pictorialChart.series.push(
      am5percent.PictorialStackedSeries.new(this.pictorialChartRoot, {
        name: "Series",
        valueField: this.myRef.current.flexmonster.amcharts.getMeasureNameByIndex(rawData, 0),
        orientation: "horizontal",
        categoryField: this.myRef.current.flexmonster.amcharts.getCategoryName(rawData),
        alignLabels: true,
        svgPath: this.iconPathValue,
        maxWidth: 500,
        centerX: am5.percent(50),
        x: am5.percent(50),
      })
    );
    series.ticks.template.set("visible", false);
    series.labels.template.set("visible", false);

    series.get("colors").set("colors", this.cheeseColors);

    series.data.setAll(chartData.data);

    //Create legend
    var legend = pictorialChart.children.push(
      am5.Legend.new(this.pictorialChartRoot, {
        centerY: am5.percent(50),
        y: am5.percent(50),
        layout: this.pictorialChartRoot.verticalLayout,
      })
    );

    legend.markerRectangles.template.setAll({
      cornerRadiusTL: 10,
      cornerRadiusTR: 10,
      cornerRadiusBL: 10,
      cornerRadiusBR: 10,
    });

    legend.data.setAll(series.dataItems);
  };

  updatePictorialChart = (chartData, rawData) => {
    // Here you can add your own logic for updating the chart
  };

  createPieChart = () => {
    this.myRef.current.flexmonster.amcharts.getData(
      {
        slice: {
          rows: [
            {
              uniqueName: "Date.Month",
              filter: {
                members: [
                  "date.month.[january]",
                  "date.month.[february]",
                  "date.month.[march]",
                  "date.month.[april]",
                  "date.month.[may]",
                  "date.month.[june]",
                ],
              },
            },
          ],
          measures: [
            {
              uniqueName: "Feta",
              aggregation: "sum",
            },
          ],
        },
      },
      this.drawPieChart,
      this.updatePieChart
    );
  };

  drawPieChart = (chartData, rawData) => {
    // Initialize the chart
    this.pieChartRoot = am5.Root.new("amcharts-pie-container");
    let pieChart = this.pieChartRoot.container.children.push(
      am5percent.PieChart.new(this.pieChartRoot, {
        numberFormatter: am5.NumberFormatter.new(this.pieChartRoot, {
          numberFormat: this.myRef.current.flexmonster.amcharts.getNumberFormatPattern(
            rawData.meta.formats[0]
          ),
        }),
      })
    );

    //Set themes
    this.stackedChartRoot.setThemes([am5themes_Animated.new(this.stackedChartRoot)]);

    // Create pie series
    let series = pieChart.series.push(
      am5percent.PieSeries.new(this.pieChartRoot, {
        name: "Series",
        y: am5.percent(-10),
        valueField: this.myRef.current.flexmonster.amcharts.getMeasureNameByIndex(rawData, 0),
        categoryField: this.myRef.current.flexmonster.amcharts.getCategoryName(rawData),
        alignLabels: true,
      })
    );
    series.get("colors").set("colors", this.chartColors);
    series.labels.template.set("text", "{category}: {value}");

    series.slices.template.adapters.add("radius", function (radius, target) {
      let dataItem = target.dataItem;
      let high = series.getPrivate("valueHigh");

      if (dataItem) {
        let value = target.dataItem.get("valueWorking", 0);
        return (radius * value) / high;
      }
      return radius;
    });

    series.slices.template.setAll({
      cornerRadius: 6,
      stroke: am5.color("#fff"),
      strokeWidth: 2,
      strokeOpacity: 1,
    });

    // Fill the chart with the data from Flexmonster
    series.data.setAll(chartData.data);

    //Create legend
    var legend = pieChart.children.push(
      am5.Legend.new(this.pieChartRoot, {
        centerX: am5.percent(50),
        x: am5.percent(50),
        y: am5.percent(95),
        centerY: am5.percent(100),
      })
    );

    const responsive = am5themes_Responsive.new(this.pieChartRoot);

    responsive.addRule({
      name: "Series",
      relevant: function (width, height) {
        return width <= 600;
      },
      applying: () => {
        series.ticks.template.set("visible", false);
        series.labels.template.set("visible", false);
      },
      removing: () => {
        series.ticks.template.set("visible", true);
        series.labels.template.set("visible", true);
      },
    });

    this.pieChartRoot.setThemes([responsive]);

    legend.data.setAll(series.dataItems);
  };

  updatePieChart = (chartData, rawData) => {
    // Here you can add your own logic for updating the chart
  };

  createMapChart = () => {
    this.myRef.current.flexmonster.amcharts.getData(
      {
        slice: {
          rows: [
            {
              uniqueName: "id",
            },
          ],
          columns: [
            {
              uniqueName: "[Measures]",
            },
          ],
          measures: [
            {
              uniqueName: "Fetas",
              formula: 'sum("Feta")',
              caption: "value",
            },
          ],
        },
      },
      this.drawMapChart,
      this.updateMapChart
    );
  };

  drawMapChart = (chartData, rawData) => {
    this.mapChartRoot = am5.Root.new("amcharts-map-container");

    // Set themes
    this.mapChartRoot.setThemes([am5themes_Animated.new(this.mapChartRoot)]);
    // Create chart
    let mapChart = this.mapChartRoot.container.children.push(
      am5map.MapChart.new(this.mapChartRoot, {
        panX: "rotateX",
        panY: "none",
        valueField: this.myRef.current.flexmonster.amcharts.getMeasureNameByIndex(rawData, 0),
        homeZoomLevel: 9,
        maxZoomLevel: 9,
        minZoomLevel: 9,
        wheelY: "none",
        homeGeoPoint: {
          longitude: 12.496366,
          latitude: 42.399982,
        },
      })
    );

    // Create polygon series
    let polygonSeries = mapChart.series.push(
      am5map.MapPolygonSeries.new(this.mapChartRoot, {
        geoJSON: am5geodata_worldHigh,
        valueField: this.myRef.current.flexmonster.amcharts.getMeasureNameByIndex(rawData, 0),
        calculateAggregates: true,
        exclude: ["AQ"],
      })
    );

    polygonSeries.mapPolygons.template.setAll({
      tooltipText: "{name} {value}",
      fill: am5.color("#D3D3D3"),
    });

    polygonSeries.mapPolygons.template.events.on("pointerover", function (ev) {
      heatLegend.showValue(ev.target.dataItem.get("value"));
    });

    polygonSeries.events.on("datavalidated", () => {
      mapChart.goHome();
    });

    polygonSeries.set("heatRules", [
      {
        target: polygonSeries.mapPolygons.template,
        dataField: this.myRef.current.flexmonster.amcharts.getMeasureNameByIndex(rawData, 0),
        min: am5.color("#F1D34C"),
        max: am5.color("#4CBF8B"),
        key: "fill",
      },
    ]);

    polygonSeries.data.setAll(chartData.data);

    var heatLegend = mapChart.children.push(
      am5.HeatLegend.new(this.mapChartRoot, {
        target: polygonSeries.mapPolygons.template,
        orientation: "horizontal",
        width: am5.percent(100),
        y: am5.percent(100),
        centerY: am5.percent(100),
        startColor: am5.color("#F1D34C"),
        endColor: am5.color("#4CBF8B"),
        paddingBottom: 20,
        paddingTop: 20,
        paddingLeft: 20,
        paddingRight: 20,
      })
    );

    polygonSeries.events.on("datavalidated", function () {
      heatLegend.set("startValue", polygonSeries.getPrivate("valueLow"));
      heatLegend.set("endValue", polygonSeries.getPrivate("valueHigh"));
    });
  };

  updateMapChart = (chartData, rawData) => {
    // Here you can add your own logic for updating the chart
  };

  componentWillUnmount() {
    if (this.stackedChartRoot) {
      this.stackedChartRoot.dispose();
    }
    if (this.pictorialChartRoot) {
      this.pictorialChartRoot.dispose();
    }
    if (this.pieChartRoot) {
      this.pieChartRoot.dispose();
    }
    if (this.mapChartRoot) {
      this.mapChartRoot.dispose();
    }
  }

  customizeCell = (cell, data) => {
    if (data.hierarchy && data.type === "header") {
      if (data.hierarchy.caption === "Country" && data.member && data.member.properties) {
        let name = data.member.properties.CountryCode;
        let flag = `<i class="fm-icon ${data.expanded ? "fm-expanded-icon" : "fm-collapsed-icon"}"
              title="${data.expanded ? "Click to collapse" : "Click to expand"}"></i>
              <img class="flag-icon" src="https://cdn.flexmonster.com/i/flags/${name.toLowerCase()}.svg">`;
        cell.text = `${flag}<span style="margin-left: 2px; line-height: 16px">${data.member.caption}</span>`;
        cell.addClass("fm-custom-cell");
      }
    }
  };
}

export default PivotTableDemo;
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}

.chart-container {
  height: 450px;
}

.demo-box {
  background-color: #fafafa;
  position: relative;
  padding: 40px 30px 30px 30px;
  border: 1px solid #e9e9e9;
  margin-bottom: 20px;
  margin-top: 40px;
}

.demo-title {
  font-size: 18px;
  margin-bottom: 30px;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  line-height: 24px;
}

.fm-custom-cell {
  display: flex !important;
  align-items: center !important;
  font-size: 12px !important;
}

.fm-custom-cell .flag-icon {
  width: 21px !important;
  height: 16px !important;
  margin-left: 0 !important;
  margin-right: 2px !important;
}

#fm-pivot-view .fm-grid-layout .fm-custom-cell.fm-expanded .fm-expanded-icon::before,
#fm-pivot-view .fm-grid-layout .fm-custom-cell.fm-collapsed .fm-collapsed-icon::before {
  top: -2px;
  height: 16px;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
    <meta name="theme-color" content="#000000">
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
    <title>Flexmonster & amCharts Demo</title>
    <!-- This file contains the iconPath() function needed for the pictorial chart -->
    <script src="https://cdn.flexmonster.com/data/demos/amcharts-iconPath.js"></script>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

Check this step-by-step integration with amCharts guide to start creating the best visualizations quickly.