GoodPatchさんから最近リリースされたクラウドサービス「Strap」でPixiJSを利用しているという記事を目にしたのでどのようなものか確認するためにPixiJSの動作確認を行ってみました。

複雑なことを行うまでには時間がかかると思いますので本文書では公式サイトのサンプルとマニュアル、ネット上の情報を利用して基本的な動作確認を行いPixiJSに慣れ親しむことを目的にしています。

PixiJSとは

PixiJSはインタラクティブなアプリケーションに利用できる2Dのレンダリングライブラリで、ゲームにも利用されています。どのようなゲームに利用されているかまでは不明ですが簡単に言えばブラウザ上でアニメーションを作成することができます。

Hello World

PixiJSを使ってブラウザの画面上にHello World!を表示させてみたいと思います。動作確認を手元の環境でも行えるようにcdnを利用します。


<script src="https://pixijs.download/release/pixi.js"></script>

下記のコードでPIXIアプリケーションのインスタンスを作成することから始めます。


const app = new PIXI.Application();

PIXIアプリケーションはcanvas要素を作成するので下記のコードでbodyの中にcanvasの要素を挿入します。挿入する場所にbodyをしていますが、要素であればbodyである必要はありません。


document.body.appendChild(app.view);

index.htmファイルにcdnと上記の2行のコードを追加します。


<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>PixiJS</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.1.3/pixi.min.js"></script>
  </head>
  <body>
    <script>
      const app = new PIXI.Application();

      document.body.appendChild(app.view);

    </script>
  </body>
</html>

ブラウザで確認すると画面上に背景が黒の四角の領域が表示されます。

PIXIJSの初期画面
PIXIJSの初期画面

ブラウザのデベロッパーツールで確認するとbodyの中にcanvas要素が挿入されていることが確認でき、幅は800, 高さは600に設定されています。このcanvas要素の中に画像やテキストを描写していきます。


<canvas width="800" height="600" style="touch-action: none; cursor: inherit;"></canvas>
canvasのサイズは変更することが可能です。また背景色も変更可能です。
fukidashi

デベロッパーツールのコンソールを見るとバージョンを確認することができます。

PixiJSのバージョンを確認
PixiJSのバージョンを確認

PIXIアプリケーションで作成されたcanvasの中にテキストで文字を表示させます。テキストを表示したい場合はPIXI.textを利用します。場所をx,yで指定していますが、指定しないと左上に表示されます。テキストの色は背景色が黒なので白に設定をしています。


const message = new PIXI.Text("Hello World!");
message.x = 200;
message.y = 200;
message.style.fill = "white";
app.stage.addChild(message);

ブラウザで確認すると下記のようにHello Worldが表示されることがわかります。

PixiJSでHello World
PixiJSでHello World

文字を回転

表示したHello Worldを回転させてみましょう。tickerを含んだ一行を追加するだけで文字を回転されることができます。デフォルトでは左上が回転軸となります。下の図は静止画ですが実際には右回りに回転しています。tickerを利用することでアニメーションを実行できることがわかります。


app.ticker.add((delta) => (message.rotation += 0.01 * delta));
文字を回転させる
文字を回転させる

文字の中心で回転させるためには、anchor.set(0.5)を設定します。anchorを設定するとx,yの位置もこの位置を基準に設定されます。


const message = new PIXI.Text("Hello World!");
message.anchor.set(0.5);
message.x = 200;
message.y = 200;
message.style.fill = "white";
app.stage.addChild(message);

app.ticker.add((delta) => (message.rotation += 0.01 * delta));
anchorを設定し回転軸を設定
anchorを設定し回転軸を設定

文字の移動

文字の自動的な移動についてはx, yの値をtickerの中で変更することで移動できるのではと予想することができるかと思います。先程までの回転を設定していたrotationからxに変更すると右方向にゆっくりと文字が移動することがわかります。大きな値を入れると一瞬で画面から文字が消えます。


app.ticker.add((delta) => (message.x += 1));
右に移動
右に移動

イベントの設定

ここまではテキストがtickerの設定により自動で動いていたためブラウザを閲覧するユーザとのインタラクションは全くありませんでした。ユーザとのインタラクションを持たせるため次はイベントを利用してユーザがクリックすることでテキストの色を変える方法を確認します。

ユーザからの何かの操作を受け取るには、interactiveをtrueに設定する必要があります。この設定を行わないとclickイベントを設定しても何も反応はありません(イベントが発火しない)。


message.interactive = true;

onメソッドの第一引数にイベント名を設定し、第二引数にcallback関数を設定します。jQueryなどの書式に似ていますが、これでclickイベントの設定は完了です。ブラウザ上で右側に動いているHello Worldのテキストをクリックしブラウザのデベロッパーツールのコンソールにclickが表示されたらイベントの設定は正常に動作しています。


message.on("mousedown", () => console.log("click"));

clickイベントの設定方法がわかったのでテキストの文字の色をクリックすることで変更させます。


message.on("mousedown", () => (message.style.fill = "red"));

右に動いしている”Hello World”をクリックするとクリックするとHello World!の色が赤に変わります。たった数行のコードでアニメーションを行っているテキストに対してイベントまで設定しインタラクティブな動作を行えるようになりました。

clickイベントで色が変わる
clickイベントで色が変わる

イベントの種類、またcallback関数の中身を変更することでユーザとのさまざまなインタラクションを行うことができそうです。

tikerで設定できるのは1つの動作だけではないので右側に移動しならが回転しているHello Worldをクリックするとテキストの色を赤に変更することも可能です。


const message = new PIXI.Text("Hello World!");
message.anchor.set(0.5);
message.x = 200;
message.y = 200;
message.style.fill = "white";
app.stage.addChild(message);

message.interactive = true;

message.on("mousedown", () => (message.style.fill = "red"));

app.ticker.add((delta) => {
  message.rotation += 0.01 * delta;
  message.x += 1;
});

ドラッグ&ドロップ

次はドラッグ&ドロップでテキストの場所をユーザが移動させる方法を確認します。

mousedownイベントの設定

ドラッグ&ドロップを行うためには、マウスのイベントを利用します。最初にテキストの上でマウスを押すとイベントが発火するmousedownを設定します。

clickイベントはマウスのボタンを押して、話した時にイベントが発火します。mousedownイベントはマウスのボタンを押すとイベントが発火します。
fukidashi

callbackに入っているeはeventの略で、e.data.global.xでマウスの現在の位置を取得することができます。


const app = new PIXI.Application();

document.body.appendChild(app.view);
const message = new PIXI.Text('Hello World!');
message.interactive = true;
message.x = 200;
message.y = 200;
message.style.fill = 'white';
message.on('mousedown', (e) => {
  message.x = e.data.global.x;
  message.y = e.data.global.y;
});
app.stage.addChild(message);

Hello Worldのテキスト文字にマウスダウンイベントを設定しているのでテキストの左端もしくは右端をクリックしてください。テキストの中心がマウスを押した場所に移動します。テキスト外の場所をクリックしてもテキストにイベントが設定されているだけなので何も起きません。

mousemoveイベント

マウスの移動に合わせてイベントが発火するmousemoveイベントを設定します。まず、テキストにmousemoveイベントを設定するとどのような動作になるか確認します。


message.on("mousemove", function (e) {
    message.x = e.data.global.x;
    message.y = e.data.global.y;
});

マウスの動きでイベントが発火するのでマウスのポインターが四角の中に入った瞬間にマウスポインターの場所までHello Worldのテキストが移動してきます。その後は四角の枠にマウスポインターがある間はずっとマウスについてきます。

下記ではマウスが右上から四角に入ったのでテキストも右上にいます。

四角に入るとテキストがマウスの場所に移動
四角に入るとテキストがマウスの場所に移動

ドラッグ&ドロップを実現したいので、テキストをクリック後(mousedown)からmousemoveイベントを発火させたいため、draggableというパラメータを設定します。

draggableという名前は任意なので、どのような名前をつけても動作します。
fukidashi

