p5.jsとDjangoでインタラクティブシミュレーション(1) p5.jsのスケッチをDjangoで公開してみよう

# はじめに

筆者のラボでは，人を含むシステムの挙動を分析するために，またそうしたシステムの中に置かれた人の挙動を分析するために，ユーザが途中で介入できる形式のコンピュータシミュレーション（インタラクティブシミュレーション）をウェブ上のゲームとして開発し，よく利用している．

このドキュメントは，そうしたインタラクティブシミュレーションのアプリケーションをp5.jsとDjangoを用いて開発するための基礎を身につけてもらうことを狙いとしたもので，あまり一般的なニーズはないかもしれないが，もし多少でもどなたかの参考になれば幸いだ．

なお，p5.jsはProcessingをjavaScriptに移植したものである．[ここ](https://p5js.org/)に詳しい情報があるので，必要に応じて参照しながら読み進めてほしい．

Processingに慣れている人は，Processingとp5.jsの違いが[ここ](https://github.com/processing/p5.js/wiki/Processing-transition)にまとめられているので，はじめに目を通しておくとよいだろう．

また，Djangoについては，[ここ](https://qiita.com/j54854/items/7e935252a072a3642c01)に入門的な情報をまとめてあるので，馴染みのない人はまずそちらを読んでからこちらに進むことをおすすめする．

今回は全4回中の1回目で，全体のコードはまとめて[GitHub](https://github.com/j54854/myP5js)に置いた．

# p5.jsのスケッチをDjangoで公開してみよう

まず，p5.jsを利用するための準備から始めよう．p5.jsのダウンロードページからComplete Libraryをダウンロードして解凍すると，下記のようなディレクトリ構成でいくつかのファイルが現れる．

```console
p5/
    addons/
        p5.dom.js
        p5.dom.min.js
        p5.sound.js
        p5.sound.min.js
    empty-example/
        index.html
        sketch.js
    p5.js
    p5.min.js
    p5.pre-min.js
```

これらのファイルのうち，今後編集していくのはhtmlファイル（上ではindex.html）とスケッチのコード（上ではsketch.js）の2つである．

最初に，index.htmlのファイルを開いて，下記のように少し修正を加えよう．

```html
<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

<!--    <title>p5.js example</title>
    <style> body {padding: 0; margin: 0;} </style>  -->

    <title>Simulation</title>

    <script src="../p5.min.js"></script>
    <script src="../addons/p5.dom.min.js"></script>
<!--        <script src="../addons/p5.sound.min.js"></script>  -->
    <script src="sketch.js"></script>
  </head>

  <body>
    <h1>Interactive Simulation</h1>
    <div id="mysketch"></div>
    <h1>Please Enjoy!</h1>
  </body>
</html>
```

まず，タイトルをSimulationに変更し，`padding`と`margin`の設定をコメントアウトしている（これは純粋に好みの問題だ）．サウンド関連のライブラリも，このチュートリアルでは利用しないので，コメントアウトしている．

注意してほしいのは，bodyの中にmysketchというidのdivを挿入している点である．p5.jsのスケッチをこのdivの部分に挿入するようにしたい．後でそれが確認できるように，divの前後にInteractive SimulationとPlease Enjoy!というメッセージを表示するようにしている．

次に，sketch.jsの方を編集しよう．まずは慣習に従ってHello World!を表示してみる．

```javascript
function setup() {
  var my_element = select("#mysketch");
  var my_width = min(my_element.width, 1000);
  var my_canvas = createCanvas(my_width, my_width *0.6);
  my_canvas.parent("mysketch");

  background(200);
  textSize(32);
  textAlign(CENTER, CENTER);
  text("Hello World!", width /2, height /2);
}

function draw() {
}
```

`setup()`と`draw()`の役割はProcessingと同じである．基本的には，最初に`setup()`が1回だけ実行され，その後，`draw()`がwhileループのように何度も繰り返し実行される（が，上では`draw()`は空である）．

まず，`setup()`の中で，mysketchのidのdivを選択しそれを`my_element`という変数で参照できるようにしている．そして，キャンバスを作成し，それをmysketchの子要素に設定している．

このキャンバスのサイズ（`width`と`height`）は，`my_element`の幅（`my_element.width`）に基づいて10:6になるように指定されていることもわかる．p5.jsのスケッチはこのキャンバスの中に描かれる（`background()`, `textSize()`, `textAlign()`, `text()`は基本的なp5.jsの関数である．馴染みのない人はリファレンスを参照してほしい）．

ここで一度，index.htmlをブラウザで開いてみよう．グレーの背景のキャンバスが現れ，その中心にHello World!の文字が表示されていれば成功だ．

続いて，このスケッチをDjangoと連携させよう．Django側で，まずmysiteというプロジェクトとsimというアプリケーションを作成したとする（settings.pyの`INSTALLED_APPS`のリストにsimを忘れずに追加しておく）．

この段階で，プロジェクトのディレクトリ構成を下記のように更新しておこう．

```console
mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        wsgi.py
    sim/
        __init__.py
        admin.py
        apps.py
        migrations/
            __init__.py
        models.py
        static/ *
            code/ *
                sketch.js **
            p5/ **
        templates/ *
            sim/ *
                index.html **
        tests.py
        urls.py *
        views.py
```


*を付けているのは，デフォルトで自動的には作成されないディレクトリやファイルである．これらは手動で追加してほしい（sim/urls.pyのファイルはひとまず空でよい）．

**を付けているのは，上で作成したスケッチ関連のディレクトリやファイルである．index.htmlはsim/static/templates/simの中に，sketch.jsはsim/static/codeの中に，それぞれコピーし，それら以外はp5ディレクトリごとsim/staticの中に入れる．

次に，urlルーティングを設定しよう．まず，mysite/urls.pyの方を下記のように修正し，simアプリケーション関係のルーティングをsim/urls.pyの方に委ねるようにする．

```python
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('sim/', include('sim.urls')),
    path('admin/', admin.site.urls),
]```

sim/urls.pyの方には下記の内容を書き入れる．

```python
from django.urls import path
from django.views.generic import TemplateView
from . import views

app_name = 'sim'

urlpatterns = [
    path('', TemplateView.as_view(template_name='sim/index.html'), name='index'),
]
```

この`TemplateView`は，`as_view()`メソッドで指定されたテンプレート（index.html）をレスポンスとして返してくれる．ただし，Djangoのテンプレートとして機能させるために，index.htmlにも少し修正を加える必要がある．

```html
{% load static %}

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

<!--    <title>p5.js example</title>
    <style> body {padding: 0; margin: 0;} </style>  -->

    <title>Simulation</title>

    <script src="{% static 'p5/p5.min.js' %}"></script>
    <script src="{% static 'p5/addons/p5.dom.min.js' %}"></script>
<!--    <script src="{% static 'p5/addons/p5.sound.min.js' %}"></script>  -->
    <script src="{% static 'code/sketch.js' %}"></script>
  </head>

  <body>
    <h1>Interactive Simulation</h1>
    <div id="mysketch"></div>
    <h1>Please Enjoy!</h1>
  </body>
</html>
```

最初に`{% load static %}`を指定することで`static`タグが使えるようになる．これで，staticディレクトリ内に格納してあるstaticファイルに，上記のように`static`タグを用いてアクセスできるようになる．

これで準備が整ったはずである．Djangoの開発用サーバを立ち上げ，ブラウザで次のアドレスにアクセスしてみよう．

http://localhost:8000/sim/

先ほどのHello World!のスケッチが表示されればOKだ．

# おわりに

ひとまず第1回はここで終了．[第2回](https://qiita.com/j54854/items/ed7dccc5d3fba75d2978)に続く．