场景
在使用echarts的时候,将接口拿到的数据自定义去做一些按比例显示,通常是通过将各数相加然后除每一个数再四舍五入再乘以100%而得到百分比, 但是这样得出的数据想加可能会出现不等于100%的情况,如下
比如接口拿到的数据为[1, 1, 5] => [14.29%, 14.29%, 71.43%]
14.29 + 14.29 + 71.43 === 100.01 !== 100
解决方案
echarts本身没有该问题是使用了一个叫做最大余额的算法,所以可以参考该算法,自定义去处理百分比数据
/**
* 最大余额法(用于和echarts数据百分比一致,加上所有百分比应为100)
* @param valueList 数组数据
* @param idx 数组下标
* @param precision 精度
* @returns {number}
*/
export function getPercentValue(valueList, idx, precision) {
// 判断是否为空
if (!valueList[idx]) {
return 0
}
// 数组数据求和,若和为0则返回0
const sum = valueList.reduce((a, c) => {
return (a += isNaN(c) ? 0 : c)
}, 0)
if (sum === 0) {
return 0
}
// 10的二次幂是100, 用于计算精度
const digits = Math.pow(10, precision)
// 扩大比例100
const votesPerQuota = valueList.map(val => {
return ((isNaN(val) ? 0 : val) / sum) * digits * 100
})
// 总数,扩大比例意味总数要扩大
const targetSeats = digits * 100
// 再向下取值,组成数组
const seats = votesPerQuota.map(votes => {
return Math.floor(votes)
})
// 在新计算合计,用于判断与总数量是否相同,相同则占比会100%
let currentSum = seats.reduce((a, c) => {
return a + c
}, 0)
// 余数部分的数组:原先数组减去向下取值的数组,得到余数部分的数组
const remainder = votesPerQuota.map((votes, idx) => {
return votes - seats[idx]
})
while (currentSum < targetSeats) {
let max = Number.NEGATIVE_INFINITY
let maxId = null
for (let i = 0; i < remainder.length; i++) {
if (remainder[i] > max) {
max = remainder[i]
maxId = i
}
}
// 对最大余额项加1
++seats[maxId]
// 已经对最大余数加1,则下次判断就跳过该余额数
remainder[maxId] = 0
// 总的也要加1,用来结束循环
++currentSum
}
return seats[idx] / digits
}
const arr = [1, 1, 5]
console.log(getPercentValue(arr, 0, 2)) // 14.29
console.log(getPercentValue(arr, 1, 2)) // 14.28
console.log(getPercentValue(arr, 2, 2)) // 71.43
// 14.29 + 14.28 + 71.43 = 100