-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
可以改进给题目类别随机分配颜色的算法 #93
Comments
当前的生成算法是有意设计的,采用了 CIELUV 色彩空间。HSV 或 HSL 色彩空间没有考虑人眼对色彩的感知,固定 L 分量生成的颜色的亮度并不是相同的。color.js 依赖就是用于计算 CIELUV 色彩空间与 sRGB 色彩空间转换的。 之所以没采用把亮度固定为常数的做法,而是在 0% ~ 50% 随机生成,是因为同一个视觉感受亮度下存在的颜色实在太少了,无论如何生成都不会显得丰富。下图展示了将视觉感受亮度(L* 分量)固定在 35% 时,可以使用的所有颜色(横纵轴分别是 u* 和 v* 分量): 另外,红色盲用户感知不到 u* 分量,如果 L* 分量被固定,将只剩下 v* 这一个维度,颜色更单调。将 L* 分量也随机生成,可以让生成的颜色较为丰富。 用类别名称作为种子,用确定性伪随机数来生成颜色,是因为不然的话类别序号 i 没有好的定义。确定性生成算法有诸多好处,比如不同部署实例上相同名字的类型颜色相同,测试环境和生产环境效果相同,即使删除后重新添加了类别,或者进行了其他调整,也不会导致选手们发现“类别的颜色怎么突然变了”,也不会泄露后台信息(选手看到类别的颜色只有 i = 2 3 4 的,就可以猜测还有一个隐藏的类别 i=1,不知为何没有出现)。 |
(其实只要把 L* 的范围限制在一个比较小的区间内,然后在生成颜色时考虑一下相邻颜色不要太接近,也可以在不抛弃 CIELUV 的前提下解决上面两条) |
我倒是认为这种标签完全可以亮度和对比度不同。其实 HSL 生成的结果(原文的那个最终结果图)看起来亮度和对比度就是不同的,有一些标签明显比别的更“突出”,但五颜六色的感觉还不错啊。另一个参考:GitHub 上 issue labels 的颜色,默认用户头像的颜色,以及其他一些这样随机生成颜色的系统,其实也不固定亮度和对比度的。
啊这,科大的 hackergame 虽然尽了很大努力不在题目公开后调整顺序或增减题目,但这个项目希望尽量写得通用一些,不要假定这种情况不会发生。目前这个项目的一个 fork 就被用来提供一个长期存在的网站,会不断调整题目和分类的。 所以,如果类别名能被事先确定,保证不增减,并且可以枚举,整个问题都很好办。现在的难点主要还是来自于上游这个代码要写成通用的,应当可以妥善应对各种情况。在这个前提下我感觉选择很少。。。建议下游如果符合“类别名可以确定 + 可以枚举”这个使用场景的话,自行把 JS 中“类别名 -> 颜色”的算法改成一个 switch 语句(或者查表)即可😂 |
我觉得这个问题不需要大家讨论出一致的观点,题主可以提一个 PR,把色彩改成可以配置的,一个配置选项是使用哪种色彩空间,另一个配置选项是按顺序分配颜色还是按题目名称的哈希分配颜色。 |
目前hackergame系统给类别分配颜色的途径是 随机生成一个颜色。
这样会有两个问题,其一是相邻的类别有几率变成很相似的颜色,难以区分;其二是生成的颜色亮度不均匀,对易读性不友好。
https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/ 提出可以在 HSV 色彩空间上生成颜色,固定明度和饱和度,每生成一种颜色把相位向前移动$0.618 * 2\pi$ 。这样的话,每种颜色之间都有比较大的区分度,亮度也比较均匀。
CSS 没有原生支持 HSV,但我们可以用类似的 HSL。比如,如果令第 i 种类别的颜色是
`hsl(${360 * ((.2 + 0.618*i)%1)}deg, 50%, 35%)`
可以得到这样的效果:
这样不仅看起来比较好看,而且省去了现在的 color.js 和 seedrandom.js 两个依赖。
The text was updated successfully, but these errors were encountered: