vue-chartjs
vue-chartjs copied to clipboard
Mixed chart types support
Would you like to work on this feature?
- [ ] Check this if you would like to implement a PR, we are more than happy to help you go through the process.
What problem are you trying to solve?
I have a type issue when I try to mix chart types
Describe the solution you'd like
I would like a specific , preferably typed way, of mixing chart types. As shown in official documentation of ChartJS: https://www.chartjs.org/docs/latest/charts/mixed.html
Describe alternatives you've considered
Access the underlying chart JS instance and manually add my own data
Documentation, Adoption, Migration Strategy
<Bar :data="{
datasets: [{
type: 'bar',
label: 'Bar Dataset',
data: [10, 20, 30, 40]
}, {
type: 'line',
label: 'Line Dataset',
data: [50, 50, 50, 50],
}],
labels: ['January', 'February', 'March', 'April']
}" />
Bumping this. Is there any work arounds to do mixed chart types at the moment?
Hm, after looking for some other answers on Stackoverflow, I was able to generate a bar chart with line charts on top of it.
Example of my component:
<script setup>
import {Chart as ChartJS, Title, LineElement, PointElement, Tooltip, Legend, BarElement, CategoryScale,Filler, LinearScale} from 'chart.js'
import {Bar} from 'vue-chartjs'
import {computed, defineProps} from 'vue'
ChartJS.register(CategoryScale, PointElement, LineElement, LinearScale, BarElement, Title, Tooltip, Filler, Legend)
const props = defineProps({
labels: Array,
dataRange: Array,
dataTrend: Array,
dataAvg: Array,
})
const chartData = computed(() => {
return {
labels: props.labels,
datasets: [
{
type: 'line',
label: "Average ($)",
borderColor: "#004BA8",
backgroundColor: "#004BA8",
borderWidth: 2,
data: props.dataAvg,
tension: 0.1,
},
{
type: 'line',
label: "Trend ($)",
backgroundColor: "#E57A44",
borderColor: "#E57A44",
borderWidth: 2,
data: props.dataTrend,
tension: 0.1,
},
{
type: 'bar',
label: "Min - Max ($)",
data: props.dataRange,
backgroundColor: '#188145a8',
radius: props.labels.length > 30 ? 0 : 3,
},
]
}
})
const chartOptions = computed(() => {
return {
tooltips: {
mode: 'index',
intersect: true,
displayColors: false,
},
interaction: {
mode: 'index'
},
responsive: true,
title: {
display: true,
text: "Sale Price ($)"
},
scales: {
x: {
stacked: true,
time: {
// Luxon format string
tooltipFormat: 'DD T'
},
format: "HH mm",
title: {
display: true,
text: 'Date'
}
},
y: {
stacked: false,
title: {
display: true,
text: 'Cents per kg'
},
suggestedMin: 0,
suggestedMax: props.dataAvg.length > 0 ? Math.max(...props.dataAvg)+10 : 0
}
},
}
})
</script>
<template>
<Bar v-if="dataRange?.length" :data="chartData" :options="chartOptions"/>
</template>
Generates this (what I needed):
Im using: "vue-chartjs": "^5.2.0", "chart.js": "^4.4.0", "vue": "^3.2.31",
Hm, after looking for some other answers on Stackoverflow, I was able to generate a bar chart with line charts on top of it
Such a brilliant answer! This example have to be included in documentation 🙏🏻
In case someone is stuck with typescript error:
like Type '{ labels: string[]; datasets: ({ data: number[]; label: string; backgroundColor: string; } | { label: string; data: number[]; type: string; pointStyle: string; pointRadius: number; borderColor: string; })[]; }' is not assignable to type 'ChartData<"bar", (number | [number, number] | null)[], unknown>'.
for type mismatch
you need to uncomment the "other" type declaration so if you are using <Bar> only leave the "line" type for combining bar and line charts
let bar_dataset_obj = {
data: data,
label: 'Label',
// type: 'bar', //for mixed charts only the "other" type should be declared
// backgroundColor: '#85bb65' //for some reason other attributes do not work any longer on this object
}
let line_dataset_obj = {
label: 'Label',
data: data,
type: 'line' // this is the other 'type'
}
Thanks to the people above for figuring this out! However, type support is still needed and @raam86 's suggestion didn't work for me.
Here is my implementation where I have to use any
to get past the type fences.
Note: This also happens to be an example of using multiple axes
<template>
<Bar :data="chartData" :options="options" />
</template>
<script setup lang="ts">
import { computed, ref } from "vue";
import { Bar } from "vue-chartjs";
const options = ref<any>({
scales: {
ybar: {
type: "linear",
position: "left",
},
yline: {
type: "linear",
position: "right",
},
},
});
const datasets = computed(() => {
let toPlot= [];
// This is the bar graph
toPlot.push({
label: <bar label>,
data: <bar data>,
yAxisID: "ybar",
});
// This is the line graph
toPlot.push({
type: "line",
label: <line label>,
data: <line data>,
yAxisID: "yline",
});
return toPlot;
});
// HERE I need to use `any` to be able to pass into the Bar :data prop
const chartData = computed<any>(() => {
return { labels: <my labels>, datasets: datasets.value };
});
</script>