I'm trying to update my line chart using vue chart js.
Each 1 second I'm making a get request do a datatable and I would like to be able to update my chart so I can display the last data but i can't figure how to do it.
I tried computed properties but nothing change..
Here is my code chart.vue :
<template>
<div>
<v-col>
<v-card class="mx-auto" v-if="this.arrTemperature.length > 0">
<v-card-title class="text-h6 font-weight-black">Température</v-card-title>
<line-chart ref="chartTemp" :chartData="chartData" :options="chartOptions" :chartColors="blueChartColors"
label="Température" />
</v-card> <br>
</v-col>
</div>
</template>
<script>
import LineChart from "../components/LineChart.js";
import moment from "moment";
export default {
components: {
LineChart,
},
data() {
return {
arrTemperature: [],
},
};
},
mounted(){
setInterval(this.getTemperature, 1000)
},
computed:{
chartData(){return this.arrTemperature} //where it is supposed to update the datas
},
methods: {
async getTemperature() {
const tag_id = encodeURIComponent('bts_d02c2b7d9098aaa2');
const url = this.$api.getRESTApiUri() + `/temperature/last_id/${tag_id}`;
return fetch(url)
.then(res => res.text())
.then((result) => {
const data = JSON.parse(result);
data.forEach(d => {
let date = moment(d.time).format("DD-MM-YYYY HH:mm:ss");
const {
temperature,
} = d;
this.arrTemperature.push({
date,
value: temperature
});
console.log(date)
console.log(temperature)
let n = JSON.parse(JSON.stringify(this.arrTemperature));
console.log(n)
});
})
.catch((error) => {
console.log(error)
});
},
}
};
</script>
Here my LineChart.js :
import { Line,} from "vue-chartjs";
export default {
extends: Line,
props: {
chartData: {
type: Array
},
},
mounted() {
const dates = this.chartData.map(d => d.date);
const value = this.chartData.map(d => d.value);
this.renderChart({
labels: dates,
datasets: [{
label: this.label,
data: value,
fill: false,
tension: 0.4
}]
},
);
},
};
Related
Hello I would like to understand how to update my vue.chart.js. I make a GET request every 1 second and I would like to be able to update the display to show the latest value. But I don't see how to do it.
Does anyone know how to do it?
Here is my code :
<template>
<div>
<v-col>
<v-card class="mx-auto" v-if="this.arrTemperature.length > 0">
<v-card-title class="text-h6 font-weight-black">Température</v-card-title>
<line-chart ref="chartTemp" :chartData="arrTemperature" :options="chartOptions" :chartColors="blueChartColors"
label="Température" />
</v-card> <br>
</v-col>
</div>
</template>
<script>
import LineChart from "../components/LineChart";
import moment from "moment";
export default {
components: {
LineChart,
},
data() {
return {
arrTemperature: [],
// =============================== CHART TEMPERATURE ===============================
mounted(){
setInterval(this.getTemperature, 1000)
},
methods: {
async getTemperature() {
const tag_id = encodeURIComponent('bts_d02c2b7d9098aaa2');
const url = this.$api.getRESTApiUri() + `/temperature/last_id/${tag_id}`;
return fetch(url)
.then(res => res.text())
.then((result) => {
const data = JSON.parse(result);
data.forEach(d => {
let date = moment(d.time).format("DD-MM-YYYY HH:mm:ss");
const {
temperature,
} = d;
this.arrTemperature.push({
date,
y: data[0].temperature
});
console.log(date)
console.log(data[0].temperature)
this.ChartData = { ...this.arrTemperature }
});
})
.catch((error) => {
console.log(error)
});
},
}
};
</script>
here is my display:
I have difficult to use vuex global state combine with re-render child-component in Vue.js.
The global state is mutated but does not re-render its data in v-for loop.
All list of data is rendered, but when the new data changes, component in /blog does not change data in it.
Here is some code:
/store/index.js
export const state = () => ({
allData: [],
})
export const getters = {
getAllData: (state) => state.allData,
}
export const mutations = {
GET_DATAS(state, payload) {
state.allData = payload
},
UPDATE_DATA(state, payload) {
const item = state.allData[payload.index]
Object.assign(item, payload)
},
}
export const actions = {
getDatas({ commit, state }, payload) {
return fetch(`URL_FETCH`)
.then((data) => data.json())
.then((data) => {
commit('GET_DATAS', data)
})
.catch((err) => console.log(err))
},
updateData({ commit, state }, payload) {
commit('UPDATE_DATA', payload)
},
}
in /layouts/default.vue
beforeCreate() {
this.$store.dispatch('getDatas').then(() => {
connectSocket()
})
},
methods: {
connectSocket() {
// connect & received message from socket
// received message from socket
this.$root.$emit('updateData', {
index: 12,
price: 34,
change: 56,
percent: 78,
})
},
},
and in /pages/blog/index.vue
<template>
<div>
<div
v-for="index in getAllData"
:key="index.name"
class="w-100 grid-wrapper"
>
<div>{{ index.price }}</div>
<div>{{ index.change }}</div>
<div>{{ index.percent }}</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
data() {
return {}
},
computed: {
...mapGetters(['getAllData']),
},
mounted() {
this.$root.$on('updateData', (item) => {
this.$store.dispatch('updateData', {
index: item.index,
price: item.price,
percent: item.percent,
change: item.change,
})
})
},
}
</script>
Here is a complete example on how to use Vuex and load the data efficiently into a Nuxt app (subjective but using good practices).
/pages/index.vue
<template>
<div>
<main v-if="!$fetchState.pending">
<div v-for="user in allData" :key="user.id" style="padding: 0.5rem 0">
<span>{{ user.email }}</span>
</div>
</main>
<button #click="fakeUpdate">Update the 2nd user</button>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
data() {
return {
mockedData: {
name: 'John Doe',
username: 'jodoe',
email: 'yoloswag#gmail.com',
phone: '1-770-736-8031 x56442',
website: 'hildegard.org',
},
}
},
async fetch() {
await this.setAllData()
},
computed: {
...mapState(['allData']),
},
methods: {
...mapActions(['setAllData', 'updateData']),
fakeUpdate() {
this.updateData({ index: 1, payload: this.mockedData })
},
},
}
</script>
/store/index.js
import Vue from 'vue'
export const state = () => ({
allData: [],
})
export const mutations = {
SET_ALL_DATA(state, payload) {
state.allData = payload
},
UPDATE_SPECIFIC_DATA(state, { index, payload }) {
Vue.set(state.allData, index, payload)
},
}
export const actions = {
async setAllData({ commit }) {
try {
const httpCall = await fetch('https://jsonplaceholder.typicode.com/users')
const response = await httpCall.json()
commit('SET_ALL_DATA', response)
} catch (e) {
console.warn('error >>', e)
}
},
updateData({ commit }, { index, payload }) {
commit('UPDATE_SPECIFIC_DATA', { index, payload })
},
}
The problem is quite forward, I can't see the line of the graph, and when I press any button. The time of the X-axes should change accordingly to which button is pressed I have been looking through the documentation, for quite some time, but still can't figure it out.
ChartData
import React, { useRef, useEffect, useState } from "react";
import { historyOptions } from '../chartConfig/chartConfig';
import 'chartjs-adapter-moment';
import annotationPlugin from 'chartjs-plugin-annotation';
import { Chart, registerables } from 'chart.js';
Chart.register(...registerables);
Chart.register(annotationPlugin);
const determineTimeFormat = (
timeFormat: string,
day: any,
week: any,
year: any
) => {
switch (timeFormat) {
case "24h":
return day;
case "7d":
return week;
case "1y":
return year;
default:
return day;
}
};
interface Props {
data: any
}
const ChartData: React.FC<Props> = ({ data }) => {
const chartCanvasRef = useRef<HTMLCanvasElement | null>(null);
const { day, week, year, detail } = data;
const [timeFormat, setTimeFormat] = useState("24h");
const [isRebuildingCanvas, setIsRebuildingCanvas] = useState(false);
useEffect(() => {
setIsRebuildingCanvas(true);
}, [timeFormat]);
useEffect(() => {
if (isRebuildingCanvas) {
setIsRebuildingCanvas(false);
}
}, [isRebuildingCanvas]);
useEffect(() => {
if (chartCanvasRef && chartCanvasRef.current && detail) {
const chartCanvas = chartCanvasRef.current
if (isRebuildingCanvas || !chartCanvas) {
return;
}
const chartInstance = new Chart(chartCanvasRef.current, {
type: "line",
data: {
datasets: [
{
label: `${detail.name} price`,
data: determineTimeFormat(timeFormat, day, week, year),
backgroundColor: "rgba(134,159,152, 1)",
borderColor: "rgba(174, 305, 194, 0.4",
},
],
},
Options
options: {
plugins: {
annotation: {
annotations: {
}
}
},
animations: {
tension: {
duration: 1000,
easing: 'linear',
from: 1,
to: 0,
loop: true
}
},
maintainAspectRatio: false,
responsive: true,
scales: {
x:
{
type: 'time',
},
},
}
});
return () => {
chartInstance.destroy();
}
}}, [day, isRebuildingCanvas,timeFormat, week, year, detail]);
Rest of the Component code
return (
<div className='chart__container'>
{renderPrice()}
{isRebuildingCanvas ? undefined : (
<canvas ref={chartCanvasRef} id='myChart' width={250} height={250}></canvas>
)}
<button className='time__format' onClick={() => setTimeFormat("24h")}>24h</button>
<button className='time__format' onClick={() => setTimeFormat("7d")}>7d</button>
<button className='time__format' onClick={() => setTimeFormat("1y")}>1y</button>
</div>
);
};
export default ChartData;
Looks like your isRebuildingCanvas logic might be inconsistent, or I don't just understand it.
Anyway, from the Chart.js perspective, you'd want to change the data and call chartInstance.update() when pressing the button that changes the data.
Partial example:
const canvas = useRef(null);
const [chart, setChart] = useState();
const [timeFormat, setTimeFormat] = useState("24h");
useEffect(() => {
if (chart || !canvas.current) return;
const ctx = canvas.current.getContext("2d");
if (!ctx) return;
const config = {/*...*/};
setChart(new Chart(ctx, config));
}, [chart, canvas]);
useEffect(() => {
if (!chart) return;
chart.config.data.datasets[0].data = determineTimeFormat(timeFormat, day, week, year);
chart.update();
}, [chart, timeFormat]);
And a complete, very similar example:
https://codesandbox.io/s/blissful-faraday-hzcq0
I am using Grid.js to render a table in react. I need to extract the data in one of the cells. When I map the args, I get two results back....a MouseEvent and 'n' which contains the data that I need. How do I extract the data out of the 'n' result? Below is an image of what I receive from my current code which is below the picture.
import React, { useState, useEffect, useRef, Fragment } from 'react';
import axios from 'axios';
import { API } from '../../config';
import Layout from '../../components/Layout';
import { Grid, html, h } from 'gridjs';
import 'gridjs/dist/theme/mermaid.css';
const PendingUser = () => {
const [pendingUser, setPendingUser] = useState({});
const wrappedRef = useRef(null);
useEffect(() => {
getPendingUsers();
setPendingUser(pendingUser);
grid.render(wrappedRef.current);
}, []);
const getPendingUsers = async () => {
const { data } = await axios.get(`${API}/admin/pendinguser`);
await data.filter(user => {
user.accountApproved ? setPendingUser(user) : setPendingUser();
});
};
const handleClick = e => {
e.preventDefault();
const buttonValue = e.target.value;
console.log(buttonValue);
grid.on('rowClick', (...args) =>
args.map(data => {
console.log(data);
})
);
};
const grid = new Grid({
search: true,
columns: [
{
name: 'ID',
hidden: true
},
{
name: 'First Name'
},
{
name: 'Last Name'
},
{
name: 'Email'
},
{
name: 'Agency'
},
{
name: 'Approve',
formatter: (cell, row) => {
return h(
'button',
{
style: 'cursor: pointer',
className: 'py-2 mb-2 px-2 border rounded text-white bg-success',
value: 'approve',
onClick: e => handleClick(e, 'value')
},
'Approve'
);
}
},
{
name: 'Deny',
formatter: (cell, row) => {
return h(
'button',
{
styel: 'cursor: pointer',
className: 'py-2 mb-2 px-2 border rounded text-white bg-danger',
value: 'deny',
onClick: e => handleClick(e, 'value')
},
'Deny'
);
}
},
{
name: 'Denied Reason',
formatter: (_, row) =>
html(
'<select>' +
'<center><option value="Non Law Enforcement">Non Law Enforcement</option><option value="Non Law Enforcement">Non US Law Enforcement</option></center>' +
'</select>'
)
}
],
server: {
url: `${API}/admin/pendinguser`,
method: 'GET',
then: data =>
data.map(user => [
user._id,
user.firstName,
user.lastName,
user.email,
user.leAgency
])
}
});
return (
<Layout>
<div ref={wrappedRef} />
</Layout>
);
};
export default PendingUser;
here is what the 'n' data looks like and I have circled what I want to extract.
columns: [{ name: 'Name',
attributes: (cell) => {
// add these attributes to the td elements only
if (cell) {
return {
'data-cell-content':cell,
'onclick': () => alert(cell)
};
}
}},
This worked for me bro.
I am new in reactjs. Currently I'm developing an app which shows json COVID-19 api data into visualization using chartjs. I tried this from yesterday but I can't show the visual data.
Here is my code
App Component
import React, { useState, useEffect } from "react";
import axios from "axios";
import Chart from "./Chart";
const App = () => {
const [state, setState] = useState({});
const [loading, setLoading] = useState(true);
const [chart, setChart] = useState({});
useEffect(() => {
getData("italy");
setChart({
labels: ["Cases", "Deaths", "Recovered"],
datasets: [
{
label: "cases",
data: [state.cases]
},
{
label: "deaths",
data: [state.deaths]
},
{
label: "recovered",
data: [state.recovered]
}
]
});
}, []);
const getData = async country => {
try {
const res = await axios.get(
`https://corona.lmao.ninja/v2/historical/${country}`
);
setLoading(false);
setState(res.data.timeline);
} catch (error) {
console.log(error.response);
}
};
return (
<div>
{!loading
? console.log(
"cases",
state.cases,
"deaths",
state.deaths,
"recovered",
state.recovered
)
: null}
{!loading ? <Chart chart={chart} /> : "loading failed"}
</div>
);
};
export default App;
And Here is Chart Component
import React from "react";
import { Line } from "react-chartjs-2";
const Chart = ({chart}) => {
return (
<div>
<Line
data={chart}
height={300}
width={200}
options={{
maintainAspectRatio: false,
title: {
display: true,
text: "Covid-19",
fontSize: 25
},
legend: {
display: true,
position: "top"
}
}}
/>
</div>
);
};
export default Chart;
If I open browser and dev tools it look likes this
I want to visualize the data like this
Here is codeSandBox.io
Looks like data property within dataset takes only array of numbers. I have simplifies your code using class based component. It will help you get started.
https://codesandbox.io/s/react-chartjs-2-example-mzh9o
setChartData = () => {
let { data } = this.state;
let chartData = {
labels: ["Cases", "Deaths", "Recovered"],
datasets: [
{
label: "cases",
data: Object.values(data.cases)
},
{
label: "deaths",
data: Object.values(data.deaths)
},
{
label: "recovered",
data: Object.values(data.recovered)
}
]
};
this.setState({
chart: chartData
});
};