<p>Canvas绘制折线图的核心是数据到像素的坐标系转换:因Canvas原点在左上角且Y向下增长,需用公式“像素Y = chartHeight - ((dataY - yMin) / (yMax - yMin)) × chartHeight”将数学坐标系映射为视觉正确的倒置Y轴,再配合X轴映射、样式化坐标轴与网格线、数据点渲染及交互逻辑。</p>

Canvas 绘制带样式的折线图,核心不在“画线”本身,而在于把真实数据准确映射到像素坐标,并让坐标系符合人眼习惯——即 Y 轴数值越大,位置越靠上(数学直角坐标系),但 Canvas 默认 Y 向下增长。这中间必须做一次坐标系转换,否则折线会倒置、标签错位、交互失准。
理解 Canvas 坐标系与数学坐标的差异
Canvas 原点在左上角,X 向右递增,Y 向下递增;而折线图中我们期望:原点在左下角(或可配置的图表底部),Y 值越大,点越靠近顶部。因此不能直接用原始数据值作为 canvas 的 y 坐标。
关键转换公式(假设图表绘图区高度为 chartHeight,Y 数据范围为 [yMin, yMax]):
- 像素 Y = chartHeight - ((dataY - yMin) / (yMax - yMin)) × chartHeight
- 像素 X = leftMargin + ((dataX - xMin) / (xMax - xMin)) × usableWidth
其中 leftMargin 和 usableWidth 是为坐标轴、标签预留的边距后的真实绘图宽度。这个映射保证了数据比例不失真,且视觉方向正确。
绘制带样式的坐标轴与刻度标签
样式不只是颜色粗细,更包括可读性设计:Y 轴标签需右对齐并留出间隙,X 轴标签需居中避免重叠,箭头需小而明确,网格线宜浅灰虚线。
- 用
ctx.textAlign = 'right'+ctx.textBaseline = 'middle'对齐 Y 标签 - X 轴标签用
ctx.textAlign = 'center',并在每个刻度下方垂直居中 - 网格线建议用
ctx.setLineDash([2, 4])实现细腻虚线,不干扰主折线 - 坐标轴线宽设为 1.5,箭头用两个短斜线模拟,避免复杂路径影响性能
数据点映射与折线样式控制
每个数据点需先经上述公式转为 canvas 坐标,再统一处理样式逻辑:
- 折线使用
ctx.lineWidth和ctx.strokeStyle控制粗细与颜色 - 数据点圆圈用
ctx.beginPath() → ctx.arc() → ctx.fill(),半径建议 4–6px - 悬停高亮?可在
mousemove中计算当前点距离,若Math.hypot(x - e.x, y - e.y) 则重绘该点为更大尺寸+描边 - 若有多条折线,每条应有独立颜色、点样式(如方形/圆形/三角形),并配套图例
封装时保留可配置的映射参数
真正复用的组件,不应硬编码坐标范围。应支持传入:xRange、yRange(或自动计算)、margin、gridColor、lineStyle 等。例如:
chart.draw({
data: [{x: 1, y: 23}, {x: 2, y: 41}, ...],
xRange: [1, 10],
yRange: [0, 100],
margin: {top: 20, right: 30, bottom: 40, left: 60},
lineColor: '#4a90e2',
pointRadius: 5
})这样既适配不同量纲(温度 vs 百分比),也便于响应式缩放——只需重算 usableWidth/Height,映射关系不变。


















