rks
rks

Reputation: 61

Use an existing canvas without losing contents in pIxi.js

I am quite new to Pixi.js so I'm sorry this is a stupid question.

I understand that if I would like to render pixi.js to an existing canvas I have to specify view.

const app = new PIXI.Application({
    view: myExistingCanvas,
});

However, I realized that if I write like this, Pixi application actually overwrites my existing canvas and I end up losing all the contents inside "myExistingCanvas".

Could somebody advise me how I can create a pixi application on top of an existing canvas without overwriting?

Upvotes: 2

Views: 4230

Answers (1)

obscure
obscure

Reputation: 12891

Using the view property you can pass to the constrctor of a new PIXI.Application, we can tell it to use an existing Canvas. This canvas though doesn't necessarily have to be added to the DOM - it's enough if it exists 'virtually'.

So ultimately we need three Canvas instances - which all should have equal dimensions.

  • The first canvas would be the existing canvas you've mentioned in your question and act as an off-screen canvas
  • The second canvas is another empty off-screen canvas, which captures Pixi's output
  • The third canvas is actually the on-screen canvas which combines the output of the previous two canvases

Now you might wonder how to do this.

To do this we must intercept Pixi's update loop, which we can do by adding a ticker to PIXI.Ticker.shared.

Inside this update loop we need to do the following things:

  • Update Pixi's animations and call it's renderer
  • Clear the third (on-screen) canvas
  • Draw the contents of the first canvas to the third
  • Draw the contents of the second canvas to the third

Basically that's it - though it might sound a bit abstract.

Here's an example (Just click on 'Run code snippet'):

let offScreenCanvasA = document.createElement("canvas");
let offScreenCanvasB = document.createElement("canvas");
let onScreenCanvas = document.createElement("canvas");
let width = 400;
let height = 300;


offScreenCanvasA.width = width;
offScreenCanvasB.width = width;
onScreenCanvas.width = width;

offScreenCanvasA.height = height;
offScreenCanvasB.height = height;
onScreenCanvas.height = height;

document.body.appendChild(onScreenCanvas);

const app = new PIXI.Application({
  view: offScreenCanvasB,
  transparent: true,
  width: 400,
  height: 300
});


const container = new PIXI.Container();
const renderer = PIXI.autoDetectRenderer();

app.stage.addChild(container);

const texture = PIXI.Texture.from('https://picsum.photos/id/237/26/37');

for (let i = 0; i < 25; i++) {
  const bunny = new PIXI.Sprite(texture);
  bunny.anchor.set(0.5);
  bunny.x = (i % 5) * 40;
  bunny.y = Math.floor(i / 5) * 40;
  container.addChild(bunny);
}

container.x = app.screen.width / 2;
container.y = app.screen.height / 2;
container.pivot.x = container.width / 2;
container.pivot.y = container.height / 2;

let ticker = PIXI.Ticker.shared
ticker.add(function(delta) {
  container.rotation -= 0.01;
  renderer.render(container);
  onScreenCanvas.getContext("2d").clearRect(0, 0, width, height);
  onScreenCanvas.getContext("2d").drawImage(offScreenCanvasA, 0, 0, width, height);
  onScreenCanvas.getContext("2d").drawImage(offScreenCanvasB, 0, 0, width, height);
});

let image = new Image();
image.onload = function(e) {
  offScreenCanvasA.getContext("2d").drawImage(e.target, 0, 0, width, height);
}
image.src = "https://picsum.photos/id/237/400/300";
<script src="https://d157l7jdn8e5sf.cloudfront.net/dev/pixi-legacy.js"></script>

The dog picture in the background is the from the first canvas, and the rotating grid of dogs Pixi's output to the second canvas.

Upvotes: 3

Related Questions