I'm trying to make reactive changed graph, so I change some value, then my computed ChartData() put it to component, but nothing works. I'm trying to use update() function, but I have no instance for it.
How can I use function as .update(), .destroy() for my LineChart when I have no instance for it? Can I get instance of graph? What's wrong?
I guess i have 2 methods for update it? Is it?
Update:
Actually I get instance, but problem still exist. Computed property doesn't update data in Line and update() does nothing.
<template>
<div class="graph__busManag">
<Line ref="Graph" id="Chart" :data="ChartData" :options="options" :plugins="plugins" />
</div>
</template>
<script>
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
} from "chart.js";
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
);
import { Line } from "vue-chartjs";
data() {
return {
data: ...something,
option: ...somedata,
},
computed: {
ChartData() {
return this.data; // Should update graph, but doesn't , despite the fact that it is constantly triggered
}
},
mounted() {
this.data.datasets.data = [50, 60, 70, 80, 90, 100];
this.data = {...this.data};
const chartInstance = this.$refs.Graph.chart
console.log(chartInstance);
chartInstance.update(); // not working
chartInstance.reset(); // not w
},
}
You can use the static method getChart to which you pass the id you have given your chart. Here you get the chart instance back to which you can call update:
import { Chart } from 'chart.js';
const chartInstance = Chart.getChart(ownChartId);
Related
I'm trying to add a custom chart in a vue2 app.
The new component is registered but the extended functions have no effect.
I follow some guides: https://vue-chartjs.org/guide/#custom-new-charts, https://www.chartjs.org/docs/latest/developers/charts.html, search in issues and try many combinations but no result.
I am miss something ?
Thank you 🙏
The code :
<template>
...
<Cluster
:chart-options="chartOptions"
:chart-data="chartData"
:width="700"
:height="550"
:plugins="plugins"
ref="graph"
/>
...
</template>
import {Chart as ChartJS, Title, Tooltip, Legend, PointElement, LinearScale, BubbleController} from 'chart.js'
import ChartDataLabels from "chartjs-plugin-datalabels";
import {generateChart} from "vue-chartjs/legacy";
class ClusterController extends BubbleController {
initialize() {
console.log('foo');
}
draw() {
console.log('bar');
}
}
// ClusterController.id = 'cluster-chart';
// ClusterController.defaults = BubbleController.defaults;
const Cluster = generateChart("cluster-chart", "bubble", ClusterController);
ChartJS.register(Title, Tooltip, Legend, PointElement, LinearScale, ChartDataLabels)
// ChartJS.register(Title, Tooltip, Legend, PointElement, LinearScale, ChartDataLabels, ClusterBubbleController)
export default {
name: "ProjectRiskManagementGraphTab",
components: {
Cluster,
},
computed: {
chartData() {
const data = ...;
return {
datasets: [
{
data: data,
}
]
};
},
},
data() {
return {
chartOptions: {
responsive: true,
maintainAspectRatio: true,
},
}
}
};
</script>
First, I would like to emphasize that I am a completely new to Vue (and webdev in general).
I have to make a UI where I have to show some data that I fetch from an API. But I have some issues with chart.js: I can't update my chart when prop change.
Currently, I have the following setup:
Card.vue:
<script>
import DoughnutChart from './DoughnutChart.js'
export default {
name: 'Card',
components: {
DoughnutChart
},
props: ['scheda'],
created() {
console.log(this.scheda)
}
}
</script>
<template>
<DoughnutChart type="abcd" :chartData="this.scheda"/>
</template>
DoughnutChart.js:
import { defineComponent, h } from 'vue'
import { Doughnut } from 'vue-chartjs'
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
ArcElement,
CategoryScale
} from 'chart.js'
ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale)
export default defineComponent({
name: 'DoughnutChart',
components: {
Doughnut
},
props: ['type', 'chartData'],
setup(props) {
const chartData = {
labels: ['A', 'B'],
datasets: [
{
backgroundColor: ["#ff3333", "#131b2e"],
cutout: "75%",
borderWidth: 0,
data: [props.chartData.value, (100 - props.chartData.value)]
}
]
}
const chartOptions = {
plugins: {
legend: {
display: false
}
},
responsive: true,
maintainAspectRatio: false
}
return () =>
h(Doughnut, {
chartData,
chartOptions
})
}
})
this.scheda is a reactive value and when it changes the chart should update accordingly.
I have read the documentation, but I simply can't wrap my head around it.
I have also tried searching on the internet, but all examples reference the older version of the chart library.
Can someone help me with this issue? Thanks!
If you want to create a chart js and integrate with view, you can create your canvas on js outside of vue js flow, and then get the element reference inside vue and then integrate it, the big problem rendering components inside vue is that you need update your charts, it may cause unexpected behavior on canvas. Because tools like Vue are designed to refresh the html and canvas always are a single html tag with a lot of interactivity in js(not much html).
Vue-chart
You can install
vue-chart.js
It supports data updates and also you can access to the chart ref.
Updating charts: https://vue-chartjs.org/guide/#updating-charts
Acesing to ref: https://vue-chartjs.org/guide/#access-to-chart-instance
I've been trying to add a Bar Chart to a React Component and used this youtube tutorial for it. I use react-chartjs-2
My component looks like this:
import React, { useEffect, useState } from "react";
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
} from 'chart.js';
import { Bar } from 'react-chartjs-2';
ChartJS.register(
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend
);
const Daily = () => {
const [chartData, setChartData] = useState({
datasets: [],
})
const [chartOptions, setChartOptions] = useState({
datasets: [],
})
useEffect(() => {
setChartData({
labels: [1,2,3,4,5,6,7],
datasets: [
{
label: 'e',
data: [2,6,3,8,4,6,77],
}
]
});
setChartOptions({
responsive: true,
plugins : {
legend: {
position: "top",
},
title: {
display: true,
text: 'eh'
}
}
})
}, [])
return (
<div className="Daily">
<Bar data={chartData} options={chartOptions} />
</div>
);
};
export default Daily;
Even though I followed the tutorial exactly I get a lot of errors in the console and no Chart shows up. The errors are:
Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
Uncaught TypeError: Cannot read properties of null (reading 'useRef')
react-dom.development.js:18687 The above error occurred in the
<ForwardRef(ChartComponent)> component:
My React and React DOM versions are
"react": "^18.2.0",
"react-chartjs-2": "^4.2.0",
"react-dom": "^18.2.0", so they do seem to be matching and I'm wondering why I'm getting the error. useRef is also not referenced anywhere.
Did anyone have a similiar problem?
I think chartOptions should be {} and not {datasets:[]}
const [chartOptions, setChartOptions] = useState({});
I tried to build a reactive chart with vue-chartjs (Vue v3, Vue ChartJS v4, ChartJS v3). But instead of updating the data in the diagram it just throws the following stack trace every time the interval functions for data computation gets executed:
Uncaught RangeError: Maximum call stack size exceeded
at Object.get2 [as get] (reactivity.esm-bundler.js:432:12)
at toRaw (reactivity.esm-bundler.js:953:29)
at instrumentations.<computed> (reactivity.esm-bundler.js:424:25)
at Proxy.value (helpers.segment.js:1583:26)
at instrumentations.<computed> (reactivity.esm-bundler.js:424:42)
at Proxy.value (helpers.segment.js:1583:26)
at instrumentations.<computed> (reactivity.esm-bundler.js:424:42)
at Proxy.value (helpers.segment.js:1583:26)
at instrumentations.<computed> (reactivity.esm-bundler.js:424:42)
at Proxy.value (helpers.segment.js:1583:26)
I have no clue where to look for the error. I understand that it hints maybe a recursion but I have no idea where this recursion could happen.
If I use static dummy data instead of computing an array with data it displays that data just fine in the diagram.
It's basically the same problem as in this question here: Why using ref() in Vue3 causes "RangeError: Maximum call stack size exceeded"?
I attached below the code of the two components that lead to this error message.
LineChart.vue
<script setup lang="ts">
import { Line } from 'vue-chartjs'
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
LineElement,
LinearScale,
PointElement,
CategoryScale,
Chart
} from 'chart.js'
import type {ChartOptions,ChartData} from 'chart.js'
interface Props {
chartData: ChartData
chartOptions: ChartOptions
}
const props = defineProps<Props>();
ChartJS.register(
Title,
Tooltip,
Legend,
LineElement,
LinearScale,
PointElement,
CategoryScale
)
const plugins = [];
</script>
<template>
<Line
chartId="line-chart"
:width="400"
:height="200"
:chart-data="this.props.chartData"
:chartOptions="this.props.chartOptions"
:plugins="this.plugins"
/>
</template>
DistanceWidget.vue
<script setup lang="ts">
import {computed, reactive} from "vue";
import type DeviceDistance from "../../../model/DeviceDistance.js";
import LineChart from "../../chart/LineChart.vue";
import type {ChartData} from "chart.js";
interface Props {
device: DeviceDistance
}
const props = defineProps<Props>();
const device = reactive<DeviceDistance>(props.device);
const currentDistance = computed<number>((): number => {
const tmpDistance = device.data?.distance;
return tmpDistance && tmpDistance < 255 ? tmpDistance : 183;
});
const chartLabels = reactive<string[]>([]);
const chartValues = reactive<number[]>([]);
setInterval(() => {
// Make sure we always have no more than 10 data points
if (!currentDistance) return;
chartLabels.push(new Date().toString())
chartValues.push(currentDistance.value)
if (chartValues.length > 10) {
chartLabels.shift();
chartValues.shift();
}
}, 500)
const chartDataComp = computed<ChartData>((): ChartData => {
return {
labels: chartLabels,
datasets: [
{
label: 'Distance',
backgroundColor: '#f87979',
tension: 0.5,
data: chartValues
}
]
}
});
const chartOptions = {
responsive: true,
maintainAspectRatio: false,
}
</script>
<template>
<LineChart :chartData="chartDataComp" :chartOptions="chartOptions" />
</template>
I found a working example in the documentation: https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/main/sandboxes/reactive-prop
It's rather complex and not very intuitive. I would have never figured it out myself. But if you build up on it, you get it working. The spread operators (...) are key to get out of the Maximum call stack size exceeded hell.
Good luck!
I am trying to get the time scale (x axis) work with date-fns adapter and getting "error" for chartjs-adapter-date-fns which could be the issue:
Could not find a declaration file for module 'chartjs-adapter-date-fns'. 'C:/react/envirodata/node_modules/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.js'
implicitly has an 'any' type.
Try `npm i --save-dev #types/chartjs-adapter-date-fns` if it exists or add a new declaration (.d.ts) file containing `declare module 'chartjs-adapter-date-fns';`ts(7016)
My setup is like this:
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
} from 'chart.js';
import "chartjs-adapter-date-fns";
import {Line} from 'react-chartjs-2';
import zoomPlugin from "chartjs-plugin-zoom";
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
zoomPlugin
);
and the options are like this:
plugins: {
scales: {
x: {
type: 'time',
adapters: {
date: {
locale: en
}
...
I have tried different date formats for time scale. For example:
labels : [20220224, 20220225...]
data : [{x: 1617253200000, y: 1}, ...]
data : [{x: 2022-02-24, y: 1}, ...]
But nothing seems to work and dates are displayed like as a string. So apart from the chartjs-adapter-date-fns, I am not sure if there is not an issue with setup.
import TimeScale from 'chart.js' instead of CategoryScale