【React + MUI】HPバー的なゲージをMUIで作成してみた

![blog-hirono-038-001r.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818141/ace76819-f787-c508-a967-1bb40b69d6fd.png)
今回はゲームのHPバーやバッテリーの充電残量を表す様なゲージを作成していきます。

▼こんなやつ
![001.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818141/2810e161-b637-30dd-276f-81315d14c86b.gif)


# 完成コード
`Box`コンポーネントを等間隔並べるだけ
```React
import { Box, Slider, Stack } from '@mui/material';
import { useState } from 'react';

type GaugeType = {
  width: number;
  colorCode: string;
};

export const GaugeComponents = (): JSX.Element => {
  const [data, setData] = useState<number>(50);

  /**
   * ゲージ用のデータ配列を生成
   */
  const createGaugeData = (value: number, width: number): GaugeType[] => {
    if (!value) {
      return [{ width: 0, colorCode: 'white' }];
    }
    const roundNum = Math.round(Number(value) / 10) * 10;
    const flowNum = roundNum > 100 ? 100 : roundNum;
    const barColor = flowNum < 20 ? 'red' : flowNum > 40 ? 'blue' : 'orange';
    return Array(flowNum / 10)
      .fill([
        { width: (width / 100) * 9, color: barColor },
        { width: width / 100, color: 'white' },
      ])
      .flat();
  };

  return (
    <Stack spacing={5} sx={{ p: 30 }}>
      <Stack direction={'row'} width={300}>
        {createGaugeData(data, 300).map((e, index) => {
          return (
            <Box key={index} width={e.width} height={100} sx={{ backgroundColor: e.colorCode }} />
          );
        })}
      </Stack>
      {/* 以下は値を操作するためのスライダー */}
      <Box width={300}>
        <Slider
          defaultValue={data}
          valueLabelDisplay="auto"
          step={10}
          marks
          onChange={(_e, val) => setData(val as number)}
        />
      </Box>
    </Stack>
  );
};
```

# コード解説
### ゲージ用のデータ生成
表示するゲージ数 & ゲージ数に応じたカラーを設定
```React
const roundNum = Math.round(Number(value) / 10) * 10;
const flowNum = roundNum > 100 ? 100 : roundNum;
const barColor = flowNum < 20 ? 'red' : flowNum > 40 ? 'blue' : 'orange';
```
ゲージ数を元にデータ配列を生成
色付きと色無し（白）を組み合わせとしてセットする
※色無し（白）の部分は`Stack`コンポーネントの`spacing`プロパティでも同じ様に実現できると思います
```React
return Array(flowNum / 10)
    .fill([
        { width: (width / 100) * 9, color: barColor },
        { width: width / 100, color: 'white' },
    ])
    .flat();
```

### 表示部分
`Stack`コンポーネントで並べます
```React
<Stack direction={'row'} width={300}>
    {createGaugeData(data, 300).map((e, index) => {
        return (
            <Box key={index} width={e.width} height={100} sx={{ backgroundColor: e.colorCode }} />
        );
    })}
</Stack>
```

# おわりに
こういうゲージを一般的になんと呼ばれているかわからない上にサンプルも見つけられなかったので備忘録的に作成してみました

# 余談
ゲージをかたむけたい場合は以下のように`transform`を当ててみる
```React
<Stack direction={'row'} width={300}>
    {createGaugeData(data, 300).map((e, index) => {
        return (
            <Box
                key={index}
                width={e.width}
                height={100}
                sx={{
                    backgroundColor: e.color,
                    transform: 'skewX(-10deg)',//追加
                }}
            />
        );
    })}
</Stack>
```
![スクリーンショット 2024-08-12 18.34.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818141/8d874615-c15a-9d0b-23df-9dda1590159c.png)