// data :参数列表这里指代坐标列表
// threshold:采样后数量
// respectNullValue:采样过程中是否保留 null
const Downsample = (data, threshold, respectNullValue = true) => {
// this function is from flot-downsample (MIT), with modifications
var dataLength = data.length;
// 阈值检查
if (threshold >= dataLength || threshold <= 0) {
return data;
}
var sampled = [],
sampledIndex = 0;
// dataLength - 2 排除起始元素
// threshold - 2 预留起始数据位置
// every 计算每个数据点之间的间隔
var every = (dataLength - 2) / (threshold - 2);
var a = 0, // a代表当前选择的“锚点”,用于构建三角形并计算面积的关键点之一
maxAreaPoint,
maxArea,
area,
nextA;
// 添加初始数据 注意:sampledIndex++是将sampled[0]添加后为下一个数据点做准备
sampled[sampledIndex++] = data[a];
for (var i = 0; i < threshold - 2; i++) {
// 计算下一个区间平均值
var avgX = 0,
avgY = 0,
avgRangeStart = Math.floor((i + 1) * every) + 1,
avgRangeEnd = Math.floor((i + 2) * every) + 1;
avgRangeEnd = avgRangeEnd < dataLength ? avgRangeEnd : dataLength;
var avgRangeLength = avgRangeEnd - avgRangeStart;
let hasNullValue = false;
for (; avgRangeStart < avgRangeEnd; avgRangeStart++) {
if (respectNullValue && data[avgRangeStart].y === null) { // 总是添加null值
sampled[sampledIndex++] = data[avgRangeStart]
hasNullValue = true;
break;
} else {
avgX += data[avgRangeStart].x * 1; // * 1 强制数据格式
avgY += data[avgRangeStart].y * 1;
}
}
if (hasNullValue)
continue;
avgX /= avgRangeLength;
avgY /= avgRangeLength;
// 获取当前区间范围
var rangeOffs = Math.floor((i + 0) * every) + 1,
rangeTo = Math.floor((i + 1) * every) + 1;
// 前一个选择的点
var pointAX = data[a].x * 1,
pointAY = data[a].y * 1;
maxArea = area = -1;
for (; rangeOffs < rangeTo; rangeOffs++) {
// 计算三角形面积
area = Math.abs((pointAX - avgX) * (data[rangeOffs].y - pointAY) -
(pointAX - data[rangeOffs].x) * (avgY - pointAY)
) * 0.5;
if (area > maxArea) { // 更新最大三角形面积
maxArea = area;
maxAreaPoint = data[rangeOffs];
nextA = rangeOffs;
}
}
sampled[sampledIndex++] = maxAreaPoint; // 保存当前区间最具代表性点位
a = nextA; // 更新参考点
}
sampled[sampledIndex] = data[dataLength - 1]; // 添加最后元素
return sampled;
}
数据采样函数,主要用于数据可视化时减少图形的复杂度,同时保持数据的整体特征
最新推荐文章于 2024-07-16 17:18:30 发布