How to dynamically update the maximum y-axis value in Vue-Chart.js without having to completely re-render the entire

Currently, I am involved in a project that requires the implementation of various charts from the Vue-Chartjs library. One specific requirement is to dynamically change the maximum value on the Y-axis whenever users apply different filters. To achieve this, I have imported an existing barchart component from the vue-chartjs library. The code includes a JavaScript file with pre-defined defaults, and for customization, I can utilize the extraOptions object as a prop to tailor each chart accordingly. Here is the default component structure:

import { Bar } from 'vue-chartjs'
import { hexToRGB } from "./utils";
import reactiveChartMixin from "./mixins/reactiveChart";

let defaultOptions = {
  tooltips: {
   tooltipFillColor: "rgba(0,0,0,0.5)",
   tooltipFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
   tooltipFontSize: 14,
   tooltipFontStyle: "normal",
   tooltipFontColor: "#fff",
   tooltipTitleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
   tooltipTitleFontSize: 14,
   tooltipTitleFontStyle: "bold",
   tooltipTitleFontColor: "#fff",
   tooltipYPadding: 6,
   tooltipXPadding: 6,
   tooltipCaretSize: 8,
   tooltipCornerRadius: 6,
   tooltipXOffset: 10,
},
legend: {
  display: false
},
scales: {
  yAxes: [{
    ticks: {
      fontColor: "#9f9f9f",
      fontStyle: "bold",
      beginAtZero: true,
      display: false,
      min: 0,
      max: 100
    },
  gridLines: {
    display: false,
    drawBorder: false,
  }
}],
xAxes: [{
  gridLines: {
    display: false,
    drawBorder: false,
   },
 }],
    }
   };
     export default {
        name: 'BarChart',
        extends: Bar,
        mixins: [reactiveChartMixin],
        props: {
        labels: {
        type: [Object, Array],
        description: 'Chart labels. This is overridden when `data` is provided'
    },
    datasets: {
      type: [Object, Array],
      description: 'Chart datasets. This is overridden when `data` is provided'
    },
    data: {
      type: [Object, Array],
      description: 'Chart.js chart data (overrides all default data)'
    },
    color: {
      type: String,
      description: 'Chart color. This is overridden when `data` is provided'
    },
    extraOptions: {
      type: Object,
      description: 'Chart.js options'
    },
    title: {
      type: String,
      description: 'Chart title'
    },
  },
  methods: {
    assignChartData() {
      let { gradientFill } = this.assignChartOptions(defaultOptions);
      let color = this.color || this.fallBackColor;
      return {
        labels: this.labels || [],
        datasets: this.datasets ? this.datasets : [{
          label: this.title || '',
          backgroundColor: gradientFill,
          borderColor: color,
          pointBorderColor: "#FFF",
          pointBackgroundColor: color,
          pointBorderWidth: 2,
          pointHoverRadius: 4,
          pointHoverBorderWidth: 1,
          pointRadius: 4,
          fill: true,
          borderWidth: 1,
          data: this.data || []
        }]
      }
    },
    assignChartOptions(initialConfig) {
      let color = this.color || this.fallBackColor;
      const ctx = document.getElementById(this.chartId).getContext('2d');
      const gradientFill = ctx.createLinearGradient(0, 170, 0, 50);
      gradientFill.addColorStop(0, "rgba(128, 182, 244, 0)");
      gradientFill.addColorStop(1, hexToRGB(color, 0.6));
      let extraOptions = this.extraOptions || {}
      return {
        ...initialConfig,
        ...extraOptions,
        gradientFill
      };
    }
  },
  mounted() {
    this.chartData = this.assignChartData({});
    this.options = this.assignChartOptions(defaultOptions);
    this.renderChart(this.chartData, this.options, this.extraOptions);
  }
}

The bar chart from the above JavaScript file is imported into a Vue component shown below. Whenever there are changes in the form input, the chart needs to be re-rendered. By toggling the boolean loaded variable to false within the onInputChange() method, followed by calling the loadData() function, the chart refreshes. In the loadData() method, an axios request fetches the required data along with the maximum Y-axis value.

After receiving a response, the updateChart() function is triggered to update the chart's data and maximum value. Subsequently, setting loaded back to true ensures a proper visualization of the chart without any sudden disappearance. However, the challenge lies in preventing the brief disappearance of the chart upon updating the Y-axis max value.

To address this issue, a computed property might offer a solution, although the functioning of which requires further understanding. Below is the component code excluding the form fields.

The main goal is to dynamically adjust the max value on the Y-axis without entirely refreshing the chart.

