南丁格尔玫瑰图必须用SVG+d3.js实现,因其本质是极坐标下面积正比于数据值的扇形图,需通过d3.scaleSqrt()将数值映射为半径(outerRadius ∝ √value),设innerRadius=0确保面积∝value;纯CSS或Canvas无法满足数学精度与交互需求。

用 SVG + d3.js 画南丁格尔玫瑰图最靠谱
纯 HTML/CSS 做不了真正的南丁格尔玫瑰图——它本质是极坐标下的扇形面积图,必须靠数学计算半径和角度,再生成路径。浏览器原生不支持极坐标绘图,所以得用 SVG 手动画 <path></path>,或借助 d3.js 这类库封装好的 d3.pie() 和 d3.arc()。网上很多“CSS 玫瑰图”只是旋转叠加的饼图伪效果,数据一变就错位、不响应、面积也不正比于数值。
实操建议:
- 优先用
d3.js v7+,它的d3.scaleRadial()和d3.arc().innerRadius()/outerRadius()能直接映射数据到极径,避免手算平方根(面积正比于数值,半径就得正比于 √数值) - 别用
canvas:重绘复杂、无 DOM 事件穿透、缩放失真,交互成本高 - 如果项目已用
echarts,可启用series.type: 'pie'+roseType: 'area',但注意它默认按角度均分,要设radius: ['20%', '80%']并手动用data[i].value控制半径,否则不是严格南丁格尔
d3.arc() 的 innerRadius 和 outerRadius 怎么设才对
南丁格尔的核心是:每个扇形的面积 ∝ 数据值。而扇形面积 = ½ × (R² − r²) × θ,若所有扇形角度 θ 相同(即等分圆),那就要让 R² − r² ∝ value。最常用做法是统一设 innerRadius: 0,只变 outerRadius,此时面积 ∝ R²,所以 outerRadius 必须设为 Math.sqrt(value) 的线性映射。
示例关键代码:
const radiusScale = d3.scaleSqrt() .domain([0, d3.max(data, d => d.value)]) .range([0, 200]); // 最大半径 200px const arc = d3.arc() .innerRadius(0) .outerRadius(d => radiusScale(d.value)) .startAngle(d => d.startAngle) .endAngle(d => d.endAngle);
常见错误:
- 直接用
value当半径:导致大值扇形面积爆炸式膨胀,视觉严重失真 - 忘了归一化:不同量级数据混在一起时,
scaleSqrt输入域没覆盖全范围,小值被压缩成看不见 -
innerRadius设成固定非零值(如 50):这时必须同步调整outerRadius使 R² − 50² ∝ value,否则面积比例就崩了
IE 不支持?Math.sqrt 和 scaleSqrt 兼容性怎么处理
d3.scaleSqrt 在 d3 v4+ 中依赖 Math.sqrt,而 IE9+ 是支持的;真正卡住的是 IE 对 SVG 的部分属性(比如 transform="rotate()" 在 <g></g> 上的累积精度误差),以及没有 Array.prototype.find 这类方法。不是算法问题,是运行时环境缺失。
兼容方案:
- 用
babel-polyfill或core-js补Array.find、Promise等(d3 内部会用) - 避免在 IE 中用
transition()动画,直接attr()静态渲染,否则扇形可能错位 - 如果必须支持 IE8,放弃
d3,改用Raphaël.js(基于 VML),但功能弱、维护停更,仅作保底 - 现代项目建议明确声明不支持 IE,用
caniuse查svg+sqrt覆盖率,实际 >98%
数据有负值或零值时,scaleSqrt 直接报错怎么办
scaleSqrt 输入负数会返回 NaN,导致 outerRadius 失效,整个 <path></path> 渲染失败。南丁格尔图本身不支持负值——面积不能为负。但现实数据常有零或空缺,必须预处理。
安全做法:
- 过滤掉
value 的项,或用 <code>Math.max(0.1, d.value)给个最小底值(0.1 可调),避免 sqrt(0) 后半径为 0 导致扇形消失 - 若业务上“零”有意义(比如占比 0%),应改用普通环形图(
innerRadius > 0),而非南丁格尔 - 后端返回前就做清洗:把负值转为
null,前端用d3.filter(d => d.value > 0)截断,比运行时判断更干净
南丁格尔图的“面积正比”是硬约束,任何绕过平方根映射的取巧(比如线性缩放+强行裁剪)都会让图表失去统计意义。这点容易被忽略,但恰恰是它和普通饼图的本质区别。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











