首页
博客 前端

120 行 SVG 换掉 204 KB 图表库

数据页只需要四张静态图,却要为此背一个通用图表库。换成自己算几何、自己画 SVG 之后,体积降了 40 倍,还顺手解决了主题跟随。

2 周前 2 分钟读完 459 字

数据页上线时我很满意四张图,直到量了体积:仅图表这一块,构建产物是 613 KB,gzip 后 204 KB。整站其余 JS 加起来才 45 KB。

为什么一个图表库会这么大

图表库默认要照顾:二十几种图类型、坐标系、动画、交互、无障碍、导出、主题。哪怕按需引入,echarts 里坐标轴与组件的公共部分仍然很重。

我用到的能力只有四样:

  • 折线(含面积填充)与刻度
  • 横向条形
  • 环形分段
  • 七行网格的热力块

换掉的思路:几何归几何,渲染归渲染

把「算点」和「画点」拆开,charts.ts 只做纯几何,返回路径字符串和刻度值;组件负责把字符串塞进 <path>。

const yAt = (value: number, domain: { min: number; max: number }) => {
  const ratio = (value - domain.min) / (domain.max - domain.min || 1);
  return plot.bottom - ratio * (plot.bottom - plot.top);
};

const path = points.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x},${yAt(p.value, domain)}`).join(' ');

一行 M/L 拼出来的折线,浏览器渲染质量和图表库没有区别——因为最终都是同样的 SVG 路径。

顺手解决的两个老问题

主题跟随:原来要读 CSS 变量再传给图表库重绘,现在 SVG 直接用 stroke="currentColor" 或读一次变量写进 path,切主题时 MutationObserver 重算一遍就够。

量纲:粉丝三百级、获赞一万六,同一个轴上要么一条贴底、要么刻度出负数。改成每条线各自算 domain,只比走势不比绝对值,图上加一句说明就行。

什么时候该用库

  • 需要缩略图、框选、联动、动态数据量上千点。
  • 团队里没人愿意维护几何代码。

否则先问一句:这张图需要交互吗?如果答案是不需要,手写 SVG 往往是更小的那个选择。代价是热力图的行列索引、弧线的 largeArc 判断这些细节要自己验一遍——我踩过的坑都写进注释了。