<template>
      <div>
          <BarChart v-if="loaded" :labels="chartLabels"
                 :datasets="datasets"
                 :height="100"
                 :extraOptions="extraOptions"
          >
          </BarChart>
        <br>
      </div>
    </template>
    <script>
    import BarChart from '../../components/Library/UIComponents/Charts/BarChart'
    import Dropdown from "../../components/Library/UIComponents/Dropdown"
    import GroupedMultiSelectWidget from "~/components/widgets/GroupedMultiSelectWidget"
    import SelectWidget from "../../components/widgets/SelectWidget";
    
    
    export default{
      name: 'PopularChart',
      components: {BarChart, Dropdown, SelectWidget, GroupedMultiSelectWidget},
      data(){
        return {
          loaded:true,
          form:{
              day: 'Today',
              workspace:'',
              machine_family: [],
              duration: [],
              user_group: [],
              dt_start:'',
              dt_end:''
          },
          url: `/api/data_app/job_count_by_hour/`,
          chart_data: [],
          days: [ {day:"Today", id:"Today"},
                  {day:"Monday", id:"0"},
                  {day:"Tuesday",id:"1"},
                  {day:"Wednesday",id:"2"},
                  {day:"Thursday",id:"3"},
                  {day:"Friday",id:"4"},
                  {day:"Saturday",id:"5"},
                  {day:"sunday",id:"6"} ],
          chartLabels: ["00u", "1u", "2u", "3u","4u","5u", "6u", "7u", "8u", "9u", "10u", "11u", "12u", "13u", "14u", "15u","16u", "17", "18u","19u","20u","21u","22u","23u"],
          datasets: [],
          maximumValue: '',
          extraOptions:{}
    
        }
      },
      methods: {
        onInputChange() {
          this.loaded = false
          this.loadData()
        },
        async loadData() {
            await this.$axios.get(`${this.url}?day=${this.form.day}&date_start=${this.form.dt_start}&date_end=${this.form.dt_end}&workspace=${this.form.workspace}&user_group=${this.form.user_group}&machine_family=${this.form.machine_family}`)
              .then(response => {
                this.updateChart(response.data.results,response.data.maximum)
                this.loaded = true
            })
        },
        updateChart(data,maxValue) {
            this.datasets = [{
                  label: ["jobs %"],
                  backgroundColor:"#f93232",
                  data: data
            },]
            this.maximumValue = maxValue
            this.extraOptions = {
              tooltips: {
                callbacks:{
                  label: function (tooltipItems,){
                          if (tooltipItems.value > ((50/100) * maxValue)){
                            return 'busy';
                          }else if (tooltipItems.value < ((30/ 100) * maxValue) ){
                             return ' not busy';
                          }else if ( tooltipItems.value < ((40/ 100) * maxValue )){
                            return 'kind of busy'
                          }
                      }
                }
              },
              scales: {
              yAxes: [{
                  gridLines: {
                    zeroLineColor: "transparent",
                    display: false,
                    drawBorder: false,
                  },
                  ticks: {
                    max: this.maximumValue,
                    display: true,
                  }
              }],
              xAxes: [{
                  gridLines: {
                  zeroLineColor: "transparent",
                  display: false,
                  drawBorder: false,
                  },
              }],
            },
          }
        },
    
      },
      mounted() {
        this.loadData()
      },
    }
    </script>

Answer №1

Upon reviewing your code, I have observed that you are utilizing the datasets and maximumValue within the data function. To properly update the chart data based on dataset and maximumValue, it is recommended to utilize these variables within the computed data section, rather than in the data section. Here's an example:

computed: {
   chartData() {
      let chartData = {
         labels: [],
         datasets: [...],
      }
      return chartData;
   },
   maximumValue() {
      return this.maxValue;
   }
},
methods: {
  renderBarChart() {
    this.renderChart(this.chartData, {
      legend: {
        display: false,
      },
      responsive: true,
      maintainAspectRatio: false,
      options: {
        scales: {
          yAxes: [{
              ticks: {
                  max: this.maximumValue
              }
          }],
        },
      }
    });
  },
},

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to extract the geometry information from a gltf object?

I've been using three.js to load a gltf file with the gltfloader, and now I'm trying to create a particle system. However, I'm having trouble getting the geometry object that I need. function initModel() { var planeGeometry = new THREE ...

Programmatically simulate a text cursor activation as if the user has physically clicked on the input

I have been attempting to input a value into a text field using JavaScript, similar to the Gmail email input tag. However, I encountered an issue with some fancy animations that are tied to certain events which I am unsure how to trigger, illustrated in th ...

Utilize the UseQuery graphql function in conjunction with the useState hook within useEffect, allowing for the execution of an additional useEffect to update additional state

