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
Related
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'm trying to render a background (gradient, but simple color also doesn't work) for a line chart using chart.js 3.6.0 in a Vue 3 app. Users can toggle between a bar chart and a line chart (for the same dataset). Interestingly it works for the bar chart:
But the line chart has no gradient:
This is the data configuration:
data: {
labels: props.labels as string[],
datasets: [
{
data: props.data as number[],
backgroundColor: getBackgroundColor(), // returns the gradient
borderColor: getBorderColor(), // returns a color
fill: true // tried all possible values for this
}
]
}
I have tried to remove everything that might cause an issue, but even the most basic configuration with hard-coded data doesn't work.
The canvas is accessed using a ref:
<template>
<canvas class="statistics-canvas" ref="canvas" width="100%" height="100%"></canvas>
</template>
<script lang="ts">
// ...
setup() {
const canvas = ref(document.createElement("canvas"));
let chart: Chart;
onMounted(() => createChart());
function createChart() {
chart = new Chart(canvas.value, {/*...*/});
}
return {
canvas
};
}
</script>
Any ideas about what might be causing this? I have also tried coping the configuration from the chartjs docs (https://www.chartjs.org/docs/latest/charts/line.html), but also no luck.
Please check the registrar file for chart js in your project. Add Filler to Chart.register()
import {
...,
Filler,
} from 'chart.js';
Chart.register(
...,
Filler,
);
I'd like to use chartjs-chart-financial to plot a 'candlestick' chart. However, chartjs-chart-financial isn't published to npm yet. I run an npm install followed by gulp build in the directory that has the cloned repo from https://github.com/chartjs/chartjs-chart-financial. I see chartjs-chart-financial.js in the dist folder after it has built. However, I'm clueless as to how to get this to integrate with the base chart.js library, so that I can specify a type: candlestick on my Chart. I haven't been able to come across any examples where this is demonstrated..
I'm currently using react-chartjs-2 as a wrapper around chart.js since I'm working in React:
import React, { Component } from 'react';
import Chart from '../node_modules/chart.js/dist/chart';
class Financial extends Component {
constructor() {
super();
this.myRef = React.createRef();
}
componentDidMount() {
const ctx = this.myRef.current;
this.myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["A", "B", "C"],
datasets: [{
label: 'Test',
data: [12, 20, 15],
backgroundColor: 'gray'
}]
}
});
}
render() {
return (
<canvas ref={this.myRef}/>
);
}
}
export default Financial;
As you can see, I'm rendering a sample chart with type bar for now. I'd like to be able to use type 'candlestick' instead, along with its associated dataset.
I'd appreciate any help!!
I have a single file component that uses Chart.Js to render a simple visualization for some hard coded data. I'm calling the Chart.Js library through a CDN in the head section of my index.html.
I'm using the official Webpack template.
For some reason, the chart won't render unless I click on the component inside the Vue Dev Tools extension.
I've tried changing it from computed to created/mounted and that hasn't worked.
Here's my code. Any help getting this to render properly would be much appreciated.
<template lang="html">
<div>
<div class="row">
<div class="col-sm-12 col-md-4">
<canvas id="carbChart"></canvas>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
calories: 3000,
childSex: 'male',
childAge: 'eighteen'
}
},
computed: {
nutrientCharts: function() {
let calories = this.calories;
let carbCtx = document.getElementById('carbChart').getContext('2d');
let carbChart = new Chart(carbCtx, {
type: 'doughnut',
data: {
labels: ['Low', 'Good', 'Too Much'],
datasets: [{
label: 'carbs',
data: [calories * .45, calories * .65, calories * 1],
backgroundColor: ['orange', 'blue', 'red']
}]
}
});
}
}
}
</script>
You have defined the method in a computed property but never used it.
Assuming you want to just get this running, load the chart on mounted:
mounted() {
this.nutrientCharts();
},
methods: {
nutrientCharts: function () {
// your code here
}
}