【完走賞ゲット-21】p5.js で描画する複数の色でのグラデーション：chroma.js を使った方法と drawingContext.createLinearGradient を使った方法の比較

## はじめに
こちらは、[完走賞ゲットのため小ネタを毎日投稿しようとチャレンジする Advent Calendar 2022](https://qiita.com/advent-calendar/2022/youtoy) の 21日目の記事です。

内容は、以下の記事で扱った chroma.js を使ったカラースケールに関する話です。

●【JavaScript 2022】chroma.js を使った複数色のカラースケールでカラーパレットを生成して p5.js で描画（chroma.bezier() や chroma.scale() の scale.correctLightness() などを利用） - Qiita
　https://qiita.com/youtoy/items/6b1f11238a76e327d078

上記の記事では、カラースケールからカラーパレットを生成しましたが、この記事では複数の色を使った線形のグラデーションを描画するのに利用してみようと思います。また、線形のグラデーションを描画する方法に drawingContext.createLinearGradient を使った方法もありますが、それとの比較もやってみます。

## chroma.js を使った複数色のカラースケールからグラデーションを描画
上で掲載していた前の記事で、カラーパレットを作る場合は、指定した数の色を取り出すというのを `scale.colors()` を使ってやりました。

https://gka.github.io/chroma.js/#scale-colors
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/05874167-2c66-4889-c3ff-3f6675745b87.png)

グラデーションを描画する場合、この部分を「指定の割合の値から色を取得する」ということをやります。そのためには、 `out("hex")` というのが利用できるようです。
※ 情報源 ⇒ https://fukuno.jig.jp/3743

具体的にソースコードで書くと、以下のとなります。

```javascript: カラーパレット用の色指定
const colorList = ["white", "yellow", "blue", "black"];

chroma.scale(colorList).mode("rgb").colors(10),
  chroma.scale(colorList).mode("rgb").correctLightness().colors(10),
```

```javascript: グラデーション用の色指定
const colorList = ["white", "yellow", "blue", "black"];

const outputColors = [
  chroma.scale(colorList).mode("rgb").out("hex"),
  chroma.scale(colorList).mode("rgb").correctLightness().out("hex"),
];
```

## グラデーションの描画： 3種類
以下は、グラデーションを 3つの方法で描画してみたものです。

![グラデーションの描画： 3種類](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/de932604-dcc9-6205-5357-408eb027ee40.png)

上記のグラデーションは、それぞれ以下の方法で描画しています。また、グラデーションの元になる色は、共通のものを用いました。

1. `chroma.scale()` を利用
1. 上記に `scale.correctLightness()` を追加
1. `drawingContext.createLinearGradient()` を利用し、真横へグラデーションを作成

ソースコードも掲載しておきます。

```javascript
const colorList = ["white", "yellow", "blue", "black"];

const outputColors = [
  chroma.scale(colorList).mode("rgb").out("hex"),
  chroma.scale(colorList).mode("rgb").correctLightness().out("hex"),
];

function setup() {
  createCanvas(400, 350);
}

function draw() {
  background(220);

  for (i = 0; i < width; i++) {
    noFill();
    stroke(outputColors[0](map(i, 0, width, 0, 1)));
    line(i, 30, i, 110);
  }

  for (i = 0; i < width; i++) {
    noFill();
    stroke(outputColors[1](map(i, 0, width, 0, 1)));
    line(i, 130, i, 210);
  }

  noStroke();
  fill(255);
  let gradient = drawingContext.createLinearGradient(0, 180, width, 180);

  for (let i = 0; i < colorList.length; i++) {
    const ratio = map(i, 0, colorList.length - 1, 0, 1);
    gradient.addColorStop(ratio, colorList[i]);
  }

  drawingContext.fillStyle = gradient;
  rect(0, 250, width, 80);
}
```

### 比較結果
`chroma.scale()` を利用したものと、 `drawingContext.createLinearGradient()` を利用したものは、同じ結果を得られました。

また、 `chroma.scale()` に `scale.correctLightness()` を追加したものは、カラースケールに補正がかかっているため、他の 2つとは異なる結果になりました。

## その他の書き方： hex() を使う
上記のプログラムで、 `chroma.scale()` を使った方法では、以下のようなやり方でした。

```javascript: out() を使う方法
const colorList = ["white", "yellow", "blue", "black"];

const outputColors = [
  chroma.scale(colorList).mode("rgb").out("hex"),
  ...,
];
...
    stroke(outputColors[1](map(i, 0, width, 0, 1)));
...
```

これは、以下のような書き方もできるようです。

```javascript: hex() を使う方法
const colorList = ["white", "yellow", "blue", "black"];

const outputColors = [
  chroma.scale(colorList).mode("rgb"),
  ...,
];
...
    stroke(outputColors[0](map(i, 0, width, 0, 1)).hex());
...
```