线性比例变换是将数据域映射到屏幕像素范围的核心方法,通过 y = a·x + b 实现;需明确数据最小/最大值与画布可用范围,并对y轴翻转处理;函数支持正向映射、逆映射及边界容错。

接口返回的图表坐标轴数据通常是一组原始数值(比如时间戳、温度值、用户量等),而 Canvas 或 SVG 渲染需要的是像素位置。数学映射就是把「数据域」(data domain)线性(或非线性)地转换到「显示域」(screen range),核心是**线性比例变换**,即 y = a·x + b。
明确两个关键区间:数据范围与画布范围
映射前必须知道:
- 数据最小值和最大值(例如 xData = [1609459200000, 1609545600000] 表示两天的时间戳)
- 目标画布可用像素范围(例如绘图区域宽 600px,左边界留白 60px,右边界留白 20px → 可用 x 范围是 [60, 580])
这两个区间一一对应,才能建立单射关系。注意:y 轴常需「翻转」,因为数据中 y 增大表示值升高,但屏幕坐标系 y 增大是向下延伸。
写一个通用的 scale 函数(线性映射)
不用依赖 D3 时,可手写简洁映射器:
function createScale(domain, range) {
const [dMin, dMax] = domain;
const [rMin, rMax] = range;
const scale = (value) => rMin + (value - dMin) * (rMax - rMin) / (dMax - dMin);
scale.invert = (pixel) => dMin + (pixel - rMin) * (dMax - dMin) / (rMax - rMin);
return scale;
}
<p>// 示例:横轴时间映射到 60~580px
const xScale = createScale([1609459200000, 1609545600000], [60, 580]);
console.log(xScale(1609459200000)); // → 60
console.log(xScale(1609545600000)); // → 580</p><p>// 示例:纵轴值映射(注意翻转:数据大 → 像素小)
const yScale = createScale([0, 100], [300, 40]); // [数据最小, 最大] → [画布顶部y, 底部y]
console.log(yScale(0)); // → 300(顶部)
console.log(yScale(100)); // → 40(底部)
</p>
处理常见边界情况
-
数据全相同(dMin === dMax):避免除零,此时所有点映射到区间中点,例如
rMin + (rMax - rMin) / 2 -
数据含 NaN 或 null:提前过滤或替换为 fallback 值,否则映射结果为
NaN -
对数/指数映射需求:改用
log10(value)或Math.sqrt(value)预处理 domain,再套线性映射 -
日期类型自动适配:用
new Date().getTime()统一转毫秒,确保 domain 是纯数字
配合图表绘制直接使用(Canvas 示例)
假设你有一组 { time, value } 数据点:
const data = [
{ time: 1609459200000, value: 23 },
{ time: 1609462800000, value: 27 },
{ time: 1609466400000, value: 31 }
];
<p>const ctx = canvas.getContext('2d');
ctx.beginPath();
data.forEach((d, i) => {
const x = xScale(d.time);
const y = yScale(d.value);
if (i === 0) ctx.moveTo(x, y);
else ctx.lineTo(x, y);
});
ctx.stroke();
</p>
这样每一点都准确落在逻辑位置,缩放、平移只需重算 domain 和 range,scale 函数复用即可。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











