🎨

頭文字ランダムカラーアバターを生成する mui + TypeScript

2022/10/22に公開

概要

よくあるこうゆうやつを作る方法です。

現在開発中のアプリで各地方自治体のアバターとして表示する要件があり作成しました。
できるだけカラーをばらつかせたかったので、色は地方公共団体コードから算出することを前提に作りっています。

またアプリのUI的に余り明度が高すぎる色は出したくなかったので、明度が80%まででカラーピックされるようにしています。

参考

Auto generate unique Avatar colors randomly - DEV Community 👩‍💻👨‍💻

実装

アバターを表示する GovtAvatar コンポーネントとアバター用の頭文字と色を返してくれる createAvatar 関数で構成しています。

GovtAvatar

GovtAvatar.tsx
import createAvatar from '../../utils/createAvatar';
import { Avatar } from '..';

// ----------------------------------------------------------------------
type Props = {
  name: string;
  gcode: string;
  url?: string;
};

export default function GovtAvatar({ name, gcode, url }: Props) {
  const avatar = createAvatar(name, gcode);

  return (
    <Avatar src={url} alt={name} color={avatar.color} sx={{ color: avatar.contrast }}>
      {avatar.name}
    </Avatar>
  );
}

muiAvatar コンポーネントを使用して画像のurl指定がある場合はそれを、ない場合は頭文字とピックされたカラーで表示されるようにしています。

createAvatar

createAvatar は第1引数 name を渡すだけならカラーピックにその文字列も利用しますが、第2引数 forColor を渡すとカラーピック用にはそちらの文字列を利用します。

getAvatarColor は渡された文字列をもとにランダムなカラーのHSLを color プロパティで返します。
また、選ばれたカラーの明るさに応じて、アバターの文字用のカラーを contrast プロパティで返します。

createAvatar.ts
const normalizeHash = (hash: number, min: number, max: number) =>
  Math.floor((hash % (max - min)) + min);

const generateHSL = (name: string) => {
  const hRange = [0, 360];
  const sRange = [0, 100];
  const lRange = [0, 80];

  const hash = isNaN(Number(name)) ? name.length : Number(name);
  const h = normalizeHash(hash, hRange[0], hRange[1]);
  const s = normalizeHash(hash, sRange[0], sRange[1]);
  const l = normalizeHash(hash, lRange[0], lRange[1]);
  return [h, s, l];
};

const getFirstChar = (name: string) => name && name.charAt(0).toUpperCase();

const getAvatarColor = (name: string) => {
  const hsl = generateHSL(name);
  return {
    color: `hsl(${hsl[0]}, ${hsl[1]}%, ${hsl[2]}%)`,
    contrast: hsl[2] >= 50 ? '#555555' : '#ffffff',
  };
};

export default function createAvatar(name: string, forColor?: string) {
  const forGenColor = forColor ? forColor : name;
  const { color, contrast } = getAvatarColor(forGenColor);
  return {
    name: getFirstChar(name),
    color,
    contrast,
  } as const;
}

Discussion