How to annotate any data point in ant design timeline graph? - javascript

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;

Related

Data point in Chart js line chart not positioned along y axis correctly when retrieve data from firestore

I am having an issues where my data points from data retrieved from firestore are not correctly positioned for the y-axis though the tooltip data is correct. For example, the data below is suppose to be at 23 but its positioned at 100+.
When I manually type in the data, it is positioned correctly so I thought that it might be an issue with the data type after retrieval from the database but I checked and it is appropriately a 'number' data type.
I am not so sure how this issue came about and how to rectify it. I would greatly appreciate your help on this problem! Thanks!
<script>
import {
auth,
db
} from "../../src/main";
import Sidebar from "../components/Navigation/Sidebar.vue";
import Topbar from "../components/Navigation/Topbar.vue";
import ChartTest from "../components/ProgressPage/ChartTest.vue";
import Chart from 'chart.js/auto';
import {
getFirestore,
doc,
updateDoc,
getDoc,
setDoc,
collection,
addDoc,
deleteDoc,
deleteField,
arrayUnion,
arrayRemove
} from "firebase/firestore";
export default {
name: "Progress",
components: {
Sidebar,
Topbar,
ChartTest
},
mounted() {
const progressChart = new Chart(document.getElementById("progress-chart"), {
type: 'line',
data: {
labels: ['CA1', 'SA1', 'CA2', 'SA2'],
datasets: [
]
},
options: {
plugins: {
title: {
display: true,
text: this.title
}
},
scales: {
y: {
display: true,
stacked: true,
// max: 0,
// min: 200,
title: {
display: true,
text: 'Your Score (%)'
}
}
}
}
});
this.getData().then((data) => {
progressChart.data.datasets=data
console.log(typeof(data[0].data[0]))//number data type
this.getCount(data)
progressChart.update() //updating graph with new set of data her
})
},
methods: {
getCount(data) {
this.count= data.length
},
async getData() {
var email = localStorage.getItem("email");
var ref = doc(db, 'users', email);
const docSnap = await getDoc(ref)
if (docSnap.exists()) {
var data = docSnap.data().progressResults
return data
} else {
console.log('does not exist')
}
},
async addResult() {
let count = this.existingSubjects.length
var email = localStorage.getItem("email");
var ref = doc(db, 'users', email);
if (!this.existingSubjects.includes(this.subject)) {
this.existingSubjects.push(this.subject)
const newData = {
data: [{ x: this.examType,y:this.score}],
label: this.subject,
borderColor: this.colors[this.count],
fill: false
}
await updateDoc(
ref, {
progressResults: arrayUnion(newData)
}
)
console.log(newData)
} else {
//TBC
}
}
},
data() {
return {
score: '',
examType: '',
subject: '',
count:0,
existingSubjects: [],
colors: ["#3e95cd", "#8e5ea2", "#3cba9f", "#e8c3b9", "#c45850","#21c095","#bbc021","#1a993a","##904b23","#a01359","#a04913","#534270"],
title: '',
data: {
labels: ['CA1', 'SA1', 'CA2', 'SA2'],
datasets: [
]
},
tabs: [{
link: '',
name: "subject",
dropdown: true,
dropdownTabs: [{
name: 'math',
link: '#'
},
{
name: 'science',
link: '#'
},
]
},
{
link: '#',
name: "test",
dropdown: false,
dropdownTabs: []
},
]
}
}
}
</script>
This is because you set your y axis to stacked so it puts all values on top of each other where the space between the lines is the value you provide.
To get the behaviour you want you need to remove the stacked or set it to false:
y: {
stacked: false
}

How to Render Chart Datasets in Vue?

