canvas で色相環を作ってみた

# 色相環って知っていますか？

### いわゆる色相環

カラーピッカーとかでよく見かけるこういうのですね。

![色相環](https://upload.wikimedia.org/wikipedia/commons/d/db/HLSColorSpace.png)

*via [色相 - Wikipedia](https://ja.wikipedia.org/wiki/%E8%89%B2%E7%9B%B8)*

### マンセルの色相環

ただ、僕が言ってる色相環はこっちのこと。

![マンセルの色相環](https://upload.wikimedia.org/wikipedia/ja/d/d1/MunsellColorCircle.png)
マンセル表色系 [^1] が提唱している **色相の連続的な変化を順序立てて円環にして並べたもの** を指しています。 

*via [マンセル・カラー・システム - Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%B3%E3%82%BB%E3%83%AB%E3%83%BB%E3%82%AB%E3%83%A9%E3%83%BC%E3%83%BB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0)*


### PCCS の色相環
更に PCCS（Practical Color Co-ordinate System：日本色研配色体系）によって作られた色相環もあります。
向かい合う色が心理補色 [^2] になるものでこんな感じのものです。

![pccs-hue.png](https://qiita-image-store.s3.amazonaws.com/0/317946/bb1e8d02-4b5d-afba-24b2-25b94596b550.png)

今回はこの PCCS の色相環の12色に簡略化されたものを作っていきたいと思います！

*via [PCCS（Practical Color Co-ordinate System：日本色研配色体系）](http://www.sikiken.co.jp/pccs/index.html)*


# 作ってみよう！

### ってどうやって作ろう？

色々と考えました。

- CSS でがんばる とか
- 正十二角形の辺を太くして色変えて丸める とか
- ~~もう画像でいいじゃん~~

ふたつ目の案が良さそうだと思いましたが、正十二角形を描画するのどうするの？

`canvas` でやってみるか！となったわけです :yum:



### canvas で実装

##### HTML

```html
<canvas id="hue-circle"></canvas>
```

これだけ。

##### CSS

なし（canvas は CSS で高さとか色とか指定できない）。

##### JS

大半は JS で実装します。

###### 1. canvas 要素を取得して高さとか決める

```javascript
const canvas = document.getElementById('hue-circle');
canvas.width = '300px';
canvas.height = '300px';
```

###### 2. 描画できるように2Dコンテキストを取得する

```javascript
const ctx = canvas.getContext('2d');
```

###### 3. 円弧を描いてみる

canvas の円弧を描く基本はこんな感じです。

```javascript
/**
 * 円弧の描画
 * @param {Object} ctx - 描画用 2D コンテキスト
 * @param {number} x - 円弧の中心の X 座標
 * @param {number} y - 円弧の中心の Y 座標
 * @param {number} radius - 円弧の半径
 * @param {number} startAngle - 円弧の開始角度
 * @param {number} endAngle - 円弧の終了角度
 * @param {string} colorCode - （任意）円弧の塗りつぶしカラーコード
 */
function fill(ctx, x, y, radius, startAngle, endAngle, colorCode) {
    
  // 描画用にパスを作成
  ctx.beginPath();
    
  // "注記"参照
  ctx.moveTo(x, y);
    
  // 開始角度～終了角度の円弧描画をパスに登録（toRadianメソッドはラジアン角へ変換している）
  ctx.arc(x, y, radius, toRadian(startAngle), toRadian(endAngle));
    
  // 塗りつぶしの色を登録
  ctx.fillStyle = colorCode;
    
  // パスの内部エリアを塗りつぶして、単色の図形を描く
  ctx.fill();
}
```

`moveTo` については次のような **注記** が有りました。

> **注記:** `beginPath()` を呼び出した直後や canvas を新規作成した直後など、現在のパスが空であるときに最初にパスを構築するコマンドは、実際は何であるかにかかわらず常に `moveTo()` として扱われます。このためパスをリセットした後はほぼ必ず、開始位置を明示することが必要になるでしょう。

*via [canvas に図形を描く - MDN web docs](https://developer.mozilla.org/ja/docs/Web/Guide/HTML/Canvas_tutorial/Drawing_shapes)*

今回は塗りつぶしだけど、縁取りする図形を描画する場合は `stroke` でいけます。

###### 4. 12色の円弧を描いてみる

先程の `fill` 関数を12回呼び出すことで実現しています。

```javascript
// 黄色始まりのカラーコード一式（vivid トーン）
const colors = Object.values({ 
    'Y' : '#FFE600', 
    'YG': '#99CF15', 
    'G' : '#33A23D', 
    'GB': '#008678', 
    'gB': '#055D87', 
    'B' : '#0F218B', 
    'V' : '#281285', 
    'P' : '#56007D', 
    'RP': '#AF0065', 
    'R' : '#EE0026', 
    'rO': '#FE4118', 
    'yO': '#FF7F00' 
});

// 円弧の最も高い位置 270° から 15° 引いた角度から描画をはじめる
let angle = 255

// 12 回ループ
for (let i = 0; i < 12; i++) {
  
  // 30° 分を描画する
  fill(ctx, x, y, radius, angle, angle + 30, colors[i]);
  
  // 次回描画用に 30° 加算する
  angle += 30;
}
```

黄色の円弧の中心を一番上にしたいために 255° という中途半端な角度から開始しています。

`270 - (30 / 2)` ってことですね。

###### 5. 真ん中を白い円でくり抜こう

くり抜くというか、白い小さな円弧を上から描画しているだけです。

```javascript
fill(ctx, x, y, radius / 2, 0, 360, '#FFFFFF');
```

半径を `1 / 2` して 360° まるっと描画しています。



# 色相環出来ました！

CodePen :pencil2: にUPしてみました！

描画の様子がわかりやすいように、1色ずつ止めながら描画させています。

<p data-height="370" data-theme-id="dark" data-slug-hash="aQaXwe" data-default-tab="result" data-user="azukisiromochi" data-pen-title="HueCircle" class="codepen">See the Pen <a href="https://codepen.io/azukisiromochi/pen/aQaXwe/">HueCircle</a> by あずきしろもち (<a href="https://codepen.io/azukisiromochi">@azukisiromochi</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

# おわりに

`canvas` を直接利用したのは初めてでしたが、なんとか出来ました。

座標を扱うので少しとっつきにくい感じはしますが、慣れれば便利なのかな～ :thinking::question:

ちなみに `arc` 関数使っているところを `lineTo` 関数に変えてやれば正多角形が作れたりもします。

（~~座標計算がそれこそしんどいけど~~）

こんどは CSS で作ってみようかな！ :yum:




[^1]: マンセル・カラー・システム (Munsell color system) とは、色を定量的に表す体系である表色系の1つ。色彩を色の三属性（色相、明度、彩度）によって表現する。マンセル表色系、マンセル色体系、マンセル システムとも言う。
[^2]: ある色の残像として現われる色をその色の心理補色（または生理補色）と呼ぶ。例えば赤をしばらく見たあとに、白紙に目を移すと見える青緑が該当する。