Search code examples
vue.jsvuexradar-chartvue-chartjs

Vue chart js Dynamic Radar Chart


Just wondering if someone can point me in the right direction here when it comes to dynamic data from vuex and applying it to radar charts in vue-chart.js.

Below is my vue file.

<template>
  <div>
    <h1>Chart Demo</h1>
    <v-card class="question card__text pa-sm-5 py-5 px-2">
      <div>
        <radar-chart :data="radarChartData" :options="radarChartOptions" :height="400" />
      </div>
    </v-card>
    <v-container fluid>
      <v-row dense>
        <v-col
          v-for="card in getCards"
          :key="card.id"
          cols="12"
          :sm="card.flex"
          xs="1"
        >
        <v-card>
          <v-card-title class="title" v-text="card.title">
          </v-card-title>
          <p class="pa-4">Importance: {{ card.importance }} <br />
          Effectiveness: {{ card.effectiveness }} </p>
        </v-card>
        </v-col>
      </v-row>
    </v-container>
  </div>
</template>

<script>
import { mapGetters } from "vuex"
import RadarChart from "~/components/RadarChart"
export default {
  layout: "tabs",
  components: {
    RadarChart,
  },
  data() {
    return {
      radarChartOptions: {
          responsive: true,
          scales: {
            yAxes: [
                {
                ticks: {
                    beginAtZero: true,
                    display: false,
                    min: 0,
                    max: 10,
                },
                gridLines: {
                    display: false,
                },
                scaleLabel: {
                    display: false,
                }
                }
            ],
          xAxes: [
            {
              gridLines: {
                display: false,
              },
            }
          ]
        }
      },
      /* radarChartData: {
        labels: [
        "Personal Growth",
        "Work",
        "Leisure",
        "Health",
        "Community",
        "Family",
        "Parenting",
        "Intimate",
        "Social",
        "Spirituality",
        ],
        datasets: [
          {
            label: "Importance",
            backgroundColor: 'rgb(54, 162, 235, 0.75)',
            data: [9, 8, 8, 9, 4, 6, 2, 8, 9, 5],
          },
          {
            label: "Effectiveness",
            backgroundColor: 'rgb(75, 192, 192, 0.75)',
            data: [7, 7, 7, 6, 3, 5, 10, 6, 7, 4],
          },
        ]
      } */
    } 
  },
  computed: {
    ...mapGetters("cards", ["getCards"]),
    //...mapState(["getCards"]),
    barChartData() {
      return {
        labels: ['Importance', 'Effectiveness'],
        datasets: [
          {
            // backgroundColor: ["red", "orange", "yellow"],
            backgroundColor: [chartColors.blue, chartColors.green],
            data: [this.importance, this.effectiveness]
          }
        ]
      } 
    },
    radarChartData() {
      return {
        labels: [
        "Personal Growth",
        "Work",
        "Leisure",
        "Health",
        "Community",
        "Family",
        "Parenting",
        "Intimate",
        "Social",
        "Spirituality",
        ],
        datasets: [
          {
            label: "Importance",
            backgroundColor: 'rgb(54, 162, 235, 0.75)',
            data: [9, 8, 8, 9, 4, 6, 2, 8, 9, 5],
          },
          {
            label: "Effectiveness",
            backgroundColor: 'rgb(75, 192, 192, 0.75)',
            data: [7, 7, 7, 6, 3, 5, 10, 6, 7, 4],
          },
        ]
      }
    },
    card() {
      return this.getCards.find((el) => el.id === this.id)
    },
    effectiveness: {
      get() {
        return this.card.effectiveness
      },
      set(effectiveness) {
        this.$store.commit("cards/updateEffectiveness", { card: this.card, effectiveness})
      },
    },
    importance: {
      get() {
        return this.card.importance
      },
      set(importance) {
        this.$store.commit("cards/updateImportance", { card: this.card, importance})
      },
    },
    keywords: {
      get() {
        return this.card.keywords
      },
      set(keywords) {
        this.$store.commit("cards/updateKeywords", { card: this.card, keywords})
      }
    }
  },
  /* computed: {
    radarChartData() {
      return {
        labels: [
        "Personal Growth",
        "Work",
        "Leisure",
        "Health",
        "Community",
        "Family",
        "Parenting",
        "Intimate Relationships",
        "Social",
        "Spirituality",
      ],
      datasets: [
          {
            // backgroundColor: ["red", "orange", "yellow"],
            data: [9, 8, 8, 9, 4, 6, 2, 8, 9, 5],
          }
        ]
      }
    },
  }*/
}
</script>

