坐标轴取值算法分享

767 阅读2分钟

echarts 绘制图表的时候,坐标轴上的刻度是如何取值的,刻度间隙又是多少?

最近自己用 canvas 绘制了一个 k线图 (惭愧惭愧....),分享一下刻度取值的计算思路

image.png

前戏思考

  • 希望刻度间隔都是好看的数
  • 希望刻度间隔数量不要太密集,也不要太稀松

定义一个好看的数的集合,我希望刻度间隔是这里的其中一个

const intervals = [300, 200, 100, 50, 30, 20, 10, 5, 4, 3, 2, 1]

定义最大间隔数量 和 最小间隔数量,我希望间隔数量在两者之间

const minCount = 4
const maxCount = 7

大概思路

intervals遍历, 暂时认为理想间隔是当前项,计算出理想最大值和理想最小值,之后用理想最大值减去理想最小值,得到的差除以当前项,得到的是间隔数量,判断间隔数量是否在最大间隔数量 和 最小间隔数量之间,如果在 -> 得到答案,退出循环; 如果不在 -> 继续遍历

初始数据

首先会有一些原始的随机数据 [123, 223, 423, 124, 156, 458]

理想结果

坐标轴刻度取值:[100, 200, 300, 400, 500]

计算步骤

找出最大值与最小值

找出最大值与最小值后,分别向上和向下取得理想的峰值刻度(100 和 500)

理想的峰值刻度是当前间隔的整数倍,且距离最大值和最小值最近。

比如:

  • 间隔是100,最大值是233,最小值是50,理想的峰值刻度 是 0 和300
  • 间隔是50,最大值是233,最小值是50,理想的峰值刻度 是 50 和250

最终结果还要看间隔数量是否符合

比较求出的间隔数量是否在最大间隔数量 和 最小间隔数量 之间

上一步求出的理想峰值刻度的差除以当前间隔,与 minCountmaxCount 比较

完结撒花

全部代码

// 使用 
calcPerfect(268, 35)
calcPerfect(78, 40)

function calcPerfect(max, min) {
    const intervals = [300, 200, 100, 50, 30, 20, 10, 5, 4, 3, 2, 1]
    const minCount = 4
    const maxCount = 7

    let perfectCount
    let perfectInterval

    let perfectMax
    let perfectMin

    for (const inter of intervals) {
        perfectMax = ceil(max, inter)
        perfectMin = floor(min, inter)

        const decimalCount = (perfectMax - perfectMin) / inter
        if (decimalCount >= minCount && decimalCount <= maxCount) {
            perfectCount = Math.ceil(decimalCount)
            perfectInterval = inter
            break
        }
    }

    return { perfectMax, perfectMin, perfectInterval }

    // return 100
    function floor(num = 123, multiple = 100) {
        const stack = []
        let i = 0
        while (!stack.length || stack[stack.length - 1] <= num) {
            stack.push(i * multiple)
            i++
        }
        stack.pop()
        return stack.pop()
    }
    // return 200
    function ceil(num = 123, multiple = 100) {
        const stack = []
        let i = 0
        while (!stack.length || stack[stack.length - 1] <= num) {
            stack.push(i * multiple)
            i++
        }
        return stack.pop()
    }
}