Reputation: 3
I am working on a project where I am implementing some charts from the Vue-Chartjs library. I need the Y-axis max value to change everytime the user changes the filters given. I Import an existing barchart from the vue-chartjs library. In the code there is a javascript file that has some defaults already, to set extra options I can use the extraOptions object as a prop to personalize each chart accordingly. Here is the default component:
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);
}
}
I use this js file to import the bar chart inside a vue component like you see down below.
everytime the input of the form changes i need to re render the chart. I use the onInputChange()
method to turn the boolean loaded
to false and call the loadData()
method.
Inside the loadData()
method I make an axios request that gets me the right data every time. I also get the maximum value for my Y axis.
Then in the response I call on updateChart()
so that I can update the data and the max value of the chart. then i turn the boolean loaded
to true again so that my chart renders accordingly.
The problem with this approach is that the chart disappears completely for a split of a second. Before deciding to change the max Value of the Y axis I was able to update the data of my chart without having to use the v-if="loaded".
I need to find a solution where the chart re renders without it completely disappearing from the page. I know some suggested to use computed variables but i don't fully understand how it is supposed to work. Here is the component minus the form fields.
I guess in it's essence what I want is to update the Y axis max value without having to re render the entire 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>
Upvotes: 0
Views: 775
Reputation: 529
You can bind the chart to a variable in data()
, initialize it with some defaults in mounted()
and whenever you want to update the chart data, you use the Chart.js API.
An implementation could look something like this:
export default {
data() {
return {
chart: null
};
},
mounted() {
this.chart = new Chart(/* defaults */);
},
methods: {
updateChart(data) {
this.chart.data.datasets = data;
/* rest of the chart updating */
this.chart.update();
}
}
};
Upvotes: 0