vue-chartjs vue 2 add custom chart - javascript

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>

Related

What is instance for update chartjs

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);

Reading map and ForwardRef error in Chart.JS - Javascript

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} />

Uncaught (in promise) TypeError: this.renderChart is not a function VueJs Chart.js

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>

Adding Bar Chart to a React Component

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({});

Reactive chart with vue-chartjs throws "Maximum call stack size exceeded"

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!

Categories