跳转到内容

计算每个数据值对应的高度比例

ts
/**
 * 计算每个数据值对应的高度比例(范围 0-1)。
 *
 * @param arr 输入的数据数组。
 * @returns 返回每个数据值对应的高度比例数组,范围 0-1。
 */
export function calculateHeightPercentages(arr: number[]): number[] {
  /**
   * 确保浮点数计算的精度,忽略小的浮点数误差
   */
  function fixedNum(num: number) {
    if (('' + num).indexOf('.') >= 0) num = parseFloat(num.toFixed(8))
    return num
  }

  const magic = [10, 15, 20, 25, 30, 40, 50, 60, 70, 80, 90, 100] // 魔数数组
  const splitNumber = 4 // 理想的刻度间隔段数
  const max = Math.max(...arr) // 获取数据中的最大值
  const min = Math.min(...arr) // 获取数据中的最小值

  // 计算初始刻度间隔的大小
  let tempGap = (max - min) / splitNumber
  // 计算缩放比例 multiple,使得 tempGap 落在魔数数组的区间内
  let multiple = Math.floor(Math.log10(tempGap) - 1)
  multiple = Math.pow(10, multiple)

  // 计算映射后的间隔大小 tempStep
  let tempStep = tempGap / multiple
  let estep: number = magic[magic.length - 1] * multiple // 默认取最大的魔数对应步长

  // 取出第一个大于 tempStep 的魔数,并乘以 multiple 作为期望得到的最佳间隔
  for (let i = 0; i < magic.length; i++) {
    if (magic[i] > tempStep) {
      estep = magic[i] * multiple
      break
    }
  }

  // 定义最大刻度和最小刻度
  let maxi = parseInt(String(max / estep + 1)) * estep
  let mini = parseInt(String(min / estep - 1)) * estep
  maxi = fixedNum(maxi)
  mini = fixedNum(mini)

  // 返回每个数据值对应的高度比例
  return arr.map((value) => (value - mini) / (maxi - mini))
}

// 测试用例
console.log(calculateHeightPercentages([128, 565, 35, 56]))
/*
[
  0.21333333333333335,
  0.9416666666666667,
  0.058333333333333334,
  0.09333333333333334
]
*/