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

Ways of retrieving Sveltekit session data in an endpoint

Is there a way to access a session in an endpoint using SvelteKit? I attempted the following with no success: import { get } from 'svelte/store'; import { getStores} from "$app/stores"; function getUser() { // <- execute this du ...

The issue of req.files being undefined in Express.js

I am aiming to upload files to s3 without depending on any middleware like multer. Below is the code snippet of my approach: <form role="form" action="/send" method="post"> <input type="file" name="photo" class="form-control"/> <button ...

Material UI filterSelectedOptions not functioning properly on initial search with multiple autocomplete

When I utilize the filterSelectedOptions prop in my autocomplete feature, it functions as intended when using a pre-defined chip. Check out image1 for an example: image1 However, when a brand new typed option is entered, it ends up duplicating multiple ti ...

showing javascript strings on separate lines

I need assistance with displaying an array value in a frontend Angular application. How can I insert spaces between strings and show them on two separate lines? x: any = [] x[{info: "test" + ',' + "tested"}] // Instead of showing test , teste ...

Issue with Redirecting in React: REST requests are not successful

There's a text input that triggers a submission when the [Enter Key] is pressed. const [ query, setQuery ] = React.useState('') ... <TextField label="Search Codebase" id="queryField" onChange={ event => setQuery( ...

Converting Background Images from html styling to Next.js

<div className="readyContent" style="background-image: url(assets/images/banner/banner-new.png);"> <div className="row w-100 align-items-center"> <div className="col-md-7 dFlex-center"> ...

Utilizing jQuery.ajax() to retrieve the child div from a separate page

Can anyone help me figure out how to use jQuery ajax() to load two children contents from an external page? I want a pre-loader to display before the main content loads. Below is the code snippet that I have tried. $.ajax({ url: 'notification.htm ...

Comparable to LINQ SingleOrDefault()

I frequently utilize this particular pattern in my Typescript coding: class Vegetable { constructor(public id: number, public name: string) { } } var vegetableArray = new Array<Vegetable>(); vegetableArray.push(new Vegetable(1, "Carrot")); ...

What could be causing a parse error and missing authorization token in an AJAX request?

I recently wrote some code to connect a chat bot to Viber using the REST API. The main part of the code looks like this -: $.ajax({ url : url , dataType : "jsonp", type : 'POST', jsonpCallback: 'fn', headers: { 'X-Viber-Auth- ...

Tips for organizing your JSON Structure within ReactJs

In the given example, I have a JSON structure with information about different airlines. The Airline Name is dynamic and we need to separate the JSON into an expected array format. const arr = [ { Airline: "Goair", Departure: "01:50" ...

In my specific scenario, what is the most effective method for retrieving data from an EntityFramework database using JavaScript?

Currently, within my ASP.NET MVC Core2 project, I have a model in the EF database that contains multiple properties: public class SchoolEvents { public long ID { get; set; } [Required] [StringLength(40, ErrorMessage = "Max 40 c ...

Utilizing Jquery on the client side in conjunction with a Node.js server

I am using nodejs within a docker-compose container to create a local web app. My goal is to use jquery on the client-side to load an HTML file into a div, but I'm encountering issues with it not working properly. Both the initial index.html and the n ...

Reducing div size when clicked - Using JQuery version 1.9

I am looking to make a specific div shrink in size, while keeping all the data visible, each time a user clicks on a certain icon with the class legend-icon. For example, I want the div with the ID #Chart to shrink when clicked. This is the HTML code: &l ...

Tips for utilizing document.write() with a document rather than just plain text

Currently, I am utilizing socket.io to develop a party game that shares similarities with cards against humanity. My main concern is how to retain the players' names and scores without needing to transmit all the data to a new page whenever new games ...

Ensure the http request is finished before loading the template

When my template loads first, the http request is fired. Because of this, when I load the page for the first time, it shows a 404 image src not found error in the console. However, after a few milliseconds, the data successfully loads. After researching a ...

Executing a Shortcode Using a Button in Visual Composer for Wordpress

It should be easy to do this. I've got a great plugin with a modal newsletter signup form that offers various launch options, including manual launching with the following codes. https://i.stack.imgur.com/IGbsp.png My theme utilizes Visual Composer. ...

Creating dynamic routes for every page fetched from the API in Next.js

Hello everyone, Recently, my journey with NodeJS just commenced and I have been exploring API routes in NextJS as it provides an easy setup and clear visibility of the processes. While I have a grasp on creating basic get requests, I am now intrigued by s ...

What could be the reason for my React Component not properly associating with the image?

The title appears to be correctly displayed, but there seems to be an issue with the images. I've thoroughly reviewed the code multiple times, but unfortunately, I'm unable to identify the problem. Please provide guidance on what changes need to ...

Error: Unable to access the 'create' property of an undefined object while utilizing sequelize to register a user and add an entry

Whenever I try to execute this controller, an issue arises indicating a problem with the recognition of the .create method from the model. What is the correct way to import Sequelize in order to utilize it effectively? const db = require("../Models/m_use ...

Using Vuelidate with Vue 3, vue-class-component, and TypeScript combination

Is there anyone who has successfully implemented Vuelidate with Vue 3 using the Composition API? Although Vuelidate is still in alpha for Vue 3, I believe that if it works with the Composition API, there must be a way to make it work with classes as well. ...