javascriptlaravelvue.jscharts

Vue js how to emit event on chart js on click


I use chart js with vue js, and show some data on dashboard. But what i am trying to do now is to make a function when i click on chart to go on the responsibile table on another view, maybe with filter also. I mean if i have a chart where i show how many user are and how many user is_suspended are on user table, when i click on side where i see how many is_suspended are to go on users table, maybe to add also filter to show is_suspended only

this is my chart js

<template>
    <div class="container card mx-0 my-2 p-2">
        <Doughnut v-if="loaded"
            :chart-options="chartOptions"
            :chart-data="chartData"
            :width="width"
            :height="height"
        />
    </div>
</template>

<script>
    import { Doughnut } from 'vue-chartjs/legacy'
    import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js'

    ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)

    export default {
        name: 'PieChart',
        components: { Doughnut },

        props: {
            width: {
                type: Number,
                default: 200
            },
            height: {
                type: Number,
                default: 100
            },
        },  
        
        data: () => ({
            chartOptions: {
                responsive: true
            },
            loaded: false,
            chartData: {}
        }),
        async mounted () {
            this.loaded = false
        
            try {
                let response = await fetch('/home/user-statistics-doughnutchart')
                let userdata = await response.json()
                // console.log(userdata)
                this.chartData = userdata
        
                this.loaded = true
            } catch (e) {
                console.error(e)
            }
        }
    }
</script>

and my controller

$users = User::count();
        $active = User::where('is_suspended', 0)->count();
        $suspendedUsers = User::where('is_suspended', 1)->count();

        $post_data = array(
            'labels' => [
                'Accounts '.'('.$users.')',
                'Active '.'('.$active.')',
                'Suspended '.'('.$suspendedUsers.')', 
            ],
            'datasets' => [
                [
                    'backgroundColor' => ['#695CFE', '#191641', '#F2C335'],
                    'data' => [$users, $active, $suspendedUsers]
                ],
            ]
        );

Solution

  • This solution worked for me in Nuxt2 (Vue2)

    <template>
      <Doughnut
        ref="doughnut"
        :chart-options="calcOptions"
        :chart-data="value"
        :height="+ +height"
        :styles="{height: height + 'px'}"
      />
    </template>
    
    <script>
    import {
      Chart as ChartJS,
      Title,
      Tooltip,
      Legend,
      BarElement,
      CategoryScale,
      LinearScale,
      PolarAreaController,
      RadialLinearScale,
      PointElement,
      LineElement,
      ArcElement,
    } from 'chart.js';
    
    import { Doughnut } from 'vue-chartjs';
    
    ChartJS.register(
      CategoryScale,
      LinearScale,
      BarElement,
      Title,
      Tooltip,
      Legend,
      PolarAreaController,
      RadialLinearScale,
      PointElement,
      LineElement,
      ArcElement
    );
    
    export default {
      components: {
        Doughnut,
      },
    
      props: {
        height: {
          type: [String, Number],
          default: 300,
        },
    
        options: {
          type: Object,
          default() {return {}},
        },
    
        title: {
          type: String,
          default: '',
        },
    
        value: {
          type: Object,
          default() {return {}},
        },
      },
    
      methods: {
        handleClick (ev) {
          const points = this.$refs.doughnut.chart.getElementsAtEventForMode(ev, 'nearest', { intersect: true }, false);
    
          if (points.length) {
            const firstPoint = points[0];
            const label = this.value.labels[firstPoint.index];
            const value = this.value.datasets[firstPoint.datasetIndex].data[firstPoint.index];
            this.$emit('click', { label, value, index: firstPoint.index });
          }
        },
      },
    
      computed: {
        calcOptions () {
          if (Object.keys(this.options).length) {
            return this.options;
          }
    
          return {
            responsive: true,
            maintainAspectRatio: false,
            height: + +this.height,
            plugins: {
              title: {
                display: true,
                text: this.title,
                font: {
                  size: 18,
                },
              },
              legend: {
                position: 'right',
              },
            },
          };
        },
      },
    
      mounted () {
        this.$refs.doughnut.chart.canvas.addEventListener('click', this.handleClick);
      },
    
      beforeDestroy () {
        this.$refs.doughnut.chart.canvas.addEventListener('click', this.handleClick);
      },
    }
    </script>