In my react app, I'm getting results from pouchDB that I want to use as the data points in my series for apexCharts.
I'm getting the results and putting them in state, called maxCalories, and when logging in the console they are in this format:
So I want those 7 numbers (all with the index name of caloriesBurned to be my data in the series for the chart but I'm currently getting NaN on the graph.
Here's the full code, how can I set these to the correct format to use them in the chart data?
import React, { Component } from "react";
import Chart from "react-apexcharts";
import DB from '../../db';
import * as moment from 'moment';
class TrendsComponent extends Component {
constructor(props) {
super(props);
this.state = {
maxCalories: '',
calorieRecord: {
caloriesConsumed: '',
caloriesBurned: '',
createdAt: this.newestDate,
updatedAt: undefined
},
caloriesDB: new DB('calorie-records'),
calories: {},
calorieElements: null,
options: {
},
chart: {
toolbar: {
show:false
},
id: "basic-bar"
},
xaxis: {
categories: ['3/20', '3/21', '3/22', '3/23', '3/24', '3/25','3/26']
}
},
series: [
{
name: "Trend (tracked)",
data: {this.maxCalories}
}
]
};
}
componentDidMount(){
this.setMax();
}
setMax = () => {
this.state.caloriesDB.db.find({
selector: {
$and: [
{_id: {"$gte": null}},
{caloriesBurned: {$exists: true}},
{createdAt: {$exists: true}}
]
},
fields: ['caloriesBurned', 'createdAt'],
sort: [{'_id':'desc'}],
limit: 7
}).then(result => {
console.log('max');
console.log(result);
const newDocs = result.docs;
this.setState({
maxCalories: newDocs.map(docs => docs)
});
console.log('maxCalories');
console.log(this.state.maxCalories);
}).catch((err) =>{
console.log(err);
});
}
render() {
return (
<div className="mixed-chart">
<Chart
options={this.state.options}
series={this.state.series}
type="area"
stacked="true"
width="700"
/>
</div>
);
}
}
export default TrendsComponent;
I had the same problem in my project. And I spent a lot of time in looking for solution. So here what I get:
const FinacialResultChart = (props) => {
const options = {
chart: {
toolbar: {
show: false
},
animations: {
enabled: false
}
},
stroke: {
curve: "smooth",
dashArray: [0, 8],
width: [4, 2]
},
grid: {
borderColor: props.labelColor
},
legend: {
show: false
},
colors: [props.dangerLight, props.strokeColor],
fill: {
type: "gradient",
gradient: {
shade: "dark",
inverseColors: false,
gradientToColors: [props.primary, props.strokeColor],
shadeIntensity: 1,
type: "horizontal",
opacityFrom: 1,
opacityTo: 1,
stops: [0, 100, 100, 100]
}
},
markers: {
size: 0,
hover: {
size: 5
}
},
xaxis: {
labels: {
style: {
colors: props.strokeColor
}
},
axisTicks: {
show: false
},
categories: [
"Январь",
"Февраль",
"Март",
"Апрель",
"Май",
"Июнь",
"Июль",
"Август",
"Сентябрь",
"Октябрь",
"Ноябрь",
"Декабрь"
],
axisBorder: {
show: false
},
tickPlacement: "on"
},
yaxis: {
tickAmount: 5,
labels: {
style: {
color: props.strokeColor
}
}
},
tooltip: {
x: { show: false }
}
}
const data = [
{
name: "Итоговый результат",
data: props.userData.traidingMonth
}
]
return (
<Chart
options={options}
series={data}
type="line"
height={280}
/>
)
}
export default FinacialResultChart
So you need to change your class to const, and push all your props (api data for example) into your children chart component. In chart options you can get the chart data with props.data
Related
I need to change the values and re-initiate the component with props Data.
i tried with $emit unfortunately doesn't work my code.
chart.vue
<template>
<div class="col-12">
<div class="card">
<div class="card-header header-elements">
<div>
<h5 class="card-title mb-0">Statistics</h5>
</div>
<div class="card-header-elements ms-auto py-0">
<select name="status" class="form-select form-select-sm" v-model="chartType" #click="$emit('someEvent')">
<option value="daily" data-label="Days">Last 7 Days</option>
<option value="weekly" data-label="Weeks">Weekly</option>
<option value="monthly" data-label="Months">Monthly</option>
</select>
</div>
</div>
<div class="card-body">
<line-chart v-bind:chartData="chartData" v-bind:chartOptions="chartOptions" v-if="showLineGraph" #some-event="chartData"></line-chart>
</div>
</div>
</div>
</template>
<script>
export default {
props: {},
mounted() {
},
created(){
this.params.params = {
chart_type: "daily",
};
this.chartOptions.scales.xAxes[0].scaleLabel.display = "DAYS";
this.chartOptions.scales.xAxes[0].scaleLabel.labelString = "DAYS";
this.loadGraph();
},
data() {
return {
chartType:'daily',
showLineGraph:false,
params: {
params: {}
},
datasetSample: {
data: [],
label: "",
borderColor: "#ff5b5c",
tension: 0.5,
pointStyle: "circle",
backgroundColor: "#ff5b5c",
fill: false,
pointRadius: 1,
pointHoverRadius: 5,
pointHoverBorderWidth: 5,
pointBorderColor: "transparent",
pointHoverBorderColor: "#fff",
pointHoverBackgroundColor: "#ff5b5c",
height: 500
},
chartData: {
labels: [],
datasets: []
},
chartOptions: {
responsive: true,
maintainAspectRatio: false,
scales: {
xAxes: [{
scaleLabel: {
display: "",
labelString: ""
},
gridLines: {
display: true,
},
}],
yAxes: [{
beginAtZero: true,
scaleLabel: {
display: "Amount In INR",
labelString: "Amount In INR"
},
gridLines: {
display: true,
},
ticks: {
maxTicksLimit: 10,
beginAtZero: false,
callback: function (value, index, values) {
return value.toLocaleString();
}
}
}]
},
legend: {
position: 'top',
align: 'start',
labels: {
usePointStyle: true,
padding: 15,
boxWidth: 6,
boxHeight: 6,
}
},
plugins: {
tooltip: {
// Updated default tooltip UI
backgroundColor: "#fff",
titleColor: "#000",
bodyColor: "#000",
borderWidth: 1,
borderColor: "#0560e8"
}
}
}
};
},
methods: {
loadGraph: function () {
this.chartData.datasets=[];
this.chartData.labels = [];
axios.get(window.location.href + "/get-chart-data", this.params)
.then(response => {
console.log(response.data);
if (response.data.status == 200) {
let datasets = response.data.data.datasets;
let chart_vlaues=[];
for (var key in datasets) {
if (datasets.hasOwnProperty(key)){
let temp_dataset = Object.assign({}, this.datasetSample);
temp_dataset.data = datasets[key].values;
temp_dataset.label = key;
temp_dataset.borderColor = datasets[key].colour;
temp_dataset.backgroundColor = datasets[key].colour;
temp_dataset.pointHoverBackgroundColor = datasets[key].colour;
chart_vlaues.push(temp_dataset);
}
}
this.chartData.datasets=chart_vlaues;
this.chartData.labels = response.data.data.labels;
this.showLineGraph=true;
}else {
this.chartData.datasets = [];
this.chartData.labels = [];
this.showLineGraph = true;
}
})
.catch(err => {
console.log(err);
console.log("Chart could not loaded.");
})
.then(() => {
});
},
}
}
</script>
LineChart.Vue
<script>
import { defineComponent } from 'vue'
import { Chart as ChartJS, Title, Tooltip, Legend,Line} from 'vue3-chart-v2'
export default defineComponent({
name: 'LineChart',
extends: Line,Tooltip,Legend,Title,
props: {
chartData: {
type: Object,
required: true
},
chartOptions: {
type: Object,
required: false
},
},
watch : {
someEvent: function (value) {
console.log('from watch');
}
},
mounted () {},
created(){
this.renderChart(this.chartData, this.chartOptions);
},
data(){
},
methods:{
someEvent:function(){
alert('iiiiiiiiii');
}
},
emits: {
someEvent(payload) {
console.log('some emits');
}
}
})
</script>
app.js
require('./bootstrap')
import { createApp } from 'vue'
import lineChart from './components/lineChart';
import chart from './components/chart.vue';
const app = createApp({})
app.component('chart', chart);
app.component('line-chart', lineChart);
app.mount('#app')
You use watchers wrong. They are not for watching events.
watch : {
someEvent: function (value) {
console.log('from watch');
}
},
You also did not define your custom event with emits
Please, check the Vue docs about the Component Events
The typical data flow with Vue components is
to the Component: App -> Data -> Component Props -> Watchers -> Methods
from The component: Data -> Event -> Event Handler -> App
So, if you want to re-initiate your child component, that you should update some child component's prop and then react to the change in some child component's watcher.
I want to show a line like above in ant design timeline graph, ( Line Chart ). It's a dual Axes graph. I am using React and Ant Design. I want to show the line at any data point. I think I have to use annotations, but I am not getting how.
Data Structure is like below
[
{
"date": "10/09/2020",
"type": "Financial impact",
"count": 2180
},
.....
]
Here's my below Code for reference
import React from "react";
import { DualAxes } from "#ant-design/charts";
import { Row, Typography, Col } from "antd";
import { Badge } from "antd";
import NumberFormat from "react-number-format";
const TimelineChart = ({ data }: { data: any[] }) => {
var config: any = {
xField: "date",
yField: ["count", "value"],
data: data,
xAxis: {
label: {
style: {
fill: "#6E759F",
},
},
},
yAxis: {
count: {
label: {
style: {
fill: "#6E759F",
},
},
},
value: {
label: {
style: {
fill: "#03838B",
},
},
},
},
geometryOptions: [
{
geometry: "line",
color: ["#2F54EB", "#9254DE"],
seriesField: "type",
},
{
geometry: "line",
color: "#2AABAB",
seriesField: "type",
},
],
legend: false,
formatter: (data: any) => {
return {
...data,
};
},
},
};
return <DualAxes {...config} />;
};
export default TimelineChart;
I want to have multiple highcharts with different data in my page , without having to repeat the highchart code.
here is how i define my highchart
chartOptions: {
chart: {
type: "pie"
},
title: {
text: ""
},
credits: {
enabled: false
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: "pointer",
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.1f} %'
}
}
},
series: [
{
name: 'Comparison',
data: [],
},
]
},
I call it to the html like this-
<highcharts :options="chartOptions" id="chart1"></highcharts>
I use the event bus listener to send the data to the highchart series
EventBus.$on("btn-clicked", data => {
this.chartOptions.series[0].data = data.newData;
});
Since i am using the highchart-vuejs wrapper i am able to repeat the highcharts, but all the charts will get the same data.Is there a way that i could send the data to a particular chart so it is different from the others?
You're passing down chartOptions into the highcharts component. If you've defined this data on the parent component, Vue will have made it reactive, so when you change the data the chart will update automatically.
Below is a basic example of how this would work:
<template>
<div>
<highcharts :options="chartOptions[0]"></highcharts>
<highcharts :options="chartOptions[1]"></highcharts>
<button #click="changeData">Change data for first chart</button>
</div>
</template>
<script>
import { Chart } from "highcharts-vue";
export default {
components: {
highcharts: Chart
},
data() {
return {
chartOptions: [
{
series: [
{
data: [1, 2, 3]
}
]
},
{
series: [
{
data: [4, 5, 6]
}
]
},
]
}
},
methods: {
changeData() {
this.chartOptions[0].series[0].data = [4, 8, 1];
}
}
};
</script>
EDIT:
To create multiple charts with the same options, you could create a custom chart component, and pass in just the data series as a prop:
<template>
<highcharts :options="chartOptions"></highcharts>
</template>
<script>
import { Chart } from "highcharts-vue";
export default {
name: 'CustomPie',
components: {
highcharts: Chart
},
props: ['data'],
data() {
return {
chartOptions: {
chart: {
type: "pie"
},
title: {
text: ""
},
credits: {
enabled: false
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: "pointer",
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.1f} %'
}
}
},
series: [
{
name: 'Comparison',
data: this.data,
},
]
},
}
},
watch: {
data(newVal) {
this.chartOptions.series[0].data = newVal;
}
}
};
</script>
Note that you have to set up a watcher on the data prop, in order to update the components chartOptions when the data changes.
And your parent component (where you're displaying the charts) would look something like this:
<template>
<div>
<CustomPie :data="chartData1" />
<CustomPie :data="chartData2" />
<button #click="changeData">Change data for first chart</button>
</div>
</template>
<script>
import CustomPie from "./CustomPie";
export default {
components: {
CustomPie
},
data() {
return {
chartData1: [1,2,3],
chartData2: [4,5,6]
}
},
methods: {
changeData() {
this.chartData1 = [4, 8, 1];
}
}
};
</script>
I'm using apex charts for react in my reactJS progressive web app, and have had no issues with it for static data, but I"m now trying to take a returned array from my database and use the array for the graph and it's not working.
I'm logging the array returned from the database, which is in this structure:
And in my code, I'm setting this to the third series option of my chart named "Trends" but when the graph loads the line for that data is 'Nan'
What am I doing wrong here?
class TrendsComponent extends Component {
constructor(props) {
super(props);
this.state = {
maxCalories: '',
calorieRecord: {
caloriesConsumed: '',
caloriesBurned: '',
createdAt: undefined,
updatedAt: undefined
},
options: {
fill: {
colors: ['#FF756D', '#85DE77', '#FFF49C']
},
dataLabels: {
enabled: true,
textAnchor: 'middle',
distributed: false,
offsetX: 0,
offsetY: 0,
style: {
fontSize: '14px',
fontFamily: 'Helvetica, Arial, sans-serif',
fontWeight: 'bold',
colors: ["#FF756D", "#85DE77", "#FFF49C"]
},
background: {
enabled: true,
foreColor: '#fff',
padding: 4,
borderRadius: 2,
borderWidth: 1,
borderColor: '#fff',
opacity: 0.9,
},
dropShadow: {
enabled: true,
top: 1,
left: 1,
blur: 1,
color: '#000',
opacity: 0.8
}
},
colors: ["#FF756D", "#85DE77", "#FFF49C"],
chart: {
toolbar: {
show:false
},
id: "basic-bar"
},
xaxis: {
categories: ['3/20', '3/21', '3/22', '3/23', '3/24', '3/25','3/26']
}
},
series: [
{
name: "Baseline",
data: [250,500,234,389,644,245,590]
},
{
name: "Optimal",
data: [2250,2250,2250,2250,2250,2250,2250]
},
{
//this is the line where I'm getting NaN
name: "Trend (tracked)",
data: [this.maxCalories]
}
]
};
}
...
UPDATE:
Upon component mounting, I use these functions to set MaxCalories which is the data array I'm using for the chart
getMax = () => {
this.state.caloriesDB.db.createIndex({
index: {
fields: ['_id','caloriesBurned']
}
}).then(result => {
console.log(result);
this.setMax();
}).catch((err) =>{
console.log(err);
});
}
setMax = () => {
this.state.caloriesDB.db.find({
selector: {
$and: [
{_id: {"$gte": null}},
{caloriesBurned: {$exists: true}},
]
},
fields: ['caloriesBurned'],
sort: [{'_id':'desc'}],
limit: 7
}).then(result => {
console.log('max');
console.log(result);
const newDocs = result.docs;
this.setState({
maxCalories: newDocs.map(docs => docs)
});
console.log('maxCalories');
console.log(this.state.maxCalories);
}).catch((err) =>{
console.log(err);
});
}
I need to add a date picker that contains start and end dates. When a date is selected that should pass to API to display chart. I have currently displaying Apexchart but I need date picker for my code.
Below is my chart displaying currently now I am passing selected key and I am not getting how to pass selected date to chart.
Here I need to add date picker
<template>
<div >
<select v-model="PoleSelected" #change="getPoleDetail()" >
<option :value='0'>Select Pole</option>
<option v-for='data in PoleList' :value='data.poleid'>{{ data.poleid}}
</option>
</select>
//above dorpdown is used to select the pole
<va-card >
<h3>Temperture</h3>
<AreachartTemp :_key="PoleSelected" /> //this is my
//AreachartTemp.vue anther pageand i am passing selected key to this page
</va-card>
</div>
<div >
<va-card>
<h3>Humidity</h3>
<AreachartHumd :_key="PoleSelected"/> //this is also sepearte
// page and i am passing selected key
</va-card>
</div>
</template>
<script>
export default{
data:function() {
return {
PoleSelected:'',
}
},
components: {
AreachartTemp,
AreachartHumd,
},
}
</script>
//below is my AreachartTemp.vue page
<template>
<div id="wrapper">
<div id="chart-bar" >
<apexchart type=area height=200 :options="chartOptionsArea0"
:series="series0"/>
</div>
<div id="chart-bar">
<apexchart type=area height=100 :options="chartOptionsBrush0"
:series="series0" />
</div>
</div>
</template>
<script>
import VueApexCharts from 'vue-apexcharts'
Vue.use(VueApexCharts)
Vue.component('apexchart', VueApexCharts)
import axios from 'axios'
import Vue from 'vue';
export default {
props: {
_key: {
type: String,
required: true
}
},
data() {
return {
series0: [{
data: this.generateDayWiseTimeSeries0( 185, {
min: 30,
max: 90
})
}],
chartOptionsArea0: {
chart: {
id: 'chartArea0',
foreColor: "#ccc",
toolbar: {
autoSelected: 'pan',
show: false
}
},
stroke: {
width: 3
},
dataLabels: {
enabled: false
},
fill: {
opacity: 1,
},
markers: {
size: 2,
colors: ["#000524"],
strokeColor: "#00BAEC",
strokeWidth: 3
},
xaxis: {
type: 'datetime'
}
},
chartOptionsBrush0: {
chart: {
id: 'chartBrush',
brush: {
target: 'chartArea0',
enabled: true
},
selection: {
enabled: true,
xaxis: {
}
},
},
colors: ['#546E7A'],
fill: {
type: 'gradient',
gradient: {
opacityFrom: 0.55,
opacityTo: 0
}
},
xaxis: {
type: 'datetime',
tooltip: {
enabled: false
}
},
yaxis: {
tickAmount: 2
}
}
};
},
watch: {
_key() {
this.generateDayWiseTimeSeries0();
}
},
mounted() {
//this.updateChart();
},
methods: {
generateDayWiseTimeSeries0: function () {
var me = this;
axios.get("http://34.67.88.0:3000/api/eco/temp/"+this._key)
.then(function (res) {
me.series0[0].data=res.data
/*me.$children[0].updateSeries([{
data: res.data
}]);
me.$children[1].updateSeries([{
data: res.data
}]);*/
})
return []
}
}
};
</script>