はじめに
私は普段体重管理をスマホアプリで行っているのですが、二次元のグラフがダサい…
とふと感じてしまい「そうだ!今こそWebGLを勉強だ!ただWebGLを直接扱うのは難しそう…」ということでReactからはreact-three-fiberが割と簡単にWebGLを扱えそうだったのでやってみました。
最終的にはかっこいい体重管理グラフの表示を目指しています。
ということで、今回のゴールは以下とします。
- 環境セットアップ
- 簡単な画面を表示
環境セットアップ
まずはNode.jsが必要なのでインストールします。
本稿作成時点では18.12.1が推奨版だったのでこれをインストールします。
全てインストーラのデフォルト設定でインストールします。
インストール結果確認
コマンドプロンプトを立ち上げnodeコマンドからバージョンを確認します。
バージョンが表示されればインストールは正常終了しています。
node -v
18.12.1
Reactプロジェクト作成
適当なフォルダからプロジェクト作成コマンドを実行します。
ここではtest-app-frontという名前にします。
npx create-next-app test-app-front
インストール途中で以下の質問をされるので両方ともYesを選択
? Would you like to use TypeScript with this project? » No / Yes
? Would you like to use ESLint with this project? » No / Yes
ちゃんと動くかテスト
cd test-app-front
npm run dev
http://localhost:3000/
にアクセスして以下画面が表示されれば成功です。
Three.js導入とコーディング
Three.jsとreact-three-fiber、typescript用の型定義をインストールします
npm install three @types/three @react-three/fiber
githubのサンプルを参考にindex.tsを実装します。
import type { NextPage } from "next";
import React, { useRef, useState } from "react";
import * as THREE from "three";
import { Canvas, useFrame } from "@react-three/fiber";
const Home: NextPage = () => {
const Box = (props: JSX.IntrinsicElements["mesh"]) => {
const ref = useRef<THREE.Mesh>(null!);
const [hovered, hover] = useState(false)
const [clicked, click] = useState(false)
useFrame((state, delta) => (ref.current.rotation.x += 0.01));
return (
<mesh
{...props}
ref={ref}
scale={clicked ? 1.5 : 1}
onClick={(event) => click(!clicked)}
onPointerOver={(event) => hover(true)}
onPointerOut={(event) => hover(false)}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={hovered ? "hotpink" : "orange"} />
</mesh>
);
};
return (
<Canvas>
<ambientLight />
<pointLight position={[10, 10, 10]} />
<Box position={[-1.2, 0, 0]} />
<Box position={[1.2, 0, 0]} />
</Canvas>
);
};
export default Home;
動作確認
さっそく実行してみましょう。
npm run dev
を実行してからhttp://localhost:3000/にアクセスします。
こんなオブジェクトがくるくると回転していれば成功です。
クリックすると大きくなったり、マウスを置くとピンクになります。
バージョン情報
- @react-three/fiber": "^8.9.1
- @types/node": "18.11.9
- @types/react": "18.0.25
- @types/react-dom": "18.0.8
- @types/three": "^0.146.0
- next": "13.0.3
- react": "18.2.0
- react-dom": "18.2.0
- three": "^0.146.0
- typescript": "4.8.4