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!
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.
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.
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"> <strong>Overall Cheese Interest by Month</strong> </div> <div id="amcharts-stacked-container" className="chart-container"></div> </div> <div className="demo-box"> <div className="demo-title"> <strong>Total Cheese Interest by Country</strong> </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"> <strong>Feta Interest by Month</strong> </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"> <strong>Feta Interest by Country</strong> </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.