最直接方式是用手动画散点图,关键在于将数据坐标线性映射为像素坐标并翻转y轴;chart.js需注意数据格式与坐标轴配置;svg适合静态无交互场景;避免后端生成图片方案。

用 <canvas></canvas> 手动画散点图最直接
HTML 本身不提供散点图组件,<canvas></canvas> 是最轻量、可控性最强的实现方式。适合数据量不大(比如几百个点)、需要自定义样式或交互逻辑的场景。
关键不是“画图”,而是把数据坐标映射到像素坐标——这一步最容易出错:
- 横纵轴范围要先算出数据的
min和max,再做线性缩放,别直接用原始数值当像素值 -
canvas的 y 轴向下为正,而数学坐标系 y 向上为正,必须翻转:y_px = height - (y_data - y_min) / (y_max - y_min) * height - 点太小看不清?至少设
ctx.fillStyle = '#3b82f6'并用ctx.fillRect(x-2, y-2, 4, 4)或ctx.arc()画实心圆
用 Chart.js 的 scatter 类型省事但要注意配置
Chart.js 支持原生散点图,但默认行为和你想象的可能不一样:它会自动按 x 值排序,且 x/y 轴默认是数值轴(type: 'linear'),不是分类轴。
常见踩坑点:
- 数据格式必须是对象数组:
[{x: 1.2, y: 3.5}, {x: 2.7, y: 1.8}],不能传两个平行数组 - 如果 x 是时间(如
'2023-01-01'),得显式设xAxis.type = 'time'并引入chartjs-adapter-date-fns - 点大小固定?改
pointRadius;想按数据大小缩放?得用pointRadius: function(ctx) { return Math.sqrt(ctx.raw.y) * 2; }
用 SVG 手写 <circle></circle> 适合静态图或服务端渲染
如果图表不需交互、只展示一次(比如邮件报表、PDF 导出前的 HTML 预览),纯 SVG 更语义清晰、缩放不失真。
核心就是循环生成 <circle></circle> 标签:
<svg width="600" height="400" viewbox="0 0 600 400"><circle cx="120" cy="320" r="4" fill="#10b981"></circle><circle cx="240" cy="260" r="4" fill="#8b5cf6"></circle></svg>
注意:viewBox 定义坐标系范围,比写死 width/height 更灵活;所有坐标都要提前归一化到 viewBox 范围内,否则点会跑出画布。
别碰 <img> + 后端绘图这种方案
有人图省事让后端生成 PNG 返回给前端显示。问题很实在:
- 无法响应式缩放(图片模糊)
- 没法加 hover 提示、点击事件、动画过渡
- 每次改数据都要发请求,调试成本高
除非你在嵌入式设备上跑一个连 JS 都不敢开的浏览器,否则这个方案在现代前端里基本等于主动放弃维护性。
真正麻烦的从来不是“怎么画点”,而是坐标映射是否健壮、空数据/异常值怎么处理、缩放拖拽时性能会不会掉帧——这些细节藏在第一行绘图代码之后。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











