I am trying to use chartjs-plugin-zoom to implement zooming on a chart using vue-chartjs. With the code below, I get a this.$refs.myChart.resetZoom is not a function error. How do I correctly get a reference to the chart so that I can call the resetZoom function?
<template>
<div>
<button #click="resetGraph">Reset</button>
<Bar
id="myChart"
ref="myChart"
:options="chartOptions"
:data="chartData"
/>
</div>
</template>
<script>
import { Bar } from 'vue-chartjs'
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js'
import zoomPlugin from 'chartjs-plugin-zoom';
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, zoomPlugin)
export default {
name: 'BarChart',
components: { Bar },
data() {
return {
chartData: {
labels: [ 'January', 'February', 'March' ],
datasets: [ { data: [40, 20, 12] } ]
},
chartOptions: {
responsive: true,
indexAxis: 'y',
plugins: {
zoom: {
zoom: {
wheel: {
enabled: true,
},
pinch: {
enabled: true
},
mode: 'xy',
}
}
}
}
}
},
methods: {
resetGraph() {
this.$refs.myChart.resetZoom()
}
}
}
</script>
Changing this.$refs.myChart.resetZoom() to this.$refs.myChart.chart.resetZoom() fixed the issue for me.
Related
I am using Vue-chartjs to create a bar graph in Vue 3:
The bars are vertical. How do I make them horizontal?
<template>
<Bar
id="my-chart-id"
:options="chartOptions"
:data="chartData"
/>
</template>
<script>
import { Bar } from 'vue-chartjs'
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js'
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
export default {
name: 'BarChart',
components: { Bar },
data() {
return {
chartData: {
labels: [ 'January', 'February', 'March' ],
datasets: [ { data: [40, 20, 12] } ]
},
chartOptions: {
responsive: true
}
}
}
}
</script>
Set the indexAxis property.
<template>
<Bar
id="my-chart-id"
:options="chartOptions"
:data="chartData"
/>
</template>
<script>
import { Bar } from 'vue-chartjs'
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js'
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
export default {
name: 'BarChart',
components: { Bar },
data() {
return {
chartData: {
labels: [ 'January', 'February', 'March' ],
datasets: [ { data: [40, 20, 12] } ]
},
chartOptions: {
responsive: true,
indexAxis: 'y'
}
}
}
}
</script>
When using a library, you can check their documentation to find out more.
Then you would have found the props table;
which says:
"options: The options object that is passed into the Chart.js chart".
You know that vue-chartjs is a Vue wrapper library for the Chart.js library. Therefore, you go to their documentation. Then you go to the Chart Types part and find your chart type (Bar Chart). If you scroll down a bit you find the options for Bar Charts. The obvious one that stands out to me is the indexAxis - and in fact - it works.
Demo: here
I've added tooltips.backgroundColor in chartOptions but still doesn't work, so anyone can help me?
Here is my code
<template>
<Doughnut
:chart-options="chartOptions"
:chart-data="chartData"
:chart-id="'doughnut-chart'"
:styles="styles"
:width="width"
:height="height"
/>
</template>
<script lang="ts">
import { defineComponent, type PropType } from "vue";
import TypographyComponent from "#/core/ui/components/typography/Typography.component.vue";
import { Doughnut } from "vue-chartjs";
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
ArcElement,
CategoryScale,
type Plugin,
} from "chart.js";
ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale);
export default defineComponent({
name: "ProgressChartComponent",
components: { Doughnut, TypographyComponent },
props: {
width: {
type: Number,
default: 400,
},
height: {
type: Number,
default: 400,
},
styles: {
type: Object as PropType<Partial<CSSStyleDeclaration>>,
default: () => {},
},
chartData: {
type: Object,
required: false,
default: () => {},
},
},
setup() {
const chartOptions = {
responsive: true,
maintainAspectRatio: false,
cutout: "64%",
tooltips: {
enabled: false,
backgroundColor: "#227799",
},
};
return {
chartOptions,
};
},
});
</script>
...
Guessing that you're using Chart.js v3, be aware that the tooltips are defined in the namespace options.plugins.tooltip but not options.tooltips as in your code. Therefore chartOptions needs to be changed as follows:
const chartOptions = {
responsive: true,
maintainAspectRatio: false,
cutout: "64%",
plugins: {
tooltip: {
backgroundColor: "#227799"
}
}
};
For further information, please consult Tooltip Configuration from the Chart.js documentation.
I am using Vue-Chartjs to create a simple Line chart, I'm filling the chart with data via a get request to an API
however I want to generate new values randomly when I click on a button, & pass the values as a prop to chart-line component.
I've tried using reactiveProp & I also tried using a watcher for chartData prop, but I'm always getting this error
client.js?06a0:83 TypeError: Cannot read property 'map' of undefined
Dashboard Component
<template>
<div class="container">
<h1>Dashboard Page</h1>
<v-alert v-if="errorDetected"
class="mt-4"
dense
outlined
type="error"
>
There was an error while getting the chart data
</v-alert>
<v-btn #click="generateNewData()">Generate new data</v-btn>
<div class="loader-container">
<img v-if="!loaded" class="chart-loader mt-3" src="../static/loader-dotted.gif" alt="">
</div>
<ChartLine v-if="loaded" :chartData="values" :bind="true" />
</div>
</template>
<script>
import ChartLine from '../components/chart-line'
export default {
middleware: 'session',
components: {
ChartLine
},
data() {
return {
values: [],
customValues: [],
loaded: false,
errorDetected: false
}
},
head() {
return {
title: 'Dashboard page',
meta: [
{
hid: 'description',
name: 'description',
content: 'simple dashboard SPA'
}
]
}
},
mounted() {
this.requestData()
},
methods: {
requestData() {
this.loaded = false
this.$axios.get('http://www.mocky.io/v2/5eda474f330000fefc79eab4?mocky-delay=2000ms').then(response => {
console.log("requestData -> response", response)
this.values = response.data.data.value
this.loaded = true
}).catch(error => {
this.loaded = true
this.errorDetected = true
})
},
generateNewData() {
this.values = [];
for(let i=0; i<7; i++)
this.values.push(Math.floor((Math.random() * 10) + 1))
}
}
}
</script>
<style>
.loader-container {
display: flex;
justify-content: center;
}
.chart-loader {
width: 150px;
}
</style>
ChartLine Component
<script>
//Importing Line class from the vue-chartjs wrapper
import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
//Exporting this so it can be used in other components
export default {
extends: Line,
mixins: [reactiveProp],
props: ['chartData'],
data () {
return {
datacollection: {
//Data to be represented on x-axis
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: "Data 1",
backgroundColor: "transparent",
borderColor: "rgba(1, 116, 188, 0.50)",
pointBackgroundColor: "rgba(171, 71, 188, 1)",
//Data to be represented on y-axis
data: this.chartData
}
],
},
options: {
responsive: true,
maintainAspectRatio: false
}
//Chart.js options that controls the appearance of the chart
}
},
watch: {
chartData() {
this.renderChart(this.datacollection, this.options)
}
},
mounted () {
//renderChart function renders the chart with the datacollection and options object.
this.renderChart(this.datacollection, this.options)
}
}
</script>
UPDATE
I've managed to solve the issue of updating the chart
I removed the dataCollection from the chart-line component & added it in the dashboard component, I've also used the requestData() method in the created() hook to make a get request to the API, then on a button click I generate a new values and pass it as a prop
Update Code
Dashboard Component
<template>
<div class="container">
<h1>Dashboard Page</h1>
<v-alert v-if="errorDetected"
class="mt-4"
dense
outlined
type="error"
>
There was an error while getting the chart data
</v-alert>
<v-btn class="primary" #click="generateNewData()">Generate New Data</v-btn>
<div class="loader-container">
<img v-if="!loaded" class="chart-loader mt-3" src="../static/loader-dotted.gif" alt="">
</div>
<ChartLine v-if="loaded" :chart-data="dataCollection" />
</div>
</template>
<script>
import ChartLine from '../components/chart-line'
export default {
middleware: 'session',
components: {
ChartLine
},
data() {
return {
dataCollection: null,
values: [],
customValues: [],
loaded: false,
errorDetected: false
}
},
head() {
return {
title: 'Dashboard page',
meta: [
{
hid: 'description',
name: 'description',
content: 'simple dashboard SPA'
}
]
}
},
created() {
// this.loaded = false
// this.fillData()
// this.loaded = true
this.requestData()
},
methods: {
requestData() {
this.loaded = false
this.$axios.get('http://www.mocky.io/v2/5eda474f330000fefc79eab4?mocky-delay=2000ms').then(response => {
this.values = response.data.data.value
this.loaded = true
this.fillData()
}).catch(error => {
this.loaded = true
this.errorDetected = true
})
},
fillData () {
this.dataCollection = {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: "Data 1",
backgroundColor: "transparent",
borderColor: "rgba(1, 116, 188, 0.50)",
pointBackgroundColor: "rgba(171, 71, 188, 1)",
data: this.values
}
]
}
},
generateNewData() {
this.values = []
this.loaded = false
setTimeout(function(){},2000)
for(let i=0; i<7; i++) {
this.values.push(Math.floor(Math.random() * (50 - 5 + 1)) + 5)
}
this.fillData()
this.loaded = true
}
}
}
</script>
<style>
.loader-container {
display: flex;
justify-content: center;
}
.chart-loader {
width: 150px;
}
</style>
Chart-Line Component
<script>
//Importing Line class from the vue-chartjs wrapper
import { Line, mixins } from 'vue-chartjs'
//Exporting this so it can be used in other components
export default {
extends: Line,
mixins: [mixins.reactiveProp],
// props:['chartData'],
data () {
return {
options: {
responsive: true,
maintainAspectRatio: false
}
//Chart.js options that controls the appearance of the chart
}
},
mounted () {
//renderChart function renders the chart with the datacollection and options object.
this.renderChart(this.chartData, this.options)
}
}
</script>
however there's still one thing I can't figure out, which is the loading state, when clicking on the button to generate new data
when I first open the dashboard page, the loading state works, but when I click on the button, loading state doesn't work
any Idea why??????
I'm trying to make a stacked line chart using Vue-ChartJS but am having difficulties getting it to stack.
I tried adding the following into the fill data function but saw no change.
scales: {
yAxes: [{ stacked: true}]
}
I also tried creating a this.options entry but that didn't work either. The minimal reproducible code for the chart is as follows, any advice or help would be much appreciated!
## LineChart.js
import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
export default {
extends: Line,
mixins: [reactiveProp],
props: ['options'],
mounted() {
this.renderChart(this.chartData, this.options)
}
}
## LineChart.vue
<template>
<div class="small">
<line-chart :chart-data="chartData"></line-chart>
<button #click="fillData()">Randomize</button>
</div>
</template>
<script>
import LineChart from '../store/LineChart.js'
export default {
components: {
LineChart
},
data() {
return {
chartData: null
}
},
mounted() {
this.fillData()
},
methods: {
fillData() {
this.chartData = {
labels: [this.getRandomInt(), this.getRandomInt()],
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
data: [this.getRandomInt(), this.getRandomInt()]
},
{
label: 'Data Two',
backgroundColor: '#C23596',
data: [this.getRandomInt(), this.getRandomInt()]
}
]
}
},
getRandomInt() {
return Math.floor(Math.random() * (50 - 5 + 1)) + 5
}
}
}
</script>
<style>
.small {
max-width: 600px;
margin: 150px auto;
}
</style>
You need to pass scales in the options:
...
<div class="small">
<line-chart :chart-data="chartData" :options="options"></line-chart>
<button #click="fillData()">Randomize</button>
</div>
...
data() {
return {
chartData: null,
options: {
scales: {
yAxes: [
{
stacked: true
}
]
},
},
}
},
My chart Will not render I tried using query selector and refs. It is not throwing any errors just not rendering to the DOM.
The Template
The Function
createChart() {
let article = this.$el.querySelector(".highchart");
//let article = this.$refs.highchart;
HighCharts.chart(article, {
series: [
{
type: "treemap",
layoutAlgorithm: "squarified",
data: this.chartData
}
],
colorAxis: {
minColor: "#F98C32",
maxColor: "#F04E23"
},
title: {
text: `Total Items ${this.totalCount}`
}
});
}
Called in Mounted
mounted() {
this.createChart();
}
Have you considered using highcharts-vue official wrapper which is recommended? It can be downloaded here: https://github.com/highcharts/highcharts-vue. Check the code and demo posted below.
main.js:
import Vue from "vue";
import App from "./App";
import HighchartsVue from "highcharts-vue";
Vue.config.productionTip = false;
Vue.use(HighchartsVue);
/* eslint-disable no-new */
new Vue({
el: "#app",
components: { App },
template: "<App/>"
});
App.vue:
<template>
<div id="app"><highcharts /> <btn /></div>
</template>
<script>
import Chart from "./components/Chart";
import Button from "./components/Button";
export default {
name: "App",
components: {
highcharts: Chart,
btn: Button
}
};
</script>
Chart.vue:
<template>
<div>
<highcharts
:options="chartOptions"
ref="lineCharts"
:constructor-type="stockChart"
></highcharts>
</div>
</template>
<script>
import { Chart } from "highcharts-vue";
import Highcharts from "highcharts";
import exportingInit from "highcharts/modules/exporting";
import stockInit from "highcharts/modules/stock";
import { EventBus } from "./../event-bus.js";
stockInit(Highcharts);
exportingInit(Highcharts);
export default {
props: {
partsdata: {
type: Array
}
},
components: {
highcharts: Chart
},
created() {
EventBus.$on("btn-clicked", data => {
this.chartOptions.series[0].data = data.newData;
});
},
data() {
return {
chartOptions: {
chart: {
type: "spline",
title: "Hassaan"
},
xAxis: {
categories: [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
]
},
tooltip: {
crosshairs: true,
shared: true
},
credits: {
enabled: false
},
plotOptions: {
spline: {
marker: {
radius: 4,
lineColor: "#666666",
lineWidth: 1
}
}
},
series: [
{
data: [1, 2, 3]
}
]
}
};
}
};
</script>
Demo:
https://codesandbox.io/s/nw750l07nj