I am using chartjs with the vue-chartjs wrapper and trying to create a Line Chart using data fetched from my api. The data prints to the console as expected and I do not get a error in the console. The resulting Line Chart does not display at all in the browser. There is, however a large amount of white space where the canvas tag is injected. I can create a doughnut chart fine, just not this line chart. Your help is greatly appreciated! I am using code from the Chart examples found at https://vue-chartjs.org/examples/ for the LineChart component
IndexView.vue
<script setup>
import axios from 'axios'
import { onMounted, reactive } from 'vue'
import LineChart from '#/components/LineChart.vue'
const data = reactive({
user: null,
totals: null,
checkins: null
})
const state = reactive({
loading: true
})
const charts = reactive({
doughnutConfig: null,
lineConfig: null
})
onMounted(async () => {
// load data from store and api
data.user = await userStore.fetchUser()
const user_resp = await axios.get(...)
data.totals = user_resp.data.totals
data.checkins = user_resp.data.check_ins
state.loading = false
// create line chart
var dates = []
var ratings = []
var length = data.checkins.length < 10 ? data.checkins.length : 10
for (var i = 0; i < length; i++) {
dates.push(data.checkins[i].date)
ratings.push(data.checkins[i].rating)
}
console.log(dates) // [ "2022-09-04T00:00:00", "2022-09-04T00:00:00", "2022-09-04T00:00:00", "2022-09-04T00:00:00", "2022-09-05T00:00:00" ]
console.log(ratings) // [ 5, 5, 3, 2, 4 ]
charts.lineConfig = {
data: {
labels: dates,
datasets: {
label: 'Ratings by date',
data: ratings,
backgroundColor: '#f87979'
}
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
}
}
}
})
</script>
<template>
<LineChart
v-if="charts.lineConfig"
:chart-options="charts.lineConfig.options"
:chart-data="charts.lineConfig.data"
:width="400"
:height="300"
/>
</template>
LineChart.vue
<script setup>
import { defineProps } from 'vue'
import { Line } from 'vue-chartjs'
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
LineElement,
LinearScale,
PointElement,
CategoryScale
} from 'chart.js'
ChartJS.register(
Title,
Tooltip,
Legend,
LineElement,
LinearScale,
PointElement,
CategoryScale
)
const props = defineProps({
chartData: {
type: Object,
required: true
},
chartOptions: {
type: Object,
required: true
},
chartId: {
type: String,
default: 'line-chart'
},
width: {
type: Number,
required: true
},
height: {
type: Number,
required: true
}
})
</script>
<template>
<Line
:chart-id="props.chartId"
:chart-data="props.chartData"
:chart-options="props.chartOptions"
:width="props.width"
:height="props.height"
/>
</template>
Usually when a chart is not shown, there is an issue on the data configuration.
In your data config, the datasets option seems to be defined as an object but instead should be an array.
data: {
labels: dates,
datasets: { // <--- should be an array.
label: 'Ratings by date',
data: ratings,
backgroundColor: '#f87979'
}
},
It should be:
data: {
labels: dates,
datasets: [{
label: 'Ratings by date',
data: ratings,
backgroundColor: '#f87979'
}]
},
Related
First let me clarify, i'm new to vue.
What I am trying to do is, when I get data from the defineProps. I want that the data from the defineProps goes to my script. Only I cant get the data over there. It is only available in the <template> {{ graph }} </template>. Notice that i can access the data with {{ graph }} in there. I just cant find a way to use it in export default { }
So my script is looking like this
<script setup>
const props = defineProps(['graph']);
</script>
<template>
{{ graph }} // Works
</template>
<script>
console.log(props); // Doesnt work or
console.log(graph); // Doesnt work
export default {
}
</script>
So, how do I get the data from props(graph) into export default { }?
Why do I want do this?
I saw https://vue-chartjs.org/examples/ and I followed it.
export default {
name: 'BarChart',
components: { Bar },
data() {
return {
chartData: {
labels: [ 'January', 'February', 'March' ],
datasets: [ { data: [3, 20, 12] } ]
},
chartOptions: {
responsive: true
}
}
}
}
Notice the data: [3, 20, 12]. I want to edit the values with the data I get. For example data: [props.day1, props.day2, props.day3]
Like commented, use just script setup, try like following:
<template>
<Bar :data="chartData" :options="chartOptions" />
</template>
<script setup>
import { Bar } from 'vue-chartjs'
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js'
import { ref } from 'vue'
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
const chartData = ref({
labels: [ 'January', 'February', 'March'],
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
data: [40, 20, 12]
}
]
})
const chartOptions = ref({
responsive: true,
maintainAspectRatio: false
})
</script>
demo HERE
I am trying to hide the legend of my chart created with Chart.js.
According to the official documentation (https://www.chartjs.org/docs/latest/configuration/legend.html), to hide the legend, the display property of the options.display object must be set to false.
I have tried to do it in the following way:
const options = {
legend: {
display: false,
}
};
But it doesn't work, my legend is still there. I even tried this other way, but unfortunately, without success.
const options = {
legend: {
display: false,
labels: {
display: false
}
}
}
};
This is my full code.
import React, { useEffect, useState } from 'react';
import { Line } from "react-chartjs-2";
import numeral from 'numeral';
const options = {
legend: {
display: false,
},
elements: {
point: {
radius: 1,
},
},
maintainAspectRatio: false,
tooltips: {
mode: "index",
intersect: false,
callbacks: {
label: function (tooltipItem, data) {
return numeral(tooltipItem.value).format("+0,000");
},
},
},
scales: {
xAxes: [
{
type: "time",
time: {
format: "DD/MM/YY",
tooltipFormat: "ll",
},
},
],
yAxes: [
{
gridLines: {
display: false,
},
ticks: {
callback: function(value, index, values) {
return numeral(value).format("0a");
},
},
},
],
},
};
const buildChartData = (data, casesType = "cases") => {
let chartData = [];
let lastDataPoint;
for(let date in data.cases) {
if (lastDataPoint) {
let newDataPoint = {
x: date,
y: data[casesType][date] - lastDataPoint
}
chartData.push(newDataPoint);
}
lastDataPoint = data[casesType][date];
}
return chartData;
};
function LineGraph({ casesType }) {
const [data, setData] = useState({});
useEffect(() => {
const fetchData = async() => {
await fetch("https://disease.sh/v3/covid-19/historical/all?lastdays=120")
.then ((response) => {
return response.json();
})
.then((data) => {
let chartData = buildChartData(data, casesType);
setData(chartData);
});
};
fetchData();
}, [casesType]);
return (
<div>
{data?.length > 0 && (
<Line
data={{
datasets: [
{
backgroundColor: "rgba(204, 16, 52, 0.5)",
borderColor: "#CC1034",
data: data
},
],
}}
options={options}
/>
)}
</div>
);
}
export default LineGraph;
Could someone help me? Thank you in advance!
PD: Maybe is useful to try to find a solution, but I get 'undefined' in the text of my legend and when I try to change the text like this, the text legend still appearing as 'Undefindex'.
const options = {
legend: {
display: true,
text: 'Hello!'
}
};
As described in the documentation you linked the namespace where the legend is configured is: options.plugins.legend, if you put it there it will work:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'pink'
}
]
},
options: {
plugins: {
legend: {
display: false
}
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.0/chart.js"></script>
</body>
On another note, a big part of your options object is wrong, its in V2 syntax while you are using v3, please take a look at the migration guide
Reason why you get undefined as text in your legend is, is because you dont supply any label argument in your dataset.
in the newest versions this code works fine
const options = {
plugins: {
legend: {
display: false,
},
},
};
return <Doughnut data={data} options={options} />;
Import your options value inside the charts component like so:
const options = {
legend: {
display: false
}
};
<Line data={data} options={options} />
I am creating a cryptocurrency price tracker with React. I am using axios to make API requests and get information about the price history of different cryptocurrencies. This works fine, but when I am creating the chart with ChartJS, the chart only shows one value, even though I have thousands. Anyone know how to fix this? Big thanks in advance.
Here is my code for the chart component:
import Chartjs from "chart.js";
import axios from "axios";
import { historyOptions } from "../../chartConfigs/chartConfigs";
const HistoryChart = ({ coinId }) => {
const [timeLength, setTimeLength] = useState(30);
const chartRef = useRef();
const [timeSeriesData, setTimeSeriesData] = useState([]);
useEffect(() => {
const timeSeriesDataArray = [];
axios.get(`https://api.coingecko.com/api/v3/coins/${coinId}/market_chart?vs_currency=usd&days=${30}`)
.then(response => {
response.data.prices.forEach(element => {
timeSeriesDataArray.push(
{
t: element[0],
y: element[2].toFixed(2)
}
)
})
setTimeSeriesData(timeSeriesDataArray)
})
.catch(error => console.log(error))
}, [coinId, timeLength])
useEffect(() => {
if (chartRef && chartRef.current) {
const chartInstance = new Chartjs(chartRef.current,{
type: 'line',
data: {
datasets: [{
label: "Price",
data: timeSeriesData,
backgroundColor: "rgba(174, 374, 194, 0.5)",
borderColor: "rgba(174, 374, 194, 0.4)",
pointRadius: 0,
borderWidth: 1
}]
},
options: historyOptions
})
}
}, [timeSeriesData])
return (
<div className="history-chart-container">
<canvas ref={chartRef} id="history-chart" width={1200} height={500}></canvas>
</div>
)
}
export default HistoryChart
Here is my code for the chart options (historyOptions):
lineHeighAnnotation: {
always: true,
hover: false,
lineHeight: 1.5
},
animation: {
duration: 2000
},
maintainAspectRatio: false,
responsive: true,
scales: {
xAxes: {
type: "time",
distribution: "linear",
}
}
}```
[1]: https://i.stack.imgur.com/e7g4P.png
[2]: https://i.stack.imgur.com/t4YIa.png
This could be fixed by changing your line chart into a scatter chart.
const chartInstance = new Chartjs(chartRef.current,{
type: 'scatter',
...
To still get the lines drawn between the data points, you need to define the option showLine: true on the dataset.
datasets: [{
label: "Price",
showLine: true,
...
}]
UPDATE
You should also make sure to update the chart when new data is added and the chart already exists. Not knowing much about react.js, you could make chartInstance a global variable and proceed as follows:
if (chartRef && chartRef.current) {
chartInstance = new Chartjs(chartRef.current,{
type: 'line',
...
} else {
chartInstance.update();
}
I understand that I need to set Chart.defaults.global.animation.duration = some value. I just don't know where I place this line. I've previously declared it everywhere and it doesn't seem to change anything. I thought that I could set it globally after importing Chart.
Here's the Chart Component.
<script>
import Chart from 'chart.js'
import config from '../config.js'
Chart.defaults.global.animation.duration = 3000
export default {
name: 'Chart',
props: ["positions"],
data() {
return {
}
},
created() {
this.loadData()
this.createChart('canvas', config)
},
methods: {
loadData() {
this.positions.forEach((position) => {
config.data.labels.push(position.symbol)
config.data.datasets[0].data.push(position.closePrice)
})
},
createChart(id, data) {
const ctx = document.getElementById(id)
new Chart(ctx, {
type: data.type,
data: data.data,
options: data.options,
});
}
}
}
</script>
The chart's configuration.
const config = {
type: 'pie',
data: {
labels: [],
datasets: [
{
label: '',
data: [],
backgroundColor: [
'#48beff',
'#3dfaff',
'#43c59e',
'#3d7068',
'#14453d',
],
borderWidth: 1
}
]
},
options: {
legend: {
display: false
},
},
}
export default config
I solved this. The problem was that the closing <style/> tag in my Component was missing. The styles were applied once it was added, and setting Chart.defaults.global.animation.duration now works as expected.
I'm using vue-chartjs for chart
This is my BarChart.js
import {Bar} from 'vue-chartjs'
export default {
extends: Bar,
data () {
return {
gradient: null,
gradient2: null,
datacollection: {
labels: ['January', 'February','March'],
datasets: [
{
label: 'Data One',
backgroundColor: this.gradient,
data: [40,42,99]
},
]}
}
},
mounted () {
this.gradient =
this.$refs.canvas.getContext('2d').createLinearGradient(0, 0, 0, 400);
this.gradient.addColorStop(0, 'rgba(250,274,50,1)');
this.gradient.addColorStop(1, 'rgba(250,174,50,0)');
console.log(this.$refs.canvas.getContext('2d'));
this.renderChart(this.datacollection, {responsive: true,
maintainAspectRatio: false})
}
}
And this is my Vue for it
<template>
<v-flex sm6>
<bar-chart></bar-chart>
</v-flex>
</template>
<script>
import BarChart from './BarChart.js';
export default {
components: {
BarChart
},
data() {
return {
datacollection: null
}
},
}
</script>
<style>
</style>
But I can't see the gradient, so I did console.log for this.$refs.canvas.getContext('2d') and it is referencing the bar-chart correctly but the fillstyle is not canvasgradient it is showing
CanvasRenderingContext2D
canvas:canvas#bar-chart
fillStyle:"#000000"
Well you can not reference data properties inside data properties in vue.js
data: () => ({
data1: '1',
data2: this.data1
})
This will not work tho.
You can put your datacollection directly inside the renderChart() method and then add the gradient. Or try to use computed properties