Nitish Kumar
Nitish Kumar

Reputation: 6276

Making am4Charts reactive in vuejs

I'm trying to build a component for am4chart in vuejs which I can re-utilise at different places, I've a some search options which changes the chartData values as per the search result.

When my search page loads, it displays the chart perfectly but when I try to check filters it doesn't change or show as per the data. I have all the code related to am4Chart in mounted section, so I tried placing the same in my methods and tried calling the method in mounted section from there. I also put a watch function so that the function can be called again when the data changes. But when I place it in methods the whole chart vanishes, in-fact if I place the same code in mounted and methods section it doesn't display.

I've checked via console my method is being called when chartData changes but don't know how can I make it reactive.

VueJS version 2.6.10

am4Chart version 4.4.10

My code:

<template>
    <div ref="amchart_semi_pie_chart"></div>
</template>

<script>
    import * as am4core from "@amcharts/amcharts4/core";
    import * as am4charts from "@amcharts/amcharts4/charts";

    export default {
        name: "amchart-semi-pie-chart",
        props: {
            chartData: Object,
        },
        data() {
            return {
                chart: '',
            }
        },
        methods: {
            loadChart() {
                console.log('Values are changed')
            }
        },
        mounted() {
            //Creating charts
            let chart = am4core.create(this.$refs.amchart_semi_pie_chart, am4charts.PieChart);
            chart.hiddenState.properties.opacity = 0; // this creates initial fade-in

            chart.data = this.chartData.data;

            // Add and configure Series

            chart.radius = am4core.percent(70);
            chart.innerRadius = am4core.percent(40);
            chart.startAngle = 180;
            chart.endAngle = 360;

            let series = chart.series.push(new am4charts.PieSeries());
            series.dataFields.value = "value";
            series.dataFields.category = "label";

            series.slices.template.cornerRadius = 10;
            series.slices.template.innerCornerRadius = 7;
            series.slices.template.draggable = true;
            series.slices.template.inert = true;
            series.alignLabels = false;

            if(this.chartData.legends)
                chart.legend = new am4charts.Legend();

            this.chart = chart;

        },
        watch: {
            chartData: {
                handler: 'loadChart',
                deep: true
            }
        },
        beforeDestroy() {
            if (this.chart) {
                this.chart.dispose();
            }
        }
    }
</script>

Upvotes: 1

Views: 3562

Answers (2)

SheensP
SheensP

Reputation: 21

Had the same problem and after some digging I found you can refresh the data using chart.invalidateRawData().

See documentation AMCharts Data - Dynamic Updates (Manipulating existing data points)

I applied this on the watch method of the prop which worked for me....

<template>
    <div ref="amchart_semi_pie_chart"></div>
</template>

<script>
    import * as am4core from "@amcharts/amcharts4/core";
    import * as am4charts from "@amcharts/amcharts4/charts";

    export default {
        name: "amchart-semi-pie-chart",
        props: {
            chartData: Object,
        },
        data() {
            return {
                chart: '',
            }
        },
        methods: {
            loadChart() {
                console.log('Values are changed')
                this.chart.invalidateRawData();
            }
        },
        mounted() {
            //Creating charts
            let chart = am4core.create(this.$refs.amchart_semi_pie_chart, am4charts.PieChart);
            chart.hiddenState.properties.opacity = 0; // this creates initial fade-in

            chart.data = this.chartData.data;

            // Add and configure Series

            chart.radius = am4core.percent(70);
            chart.innerRadius = am4core.percent(40);
            chart.startAngle = 180;
            chart.endAngle = 360;

            let series = chart.series.push(new am4charts.PieSeries());
            series.dataFields.value = "value";
            series.dataFields.category = "label";

            series.slices.template.cornerRadius = 10;
            series.slices.template.innerCornerRadius = 7;
            series.slices.template.draggable = true;
            series.slices.template.inert = true;
            series.alignLabels = false;

            if(this.chartData.legends)
                chart.legend = new am4charts.Legend();

            this.chart = chart;

        },
        watch: {
            chartData: {
                handler: 'loadChart',
                deep: true
            }
        },
        beforeDestroy() {
            if (this.chart) {
                this.chart.dispose();
            }
        }
    }
</script>

Upvotes: 2

vollucris
vollucris

Reputation: 78

I know this is old and you might have moved on with the project but since today I faced the same issue and found a solution, I thought it would be nice to reply. In my case, instead of using props I was using computed properties for the data set. I've tried a few things and the one that did the trick for me was to wrap the entire chart creation into a method and watch that computed property (in your case the prop) for changes and fire up the method again. It is visible that the chart is really re-drawn which is not as nice as only having the animation of the changes but for now, it works fine.

So, your code would look something like this:

<template>
    <div ref="amchart_semi_pie_chart"></div>
</template>

<script>
    import * as am4core from "@amcharts/amcharts4/core";
    import * as am4charts from "@amcharts/amcharts4/charts";

    export default {
        name: "amchart-semi-pie-chart",
        props: {
            chartData: Object,
        },
        data() {
            return {
                chart: '',
            }
        },
        methods: {
            loadChart() {
                console.log('Values are changed')
            },
            renderChart() {
                //Creating charts
                let chart = am4core.create(this.$refs.amchart_semi_pie_chart, am4charts.PieChart);
                chart.hiddenState.properties.opacity = 0; // this creates initial fade-in

                chart.data = this.chartData.data;

                // Add and configure Series

                chart.radius = am4core.percent(70);
                chart.innerRadius = am4core.percent(40);
                chart.startAngle = 180;
                chart.endAngle = 360;

                let series = chart.series.push(new am4charts.PieSeries());
                series.dataFields.value = "value";
                series.dataFields.category = "label";

                series.slices.template.cornerRadius = 10;
                series.slices.template.innerCornerRadius = 7;
                series.slices.template.draggable = true;
                series.slices.template.inert = true;
                series.alignLabels = false;

                if(this.chartData.legends)
                    chart.legend = new am4charts.Legend();

                this.chart = chart;
            }
        },
        mounted() {
            renderChart();
        },
        watch: {
            chartData: {
                renderChart();
            }
        },
        beforeDestroy() {
            if (this.chart) {
                this.chart.dispose();
            }
        }
    }
</script>

Upvotes: 1

Related Questions