I am currently making a reports page and currently struggling how to render the dataset to my BarChart. I have no problems showing static data to the chart but when I use axios it does not work. I read solutions about using watchers and mounted. But I am confused how to apply it if my BarChart is in another component.
This is my BarChart Code:
import { Bar } from "vue-chartjs";
export default {
name: "BarChart",
extends: Bar,
data() {
return {};
},
props: {
label: {
type: Array,
},
chartData: {
type: Array,
},
options: {
type: Object,
},
},
mounted() {
const dates = this.chartData.map((d) => d.date);
const totalCheckIn = this.chartData.map((d) => d.totalCheckIn);
const totalCheckOut = this.chartData.map((d) => d.totalCheckout);
this.renderChart(
{
labels: dates,
datasets: [
{
label: this.label[0],
data: totalCheckIn,
},
{
label: this.label[1],
data: totalCheckOut,
},
],
},
this.options
);
},
};
In my reports component this is how I used it:
<BarChart
v-bind:chartData="checkIn"
v-bind:options="checkInOptions"
v-bind:label="checkInLabel"
></BarChart>
import BarChart from "../components/BarChart";
export default {
name: "Reports",
components: { BarChart },
data() {
return {
checkInOptions: {
responsive: true,
maintainAspectRatio: false,
},
checkIn: [
{ date: "1", totalCheckIn: "2", totalCheckout: "2" },
{ date: "2", totalCheckIn: "1", totalCheckout: "2" },
],
checkInLabel: ["Check In", "CheckOut"],
}
},
beforeMount() {
axios
.get('http://localhost:3000/monthly-checkin/'+this.month+'/'+this.year+'')
.then((res) => {
this.checkIn = res.data.monthly;
console.log(this.checkIn)
})
.catch((err) => {
console.log(err.response.data.message);
});
}
}
Please help
Use watch inside your BarChart component as below:
watch:{
chartData:function(newVal,OldVal){
//assign chart data
},
},
Afterwards you need to execute the method where your bar chart data could be updated. Below will be the full snippet.
import { Bar } from "vue-chartjs";
export default {
name: "BarChart",
extends: Bar,
data() {
return {};
},
props: {
label: {
type: Array,
},
chartData: {
type: Array,
},
options: {
type: Object,
},
},
watch: {
chartData: function (newVal, OldVal) {
this.updateChart()
},
},
mounted() {
this.updateChart()
},
methods: {
updateChart() {
const dates = this.chartData.map((d) => d.date);
const totalCheckIn = this.chartData.map((d) => d.totalCheckIn);
const totalCheckOut = this.chartData.map((d) => d.totalCheckout);
this.renderChart(
{
labels: dates,
datasets: [
{
label: this.label[0],
data: totalCheckIn,
},
{
label: this.label[1],
data: totalCheckOut,
},
],
},
this.options
);
}
}
};

How to have multiple highcharts with different series data in vuejs without repeating code

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>

Apex charts, setting series data from array in state

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

"Error: Component series.line not exists. Load it first." in vue-echarts

I imported the line component, but it's still complaining. I created my project with vue cli 3 and according to this, but I cannot find vue.config.js in my project. So I manually created vue.config.js and put it in the same folder of babel.config.js, and it broke my router.
This is my line chart:
<template>
<v-chart :options="options"/>
</template>
<script>
import ECharts from 'vue-echarts/components/ECharts'
import 'echarts/lib/chart/line'
export default {
name: 'line-chart',
components: {
'v-chart': ECharts
},
props: {
data: Object
},
data () {
return {
options: {
xAxis: {
type: 'category',
data: this.data.xAxis
},
yAxis: {
type: 'value'
},
series: [{
type: 'line',
data: this.data.values
}],
animationEasing: 'linear'
}
}
}
}
</script>
//in my main.js
import ECharts from 'vue-echarts/components/ECharts'
import 'echarts/lib/chart/bar'
import 'echarts/lib/component/tooltip'
Vue.component('v-chart', ECharts);
import 'echarts/lib/chart/bar'
import 'echarts/lib/component/polar'
import 'echarts/lib/component/tooltip'
<template>
<v-container>
<v-chart :options="polar"/>
</v-container>
</template>
<script>
export default {
data: function () {
let data = []
for (let i = 0; i <= 360; i++) {
let t = i / 180 * Math.PI
let r = Math.sin(2 * t) * Math.cos(2 * t);
data.push([r, i])
}
return {
polar: {
title: {
text: '极坐标双数值轴'
},
legend: {
data: ['line']
},
polar: {
center: ['50%', '54%']
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
angleAxis: {
type: 'value',
startAngle: 0
},
radiusAxis: {
min: 0
},
series: [
{
coordinateSystem: 'polar',
name: 'line',
type: 'bar',
showSymbol: false,
data: data
}
],
animationDuration: 2000
}
}
}
}
</script>
<style>
</style>
and this is my view
I think you have a problem in series

Categories

Resources