I am attempting to create charts with chart.js. I have followed the example code on the chart.js website and have been able to get the example code to work. I have tried amending the code to process the data for the chart externally from the javascript file creating the chart, then providing the data through the chart parameters. Doing this, I get the following console error:
I have the following data in my data.js file:
export const UserData = [
{
id: 1,
year: 2018,
users: 2000,
},
{
id: 2,
year: 2019,
users: 2500,
},
{
id: 3,
year: 2020,
users: 3000,
}
]
I have the following code in my App.js file:
import React from "react";
import { UserData } from './Components/data';
import { Graph } from "./Components/graph";
const data = {
labels: UserData.map((data) => data.year),
datasets: [{
label: 'Revenue',
data: UserData.map((data) => data.users),
backgroundColor: ['#CCD4BF'],
borderColor: [],
borderWidth: 1
}]
};
function App() {
return <Graph graphData={data}/>
}
I have the following code in my graph.js file:
import React from 'react';
import { Bar } from 'react-chartjs-2';
import {Chart as ChartJS,} from 'chart.js/auto'
export function Graph(graphData) {
return <Bar data={graphData}/>
}
Is there anything that I am missing in my code to resolve the "reading map" and "ForwardRef" errors?
I had the same issue, to solve this read about migration to react-chartjs-2#4 here, that helped for me, I used the tree-shakable approach:
import { Chart } from 'react-chartjs-2';
import { Chart as ChartJS, LineController, LineElement, PointElement, LinearScale, Title } from 'chart.js';
ChartJS.register(LineController, LineElement, PointElement, LinearScale, Title);
<Chart type='line' data={chartData} />
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 trying to make a COVID19 visualization site using Chart.js and VueJs
this is My App.vue that contains the API call and stores the data into arrays
<template>
<div id="app" class="container">
<div class="row mt-5" v-if="PositiveCases.length > 0">
<div class="col">
<h2>Positives</h2>
<lineChart :chartData="PositiveCases" :options="chartOptions" label="Positive" />
</div>
</div>
</div>
</template>
<script>
import axios from "axios";
import moment from 'moment'
import lineChart from "./components/lineChart.vue";
export default {
name: 'App',
components: {
lineChart
},
data(){
return{
PositiveCases : [],
Deaths: [],
Recoverd: [],
chartOptions: {
responsive: true,
maintainAspectRatio: false
}
}
},
async created(){
const {data} = await axios.get('https://api.covid19api.com/live/country/egypt')
//console.log(data);
data.forEach(d => {
const date = moment(d.Date,"YYYYMMDD").format("MM/DD")
const {Confirmed,Deaths,Recovered} = d
this.PositiveCases.push({date, total : Confirmed})
this.Deaths.push({date, total : Deaths})
this.Recoverd.push({date, total : Recovered})
// console.log("PositiveCases",this.PositiveCases);
// console.log("Deaths",this.Deaths);
// console.log("Recoverd",this.Recoverd);
});
}
}
</script>
and this is my lineChart.vue that contains the Line chart code the data stored correctly in both the dates and totals
<script>
import {Line} from 'vue-chartjs'
export default {
extends: Line,
props: {
label:{
type: String,
},
chartData:{
type: Array,
},
options:{
type: Object,
}
},
mounted(){
const dates = this.chartData.map(d => d.date).reverse()
const totals = this.chartData.map(d => d.total).reverse()
console.log("dates",dates);
console.log("totals",totals);
this.renderChart({
labels: dates,
datasets: [{
label: this.label,
data: totals,
}],
},this.options
)
}
}
</script>
the error in the console says
want to know what is the solution, all the data are stored correctly in both files
You are using V4 of vue-chart.js, the chart creation process has been changed as you can read here in the migration guide.
So instead of calling this.renderChart which was the old syntax you now have to use the actual component and pass the data to it like so:
<template>
<Bar :chart-data="chartData" />
</template>
<script>
// DataPage.vue
import { Bar } from 'vue-chartjs'
import { Chart, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js'
Chart.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
export default {
name: 'BarChart',
components: { Bar },
data() {
return {
chartData: {
labels: [ 'January', 'February', 'March'],
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
data: [40, 20, 12]
}
]
}
}
}
}
</script>
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!