LoginSignup
13
5

More than 1 year has passed since last update.

React + dat.GUI でササッと入力GUIを実装

Last updated at Posted at 2019-12-11

最近、ジェネレーティブアートに興味があって
p5.jsとか使ってなにかCGアート作品作りたいなぁと考えています。

そのようなCG作品が沢山投稿されてるCodepenっていうサイトがあります
Codepenとか覗いていると、閲覧中によく右上にあるGUIでCGのパラメータを
変更できるパーツがあって、あれって何かなあとずっと疑問に思っていたので調べました。

dat.GUI とは

スクリーンショット 2019-12-11 10.21.18.png

Googleのデータアート部門の人が作った、Javascript製の
パラメーター変更のためのグラフィカルで軽量なUIです。

簡単な書き方でササッと入力用GUIを追加できるので、CGアート界隈の人がよく使ってる感じらしいです。

Tutorial

React + dat.GUI

dat.GUIでJavascriptの変数を変更できるのはわかりました。

Reactは単方向データバインディングなので、
Reactとdat.GUIを組み合わせようと思ったら、dat.GUIのパラメータ変更時にsetState()を実行しないといけません。

そのあたりのノウハウを実践してみたので共有したいと思います。

プロジェクトを作る

create-react-appでさくっと作ります。
最近はまってるのでTypescriptでやります。

yarn create react-app react_dat --template typescript

必要なライブラリを追加

dat.GUIに加えて、
state管理にunstated-nextを使います

  • dat.gui
  • @types/dat.gui
  • unstated-next
yarn add dat.gui @types/dat.gui unstated-next

unstated-next

unstated-next は React Context Hook を使いやすくしたライブラリです。

基本的な概念としては、

  • stateを管理・変更通知するContainerオブジェクトを作る
  • <Container.Provider>でコンポーネントをラップする
  • ラップされた内部ではContainer.useContainer()でstateが使える
  • stateに変更があったら、Providerがラップしているコンポーネントツリーを更新する

みたいな感じ?
偉大な先駆者様の解説記事があるのでそちらを見ると良いでしょう
https://qiita.com/kaba/items/b05f680f850dd46548f3

GUIContainerを作る

React Hooksをたくさん使います。

  • useState
  • useMemo
    • dat.GUI オブジェクトをMemonizeする(再レンダリングしても同じメモリ位置のオブジェクトを使う)
  • useEffect
    • 最初の1回だけguiにプロパティを追加する
GUI.ts
import dat from 'dat.gui'
import { createContainer } from 'unstated-next'
import { useState, useMemo, useEffect } from 'react'

const GUIContainer = createContainer(() => {
    const [message, setMessage] = useState('dat.gui')
    const [speed, setSpeed] = useState(0.8)
    const [flag, setFlag] = useState(false)
    const [fruit, setFruit] = useState('apple')
    const [number, setNumber] = useState(1)

    const gui = useMemo(() => new dat.GUI(), [])

    useEffect(() => {
        gui.add({ message }, 'message').onChange(value => setMessage(value))
        gui.add({ speed }, 'speed', -5, 5).onChange(value => setSpeed(value))
        gui.add({ flag }, 'flag').onChange(value => setFlag(value))
        gui.add({ fruit }, 'fruit', [
            'apple',
            'orange',
            'grape'
        ]).onChange(value => setFruit(value))
        gui.add({ number }, 'number', {
            one: 1,
            two: 2,
            three: 3
        }).onChange(value => setNumber(value))

        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [])

    return { message, speed, flag, fruit, number }
})

export default GUIContainer

ちょっと長いファイルになりましたが、dat.GUIの紹介ということで
色々なフォームを詰め込んで見ました。

基本的には、以下のような書式でGUIフォームを追加できます。

dat
import dat from 'dat.gui'

let gui = new dat.GUI()
gui.add(Object, "プロパティ名").onChange(value => /* code */)

.onChange() メソッドは、変更されたvalueを受け取ってなにか処理をするコールバックを登録できます。

このコールバックの中でsetState()を実行すれば、ReactDOMを再描写できるというわけですね。

作ったGUIコンテナのstateを使う

App.tsx
import React from 'react'
import GUIContainer from './GUI'

const App: React.FC = () => {
    const { message, speed, flag, fruit, number } = GUIContainer.useContainer()

    return (
        <>
            <p>{message}</p>
            <p>{speed}</p>
            <p>{`${flag}`}</p>
            <p>{fruit}</p>
            <p>{number}</p>
        </>
    )
}

export default () => (
    <GUIContainer.Provider>
        <App />
    </GUIContainer.Provider>
)

確認してみる


yarn start

localhost:3000 にブラウザでアクセス

スクリーンショット 2019-12-11 10.16.41.png

まとめ

dat.GUI と React を組み合わせるノウハウを書いてみました。

dat.GUIはとても手軽に入力用のGUIを追加できるので、
デジタルアート以外でも、仕事でプロトタイピングのwebアプリの入力を試したい
なんてときにも役に立つと思います。

終わり。

13
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
5