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

仓库

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

前言

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

分析

整个方案大致可以分四个步骤:

  • 处理最小值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。

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

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

那对于间距来说,需要取出第一个比它大的数,所以可算出interval就是2000。

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

2. 找出格式化单位

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

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. 生成结果

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

{
   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的库,天然就是封闭的,所以开放就需要提供足够的定制化能力,减少自己业务逻辑的侵入。

致谢

转载于:https://juejin.im/post/5d0a43cc6fb9a07ebb053842

猜你喜欢

转载自blog.csdn.net/weixin_34067102/article/details/93164808