如何让Highcharts仅显示JSON中指定的X轴日期?
问题描述
当前行为
图表X轴生成了连续的全周日期序列,例如:2022-5-30、2022-5-31、2022-6-1、2022-6-2、2022-6-3、2022-6-4、2022-6-5、2022-6-6。
复现方式
可通过在线演示复现问题。
代码片段
let globalData = []; let finRez = []; let chart; let duration = 500; // 控制新数据点之间的动画时长 let startIterator = 1; // 初始化图表时渲染的数据点数量 let currentIterator = startIterator; let maxIterator = 1; let guiButton = document.getElementById('start'); let guiButtonState = 'Start'; let intervalId; // 获取数据: fetch('https://raw.githubusercontent.com/veleg/trade/main/trade.json') .then(response => response.json()) .then(data => { parseData(data); createChart(); initEvents(); }); function initEvents() { guiButton.addEventListener('click', function() { if (guiButtonState === 'Stop') { // 用户点击"Stop" -> 停止动画,允许恢复 intervalId = clearInterval(intervalId); guiButton.innerText = guiButtonState = 'Resume'; } else { // 如果动画已结束,重新创建图表 if (guiButtonState === 'Restart') { createChart(); } guiButton.innerText = guiButtonState = 'Stop'; // 启动动画: redrawChart(currentIterator += 1); intervalId = setInterval(function() { // 如果到达最后一个数据点,停止动画: if (currentIterator === maxIterator) { intervalId = clearInterval(intervalId); currentIterator = startIterator; guiButton.innerText = guiButtonState = 'Restart'; } else { redrawChart(currentIterator += 1); } }, duration); } }); } function redrawChart(index) { // 每次重绘时更新副标题 chart.setTitle(null, { text: ' Заработано: ' + globalData[0].data[index][1] }, false); const newValues = globalData.map(series => series.data[index][1]); const maxIndex = newValues.indexOf(Math.max.apply(null, newValues)); // 为每个系列添加数据点: chart.series.forEach( (series, seriesIndex) => { const enabled = maxIndex === seriesIndex && ((index < 5) || (index % 5 === 0)); series.addPoint( { x: globalData[seriesIndex].data[index][0], y: globalData[seriesIndex].data[index][1] <!-- dataLabels: { --> <!-- enabled --> <!-- }, --> <!-- marker: { --> <!-- enabled --> <!-- } --> }, false, false, false ); } ); // 所有更新完成后,重绘图表: chart.redraw({ duration }); } function parseData(data) { Highcharts.objectEach( data, // 转换为Highcharts要求的数据格式: // series: [{ // data: [ [x, y], [x, y], ..., [x, y]] // }] (countryData, country) => { if (country !== 'Diamond Princess' && country !== 'Holy See') { globalData.push({ name: country, data: countryData.map(p => [Date.parse(p.date), p.recovered / getCountryPopulation(country)]) <!-- data: countryData.map(p => [p.date, p.recovered / getCountryPopulation(country)]), --> <!-- datas: countryData.date, --> <!-- datass: countryData.map(p => [p.date, p.date]) --> }); } } ); // 排序并限制数据集: globalData = globalData .sort((countryA, countryB) => { let countryALen, countryBLen; if (!countryA || !countryA.data || countryA.data.length === 0) { return 1; } if (!countryB || !countryB.data || countryB.data.length === 0) { return -1; } return countryB.data[countryB.data.length - 1][1] - countryA.data[countryA.data.length - 1][1]; }) .splice(0, 8); maxIterator = Math.max.apply(null, globalData.map(series => series.data.length - 1)); } function createChart() { function format(y) { return y.toFixed(2); } chart = Highcharts.chart('container', { chart: { type: 'spline', marginLeft: 100 }, legend: { layout: 'proximate', align: 'right' }, title: { floating: true, align: 'left', x: 93, y: 20, text: 'Confirmed cases per country per 1000 inhabitants' }, subtitle: { floating: true, align: 'left', y: 60, x: 90, text: ' Заработано: ' + globalData[0].data[0][1], style: { fontSize: '20px' } }, tooltip: { split: true, pointFormatter: function() { <!-- var value = format(this.y); --> <!-- return `<span style="color:${this.color}">●</span> ${this.series.name}: <b>${value}</b><br/>`; --> } }, yAxis: { title: { text: '' }, maxPadding: 0.2, softMax: 1 }, xAxis: { gridLineWidth: 2, min: globalData[0].data[0][0], minRange: 7 * 24 * 3600 * 1000, type: 'datetime' <!-- categories: [1] --> }, plotOptions: { series: { animation: { duration }, <!-- marker: { --> <!-- symbol: 'circle' --> <!-- }, --> dataLabels: { formatter: function() { return format(this.y); } } } }, series: globalData.map(series => { return { name: series.name, data: series.data.slice(0, startIterator).map(point => { return { x: point[0], y: point[1] } }) } }) }); } function getCountryPopulation(country) { return { "Заработано": 1, "Финансовый результат": 1 }[country]; }
使用版本
Highcharts JS v10.3.2 (2022-11-28)
需求说明
需要让X轴跳过JSON文件中未指定的日期,仅保留指定日期(例如:2022-5-30、2022-5-31、2022-6-1、2022-6-2、2022-6-3、2022-6-6)。无需过滤JSON,JSON已明确所需日期,但脚本会自动补充不存在的日期。需禁用Highcharts自动补全缺失日期的功能,仅展示JSON内的日期(可间隔或为周末)。
解决方案
要解决Highcharts自动补全缺失日期的问题,核心是将X轴类型从datetime改为category,同时调整数据格式适配分类轴,具体步骤如下:
- 修改
createChart函数中的X轴配置,移除datetime相关参数并替换类型:
xAxis: { gridLineWidth: 2, type: 'category' // 替换原有的datetime类型 }
- 调整
parseData函数中的数据处理逻辑,将日期从时间戳改为字符串格式:
data: countryData.map(p => [p.date, p.recovered / getCountryPopulation(country)])
- 确保
redrawChart函数中添加数据点时,x值保持字符串日期格式,与分类轴匹配。
修改后,X轴会严格按照JSON中提供的日期顺序展示,不会自动补全缺失的日期。
内容的提问来源于stack exchange,提问作者Ринат Ауди
相关产品推荐
相关产品推荐