In my NextJS project, I am utilizing Apollo for graphQL queries and encountering an issue with the stateData.allProducts section. Despite setting the state in the useEffect and including data as a dependency in the array, the error claims it is null when d ...

Next.js encountered an error while trying to locate the flowbite.min.js file for Tailwindcss and Flowbite, resulting in a

I'm having an issue with integrating the flowbite package with TailwindCSS in my Next.js application. Despite configuring everything correctly, I am encountering an error when adding the flowbite.min.js script: GET http://localhost:3000/node_modules/f ...

Ways to capture the value of several images and add them to an array

When working on a multiple file upload task, I encountered the need to convert images into base64 encoded strings. My form consists of two fields, one for first name and another for image upload. The user can enter their name, upload multiple photos, and c ...

Attempting to instruct my chrome extension to execute a click action on a specific element found within the webpage

I am currently working on developing a unique chrome extension that has the capability to download mp3s specifically from hiphopdx. I have discovered a potential solution, where once the play button on the website is clicked, it becomes possible to extract ...

Endless cycle of React hooks

I am struggling to understand why I keep encountering an infinite loop in my useClick function. I can see that I am updating the state value inside the useEffect using setVal, but according to the second parameter, useEffect should only run on onClick as ...

Different approach to iterating through elements

Looking to implement .forEach instead of a traditional for loop? 'use strict'; var score = (function(){ function updateScore() { for(var i = 0; i < arguments.length; i++) { this.score += arguments[i]; ...

When you encounter an open response and need to resend it, simply click the "Send Again

After the discontinuation of Firebug, I find myself in need of two crucial functionalities that I used frequently. To replace these features, I am wondering if there are similar options available within the default Firefox Web Console. Previously, when ma ...

What is the method for incorporating parameters into an array filter?

Imagine having an array containing multiple duplicate objects. How can we create a condition to specifically identify objects with certain criteria, such as matching IDs, duplicate status, and duplicate dates? The goal is to only display the object with th ...

Modify the names of the array variables

I am currently working with JSON data that consists of an array of blog categories, all represented by category id numbers. I am uncertain about how to create a new array that will translate these id numbers into their corresponding category names. Essen ...

Tips on how to efficiently wrap content within a column layout, and to seamlessly shrink it if necessary

I recently encountered an issue where I am attempting to create a three-column layout with each column filled with a dynamic number of divs (boxes) ranging from 5 to 15, each with its own height based on its content. These divs are expected to: 1) Be dis ...

No receiving a callback_query update upon user pressing an inline button in the Telegram webhook

When using the node-telegram-bot-api library, I encountered an issue with my Webhook. Although I am able to receive updates when messages are sent, I do not get any updates when a user presses a button in an inline keyboard. class BotController { async ...

Combine activities from a dynamic array of Observables

I'm currently utilizing the rxjs library. In my application, I have a Browser object overseeing multiple instances of Page objects. Each page emits a stream of events through an Observable<Event>. Pages can be opened and closed dynamically, le ...

What is the best way to showcase an image using Next.js?

I'm having a problem with displaying an image in my main component. The alt attribute is showing up, but the actual image is not appearing on the browser. Can someone please point out what I might be doing wrong? import port from "../public/port. ...

Ways to isolate and limit the application of CSS in React and Gatsby to specific pages instead of having it affect the global scope

At the moment, I'm working on integrating a keen-slider library(https://www.npmjs.com/package/keen-slider). To install it, we have to include import 'keen-slider/keen-slider.min.css'. This essentially adds the CSS globally to our project. Ho ...

The error message "ReferenceError: $ is not defined" is displayed within

My current requirement involves loading templates within an iframe, and to achieve this, I have implemented the following code: <div class="col m8 l8 s12 margin-top-30" id="hue-demo-bg-div"> <iframe id="myiframe" src="/themes/{{$themeid}}.ht ...

Node.js - Synchronize asynchronous calls to ensure coordinated execution in code

I am trying to figure out how to make a for loop with an async function wait until all the async functions called within it are finished before allowing the code to continue. In my scenario, I have a variable "bar" that contains a JSON array with other ne ...

Issue with VueJS compilation: JSON data import causing failure

I'm attempting to bring in a static .json file within the <script> section of a .Vue file using the code snippet import Test from '@assets/test.json' From what I've gathered about webpack, this should work effortlessly. I have ev ...

How to adjust the "skipNatural" boolean in AngularJS Smart-Table without altering the smart-table.js script

Looking to customize the "skipNatural" boolean in the smart-table.js file, but concerned about it being overwritten when using Bower for updates. The current setting in the Smart-Table file is as follows: ng.module('smart-table') .constant(&ap ...