どう実現するのか
発言者毎に不変な ID を種に HSL の H を決める関数を用意する。S と L は固定値を使うことでチャットに適した色を確実に出させる
つまりこんな感じ。
const generateColor = (seed)=>{
return `hsl(${Number(seed) % 360}, 100%, 40%`;
};
発言者ごとに色を分けたい
著者はしばしば Discord のテキストチャネル上で TRPG をやる。
テキストチャットでやると後から実施したログを簡単に共有できるのは便利だ、と思ったのだが Discord のログを後から読み返すために目標地点までログをさかのぼるのは少々面倒だ。
「ログを HTML 形式でダウンロードして適当な場所にアップロードすればいいじゃないか」と思いそういうツールを用意して実行、無事チャットログを取得できた。だが、取得してみて欲が出た。発言者毎に色を分けたい。
発言者毎に色を分けることそのものについては賛否あると思うが、私のプレイ環境では発言者毎に色を分けるのが一般的だったのである。
当たった課題
どのチャンネル(チャットルーム)をどのタイミングでダウンロードしても同じ人は同じ色であってほしい
テキストチャットのログを処理する度に発言者 ID 毎に色を設定し、生成される HTML すべてに色を割り当てていく、という方法を原則としては採る。
しかし、ダウンロードするごとに色をランダムで生成しているとダウンロードするごとに発言者毎の色が変わる。全12回のゲームで毎回発言者毎に色が違う、とかそういった事態になると読者は混乱するだろう。
そのため、特定の文字列を入力すると常に特定の色を返す関数を用意することにした。これを用いれば同じ発言者による発言は常に同じ色を割り当てることができる。先の関数に発言者の ID を入力して、出力された色を用いればよい。
背景色とのコントラストを維持したい
先の関数で色を生成する際に素直に色を生成すると次のような方法になるかと思う。
const color = `#${(Number(id) % (255*255*255)).toString(16)}`;
しかし、これで出すと #fff4f8
といった値が出力されることもある。残念ながら大変に読みにくい。白い背景であれば暗めの色を常に出してほしい。常に暗めの色を出力させるためには HSL の形式で色を決めると簡単。すなわち hsl(90, 100%, 40%)
のような形式である。
const color = `hsl(${Number(id) % 360}, 100%, 40%`;
HSL の形式で色を表現する場合は1つめの値に色相を入力する。これが具体的な色を定義する要素であるため、この値が ID によって決まるようにする。
2つめの値には彩度が入る。色の鮮やかさや濃さを定める値となる。数字が小さければ色はくすむ。この値は文脈にもよるものの今回の目的では 100% でよいだろう、と考えた。
3つ目の値には輝度が入る。 50% が標準の値であり、値が増えると明るい色になり値が減ると暗い色になる。白背景には暗い色の方が読みやすいだろうということで今回は 50% より低い 40% を与えている。背景が暗い色なのであれば大きな値を入れる必要がある。
と書いても分かりにくいので彩度、輝度については以下にサンプルを書いてみた。
彩度\輝度 | 0% | 20% | 40% | 50% | 60% | 80% | 100% |
---|---|---|---|---|---|---|---|
0% | hsl(90, 0%, 0%) |
hsl(90, 0%, 20%) |
hsl(90, 0%, 40%) |
hsl(90, 0%, 50%) |
hsl(90, 0%, 60%) |
hsl(90, 0%, 80%) |
hsl(90, 0%, 100%) |
20% | hsl(90, 20%, 0%) |
hsl(90, 20%, 20%) |
hsl(90, 20%, 40%) |
hsl(90, 20%, 50%) |
hsl(90, 20%, 60%) |
hsl(90, 20%, 80%) |
hsl(90, 20%, 100%) |
40% | hsl(90, 40%, 0%) |
hsl(90, 40%, 20%) |
hsl(90, 40%, 40%) |
hsl(90, 40%, 50%) |
hsl(90, 40%, 60%) |
hsl(90, 40%, 80%) |
hsl(90, 40%, 100%) |
50% | hsl(90, 50%, 0%) |
hsl(90, 50%, 20%) |
hsl(90, 50%, 40%) |
hsl(90, 50%, 50%) |
hsl(90, 50%, 60%) |
hsl(90, 50%, 80%) |
hsl(90, 50%, 100%) |
60% | hsl(90, 60%, 0%) |
hsl(90, 60%, 20%) |
hsl(90, 60%, 40%) |
hsl(90, 60%, 50%) |
hsl(90, 60%, 60%) |
hsl(90, 60%, 80%) |
hsl(90, 60%, 100%) |
80% | hsl(90, 80%, 0%) |
hsl(90, 80%, 20%) |
hsl(90, 80%, 40%) |
hsl(90, 80%, 50%) |
hsl(90, 80%, 60%) |
hsl(90, 80%, 80%) |
hsl(90, 80%, 100%) |
100% | hsl(90, 100%, 0%) |
hsl(90, 100%, 20%) |
hsl(90, 100%, 40%) |
hsl(90, 100%, 50%) |
hsl(90, 100%, 60%) |
hsl(90, 100%, 80%) |
hsl(90, 100%, 100%) |
発言者の ID じゃなくて発言者の名前で色を決めたい
以下のようにして文字を数字に見立てることで実現できる。
let id = 0;
for(var i = 0; i < name.length; i++) {
id += name.charCodeAt(i);
}
const color = `hsl(${Number(id) % 360}, 100%, 40%`;