Pixi.js Viewport 예제코드

|

Pixi.js Viewport 예제코드

PixiView.vue

<template>
  <div id="container">
    <canvas id="pixi-canvas"></canvas>
  </div>
</template>

<script>
import "./js/pixi-app";
import { PixiApp } from "./js/pixi-app";
export default {
  mounted() {
    this.createPixiApp();
  },
  methods: {
    createPixiApp() {
      const app = new PixiApp(800, 600);
      const canvas = document.getElementById("pixi-canvas");
      canvas.appendChild(app.view);
      console.log(`window size(${window.innerWidth}, ${window.innerHeight})`);
      console.log(`app size(${app.view.width}, ${app.view.height})`);
    },
  },
};
</script>

<style>
#container {
  display: block;
  width: 100vw;
  height: 100vh;
  background: whitesmoke;
}
#pixi-canvas {
  display: block;
  margin: 5%;
}
</style>

js/pixi-app.js

import * as PIXI from "pixi.js-legacy";
import { Viewport } from "pixi-viewport";

class PixiApp extends PIXI.Application {
  constructor(width, height) {
    super({
      width: width,
      height: height,
      backgroundColor: 0xffebee,
      antialias: true,
    });

    const screenWidth = 800;
    const screenHeight = 600;
    const worldWidth = screenWidth * 2;
    const worldHeight = screenHeight * 2;

    const viewport = new Viewport({
      screenWidth: screenWidth,
      screenHeight: screenHeight,
      worldWidth: worldWidth,
      worldHeight: worldHeight,

      interaction: this.renderer.plugins.interaction,
    });

    this.stage.addChild(viewport);

    const grid = this.#createGrid();
    viewport.addChild(grid);

    const boundary = this.#createBoundary(worldWidth, worldHeight);
    viewport.addChild(boundary);

    this.#registerViewportEventHandler(viewport);

    console.log(viewport);
    console.log(`Screen width: ${viewport.screenWidth}`);
    console.log(`World width: ${viewport.worldWidth}`); // World height, in pixels
    console.log(
      `Screen width in World pixels width(${viewport.screenWidthInWorldPixels})`
    ); // Get how many world pixels fit in screen's width
    console.log(`Screen World width(${viewport.screenWorldWidth})`); // World width in screen coordinates
    console.log(`World Screen width(${viewport.worldScreenWidth})`); // Screen width in world coordinates
    console.log(`Viewport Corner`, viewport.corner); // Screen width in world coordinates
    console.log(`Viewport Center`, viewport.center); // Screen width in world coordinates
  }

  #registerViewportEventHandler(viewport) {
    const screenWidth = 800;
    const screenHeight = 600;

    viewport
      .drag()
      .pinch()
      .wheel()
      .decelerate()
      .clamp({
        direction: "all",
        underflow: "center",
      })
      .clampZoom({
        minWidth: screenWidth,
        minHeight: screenHeight,
        maxWidth: screenWidth * 3,
        maxHeight: screenHeight * 3,
      })
      .clampZoom({
        minScale: 0.5,
        maxScale: 2,
      })
      .fit();

    viewport.on("pointerup", (e) => {
      const x = e.data.global.x;
      const y = e.data.global.y;
      console.log(`point UP (${x}, ${y})`); // Viewport 좌표
      console.log(`toScreen: `, viewport.toScreen(x, y));
      console.log(`toWorld: `, viewport.toWorld(x, y));
      console.log(`visibleBounds()`, viewport.getVisibleBounds());
    });
  }

  #createBoundary(width, height) {
    const container = new PIXI.Container();
    const boundary = new PIXI.Graphics();
    boundary.lineStyle(8, 0xff0000);
    boundary.drawRect(0, 0, width, height);
    container.addChild(boundary);

    return container;
  }

  #createGrid() {
    const container = new PIXI.Container();
    const origin = this.#createCrossPoint({
      x: 0,
      y: 0,
      color: 0xff0000,
      size: 50,
      fontsize: 14,
    });
    container.addChild(origin);

    for (let row = 0; row <= 20; row++) {
      for (let col = 0; col <= 20; col++) {
        if (row == 0 && col == 0) continue;

        const p = this.#createCrossPoint({
          x: col * 100,
          y: row * 100,
        });
        container.addChild(p);
      }
    }

    return container;
  }

  #createCrossPoint({
    x,
    y,
    color = 0x000000,
    size = 5,
    thickness = 1,
    fontsize = 8,
  }) {
    const container = new PIXI.Container();

    const grid = new PIXI.Graphics();
    grid.lineStyle(thickness, color);
    grid.moveTo(x - size, y);
    grid.lineTo(x + size, y);
    grid.moveTo(x, y - size);
    grid.lineTo(x, y + size);
    container.addChild(grid);

    const text = new PIXI.Text(`(${x},${y})`, {
      fontFamily: "Arial",
      fontSize: fontsize,
      fill: color,
    });
    text.position.set(x + 3, y + 3);
    container.addChild(text);

    return container;
  }
}

export { PixiApp };

실행화면

화면의 각 위치를 터치해보고, 화면을 panning으로 이동 후 각 위치를 터치, Zoom 등으로 화면을 확대/축소하면서 각 위치를 터치하면서 좌표계를 확인해볼 수 있습니다.

image

각 이벤트를 거쳐 전달되는 좌표값은 Viewport 상의 좌표이며, 이를 World 좌표로 변환하면 각 오브젝트가 그려진 Canvas 상의 좌표라고 볼 수 있습니다.