Highcharts 10.1.0对数y轴显示指数值 自定义刻度标签异常
问题说明
使用Highcharts/Highstock 10.1.0版本开发时,为logarithmic类型y轴配置自定义tickPositioner函数后,出现y轴标签显示指数值的异常,异常效果如下:
问题复现代码片段如下:
const chart = Highcharts.stockChart('container', { rangeSelector: { selected: 1, inputBoxStyle: { right: '80px' } }, yAxis: [{ type: 'logarithmic', tickPositioner: function () { let lowestValue = this.dataMin; let highestValue = this.dataMax; if((highestValue - lowestValue) < 5 ) { lowestValue = this.dataMin; highestValue = this.dataMax; } else { lowestValue = Math.floor((this.dataMin)); highestValue = Math.ceil((this.dataMax)); } let numberOfTicks = 5; let positions = []; // 首尾刻度固定 if(this.isLog) { positions.push(Math.log(lowestValue) / Math.log(10)); } else { positions.push(lowestValue); } for(let i = 1; i < numberOfTicks; i++) { let eachPosition = lowestValue + (((highestValue - lowestValue)/numberOfTicks) * i); if(this.isLog) { let eachPositionAsLog = Math.log(eachPosition) / Math.log(10); positions.push(eachPositionAsLog); } else { // 兼容多数浏览器1.005四舍五入bug,加0.00001处理,最多保留2位小数 eachPosition = Math.round((eachPosition + 0.00001) * 100) / 100; positions.push(eachPosition); } } // 首尾刻度固定 if(this.isLog) { positions.push(Math.log(highestValue) / Math.log(10)); } else { positions.push(highestValue); } console.log( positions ) return positions; } }], series: [{ name: 'USD to EUR', data: usdeur }], exporting: { chartOptions: { chart: { width: 1024, height: 768 } } } }); document.getElementById('button').addEventListener('click', () => { chart.exportChart(); });
期望实现的效果:
自行排查确认:自定义tickPositioner计算返回的刻度位置数组完全正确,问题出在highstock.js内部渲染逻辑,计算得到的正确刻度点没有被正确渲染为轴标签,无法定位具体根因。
根因分析
问题出在自定义tickPositioner的返回值逻辑错误:
Highcharts 对数轴的tickPositioner要求返回原始业务维度的实际数据值,不需要开发者手动做Math.log(val)/Math.log(10)的对数转换,对数坐标到像素位置的映射逻辑由框架内部自动完成。
原代码判断this.isLog后手动将刻度值转换为以10为底的对数值返回,框架会将传入的值默认当作原始数据值处理,一方面会重复做对数转换导致刻度位置偏移,另一方面这些手动计算的对数值不符合对数轴默认的10的整数次幂刻度规则,框架会自动启用指数格式渲染标签,最终出现指数值显示异常。
解决方案
- 移除
tickPositioner中所有针对this.isLog的手动对数转换分支,无论轴类型是什么,都直接返回计算好的原始数据值作为刻度位置。修复后的tickPositioner代码如下:
tickPositioner: function () { let lowestValue = this.dataMin; let highestValue = this.dataMax; if((highestValue - lowestValue) < 5 ) { lowestValue = this.dataMin; highestValue = this.dataMax; } else { lowestValue = Math.floor(this.dataMin); highestValue = Math.ceil(this.dataMax); } let numberOfTicks = 5; let positions = []; // 直接推入原始值,无需手动做对数转换 positions.push(lowestValue); for(let i = 1; i < numberOfTicks; i++) { let eachPosition = lowestValue + (((highestValue - lowestValue)/numberOfTicks) * i); // 保留2位小数,兼容浏览器四舍五入bug eachPosition = Math.round((eachPosition + 0.00001) * 100) / 100; positions.push(eachPosition); } positions.push(highestValue); return positions; }
- 如果修复后仍存在标签格式不符合预期的问题,可以给y轴添加自定义标签格式化规则,强制按普通数值格式渲染:
yAxis: [{ type: 'logarithmic', labels: { formatter: function () { // 按需调整小数位数 return this.value.toFixed(2); } }, // 其余y轴配置 }]
内容的提问来源于stack exchange,提问作者Subhabrata Banerjee
相关产品推荐
相关产品推荐

