问题
Introduction:
I have a ApexCharts chart with data from an API. I'm using an API called finnhub to get the stock market data which is displayed on the chart. The data returned has an array of prices and a corresponding array of times, which are not at an equal interval (stock market is closed at certain times) (prices on the y-axis and time on the x-axis). The data I'm getting is quite high resolution, which means there are a LOT of labels on the x-axis, making it look really cluttered and unreadable. I'm using React Hooks.
The problem I'm getting:
X-axis labels are too close together (image)
As you can see, the labels on the on the x-axis which are displaying the time, are really close together. It looks too cluttered. I want to make it so that there are only about 4-5 labels on the chart which are spaced out evenly across.
Code:
import React, { useState, useEffect } from "react";
import Chart from "react-apexcharts";
import axios from "axios";
import dayjs from "dayjs";
function StockChart() {
const [options, setOptions] = useState({
chart: {
type: "area",
height: 350,
zoom: {
enabled: false
}
},
dataLabels: {
enabled: false
},
stroke: {
curve: "straight"
},
xaxis: {
categories: [],
labels: {
formatter: function (val) {
return dayjs(val).format("DD. HH:mm");
},
hideOverlappingLabels: Boolean,
rotate: 0,
trim: false
},
axisTicks: {
autoskip: true,
maxTicksLimit: 4,
interval: 3
}
},
tooltip: {
x: {
format: "dd MMM yyyy"
}
},
fill: {
type: "gradient",
gradient: {
shadeIntensity: 1,
opacityFrom: 0.7,
opacityTo: 0.9,
stops: [0, 100]
}
}
});
const [series, setSeries] = useState([
{
name: "Closing Price",
data: []
}
]);
useEffect(() => {
axios
.get(
"https://finnhub.io/api/v1/stock/candle?symbol=AAPL&resolution=60&from=1572100000&to=1572910590"
)
.then(res => {
setSeries(prev => {
prev[0].data = res.data.c.map(val => val);
return prev;
});
setOptions(prev => {
prev.xaxis.categories = res.data.t.map(time => time * 1000);
return prev;
});
})
.catch(err => console.log(err));
});
// Ignore the below function and state, it's just for testing
const [disableChart, setDisableChart] = useState(false);
function toggleChart() {
setDisableChart(prev => !prev);
}
return (
<div className="chart-container">
<h1 onClick={toggleChart}>my chart</h1>
{disableChart ? null : (
<Chart options={options} series={series} type="area" width="50%" />
)}
</div>
);
}
export default StockChart;
What I've tried:
I've tried messing around with the ticks property. There was no effect. I've tried setting it to a type: "numeric"
and type: "datetime"
chart but that caused the following effect:
Irregular data intervals(image)
The x-axis labels are now spaced perfectly, but the problem now is that the data on the chart isn't evenly spaced. As you can see, the data interval between 5:50 and 5:55 is very large, unlike the data interval right above 5:55. I want the data interval of the chart to be equal in all places, like in the first image.
Code:
import React, { useState, useEffect } from "react";
import Chart from "react-apexcharts";
import axios from "axios";
import dayjs from "dayjs";
function StockChart() {
const [options, setOptions] = useState({
chart: {
type: "area",
height: 350,
zoom: {
enabled: false
}
},
dataLabels: {
enabled: false
},
stroke: {
curve: "straight"
},
xaxis: {
type: "numeric",
labels: {
formatter: function (val) {
return dayjs(val).format("DD. HH:mm");
},
hideOverlappingLabels: Boolean,
rotate: 0,
trim: false
},
axisTicks: {
show: true
}
},
tooltip: {
x: {
format: "dd MMM yyyy"
}
},
fill: {
type: "gradient",
gradient: {
shadeIntensity: 1,
opacityFrom: 0.7,
opacityTo: 0.9,
stops: [0, 100]
}
}
});
const [series, setSeries] = useState([
{
name: "Closing Price",
data: []
}
]);
useEffect(() => {
axios
.get(
"https://finnhub.io/api/v1/stock/candle?symbol=AAPL&resolution=60&from=1572100000&to=1572910590"
)
.then(res => {
setSeries(prev => {
for (let i = 0; i < res.data.c.length; i++) {
console.log(res.data.t[i]);
prev[0].data[i] = [res.data.t[i], res.data.c[i]];
}
console.log(prev);
return prev;
});
})
.catch(err => console.log(err));
});
// Ignore the below function and state, it's just for testing
const [disableChart, setDisableChart] = useState(false);
function toggleChart() {
setDisableChart(prev => !prev);
}
return (
<div className="chart-container">
<h1 onClick={toggleChart}>my chart</h1>
{disableChart ? null : (
<Chart options={options} series={series} type="area" width="50%" />
)}
</div>
);
}
export default StockChart;
What I want to achieve:
I want to have the data labels on the x-axis be similar to the ones like in the second picture (not too cluttered, only about 4-5 labels per chart), while having the chart itself look like the second picture (distance between data changes is equal). Any help would be greatly appreaciated.
PS: This is my first StackOverflow question, sorry if I did something incorrectly.
回答1:
Well, I faced the same problem but in vue-project. So this helped to me:
methods: {
onChartResize(event) {
this.$refs.oilProductionProfile.updateOptions({
xaxis: { tickAmount: Math.ceil(event.srcElement.innerWidth / 140) },
});
},
},
created() {
window.addEventListener("resize", this.onChartResize);
},
destroyed() {
window.removeEventListener("resize", this.onChartResize);
},
We subscribing on window event, recalculating tickAmount according to current window's innerwidth, and then calling "updateOptions" to refresh axis.
来源:https://stackoverflow.com/questions/63283055/set-a-certain-interval-for-x-axis-ticks-in-apexcharts