below the radar chart is an array of cards that dynamically display the information that I also want to use for the radar chart. I can get the info to show for the cards, but not the radar chart.

I am guessing I am missing something really obvious, and I know I have to somehow reference the card.id, but I am not sure how to do that. I have tried a :key binding on the radar-chart tag but that throws an error of:

‘card’ is not defined

below is the array of store data in my store js file:

import createPersistedState from "vuex-persistedstate"
export const state = () => ({
cards: [
{
title: “Personal Growth”,
src: require("~/assets/images/values/growth.svg"),
flex: 6,
id: “1”,
keywords: [],
importance: “”,
effectiveness: “”,
},
{
title: “Leisure”,
src: require("~/assets/images/customize.svg"),
flex: 6,
id: “2”,
keywords: [],
importance: “”,
effectiveness: “”,
},
{
title: “Sprituality”,
src: require("~/assets/images/values/spirituality.svg"),
flex: 6,
id: “3”,
keywords: [],
importance: “”,
effectiveness: “”,
},
{
title: “Work”,
src: require("~/assets/images/values/work.svg"),
flex: 6,
id: “4”,
keywords: [],
importance: “”,
effectiveness: “”,
},
{
title: “Health”,
src: require("~/assets/images/values/health.svg"),
flex: 6,
id: “5”,
keywords: [],
importance: “”,
effectiveness: “”,
},
{
title: “Community \n& Environment”,
src: require("~/assets/images/values/community.svg"),
flex: 6,
id: “6”,
keywords: [],
importance: “”,
effectiveness: “”,
},
{
title: “Family Relationships”,
src: require("~/assets/images/values/family.svg"),
flex: 6,
id: “7”,
keywords: [],
importance: “”,
effectiveness: “”,
},
{
title: “Social Relationships”,
src: require("~/assets/images/values/social.svg"),
flex: 6,
id: “8”,
keywords: [],
importance: “”,
effectiveness: “”,
},
{
title: “Intimate Relationships”,
src: require("~/assets/images/values/intimate.svg"),
flex: 6,
id: “9”,
keywords: [],
importance: “”,
effectiveness: “”,
},
{
title: “Parenting”,
src: require("~/assets/images/values/parenting.svg"),
flex: 6,
id: “10”,
keywords: [],
importance: “”,
effectiveness: “”,
},
],
})

export const plugins = [createPersistedState()]

export const getters = {
  getCards: (state) => {
    return state.cards
  },
}

export const mutations = {
  updateEffectiveness(state, {card, effectiveness}) {
    card.effectiveness = effectiveness
  },
  updateImportance(state, {card, importance}) {
    card.importance = importance
  },
  updateKeywords(state, {card, keywords}) {
    card.keywords = keywords
  }
}

Any tips, advice are welcome and thanks for any help! :)

Screenshots of what the radar chart looks like with static data are attached.

enter image description here enter image description here


Solution

  • You can use reactiveProp and reactiveData to make your chart reactive. See Updating Charts for more details.

    For reactiveProp, it just creates a prop named chartData and adds a vue watch on this prop then call renderChart() when this prop changed.

    Example for RadarChart.vue:

    <script>
    import { Radar, mixins } from "vue-chartjs";
    
    export default {
      extends: Radar,
      mixins: [mixins.reactiveProp],
      props: ["options"],
      mounted() {
        this.renderChart(this.chartData, this.options);
      }
    };
    </script>
    

    And then use the component:

    <radar-chart :chart-data="radarChartData" :options="radarChartOptions"/>
    

    CodeSandbox Example