I'm trying to create an event that fires when the user click on a single bar, I've read the Chartjs docs and look for others with the same needs but there nothing specific about how to handle this kind of matter I think this method would be the one but don't know how to locate the chart instance. I share my code:
<script setup lang="ts">
import type { IChartObject } from '@/interfaces/IChartObject'
import type { IGrafica } from '@/interfaces/IGrafica'
import axios from 'axios'
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
BarElement,
CategoryScale,
LinearScale,
type ChartData
} from 'chart.js'
import { onMounted, onUnmounted, ref, watch } from 'vue'
import { Bar } from 'vue-chartjs'
import Pivot from 'quick-pivot'
ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend)
ChartJS.defaults.color = 'white'
let initalDataSet: string[][] = [['cuando', 'quien', 'cuanto']]
let pivot: any
let itemReactive = ref<ChartData<'bar'>>({
datasets: []
})
let temporizador: any = null
const props = defineProps<{
url: string
}>()
watch(
() => props.url,
async (newUrl) => {
await getDataset(newUrl)
},
{ immediate: true }
)
const options = {
responsive: true,
maintainAspectRatio: true,
scales: {
x: {
stacked: true
},
y: {
stacked: true
}
},
plugins: {
legend: {
display: false,
}
},
}
let object: IChartObject = {
labels: [''],
datasets: [
{
label: '',
backgroundColor: '',
barThickness: 0,
borderRadius: 0,
data: [{}]
}
]
}
onMounted(() => {
getDataset(props.url)
temporizador = setInterval(paintChart, 300000)
})
onUnmounted(() => {
clearInterval(temporizador)
})
async function paintChart() {
await getDataset(props.url)
}
async function getDataset(url: string): Promise<void> {
const response = await axios.get<IGrafica[]>(url)
readyChartDataSet(response.data, object)
itemReactive = object as any
emptyObject()
}
function emptyObject(): void {
object = {
labels: [''],
datasets: [
{
label: '',
backgroundColor: '',
barThickness: 0,
borderRadius: 0,
data: [{}]
}
]
}
}
function dameColorAleatorio(): string {
//method that give a color to the label...
}
function readyChartDataSet(data: any, chart: IChartObject): void {
//method that fullfill the dataset...
}
function clickHandler(e: any){
const chartInstance = document.getElementById('barChart')
}
</script>
<template>
<Bar :data="itemReactive" id="barChart" @click="clickHandler" :options="options" class="grafica" />
</template>
I did find an answer to my question: the key was in the options object that we inject on the <Bar :data="itemReactive" :options="options" class="grafica" ref="chart "/>
.
In first place I get the barChart instance by ref template then, I create a global variable to save the instance like this ->
const chart = ref<HTMLInputElement | null>(null)
after that on onMounted() I use the directive ->
chart.value?.focus
Finally, there a reserved keyword to the event to capture it on the options object of the bar Chart, I share the code ->
const options = {
responsive: true,
maintainAspectRatio: true,
scales: {
x: {
stacked: true
},
y: {
stacked: true
}
},
plugins: {
legend: {
display: false
}
},
onClick: (e: any) => {
let chartR = Object.assign({}, chart.value) as Object as { chart: ChartJS }
const points = chartR.chart.getElementsAtEventForMode(e, 'nearest', { intersect: true }, false)
if (points.length) {
const firstPoint = points[0]
label = chartR.chart.data.labels![firstPoint.index] as number
router.push({ name: 'detalleConsumo', params: { grafica: props.type, label } })
}
}
}
this way every time the user click on a bar we get the label info on the variable label.