个人技术分享

技术笔记

用 Canvas 画图表,而不是先引一个库

· 标签:可视化 · Canvas

需要画一张折线图时,直觉是先找一个图表库。但如果需求只有"把一组数据画成线",引入一个几百 KB 的库,意味着你要接受它的默认样式、它的配置体系,以及它带来的加载体积。

先把坐标映射写对

画图的核心只有一件事:把数据值映射到画布像素。这一步写错,后面怎么调样式都是白费。

// 数据值 → 像素坐标
const x = i => pad + (i / (data.length - 1)) * (W - pad * 2);
const y = v => H - pad - ((v - min) / (max - min || 1)) * (H - pad * 2);

注意 max - min || 1:当所有数据点相同时分母会是 0,映射结果直接变成 NaN,整张图消失。这种边界情况在真实数据里很常见,必须处理。

devicePixelRatio 不做处理,图一定是糊的

在 Retina 或高 DPI 屏上,把 canvas 的 CSS 尺寸直接当画布尺寸用,线条会发虚。正确做法是把画布实际像素放大 dpr 倍,再用 CSS 把它缩回去:

const dpr = window.devicePixelRatio || 1;
canvas.width  = W * dpr;
canvas.height = H * dpr;
canvas.style.width  = W + 'px';
canvas.style.height = H + 'px';
const ctx = canvas.getContext('2d');
ctx.scale(dpr, dpr);

三种常见图形的基本画法

直接标注,比画坐标轴划算

自己实现坐标轴、刻度、网格线,是这类"手写图表"最费时间的部分,收益却很低。如果数据点不多,把数值直接写在折线末端或柱子顶部,读者反而更快获取信息——省掉了眼睛在轴和图元之间的来回移动。

必须做的一个降级处理

Canvas 里的内容对屏幕阅读器和搜索引擎都是不可见的。至少要给 <canvas> 加上替代说明,并把关键数值用文本形式列在图表下方。这既是无障碍要求,也避免图挂了之后页面变成一片空白。

什么时候该换成成熟库

出现下面任一情况,别再自己写了:需要缩放、框选、十字准线等交互;数据点上万需要增量渲染和抽稀;需要堆叠、桑基、力导等复杂图型;团队里其他人也要维护这些图。省下的几百 KB 换不来这些功能的开发与调试成本。

判断标准可以简化成一句:只是展示一组趋势,就手写;需要让人和图表交互,就用库。

← 返回首页