可视化开发是前端开发的重要分支之一。日常的数据需求需要我们去熟练使用Echarts
、Antv
、Highcharts
等开源可视化库。可能还有些定制化的需求,这就需要去深入了解svg
、canvas
更底层的东西。操作svg
的有D3
,canvas
则有Zrender
等。
本文以Echarts
为例,讲解如何运用基本初等函数中的对数函数
去解决极端
数据的业务场景。如果听懂了,其他图表库相信也能触类旁通地解决。
对数函数
对数函数是6
种基本初等函数之一。如果a^x=N(a>0,且a≠1)
,那么数x
叫做以a
为底N
的对数,记作x=logaN
,其中a
叫做对数的底数,N
叫做真数。
一般,函数y=logax(a>0,且a≠1)
叫做对数函数。
由图可看出,随着x
增长,对数函数的增长趋势越来越平缓,本文的解决核心思想也就是利用对数函数增长缓慢的特性。
进入正题 ~
业务场景
模拟下业务场景。 产品经理:js 需要用折线图表展示这份数据。 后端:返回的真实数据类似[212, 0, 0.001, 9, 1, 133, 13200]
可以看出目前数据差异较大,拿Echarts
配置如下所示。
letoption={xAxis:{type:'category',name:'x',data:['Mon','Tue','Wed','Thu','Fri','Sat','Sun']},toolbox:{show:true,feature:{saveAsImage:{type:'png'}}},tooltip:{show:true,trigger:'axis'},yAxis:{type:'value',name:'y',minorSplitLine:{show:true}},series:[{data:[212,0,0.001,9,1,133,13200],type:'line',smooth:true}]};
产品经理:数据差异太大,这图感觉不太行,能不能优化下? 前端:这... 真实数据是这样,能有什么办法?(推锅)给我点时间,我先想想吧。
翻阅Echarts文档,发现轴的type
属性有log
的概念,立马替换,结果如下,跟想像中的不太一样,好像报错了。?
仔细排查 + 搜索引擎,发现是因为0
的原因,毕竟对数x
的定义域是大于0的。所以这里可以改成null
。图是不是就好看很多了,兴奋地叫产品经理过来看效果。
letoption={xAxis:{type:'category',name:'x',data:['Mon','Tue','Wed','Thu','Fri','Sat','Sun']},toolbox:{show:true,feature:{saveAsImage:{type:'png'}}},tooltip:{show:true,trigger:'axis'},yAxis:{type:'log',name:'y',minorSplitLine:{show:true}},series:[{data:[212,null,0.001,9,1,133,13200],type:'line',smooth:true}]};
产品经理:嗯嗯,好看多了,但怎么中间断开了? 前端:因为数据是0,没有了啊。 产品经理:需求是满足了,好想线是连一起的(得寸进尺?) 前端:...
虽然嘴上拒绝,但还是得快速地去想方案,毕竟得优雅
处理。Echarts
没有提供相关解决方案,重新换个库,再研究,有点浪费时间了。自己用canvas
画,更不可能了。那怎么去延伸对数
的思想呢?
在翻阅对数概念时,突然看到一句话:指数函数是对数函数的反函数
,灵光乍现✨。
先将原始数据用对数函数转换一下。
显示的时候再用指数函数转换回来。
这里处理原数据的时候需要+1
处理,显示的时候-1
即可。因为对数在(0,1)
范围内是负数,趋于0
的时候又接近于负无穷。图表数据本身是正数的情况下,映射成负数,更容易误导。
改造成功,如下图所示,线也连一起了,骄傲地把产品经理叫过来。 产品经理:?。 前端:小事小事~。
代码思路如下:
转换数据用Math.log10(d + 1)
即可。
显示数据的时候用Math.pow(10, d) - 1
。图表方面利用Echarts
提供的formatter
格式化显示y轴
和tooltip
。
具体代码如下,即插即用,拿去直接用!!!
//转换原始数据lettransformToLog=(d)=>{returnMath.log10(d+1)}//对数转原始数据lettransformToOrigin=(d)=>{returnMath.pow(10,d)-1}letorginData=[212,null,0.001,9,1,133,13200]letoption={xAxis:{type:'category',data:['Mon','Tue','Wed','Thu','Fri','Sat','Sun']},toolbox:{show:true,feature:{saveAsImage:{type:'png'}}},tooltip:{show:true,trigger:'axis',formatter:function(params){returnparams[0].axisValue+':'+Number(transformToOrigin(params[0].value).toFixed(3))}},yAxis:{type:'value',axisLabel:{formatter:function(value,index){if(value>0){returnMath.pow(10,value)}returnvalue}},minorSplitLine:{show:true}},series:[{data:logData,type:'line',smooth:true}]};
产品需求满足了,但故事还没结束,毕竟标题还有极端
两个字。
这算是自己的疑问吧,如果数据有负数
怎么办,那这又不可行了?毕竟对数定义域是大于0
。 那怎么办?既然是负数,我们是不是可以想到取绝对值
。
若是负数,先取绝对值,再用对数,最后乘以-1
。
显示的时候,再反向操作即可。
首先原数据改为:[212, null, 0.001, 9, 1, -133, 13200]
。先看结果图,优雅
么?
//转换原始数据lettransformToLog=(d)=>{letoperator=1d<0&&(operator=-1)returnMath.log10(Math.abs(d)+1)*operator}//对数转原始数据lettransformToOrigin=(d)=>{letoperator=1d<0&&(operator=-1)return(Math.pow(10,d*operator))*operator-1*operator}letorginData=[212,null,0.001,9,1,-133,13200]letlogData=orginData.map(item=>transformToLog(item))letoption={xAxis:{type:'category',data:['Mon','Tue','Wed','Thu','Fri','Sat','Sun']},toolbox:{show:true,feature:{saveAsImage:{type:'png'}}},tooltip:{show:true,trigger:'axis',formatter:function(params){returnparams[0].axisValue+':'+Number(transformToOrigin(params[0].value).toFixed(3))}},yAxis:{type:'value',axisLabel:{formatter:function(value,index){letoperator=1if(value<0)operator=-1if(value===0)return0returnMath.pow(10,value*operator)*operator}},minorSplitLine:{show:true}},series:[{data:logData,type:'line',smooth:true}]};
总结
先前文章大多是JS
基础,接下来我会分享的更全面一点,比如CSS
、node
、可视化
、浏览器
等,也会继续分享自己的小心得(结合真实业务场景,绝对干货),比如这一篇,看大家兴趣(其实看点赞量了,哈哈哈哈)。
如果本篇文章帮到你了,记得毫不吝啬地三连点赞
+关注
+收藏
啊!!!
当然,也欢迎各路大佬评论
交流学习,批评指正。
作者:瑾行著作权归作者所有。
链接:https://juejin.cn/post/7002074555745304583