y轴数据变换利器——yaxis-transformer

仓库

yaxis-transformer已经发布到npm, 点击查看源码, 欢迎star。git

前言

前不久笔者分享过y轴数据处理方案的基本思路,当时需求比较紧张,苦于没有时间去整理代码。如今恰好空闲下来,回头看看以前的代码,发现存在几个问题:业务侵入性太强, 定制化能力太弱和方案设计不够合理。因此决定这一次趁热打铁,对整个方案从新设计,将y轴的数据变换能力抽成底层功能库,而且提供足够强的定制化能力。这样的好处是能够移出以前的业务逻辑代码,避免库逻辑混乱和过于累赘,将业务逻辑的处理转交给使用者。github

分析

整个方案大体能够分四个步骤:npm

  • 处理最小值minData,找出规整间距interval,计算最大值maxData;
  • 找出须要格式化的单位unit;
  • 计算建议小数位数adviseDecimal;
  • 生成最终结果transformResult。

1. 数据处理

如下例子使用的count=3,即总共生成四个数据。数组

  • 首先是处理最小值minData, 首先根据原始的interval获得规整的基准值baseInterval, baseInterval的做用是找出minData须要处理的部分remainPart,例如minData为1542,baseInterval为200,那么可知remainPart为542,接着再对remainPart进行查找基准值的操做,假定结果为500,那么处理以后的minData就为1000 + 500 = 1500。bash

  • 找出规整间距interval,根据前面处理的minData和原始的maxData,再根据基准值生成的策略获得新的间距,如minData=1000, maxData=6100, interval=1700, 生成的基准值数组为1000, 2000, 5000, 生成的策略以下:post

defaultBaseGenStrategy = (originInterval: number) =>  {
        let base = AxisHelper.genPowNum(originInterval)
        return [10 * base, 5 * base, 2 * base, base]
  }
复制代码

那对于间距来讲,须要取出第一个比它大的数,因此可算出interval就是2000。ui

  • 最大值就等于 minData + count * interval

2. 找出格式化单位

一般会预设一组用于格式化的单位,例如:[{range: 10000, unit: "万"}, {range: 100000000, unit: "亿"}]
若是超过range,则使用相对应的unit。
特别地,对于百分数的状况使用的单位以下:{range:0.01, unit:"%"}
对于单位的格式化,主要在于使用哪一个值用来作单位的查找,所以我提供了maxData和minData两种选择。spa

3. 计算建议小数位数

因此建议的小数位数,我这里的定义是指在单位unit的格式化下,仍然能完整显示出全部有效的小数位数。例如一组数据[100, 10100, 20100],单位是{range: 10000, unit: "万"}, 那么建议的小数位数就是2,这样格式化出来的数据就是[0.01万, 1.01万,2.01万]。
关键的地方在于找出最小值min和参考值reference,最小值是为了保证有效的数据输出,而reference则是min用于参考的值。如上,min为100,reference为20100, 那么单位就为万,小数位数为2。设计

4. 生成结果

当完成上述步骤,结果就已经呼之欲出。最后就是生成相应的数组,格式大体以下:code

{
   data: [0, 10000, 20000, 30000],
   dataUnit: ['0.00', '1.00万', '2.00万', '3.00万'], 
   adviseDecimal: 1 
 }
复制代码

使用

const yaxisTransformer = new YaxisTransformer([1542, 6100])
    let transformResult  = yaxisTransformer
     .withCount(3)
     .withMinToZero(false)
     .withUnitFollowMax(false)
     .withFormatRuler((data, decimal) => {
         return data.toFixed(decimal)
     })
     .withUnitSet([{range:10000, unit:"万"}])
     .transform()

复制代码

经过建造者模式,增长灵活的定制化配置,目前有的配置以下:

  • withCount 设置生成间距的数量,四个数的数组count即为3
  • withUnitSet 设置格式化单位,默认为 [{range: 10000, unit: "万"}, {range: 100000000, unit: "亿"}]
  • withPercentUnit 使用百分比作格式化
  • withMinMaxData 设置最大值最小值
  • withBaseGenStrategy 设置基准值生成策略,默认为
defaultBaseGenStrategy = (originInterval: number) =>  {
        let base = AxisHelper.genPowNum(originInterval)
        return [10 * base, 5 * base, 2 * base, base]
  }
复制代码
  • withFormatRuler 设置格式化小数位数的规则,默认为 number.toFixed(decimal)

  • withForceDecimal 强制设置小数位数

  • withKeepZeroUnit 是否保留0的单位

  • withKeepUnitSame 数组里的每一个值单位是否保持单位一致

  • withUnitFollowMax 格式化的单位否是参考最大值

  • withMinToZero 最小值< 间距时,是否取0, 如min=100,interval为1000,是否令min = 0

  • withKeepZeroDecimal 是否保持0的小数位数,如0.00是否格式化为0

提供了大量能想到用以配置的属性。

总结

对于底层通用库,亟需遵照开闭原则,对扩展开放,对修改封闭,对于npm的库,自然就是封闭的,因此开放就须要提供足够的定制化能力,减小本身业务逻辑的侵入。

致谢

相关文章
相关标签/搜索