颜色映射需数值域、色系、渲染目标三者校准:用数据算domain防截断,色盲友好选blue-orange渐变并加纹理,css变量不支持计算须js注入颜色值,webgl需手动转css颜色为数值数组。

颜色映射必须绑定数值区间,不能只靠视觉猜
数值到颜色的转换不是“选个好看渐变”就完事——如果 min 和 max 没对齐真实数据分布,再漂亮的配色也会误导人。比如用 d3.scaleLinear() 时传了 [0, 100] 当域(domain),但实际数据最大值是 127,所有超过 100 的值都会被截断到最深色,丢失区分度。
实操建议:
- 始终用数据本身算域:
d3.extent(data, d => d.value)或math.min(...values)/Math.max(...values) - 警惕离群值:若存在极端异常值(如
9999),考虑用分位数(quantile)或 winsorize 处理,而不是直接用min/max - 离散映射(如分类)别误用连续标尺:该用
d3.scaleOrdinal()就别硬套scaleLinear()
CSS 自定义属性(CSS vars)无法直接参与数值计算
想用 --color-min 和 --color-max 在 CSS 里做插值?不行。CSS 不支持运行时数值运算,var(--color-min) 只能当字符串用,没法和 JS 里的数值联动。
常见错误现象:
立即学习“前端免费学习笔记(深入)”;
- 在
:root定义了--value: 42,然后指望background: hsl(calc(var(--value) * 2), 70%, 60%)生效 → 实际无效,calc()不支持变量嵌套计算 - 把颜色映射逻辑全塞进 CSS,结果发现响应式重绘时颜色不更新,因为 CSS 没法监听 JS 数据变化
正确做法是:JS 算好颜色值(如 rgb(80, 120, 200)),再通过 element.style.setProperty('--mapped-color', color) 注入,CSS 仅负责接收和渲染。
色盲友好性不是加个滤镜,而是换色系+加纹理/形状辅助
用红绿映射温度或涨跌,对红绿色觉障碍者基本等于黑白图。单纯调亮度或加 opacity 不解决问题,必须从色相选择入手。
实操建议:
- 优先选
blue→orange或blue→yellow渐变,避开红/绿/棕邻近色区 - 用
ColorBrewer的Paired或Viridis调色板(它们已通过色觉缺陷模拟测试) - 关键数据点叠加图标(▲/▼)、边框虚实或点线样式,别只依赖颜色区分
- 检查工具推荐:
chrome DevTools → Rendering → Emulate vision deficiencies
WebGL / canvas 绘图时,CSS 颜色字符串要转成数值数组
Canvas fillStyle 或 WebGL uniform 接收的是 RGB 数值(0–255 或 0–1),不是 #ff6b6b 或 hsl(12, 100%, 60%) 这类字符串。JS 里没自动转换,写错会静默失败或渲染为黑色。
容易踩的坑:
- 直接把
getComputedStyle(el).color返回的rgb(255, 107, 107)字符串传给gl.uniform3f()→ 报错或无效果 - 用
ctx.fillStyle = colorString是 OK 的,但同一套逻辑复制到 WebGL 就崩
快速转换示例:
function parseCSSColor(colorStr) { const match = colorStr.match(/rgb((d+), (d+), (d+))/); return match ? [match[1]/255, match[2]/255, match[3]/255] : [0,0,0]; } // 用法:gl.uniform3f(uColor, ...parseCSSColor("rgb(255, 107, 107)"));
颜色映射最麻烦的从来不是怎么画出来,而是怎么让不同人、不同设备、不同数据分布下,看到的“深浅”真对应“大小”。数值域、色系选择、渲染目标三者必须同步校准,漏掉任一环,可视化就从表达工具变成误导源头。