Flexmonster Software License Agreement (“Agreement”) has been revised and is effective as of February 18, 2025.
The following modifications were made:
Downloading, installing, and/or continuing to use Flexmonster Software after February 18, 2026, constitutes Licensee’s acceptance of the terms and conditions of the modified version of Agreement. If Licensee does not agree to any of these terms and conditions, they must cease using Flexmonster Software and must not download, install, use, access, or continue to access Flexmonster Software. By continuing to use Flexmonster Software or renewing the license or maintenance after the effective date of these modifications to Agreement, Licensee accepts and agrees to be bound by the terms and conditions of the modified Agreement.
Seamlessly integrate Flexmonster Pivot with amCharts and add them to your Vue.js applications.
For the demo example, we used Kaggle data about the cheese industry to show how perfectly the combination of Flexmonster Pivot & amCharts works for the analytical Vue dashboard.
Play with the demo on a larger screen: save this link for later or watch the video review now.
Use our special Connector for amCharts to create interactive visualizations for your Vue project. The Connector preprocesses the data into a format required by amCharts, so you can easily use it to show any chart type.
With the mix of a robust Vue pivot grid and a variety of stylish charts provided by the amCharts library, you can create interactive and responsive dashboards. Check out the chart types that can be used for your Vue app.
Icons made by Freepik from www.flaticon.com
All you need is to configure the pivot table view according to your data logic and instantly transfer all the information to interactive charts.
<template>
<Pivot
ref="pivot"
componentFolder="https://cdn.flexmonster.com/"
height="440"
licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key"
v-bind:report="report"
v-bind:customizeCell="customizeCellFunction"
v-bind:reportcomplete="reportcomplete"
/>
<div class="demo-box">
<div class="demo-title">Overall Cheese Interest by Month</div>
<div id="amcharts-stacked-container" class="chart-container"></div>
</div>
<div class="demo-box">
<div class="demo-title">Total Cheese Interest by Country</div>
<div id="amcharts-pictorial-container" class="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 class="demo-box">
<div class="demo-title">Feta Interest by Month</div>
<div id="amcharts-pie-container" class="chart-container"></div>
</div>
<div class="demo-box no-text-before no-text-after">
<div class="demo-title">Feta Interest by Country</div>
<div id="amcharts-map-container" class="chart-container"></div>
</div>
</template>
<script>
import Pivot from "vue-flexmonster/vue3";
import "flexmonster/flexmonster.css";
// Importing Flexmonster Connector for amCharts
import "flexmonster/lib/flexmonster.amcharts";
// 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";
const 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"),
];
const cheeseColors = [am5.color("#FFE268"), am5.color("#FFCD4C"), am5.color("#FFB037")];
export default {
name: "PivotComponent",
components: {
Pivot,
},
data() {
return {
report: {
dataSource: {
type: "json",
filename: "https://cdn.flexmonster.com/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",
},
],
},
options: {
grid: {
showHeaders: false,
showGrandTotals: "rows",
},
showAggregationLabels: false,
},
},
};
},
methods: {
reportcomplete() {
this.$refs.pivot.flexmonster.off(this.reportComplete);
this.createStackedChart();
this.createPictorialChart();
this.createPieChart();
this.createMapChart();
},
createStackedChart() {
this.$refs.pivot.flexmonster.amcharts.getData(
{},
this.drawStackedChart,
this.updateStackedChart
);
},
createPictorialChart() {
this.$refs.pivot.flexmonster.amcharts.getData(
{
slice: {
rows: [
{
uniqueName: "Country",
},
{
uniqueName: "[Measures]",
},
],
measures: [
{
uniqueName: "Fetas",
formula: 'sum("Feta")',
caption: "value",
},
],
},
},
this.drawPictorialChart,
this.updatePictorialChart
);
},
updateStackedChart(chartData, rawData) {
this.stackedChartRoot.dispose();
this.drawStackedChart(chartData, rawData);
},
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", 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.$refs.pivot.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.$refs.pivot.flexmonster.amcharts.getNumberOfMeasures(rawData); i++) {
// Create series
let series = stackedChart.series.push(
am5xy.ColumnSeries.new(this.stackedChartRoot, {
xAxis: categoryAxis,
yAxis: valueAxis,
categoryXField: this.$refs.pivot.flexmonster.amcharts.getCategoryName(rawData),
valueYField: this.$refs.pivot.flexmonster.amcharts.getMeasureNameByIndex(rawData, i),
name: this.$refs.pivot.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, {}));
},
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.$refs.pivot.flexmonster.amcharts.getMeasureNameByIndex(rawData, 0),
orientation: "horizontal",
categoryField: this.$refs.pivot.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", 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,
clickTarget: "none"
})
);
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.$refs.pivot.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.$refs.pivot.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.$refs.pivot.flexmonster.amcharts.getMeasureNameByIndex(rawData, 0),
categoryField: this.$refs.pivot.flexmonster.amcharts.getCategoryName(rawData),
alignLabels: true,
})
);
series.get("colors").set("colors", 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.$refs.pivot.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.$refs.pivot.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.$refs.pivot.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();
});
// Create polygon series
polygonSeries.set("heatRules", [
{
target: polygonSeries.mapPolygons.template,
dataField: this.$refs.pivot.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
},
},
beforeUnmount() {
if (this.stackedChart) {
this.stackedChart.dispose();
}
if (this.pictorialChart) {
this.pictorialChart.dispose();
}
if (this.pieChart) {
this.pieChart.dispose();
}
if (this.mapChart) {
this.mapChart.dispose();
}
},
customizeCellFunction(cell, data) {
if (
data.hierarchy?.caption === "Country" &&
data.type === "header" &&
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");
}
},
};
</script>
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;
font-weight: 600;
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="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<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>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
Read more about our integration with amCharts and easily start creating colorful and insightful visualizations.
Can't find your answer here?
Visit the FAQ page
Flexmonster Pivot Table & Charts is a JavaScript pivot table component for adding interactive reporting and data analysis to web applications. Users can summarize, filter, sort, and explore data in pivot tables and charts, drill into results, and export reports.
Flexmonster works in plain JavaScript and TypeScript projects. It also integrates with React, Next.js, Angular, Vue, Blazor, and other technologies. See all integration options.
Flexmonster supports JSON and CSV files, SQL databases, MongoDB, Elasticsearch, and Microsoft Analysis Services (SSAS). You can also connect other data sources through your own backend. See supported data sources.
Flexmonster offers licenses for internal corporate use, SaaS products, and OEM distribution. Pricing varies by license and plan. SaaS projects can also use the free SaaS Entry license during development. Learn more on the pricing page.
Yes. Flexmonster offers a 30-day free trial that lets you evaluate all its features. No credit card is required. The trial version has a watermark.
To get started with Flexmonster, follow our integration guide.