mousedownイベントを発火した際にdraggableをtrueにして、draggableがtrueの場合のみmousemoveでマウスの移動についていくように設定を行います。


message.on("mousedown", (e) => {
    message.x = e.data.global.x;
    message.y = e.data.global.y;
    message.draggable = true;
});

message.on("mousemove", function (e) {
    if (message.draggable) {
      message.x = e.data.global.x;
      message.y = e.data.global.y;
    }
});

ここまでの設定でドラッグが動作することが確認できます。一度ドラッグできるようになったテキストを離すことができません。ドロップを実現するためにmouseupイベントを利用します。

mouseupイベントの設定

mouseupイベントはmousedownボタンで押しているマウスのボタンが上がった時にイベントが発火します。このイベントが発火した時にdraggableをfalseにするとドラッグ処理が停止します。


message.on("mouseup", (e) => {
    message.x = e.data.global.x;
    message.y = e.data.global.y;
    message.draggable = false;
});

もう一点四角の外側にマウスが出た際にもmouseupするとドロップできるようにmouseupoutsideイベントを設定します。


message.on("mouseoutside", (e) => {
    message.x = e.data.global.x;
    message.y = e.data.global.y;
    message.draggable = false;
});

アルファ値を設定

ドラッグ&ドロップが行われていることがわかるようにアルファ値を設定し、透明度を変えます。


      message.on("mousedown", (e) => {
        message.x = e.data.global.x;
        message.y = e.data.global.y;
        message.draggable = true;
        message.alpha = 0.5;
      });

      message.on("mousemove", (e) => {
        if (message.draggable) {
          message.x = e.data.global.x;
          message.y = e.data.global.y;
        }
      });

      message.on("mouseup", (e) => {
        message.x = e.data.global.x;
        message.y = e.data.global.y;
        message.draggable = false;
        message.alpha = 1;
      });

      message.on("mouseoutside", (e) => {
        message.x = e.data.global.x;
        message.y = e.data.global.y;
        message.draggable = false;
        message.alpha = 1;
      });

ドラッグしている間はテキストが薄くなっていることがわかります。

ドラッグ中は透明度を変える
ドラッグ中は透明度を変える

複数のHello Worldを画面に表示

先ほど作成したドラッグ&ドロップのコードからテキストのmessageを作成する関数createTextを作成します。


const createText = (x, y) => {
    const message = new PIXI.Text("Hello World!");
    message.anchor.set(0.5);
    message.x = x;
    message.y = y;
    message.style.fill = "white";
    app.stage.addChild(message);

    message.interactive = true;

    message.on("mousedown", (e) => {
        message.x = e.data.global.x;
        message.y = e.data.global.y;
        message.draggable = true;
        message.alpha = 0.5;
    });

    message.on("mousemove", (e) => {
        if (message.draggable) {
        message.x = e.data.global.x;
        message.y = e.data.global.y;
        }
    });

    message.on("mouseup", (e) => {
        message.x = e.data.global.x;
        message.y = e.data.global.y;
        message.draggable = false;
        message.alpha = 1;
    });

    message.on("mouseoutside", (e) => {
        message.x = e.data.global.x;
        message.y = e.data.global.y;
        message.draggable = false;
        message.alpha = 1;
    });
};

forループを利用して画面上に50個のテキストを作成します。x, yのテキストの位置をランダムに決めています。app.screenは四角枠の幅と高さを取得することができます。


  for (let i = 0; i < 50; i++) {
    createText(
      Math.floor(Math.random() * app.screen.width),
      Math.floor(Math.random() * app.screen.height)
    );
  }

ブラウザで確認すると50のテキストが作成し、それぞれを個別にドラッグ&ドロップすることができます。

複数のメッセージを表示し個別にdrag&drop
複数のメッセージを表示し個別にdrag&drop

シンプルな動作確認しかしていませんPixiJsはいかがだったでしょうか。ブラウザ上に表示したテキストに対してアニメーション、イベントを設定してユーザとのインタラクティブな動作を行えることがわかりました。