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>
After checking your code, I noticed that you are using the datasets and maximumValue in data function.
To update the chart data based on dataset and maximumValue, you need to use those variables in computed data, not data.
For 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
}
}],
},
}
});
},
},
class AreaChart extends React.Component {
constructor(props) {
super(props);
this.state = {
chartData: CHART_DATA,
chartDataSelection: CHART_DATA.selection
};}
My CHART_DATA is my object and I assigned it to chartData.
Below is my updateData function. This is where I am having a problem. Under this.setState, chartDataSelection is not grabbing the data from my object. I don't know how to properly grab the selection key from the CHART_DATA object. Below this code is the other js file that holds that object.
updateData(timeline) {
this.setState({
chartDataSelection: timeline
});
switch (timeline) {
case "one_month":
this.setState({
options: {
xaxis: {
min: new Date("28 Jan 2013").getTime(),
max: new Date("27 Feb 2013").getTime()
}
}
});
break;
case "six_months":
this.setState({
options: {
xaxis: {
min: new Date("27 Sep 2012").getTime(),
max: new Date("27 Feb 2013").getTime()
}
}
});
break;
case "one_year":
this.setState({
options: {
xaxis: {
min: new Date("27 Feb 2012").getTime(),
max: new Date("27 Feb 2013").getTime()
}
}
});
break;
case "ytd":
this.setState({
options: {
xaxis: {
min: new Date("01 Jan 2013").getTime(),
max: new Date("27 Feb 2013").getTime()
}
}
});
break;
case "all":
this.setState({
options: {
xaxis: {
min: undefined,
max: undefined
}
}
});
break;
default:
}
}
CHART_DATA.js --- this data is for my Area Chart from ApexCharts
const CHART_DATA = {
coins: "hello",
isFetching: false,
selection: "one_year", // this data is for the ReactApexChart line 14-395
options: {
annotations: {
yaxis: [
{
y: 0,
tickAmount: 0,
borderColor: "transparent",
label: {
borderColor: "red",
show: false,
showAlways: false,
style: {
color: "#fff",
background: "#00E396"
}
},
floating: true,
axisTicks: {
show: false
},
axisBorder: {
show: false
},
labels: {
show: false
},
crosshairs: {
show: false
}
}
],
xaxis: [
{
x: new Date("14 Nov 2012").getTime(),
borderColor: "transparent",
yAxisIndex: 0,
label: {
show: false,
text: "",
style: {
color: "#fff",
background: "#775DD0"
}
},
axisTicks: {
show: false
}
}
]
},
dataLabels: {
enabled: false,
enabledOnSeries: false
},
markers: {
size: 0,
style: "hollow"
},
xaxis: {
type: "datetime",
min: new Date("01 Mar 2012").getTime(),
tickAmount: 6
},
tooltip: {
x: {
format: "MMMM dd yyyy"
}
},
fill: {
type: "gradient",
gradient: {
shadeIntensity: 1,
opacityFrom: 0.3,
opacityTo: 0.9,
stops: [0, 100]
}
},
colors: ["#6433ff", "#00E396", "#CED4DC"],
stroke: {
width: "2"
},
chart: {
toolbar: {
show: false,
tools: {
download: true,
selection: true,
zoom: true,
zoomin: true,
zoomout: true,
pan: true,
reset: true | '<img src="/static/icons/reset.png" width="20">',
customIcons: []
},
autoSelected: "zoom"
}
}
},
series: [
{
//timestamps for the areaChart
data: [
[1327359600000, 30.95],
[1327446000000, 31.34],
[1327532400000, 31.18],
[1327618800000, 31.05],
[1327878000000, 31.0],
[1327964400000, 30.95],
[1328050800000, 31.24],
[1328137200000, 31.29],
[1328223600000, 31.85],
[1328482800000, 31.86],
[1328569200000, 32.28],
[1328655600000, 32.1],
[1328742000000, 32.65],
[1328828400000, 32.21],
[1329087600000, 32.35],
[1329174000000, 32.44],
[1329260400000, 32.46],
[1329346800000, 32.86],
[1329433200000, 32.75],
[1329778800000, 32.54],
[1329865200000, 32.33],
[1329951600000, 32.97],
[1330038000000, 33.41],
[1330297200000, 33.27],
[1330383600000, 33.27],
[1330470000000, 32.89],
[1330556400000, 33.1],
[1330642800000, 33.73],
[1330902000000, 33.22],
[1330988400000, 31.99],
[1331074800000, 32.41],
[1331161200000, 33.05],
[1331247600000, 33.64],
[1331506800000, 33.56],
[1331593200000, 34.22],
[1331679600000, 33.77],
[1331766000000, 34.17],
[1331852400000, 33.82],
[1332111600000, 34.51],
[1332198000000, 33.16],
[1332284400000, 33.56],
[1332370800000, 33.71],
[1332457200000, 33.81],
[1332712800000, 34.4],
[1332799200000, 34.63],
[1332885600000, 34.46],
[1332972000000, 34.48],
[1333058400000, 34.31],
[1333317600000, 34.7],
[1333404000000, 34.31],
[1333490400000, 33.46],
[1333576800000, 33.59],
[1333922400000, 33.22],
[1334008800000, 32.61],
[1334095200000, 33.01],
[1334181600000, 33.55],
[1334268000000, 33.18],
[1334527200000, 32.84],
[1334613600000, 33.84],
[1334700000000, 33.39],
[1334786400000, 32.91],
[1334872800000, 33.06],
[1335132000000, 32.62],
[1335218400000, 32.4],
[1335304800000, 33.13],
[1335391200000, 33.26],
[1335477600000, 33.58],
[1335736800000, 33.55],
[1335823200000, 33.77],
[1335909600000, 33.76],
[1335996000000, 33.32],
[1336082400000, 32.61],
[1336341600000, 32.52],
[1336428000000, 32.67],
[1336514400000, 32.52],
[1336600800000, 31.92],
[1336687200000, 32.2],
[1336946400000, 32.23],
[1337032800000, 32.33],
[1337119200000, 32.36],
[1337205600000, 32.01],
[1337292000000, 31.31],
[1337551200000, 32.01],
[1337637600000, 32.01],
[1337724000000, 32.18],
[1337810400000, 31.54],
[1337896800000, 31.6],
[1338242400000, 32.05],
[1338328800000, 31.29],
[1338415200000, 31.05],
[1338501600000, 29.82],
[1338760800000, 30.31],
[1338847200000, 30.7],
[1338933600000, 31.69],
[1339020000000, 31.32],
[1339106400000, 31.65],
[1339365600000, 31.13],
[1339452000000, 31.77],
[1339538400000, 31.79],
[1339624800000, 31.67],
[1339711200000, 32.39],
[1339970400000, 32.63],
[1340056800000, 32.89],
[1340143200000, 31.99],
[1340229600000, 31.23],
[1340316000000, 31.57],
[1340575200000, 30.84],
[1340661600000, 31.07],
[1340748000000, 31.41],
[1340834400000, 31.17],
[1340920800000, 32.37],
[1341180000000, 32.19],
[1341266400000, 32.51],
[1341439200000, 32.53],
[1341525600000, 31.37],
[1341784800000, 30.43],
[1341871200000, 30.44],
[1341957600000, 30.2],
[1342044000000, 30.14],
[1342130400000, 30.65],
[1342389600000, 30.4],
[1342476000000, 30.65],
[1342562400000, 31.43],
[1342648800000, 31.89],
[1342735200000, 31.38],
[1342994400000, 30.64],
[1343080800000, 30.02],
[1343167200000, 30.33],
[1343253600000, 30.95],
[1343340000000, 31.89],
[1343599200000, 31.01],
[1343685600000, 30.88],
[1343772000000, 30.69],
[1343858400000, 30.58],
[1343944800000, 32.02],
[1344204000000, 32.14],
[1344290400000, 32.37],
[1344376800000, 32.51],
[1344463200000, 32.65],
[1344549600000, 32.64],
[1344808800000, 32.27],
[1344895200000, 32.1],
[1344981600000, 32.91],
[1345068000000, 33.65],
[1345154400000, 33.8],
[1345413600000, 33.92],
[1345500000000, 33.75],
[1345586400000, 33.84],
[1345672800000, 33.5],
[1345759200000, 32.26],
[1346018400000, 32.32],
[1346104800000, 32.06],
[1346191200000, 31.96],
[1346277600000, 31.46],
[1346364000000, 31.27],
[1346709600000, 31.43],
[1346796000000, 32.26],
[1346882400000, 32.79],
[1346968800000, 32.46],
[1347228000000, 32.13],
[1347314400000, 32.43],
[1347400800000, 32.42],
[1347487200000, 32.81],
[1347573600000, 33.34],
[1347832800000, 33.41],
[1347919200000, 32.57],
[1348005600000, 33.12],
[1348092000000, 34.53],
[1348178400000, 33.83],
[1348437600000, 33.41],
[1348524000000, 32.9],
[1348610400000, 32.53],
[1348696800000, 32.8],
[1348783200000, 32.44],
[1349042400000, 32.62],
[1349128800000, 32.57],
[1349215200000, 32.6],
[1349301600000, 32.68],
[1349388000000, 32.47],
[1349647200000, 32.23],
[1349733600000, 31.68],
[1349820000000, 31.51],
[1349906400000, 31.78],
[1349992800000, 31.94],
[1350252000000, 32.33],
[1350338400000, 33.24],
[1350424800000, 33.44],
[1350511200000, 33.48],
[1350597600000, 33.24],
[1350856800000, 33.49],
[1350943200000, 33.31],
[1351029600000, 33.36],
[1351116000000, 33.4],
[1351202400000, 34.01],
[1351638000000, 34.02],
[1351724400000, 34.36],
[1351810800000, 34.39],
[1352070000000, 34.24],
[1352156400000, 34.39],
[1352242800000, 33.47],
[1352329200000, 32.98],
[1352415600000, 32.9],
[1352674800000, 32.7],
[1352761200000, 32.54],
[1352847600000, 32.23],
[1352934000000, 32.64],
[1353020400000, 32.65],
[1353279600000, 32.92],
[1353366000000, 32.64],
[1353452400000, 32.84],
[1353625200000, 33.4],
[1353884400000, 33.3],
[1353970800000, 33.18],
[1354057200000, 33.88],
[1354143600000, 34.09],
[1354230000000, 34.61],
[1354489200000, 34.7],
[1354575600000, 35.3],
[1354662000000, 35.4],
[1354748400000, 35.14],
[1354834800000, 35.48],
[1355094000000, 35.75],
[1355180400000, 35.54],
[1355266800000, 35.96],
[1355353200000, 35.53],
[1355439600000, 37.56],
[1355698800000, 37.42],
[1355785200000, 37.49],
[1355871600000, 38.09],
[1355958000000, 37.87],
[1356044400000, 37.71],
[1356303600000, 37.53],
[1356476400000, 37.55],
[1356562800000, 37.3],
[1356649200000, 36.9],
[1356908400000, 37.68],
[1357081200000, 38.34],
[1357167600000, 37.75],
[1357254000000, 38.13],
[1357513200000, 37.94],
[1357599600000, 38.14],
[1357686000000, 38.66],
[1357772400000, 38.62],
[1357858800000, 38.09],
[1358118000000, 38.16],
[1358204400000, 38.15],
[1358290800000, 37.88],
[1358377200000, 37.73],
[1358463600000, 37.98],
[1358809200000, 37.95],
[1358895600000, 38.25],
[1358982000000, 38.1],
[1359068400000, 38.32],
[1359327600000, 38.24],
[1359414000000, 38.52],
[1359500400000, 37.94],
[1359586800000, 37.83],
[1359673200000, 38.34],
[1359932400000, 38.1],
[1360018800000, 38.51],
[1360105200000, 38.4],
[1360191600000, 38.07],
[1360278000000, 39.12],
[1360537200000, 38.64],
[1360623600000, 38.89],
[1360710000000, 38.81],
[1360796400000, 38.61],
[1360882800000, 38.63],
[1361228400000, 38.99],
[1361314800000, 38.77],
[1361401200000, 38.34],
[1361487600000, 38.55],
[1361746800000, 38.11],
[1361833200000, 38.59],
[1361919600000, 39.6]
]
}
]
};
export default CHART_DATA;
It looks like you aren't telling setState to update your chartData (setState{chartData: {updatedData}}) but creating a new state object called options. First you need modify the existing charData. In this case I've spread it out into a variable called data. Then you modify data with the new xaxis and then replace chartData completely with your updated object. I've shortened your switch just for the example but you will have to update each of them. I hope this helps.
updateData(timeline) {
this.setState({
chartDataSelection: timeline
});
let data = {...d}
switch (timeline) {
case "one_month":
data.options.xaxis = {
min: new Date("28 Jan 2013").getTime(),
max: new Date("27 Feb 2013").getTime()
}
this.setState({chartData: data});
break;
default:
}
}
I'm looking to simplify this code. Any way to it so? Spring MVC + Apex Charts
var d = /*[[${s0}]]*/ null`; <-- It is sent via the Spring Framework. Basically represents datetime(in millis) at `d[0]`, `d[3]`,... Temperature at `d[1]`, `d[4]`,... and Humidity at `d[2]`, `d[5]`,...
<script type="text/javascript" th:inline="javascript">
var d = /*[[${s0}]]*/ null;
var options = {
chart: {
type: 'area',
height: 300
},
series: [
{
name: 'Temperature',
data: [
[d[0], d[1]],
[d[3], d[4]],
[d[6], d[7]],
[d[9], d[10]],
[d[12], d[13]],
[d[15], d[16]],
[d[18], d[19]],
[d[21], d[22]],
[d[24], d[25]],
[d[27], d[28]],
[d[30], d[31]],
[d[33], d[34]],
[d[36], d[37]],
[d[39], d[40]],
[d[42], d[43]],
[d[45], d[46]],
[d[48], d[49]],
[d[51], d[52]],
[d[54], d[55]],
[d[57], d[58]],
[d[60], d[61]],
[d[63], d[64]],
[d[66], d[67]],
[d[69], d[70]]
]
},
{
name: "Humidity",
data: [
[d[0], d[2]],
[d[3], d[5]],
[d[6], d[8]],
[d[9], d[11]],
[d[12], d[14]],
[d[15], d[17]],
[d[18], d[20]],
[d[21], d[23]],
[d[24], d[26]],
[d[27], d[29]],
[d[30], d[32]],
[d[33], d[35]],
[d[36], d[38]],
[d[39], d[41]],
[d[42], d[44]],
[d[45], d[47]],
[d[48], d[50]],
[d[51], d[53]],
[d[54], d[56]],
[d[57], d[59]],
[d[60], d[62]],
[d[63], d[65]],
[d[66], d[68]],
[d[69], d[71]]
]
}
],
xaxis: {
type: 'datetime'
},
yaxis: [
{
axisTicks: {
show: true
},
axisBorder: {
show: true,
},
title: {
text: "Temperature"
}
}, {
min: 0,
max: 100,
opposite: true,
axisTicks: {
show: true
},
axisBorder: {
show: true,
},
title: {
text: "Humidity"
}
}
],
legend: {
position: 'top',
horizontalAlign: 'center'
},
tooltip: {
x: {
format: 'HH:mm dd/MM/yy'
},
}
}
var chart = new ApexCharts(document.querySelector("#chart0"), options);
chart.render();
</script>
I just need to simplify sending data via d[0], d[1] etc. Is there any kind of loop or anything else I can use?
You could take a function which takes the data and a pattern for the wanted elements and an offset for increment for the next row.
function mapByPattern(data, pattern, offset) {
var result = [], i = 0;
while (i < data.length) {
result.push(pattern.map(j => data[i + j]));
i += offset;
}
return result;
}
var data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
result = { series: [
{ name: 'Temperature', data: mapByPattern(data, [0, 1], 3) },
{ name: "Humidity", data: mapByPattern(data, [0, 2], 3) }
]};
console.log(result);
Thank You, Nina. Code code didn't work exactly as i wanted but was so helpful to fix my own. Thanks alot! Here's some fixed code :)
var data = /*[[${s0}]]*/ null;
function mapByPattern(data, pattern, offset) {
var result = [], i = 0;
while (i < data.length) {
result.push(pattern.map(j => data[i + j]));
i += offset;
}
return result;
}
var options = {
chart: {
type: 'area',
height: 300
},
series: [
{
name: 'Temperature',
data: mapByPattern(data, [0, 1], 3)
},
{
name: "Humidity",
data: mapByPattern(data, [0, 2], 3)
}
],
xaxis: {
type: 'datetime'
},
yaxis: [
{
axisTicks: {
show: true
},
axisBorder: {
show: true,
},
title: {
text: "Temperature"
}
}, {
min: 0,
max: 100,
opposite: true,
axisTicks: {
show: true
},
axisBorder: {
show: true,
},
title: {
text: "Humidity"
}
}
],
legend: {
position: 'top',
horizontalAlign: 'center'
},
tooltip: {
x: {
format: 'HH:mm dd/MM/yy'
},
}
}
var chart = new ApexCharts(document.querySelector("#chart0"), options);
chart.render();