I am using vue2 with vue-chartjs4 legacy mode and I want to create a mixed chart that uses the line chart and bubble chart component.
My MixedChart component looks like this:
<template>
<Bubble :chart-data="chartData" :chart-options="options"/>
</template>
<script>
import { Bubble } from 'vue-chartjs/legacy';
import { Chart as ChartJS, Title, Tooltip, Legend, PointElement, LineElement, CategoryScale, LinearScale } from 'chart.js'
ChartJS.register(Title, Tooltip, Legend, PointElement, LineElement, CategoryScale, LinearScale)
export default {
name: 'bubble-chart',
components: { Bubble },
props: {
chartData: {
type: Object,
required: true
},
options: {
type: Object,
default: () => {}
}
}
};
</script>
And my data looks like this:
{
labels: ['', ' ', ''],
datasets: [{
type: 'bubble',
label: 'bubble',
backgroundColor: config.colors.info,
borderColor: config.colors.info,
data: [{
x: ' ', // use middle label
y: 20,
r: 8
}],
order: 3
}, {
type: 'line',
label: 'test',
borderColor: config.colors.danger,
data: [20, 20, 20],
fill: false,
pointRadius: 0,
order: 1
}, {
type: 'line',
label: 'test1',
borderColor: config.colors.warning,
data: [30, 30, 30],
fill: false,
pointRadius: 0,
order: 1,
hidden: true
}, {
type: 'line',
label: 'test2',
borderColor: config.colors.primary,
data: [40, 40, 40],
fill: false,
pointRadius: 0,
order: 2
}],
}
This results in; Error in mounted hook: "Error: "line" is not a registered controller.".
How do you create a mixed chart in chart-vuejs4?
As your error states you need to import and register the LineController
import {Chart, LineController} from 'chart.js';
Chart.register(LineController);
Or you can just import everything and let chart.js register it:
import Chart from 'chart.js/auto'
Related
I'm using ApexCharts with vue3 (Composition API). I try to set the series dynamically via a reactive variable. Everything works fine until a dataset is empty - in the sense of its values being 0.
This is the general stub:
<template>
...
<apexchart width="100%" height="400" type="bar" :options="orderOptions" :series="orderSeries" ref="orderChart"></apexchart>
...
</template>
<script setup>
...
const orderSeries = ref([
{
name: 'Orders',
data: []
}
]);
const orderOptions = ref({
xaxis: {
type: 'datetime'
},
yaxis: {
min: 0,
labels: {
formatter: val => val.toFixed(0)
}
},
dataLabels: {
enabled: false
},
markers: {
size: 7,
hover: {
size: 10
}
},
plotOptions: {
bar: {
borderRadius: 4,
borderRadiusApplication: 'end',
columnWidth: '90%'
}
},
title: {
text: 'Orders',
style: {
fontSize: '20px'
}
}
});
...
</script>
This works fine:
orderSeries.value[0].data = [{ x: '2022-03', y: 2 }]
But this:
orderSeries.value[0].data = [{ x: '2022-03', y: 0 }]
Gives me following error:
Uncaught TypeError: Cannot read properties of undefined (reading '0')
at s2 (apexcharts.common.js:10:11991)
...
As long as there is at least one element with a y value different than 0, it will work, but as soon as all y-values are 0, it throws this error.
Can anyone tell me what's wrong with that code?
I have a bar chart and I would like to change the font color, border width and some other tings, but it doesn't work. It is in my computed property. In the chartOptions I want to change the y axis min and max value but I don't know if it is correct. Can anyone help me?
Also I want to make a horizontal line in this bar chart. It is the "Enemy's Avarage" and now it is a constant. I set the type to line and now I have a dot in my chart.
This is my chart component:
<script>
import { defineComponent } from 'vue'
import { Bar } from 'vue3-chart-v2'
export default defineComponent({
name: 'ChanceChart',
extends: Bar,
props: {
chartData: {
type: Object,
required: true
},
chartOptions: {
type: Object,
required: false,
},
},
mounted () {
this.renderChart(this.chartData, this.chartOptions)
}
})
</script>
And this is my app:
<template>
<div id="chart">
<ChanceChart :chartData="chartData" :chartOptions="chartOptions" />
</div>
</template>
<script>
import Navigation from "../components/Navigation.vue";
import ChanceChart from "../components/ChanceChart.vue";
import PageLoader from "../components/PageLoader.vue";
export default {
components: {
ChanceChart,
},
computed: {
chartOptions() {
return {
options: {
scales: {
y: {
title: {
display: true,
text: 'Value'
},
min: 0,
max: 100,
ticks: {
stepSize: 10,
}
},
},
elements: {
point: {
radius: 0
},
line: {
borderWidth: 2
}
},
plugins: {
legend: {
labels: {
boxWidth: 0,
font: {
fontColor: "#fff",
color: "#fff"
},
},
},
},
}
}
},
chartData() {
return {
datasets: [
{
type: 'bar',
label: "Enemy's Chance",
borderColor: "#1161ed",
borderWidth: 2,
data: this.emnemyCardsFilled,
},
{
type: 'bar',
label: "My Chance",
borderColor: "#f87979",
borderWidth: 2,
data: this.myCardsFilled,
},
{
type: 'line',
label: "Enemy's Avarage",
borderColor: "rgb(238, 255, 0)",
borderWidth: 2,
data: [50],
},
],
}
},
},
You need to remove the options part in the computed chartOptions prop:
chartOptions() {
return {
scales: {
y: {
title: {
display: true,
text: 'Value'
},
min: 0,
max: 100,
ticks: {
stepSize: 10,
}
},
},
elements: {
point: {
radius: 0
},
line: {
borderWidth: 2
}
},
plugins: {
legend: {
labels: {
boxWidth: 0,
font: {
fontColor: "#fff",
color: "#fff"
},
},
},
},
}
},
I have the following Chart Component:
<template>
<div class="gauge-chart">
<chart :options="options"></chart>
</div>
</template>
<script>
export default {
props: {
chartValue: { type: Number, required: true },
chartName: { type: String, required: true },
},
data: () => ({
options: {
series: [
{
type: "gauge",
startAngle: 180,
endAngle: 0,
min: 1,
max: 5,
splitNumber: 8,
axisLine: {
lineStyle: {
width: 6,
color: [
[0.25, "#7CFFB2"],
[0.5, "#58D9F9"],
[0.75, "#FDDD60"],
[1, "#FF6E76"],
],
},
},
pointer: {
icon: "arrow",
offsetCenter: [0, "-30%"],
itemStyle: {
color: "auto",
},
},
axisTick: {
length: 12,
lineStyle: {
color: "auto",
width: 1,
},
},
splitLine: {
length: 20,
lineStyle: {
color: "auto",
width: 5,
},
},
title: {
fontSize: 30,
},
data: [
{
value: this.chartValue,
name: this.chartName,
},
],
},
],
},
}),
};
</script>
As you can see I am tryng to inject chartValue and chartName props into options.series.data.value and options.series.data.name respectively.
The values for the properties are coming from
<GaugeChart chartName="Sleep" :chartValue="2" />
At the moment the values are hardcoded, but eventually they will be dynamic.
However it keep throwing the following error:
"TypeError: Cannot read property 'chartName' of undefined"
"TypeError: Cannot read property 'chartValue' of undefined"
I have done a colsole.log of both properties and they come up as "Sleep" and 2. I have also done a typeof on both property names and they both come up as String and Number, respectively.
Could somebody tell me where I am going wrong please?
Many thanks in advance.
You cannot use 'this' operator inside an arrow function so define your data section as a normal function
<script>
export default {
props: {
chartValue: { type: Number, required: true },
chartName: { type: String, required: true },
},
data() {
return {
options: {
series: [
{
type: "gauge",
startAngle: 180,
endAngle: 0,
min: 1,
max: 5,
splitNumber: 8,
axisLine: {
lineStyle: {
width: 6,
color: [
[0.25, "#7CFFB2"],
[0.5, "#58D9F9"],
[0.75, "#FDDD60"],
[1, "#FF6E76"],
],
},
},
pointer: {
icon: "arrow",
offsetCenter: [0, "-30%"],
itemStyle: {
color: "auto",
},
},
axisTick: {
length: 12,
lineStyle: {
color: "auto",
width: 1,
},
},
splitLine: {
length: 20,
lineStyle: {
color: "auto",
width: 5,
},
},
title: {
fontSize: 30,
},
data: [
{
value: this.chartValue,
name: this.chartName,
},
],
},
],
},
};
}
};
</script>
You should use the prop in following manner:
<GaugeChart chart-name="Sleep" chart-value="2" />
Documentation
HTML attribute names are case-insensitive, so browsers will interpret any uppercase characters as lowercase.
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>
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();
}
}
};
I am new to vue.js and your help and advise would be much appreciated.
I am using Chartjs and i would like to rotate my pie chart so it looks like a gauge. I am unsure where i am going wrong with my javascript and i am getting no errors in the console - could one kindly advise me
i am unsure if i have not placed "options" in the right place
chartjs.html
<div class="wrapper">
<div class="chart_header">chartjs guage</div>
<vue-chartsguagejs></vue-chartsguagejs>
</div>
chartsjsgauge.js
import { Doughnut } from 'vue-chartjs'
export default {
extends: Doughnut,
mounted () {
this.renderChart({
labels: ["Log Level", "Debug", "Info", "Warn", "Error", "Fatal"],
datasets: [{
label: 'GitHub Commits',
backgroundColor: ['rgb(255, 255, 255)', 'rgb(232,226,202)', 'rgb(226,210,172)', 'rgb(223,189,139)', 'rgb(223,162,103)','rgb(226,126,64)'],
borderWidth: 0,
hoverBorderWidth: 0,
data: [50, 10, 10, 10, 10, 10],
}],
options: {
cutoutPercentage: 0,
rotation: -3.1415926535898,
circumference: 3.1415926535898,
}
}, {responsive: true, maintainAspectRatio: false})
}
}
this is currently my dougnut chart which i am trying to rotate as a gauage
i found that restructuring my code in this format made a huge difference:
import { Doughnut } from 'vue-chartjs'
export default {
extends: Doughnut,
data () {
return {
datacollection: {
labels: ["Log Level", "Debug", "Info", "Warn", "Error", "Fatal"],
datasets: [
{
label: 'GitHub Commits',
backgroundColor: ['rgb(226,126,64)', 'rgb(232,226,202)', 'rgb(226,210,172)', 'rgb(223,189,139)', 'rgb(223,162,103)','rgb(226,126,64)'],
borderWidth: 0,
hoverBorderWidth: 0,
data: [10, 10, 10, 10, 10],
}
]
},
options: {
rotation: -1.0 * Math.PI,
circumference: Math.PI,
}
}
},
mounted () {
this.renderChart(this.datacollection, this.options, {responsive: true, maintainAspectRatio: false})
}
}