記事目次
クリエイターブログ/システム開発
システム開発
【PHP】任意の数の色コードを自動作成
経緯
Webアプリケーションを作成する際にグラフ機能が必要になることが有ります。
単純な棒グラフであれば悩むことはありませんが、パイチャートなどで複数の色を使用するときにどんな色を使えばよいか悩んだ経験はないでしょうか?
特にアンケート結果など、項目数が不定の時に色を指定するには色コードをプログラムで作ってしまうしかありません。
色を作るには?
色を表現する手段としてHSV色空間という方法があります。
H(色相)、S(彩度)、V(明度)です。
この内色相は0~360°で表現されます。
Hを変化させることによって鮮やかさ・明るさが同じ、別の色を作り出せます。
鮮やかさ、明るさが同じなのである程度違和感のない色と言ってよいのではないかと思います。
ベースとなる色をRGBで決めて、その色をベースに必要数色相を調整した色を作ることにします。
RGBからHSVへの変換
Webアプリで色を表現するときはRGBを使います。
RGBで指定したベースの色を調整していくにはHSVに変換して色相を調整する必要があります。
そこで、まずはRGBからHSVに変換する機能を作成します。
RGB→HSVに変換するにあたっては計算式があるのですが、その説明は割愛させていただきます。
/**
* RGB値をHSVに変換する
* @param string $color RGB
* @return array HSVの配列
*/
function rgb2hsv($color){
$r = substr($color,1,2);
$g = substr($color,3,2);
$b = substr($color,5,2);
//10進数に変換
$r_dec = hexdec($r);
$g_dec = hexdec($g);
$b_dec = hexdec($b);
$ary = Array($r_dec,$g_dec,$b_dec);
//3値の最大値
$max = max($ary);
//3値の最小値
$min = min($ary);
//Hを求める
if($max == $min){
$h_val = 0;
} else {
switch($max){
case $r_dec:
$h_val = (60 * (($g_dec - $b_dec)/($max - $min)));
break;
case $g_dec:
$h_val = (60 * (($b_dec - $r_dec)/($max - $min))) + 120;
break;
case $b_dec:
$h_val = (60 * (($r_dec - $g_dec)/($max - $min))) + 240;
break;
}
while($h_val < 0){
$h_val += 360;
}
}
//Sを求める
$s_val = ($max === 0)? 0:($max - $min) / $max;
$s_val *= 255;
//Vを求める
$v_val = $max;
return Array('h' => $h_val, 's' => $s_val, 'v' => $v_val);
}
HSVからRGBへの変換
HSVに変換したベース色の色相を調整して色を作成した後、Webアプリで使用するためにRGBに戻す必要があります。
HSVからRGBに戻すには先程の変換と逆のことを行います。
それがこちらになります。
/**
* HSVをRGBに変換
* @param int $h_val
* @param int $s_val
* @param int $v_val
* @return string
*/
function hsv2rgb($h_val, $s_val, $v_val){
$max = $v_val;
$min = ($max === 0)? 0:floor($max - (($s_val / 255) * $max));
//360°を超えるとき調整
while($h_val > 360){
$h_val -= 360;
}
//0°を下回るとき調整
while($h_val < 0){
$h_val += 360;
}
if($s_val == 0){
$r_dec = $v_val;
$g_dec = $v_val;
$b_dec = $v_val;
} else {
if($h_val <= 60){
$r_dec = $max;
$g_dec = floor((($h_val / 60) * ($max - $min)) + $min);
$b_dec = $min;
} elseif($h_val <= 120){
$r_dec = floor((((120 - $h_val) / 60) * ($max - $min)) + $min);
$g_dec = $max;
$b_dec = $min;
} elseif($h_val <= 180){
$r_dec = $min;
$g_dec = $max;
$b_dec = floor(((($h_val - 120) / 60) * ($max - $min)) + $min);
} elseif($h_val <= 240){
$r_dec = $min;
$g_dec = floor((((240 - $h_val) / 60) * ($max - $min)) + $min);
$b_dec = $max;
} elseif($h_val <= 300){
$r_dec = floor(((($h_val - 240) / 60) * ($max - $min)) + $min);
$g_dec = $min;
$b_dec = $max;
} else {
$r_dec = $max;
$g_dec = $min;
$b_dec = floor((((360 - $h_val)/60) * ($max - $min)) + $min);
}
}
$r = substr("0" . dechex($r_dec),-2);
$g = substr("0" . dechex($g_dec),-2);
$b = substr("0" . dechex($b_dec),-2);
return "#" . $r . $g . $b;
}
指定数の色を作成
最後に、数を指定して必要な分だけ色コードを作成する機能を作ります。
色相は360°で表せるので、360°を必要な色の数で分割して色を作ります。
これにより色相が等間隔で作成されるので変な偏りはなくなります。
/**
* 指定個数の色配列を取得する
* @param string $color ベースの色コード
* @param int $cnt 作成する色の個数
* @return array
*/
function get_rgb_ary($cnt = 8, $color = '#ff0000'){
$ary = Array();
$cnt_m = ($cnt + 1);
//Hに加算して調整する値を360°に対して必要個数から算出する
$diff = ($cnt_m <= 0)? 0:ceil(360 / ($cnt_m));
$hsv_ary = rgb2hsv($color);
$h_val = $hsv_ary['h'];
for($i = 0;$i<$cnt;$i++){
// RGBを取得して配列にpush
$ary[] = hsv2rgb($h_val, $hsv_ary['s'], $hsv_ary['v']);
// H加算
$h_val += $diff;
}
return $ary;
}